Last week of rasterizer

:p silly cats FTW
This commit is contained in:
2024-12-02 03:47:25 +01:00
parent 8f8605b76f
commit 98f3fc50cd
13 changed files with 636 additions and 475 deletions

View File

@@ -21,8 +21,6 @@ set(IMGUI_SOURCES
"imgui/backends/imgui_impl_sdlrenderer2.cpp" "imgui/backends/imgui_impl_sdlrenderer2.cpp"
) )
# Create the executable # Create the executable
add_executable(${PROJECT_NAME} ${SOURCES}) add_executable(${PROJECT_NAME} ${SOURCES})
#add_executable(${PROJECT_NAME} ${SOURCES} ${IMGUI_SOURCES}) #add_executable(${PROJECT_NAME} ${SOURCES} ${IMGUI_SOURCES})

BIN
project/resources/cat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -40,9 +40,10 @@ namespace dae {
float zNear{.1f}; float zNear{.1f};
float zFar{100.f}; float zFar{100.f};
void Initialize(float _fovAngle = 90.f, Vector3 _origin = {0.f, 0.f, 0.f}) { void Initialize(float _fovAngle = 90.f, Vector3 _origin = {0.f, 0.f, 0.f}, float _aspect = 1.f) {
fovAngle = _fovAngle; fovAngle = _fovAngle;
fov = tanf((fovAngle * TO_RADIANS) / 2.f); fov = tanf((fovAngle * TO_RADIANS) / 2.f);
aspect = _aspect;
origin = _origin; origin = _origin;
} }
@@ -54,15 +55,14 @@ namespace dae {
void CalculateViewMatrix() { void CalculateViewMatrix() {
viewMatrix = Matrix::CreateLookAtLH(origin, forward, up); viewMatrix = Matrix::CreateLookAtLH(origin, origin + forward, Vector3::UnitY);
invViewMatrix = Matrix::Inverse(viewMatrix); Matrix temp = viewMatrix;
//TODO W1 invViewMatrix = temp.Inverse();
//ONB => invViewMatrix
//Inverse(ONB) => ViewMatrix
//ViewMatrix => Matrix::CreateLookAtLH(...) [not implemented yet] right = invViewMatrix.GetAxisX();
//DirectX Implementation => https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixlookatlh up = invViewMatrix.GetAxisY();
forward = invViewMatrix.GetAxisZ();
} }
void CalculateProjectionMatrix() { void CalculateProjectionMatrix() {
@@ -77,43 +77,50 @@ namespace dae {
const float deltaTime = pTimer->GetElapsed(); const float deltaTime = pTimer->GetElapsed();
//Keyboard Input //Keyboard Input
const uint8_t *pKeyboardState = SDL_GetKeyboardState(nullptr); const uint8_t* pKeyboardState = SDL_GetKeyboardState(nullptr);
Vector3 zDirection{0.f, 0.f, 0.f}; Vector3 zDirection{ 0.f,0.f,0.f };
const Vector3 xDirection{0.f, 0.f, 0.f}; const Vector3 xDirection{ 0.f,0.f,0.f };
const Vector3 yDirection{0.f, 0.f, 0.f}; const Vector3 yDirection{ 0.f,0.f,0.f };
float MovementSpeed{10.f}; float MovementSpeed{ 10.f };
if (pKeyboardState[SDL_SCANCODE_LSHIFT]) { if (pKeyboardState[SDL_SCANCODE_LSHIFT])
{
MovementSpeed *= 2; MovementSpeed *= 2;
} }
if (pKeyboardState[SDL_SCANCODE_W]) { if (pKeyboardState[SDL_SCANCODE_W])
{
origin += forward * deltaTime * MovementSpeed; origin += forward * deltaTime * MovementSpeed;
} }
if (pKeyboardState[SDL_SCANCODE_A]) { if (pKeyboardState[SDL_SCANCODE_A])
{
origin -= right * deltaTime * MovementSpeed; origin -= right * deltaTime * MovementSpeed;
} }
if (pKeyboardState[SDL_SCANCODE_S]) { if (pKeyboardState[SDL_SCANCODE_S])
{
origin -= forward * deltaTime * MovementSpeed; origin -= forward * deltaTime * MovementSpeed;
} }
if (pKeyboardState[SDL_SCANCODE_D]) { if (pKeyboardState[SDL_SCANCODE_D])
{
origin += right * deltaTime * MovementSpeed; origin += right * deltaTime * MovementSpeed;
} }
if (pKeyboardState[SDL_SCANCODE_E]) { if (pKeyboardState[SDL_SCANCODE_E])
{
origin += up * deltaTime * MovementSpeed; origin += up * deltaTime * MovementSpeed;
} }
if (pKeyboardState[SDL_SCANCODE_Q]) { if (pKeyboardState[SDL_SCANCODE_Q])
{
origin -= up * deltaTime * MovementSpeed; origin -= up * deltaTime * MovementSpeed;
} }
//Mouse Input //Mouse Input
bool mousePosChange{false}; bool mousePosChange{ false };
int mouseX{}, mouseY{}; int mouseX{}, mouseY{};
const uint32_t mouseState = SDL_GetRelativeMouseState(&mouseX, &mouseY); const uint32_t mouseState = SDL_GetRelativeMouseState(&mouseX, &mouseY);
mouseY *= -1; mouseY *= -1;
@@ -125,13 +132,16 @@ namespace dae {
totalPitch += (static_cast<float>(mouseY) * mouseSens) * TO_RADIANS; totalPitch += (static_cast<float>(mouseY) * mouseSens) * TO_RADIANS;
mousePosChange = true; mousePosChange = true;
} else if (mouseState == SDL_BUTTON_LEFT) { }
else if (mouseState == SDL_BUTTON_LEFT)
{
zDirection = forward.Normalized() * static_cast<float>(-mouseY); zDirection = forward.Normalized() * static_cast<float>(-mouseY);
totalYaw += static_cast<float>(mouseX) * mouseSens * TO_RADIANS; totalYaw += static_cast<float>(mouseX) * mouseSens * TO_RADIANS;
mousePosChange = true; mousePosChange = true;
} else if (mouseState == SDL_BUTTON_X2) //lmb + rmb }
else if (mouseState == SDL_BUTTON_X2) //lmb + rmb
{ {
origin.y += static_cast<float>(mouseY) / 2; origin.y += static_cast<float>(mouseY) / 2;
@@ -140,11 +150,12 @@ namespace dae {
origin += ((zDirection + xDirection + yDirection) * cameraSpeed * deltaTime); origin += ((zDirection + xDirection + yDirection) * cameraSpeed * deltaTime);
if (mousePosChange) { if (mousePosChange)
const Matrix yawMatrix{Matrix::CreateRotationY(totalYaw)}; {
const Matrix pitchMatrix{Matrix::CreateRotationX(totalPitch)}; const Matrix yawMatrix{ Matrix::CreateRotationY(totalYaw) };
const Matrix pitchMatrix{ Matrix::CreateRotationX(totalPitch) };
const Matrix finalRotation{pitchMatrix * yawMatrix}; const Matrix finalRotation{ pitchMatrix * yawMatrix };
forward = finalRotation.TransformVector(Vector3::UnitZ); forward = finalRotation.TransformVector(Vector3::UnitZ);
forward.Normalize(); forward.Normalize();
} }
@@ -152,6 +163,7 @@ namespace dae {
//Update Matrices //Update Matrices
CalculateViewMatrix(); CalculateViewMatrix();
CalculateProjectionMatrix(); //Try to optimize this - should only be called once or when fov/aspectRatio changes CalculateProjectionMatrix(); //Try to optimize this - should only be called once or when fov/aspectRatio changes
} }
}; };
} }

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "MathHelpers.h" #include "MathHelpers.h"
#include <algorithm>
namespace dae namespace dae
{ {

View File

@@ -8,22 +8,23 @@ namespace dae
{ {
struct Vertex struct Vertex
{ {
Vector3 position{}; Vector4 position{};
ColorRGB color{colors::White}; ColorRGB color{colors::White};
Vector2 uv{}; //W2 Vector2 uv{};
//Vector3 normal{}; //W4 bool valid{ true };
//Vector3 tangent{}; //W4 Vector3 normal{};
//Vector3 viewDirection{}; //W4 Vector3 tangent{};
Vector3 viewDir{};
}; };
struct Vertex_Out struct Sample
{ {
Vector4 position{};
ColorRGB color{ colors::White };
Vector2 uv{}; Vector2 uv{};
//Vector3 normal{}; Vector3 normal{};
//Vector3 tangent{}; Vector3 tangent{};
//Vector3 viewDirection{}; Vector3 viewDirection{};
float depth{};
Vector3 weight{};
}; };
enum class PrimitiveTopology enum class PrimitiveTopology
@@ -36,9 +37,9 @@ namespace dae
{ {
std::vector<Vertex> vertices{}; std::vector<Vertex> vertices{};
std::vector<uint32_t> indices{}; std::vector<uint32_t> indices{};
PrimitiveTopology primitiveTopology{ PrimitiveTopology::TriangleStrip }; PrimitiveTopology primitiveTopology{ PrimitiveTopology::TriangleList };
std::vector<Vertex_Out> vertices_out{}; std::vector<Vertex> vertices_out{};
Matrix worldMatrix{}; Matrix worldMatrix{};
}; };
} }

View File

@@ -15,11 +15,84 @@ float max(float a, float b, float c) {
float CrossZ(const Vector3& p0, const Vector3& p1, const Vector3& point) float CrossZ(const Vector3& p0, const Vector3& p1, const Vector3& point)
{ {
return (point.x - p0.x) * (p1.y - p0.y) return (p1.x - p0.x) * (point.y - p0.y)
- (point.y - p0.y) * (p1.x - p0.x); - (p1.y - p0.y) * (point.x - p0.x);
} }
template<typename Type>
Type interpolate(const Type& val0, const Type& val1, const Type& val2, float depth, float weight)
{
return {
val0 * depth * weight +
val1 * depth * weight +
val2 * depth * weight
};
}
std::optional<Sample> HitTest::TriangleHitTest(const Vector3& fragPos, const Vertex& v0, const Vertex& v1, const Vertex& 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
};
}
HitTest::HitTestSample HitTest::Triangle(const Vector3 &pos, const std::vector<Vertex> &vertices) { HitTest::HitTestSample HitTest::Triangle(const Vector3 &pos, const std::vector<Vertex> &vertices) {
float minX = min(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x); float minX = min(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x);
float maxX = max(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x); float maxX = max(vertices[0].position.x, vertices[1].position.x, vertices[2].position.x);
@@ -46,9 +119,10 @@ HitTest::HitTestSample HitTest::Triangle(const Vector3 &pos, const std::vector<V
} }
const double totalWeight{ w0 + w1 + w2 }; const double totalWeight{ w0 + w1 + w2 };
w0 /= totalWeight; const float invTotalWeight{ static_cast<float>(1.0f / totalWeight) };
w1 /= totalWeight; w0 *= invTotalWeight;
w2 /= totalWeight; w1 *= invTotalWeight;
w2 *= invTotalWeight;
assert(std::abs(w0 + w1 + w2 - 1) < 0.0001); assert(std::abs(w0 + w1 + w2 - 1) < 0.0001);

View File

@@ -5,6 +5,7 @@
#ifndef GP1_RASTERIZER_HITTEST_H #ifndef GP1_RASTERIZER_HITTEST_H
#define GP1_RASTERIZER_HITTEST_H #define GP1_RASTERIZER_HITTEST_H
#include <optional>
#include "DataTypes.h" #include "DataTypes.h"
#include "Maths.h" #include "Maths.h"
@@ -17,6 +18,9 @@ namespace HitTest {
}; };
HitTestSample Triangle(const Vector3& pos, const std::vector<Vertex>& vertices); HitTestSample Triangle(const Vector3& pos, const std::vector<Vertex>& vertices);
std::optional<Sample> TriangleHitTest(const Vector3& fragPos, const Vertex& v0, const Vertex& v1, const Vertex& v2);
} }
#endif //GP1_RASTERIZER_HITTEST_H #endif //GP1_RASTERIZER_HITTEST_H

View File

@@ -6,34 +6,29 @@
#include <cmath> #include <cmath>
namespace dae { namespace dae {
Matrix::Matrix(const Vector3& xAxis, const Vector3& yAxis, const Vector3& zAxis, const Vector3& t) : Matrix::Matrix(const Vector3 &xAxis, const Vector3 &yAxis, const Vector3 &zAxis, const Vector3 &t) :
Matrix({ xAxis, 0 }, { yAxis, 0 }, { zAxis, 0 }, { t, 1 }) Matrix({xAxis, 0}, {yAxis, 0}, {zAxis, 0}, {t, 1}) {
{
} }
Matrix::Matrix(const Vector4& xAxis, const Vector4& yAxis, const Vector4& zAxis, const Vector4& t) Matrix::Matrix(const Vector4 &xAxis, const Vector4 &yAxis, const Vector4 &zAxis, const Vector4 &t) {
{
data[0] = xAxis; data[0] = xAxis;
data[1] = yAxis; data[1] = yAxis;
data[2] = zAxis; data[2] = zAxis;
data[3] = t; data[3] = t;
} }
Matrix::Matrix(const Matrix& m) Matrix::Matrix(const Matrix &m) {
{
data[0] = m[0]; data[0] = m[0];
data[1] = m[1]; data[1] = m[1];
data[2] = m[2]; data[2] = m[2];
data[3] = m[3]; data[3] = m[3];
} }
Vector3 Matrix::TransformVector(const Vector3& v) const Vector3 Matrix::TransformVector(const Vector3 &v) const {
{
return TransformVector(v.x, v.y, v.z); return TransformVector(v.x, v.y, v.z);
} }
Vector3 Matrix::TransformVector(float x, float y, float z) const Vector3 Matrix::TransformVector(float x, float y, float z) const {
{
return Vector3{ return Vector3{
data[0].x * x + data[1].x * y + data[2].x * z, 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].y * x + data[1].y * y + data[2].y * z,
@@ -41,13 +36,11 @@ namespace dae {
}; };
} }
Vector3 Matrix::TransformPoint(const Vector3& p) const Vector3 Matrix::TransformPoint(const Vector3 &p) const {
{
return TransformPoint(p.x, p.y, p.z); return TransformPoint(p.x, p.y, p.z);
} }
Vector3 Matrix::TransformPoint(float x, float y, float z) const Vector3 Matrix::TransformPoint(float x, float y, float z) const {
{
return Vector3{ return Vector3{
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x, 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].y * x + data[1].y * y + data[2].y * z + data[3].y,
@@ -55,13 +48,11 @@ namespace dae {
}; };
} }
Vector4 Matrix::TransformPoint(const Vector4& p) const Vector4 Matrix::TransformPoint(const Vector4 &p) const {
{
return TransformPoint(p.x, p.y, p.z, p.w); return TransformPoint(p.x, p.y, p.z, p.w);
} }
Vector4 Matrix::TransformPoint(float x, float y, float z, float w) const Vector4 Matrix::TransformPoint(float x, float y, float z, float w) const {
{
return Vector4{ return Vector4{
data[0].x * x + data[1].x * y + data[2].x * z + data[3].x, 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].y * x + data[1].y * y + data[2].y * z + data[3].y,
@@ -70,13 +61,10 @@ namespace dae {
}; };
} }
const Matrix& Matrix::Transpose() const Matrix &Matrix::Transpose() {
{
Matrix result{}; Matrix result{};
for (int r{ 0 }; r < 4; ++r) for (int r{0}; r < 4; ++r) {
{ for (int c{0}; c < 4; ++c) {
for (int c{ 0 }; c < 4; ++c)
{
result[r][c] = data[c][r]; result[r][c] = data[c][r];
} }
} }
@@ -89,13 +77,12 @@ namespace dae {
return *this; return *this;
} }
const Matrix& Matrix::Inverse() const Matrix &Matrix::Inverse() {
{
//Optimized Inverse as explained in FGED1 - used widely in other libraries too. //Optimized Inverse as explained in FGED1 - used widely in other libraries too.
const Vector3& a = data[0]; const Vector3 &a = data[0];
const Vector3& b = data[1]; const Vector3 &b = data[1];
const Vector3& c = data[2]; const Vector3 &c = data[2];
const Vector3& d = data[3]; const Vector3 &d = data[3];
const float x = data[0][3]; const float x = data[0][3];
const float y = data[1][3]; const float y = data[1][3];
@@ -111,89 +98,103 @@ namespace dae {
assert((!AreEqual(det, 0.f)) && "ERROR: determinant is 0, there is no INVERSE!"); assert((!AreEqual(det, 0.f)) && "ERROR: determinant is 0, there is no INVERSE!");
float invDet = 1.f / det; float invDet = 1.f / det;
s *= invDet; t *= invDet; u *= invDet; v *= invDet; s *= invDet;
t *= invDet;
u *= invDet;
v *= invDet;
Vector3 r0 = Vector3::Cross(b, v) + t * y; Vector3 r0 = Vector3::Cross(b, v) + t * y;
Vector3 r1 = Vector3::Cross(v, a) - t * x; Vector3 r1 = Vector3::Cross(v, a) - t * x;
Vector3 r2 = Vector3::Cross(d, u) + s * w; Vector3 r2 = Vector3::Cross(d, u) + s * w;
Vector3 r3 = Vector3::Cross(u, c) - s * z; Vector3 r3 = Vector3::Cross(u, c) - s * z;
data[0] = Vector4{ r0.x, r1.x, r2.x, 0.f }; data[0] = Vector4{r0.x, r1.x, r2.x, 0.f};
data[1] = Vector4{ r0.y, r1.y, r2.y, 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[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)} }; data[3] = {{-Vector3::Dot(b, t)},
{Vector3::Dot(a, t)},
{-Vector3::Dot(d, s)},
{Vector3::Dot(c, s)}};
return *this; return *this;
} }
Matrix Matrix::Transpose(const Matrix& m) Matrix Matrix::Transpose(const Matrix &m) {
{ Matrix out{m};
Matrix out{ m };
out.Transpose(); out.Transpose();
return out; return out;
} }
Matrix Matrix::Inverse(const Matrix& m) Matrix Matrix::Inverse(const Matrix &m) {
{ Matrix out{m};
Matrix out{ m };
out.Inverse(); out.Inverse();
return out; return out;
} }
Matrix Matrix::CreateLookAtLH(const Vector3& origin, const Vector3& forward, const Vector3& up) Matrix Matrix::CreateLookAtLH(const Vector3 &origin, const Vector3 &forward, const Vector3 &up) {
{ Vector3 zAxis = (forward - origin).Normalized();
Vector3 zAxis = forward.Normalized();
Vector3 xAxis = Vector3::Cross(up, zAxis).Normalized(); Vector3 xAxis = Vector3::Cross(up, zAxis).Normalized();
Vector3 yAxis = Vector3::Cross(zAxis, xAxis); Vector3 yAxis = Vector3::Cross(zAxis, xAxis).Normalized();
Vector3 trans =
return { xAxis, yAxis, zAxis, origin }; {
} -Vector3::Dot(xAxis, origin),
-Vector3::Dot(yAxis, origin),
Matrix Matrix::CreatePerspectiveFovLH(float fov, float aspect, float zn, float zf) { -Vector3::Dot(zAxis, origin)
const float yScale = 1.f / tanf(fov / 2.f); };
const float xScale = yScale / aspect;
return { return {
{ xScale, 0, 0, 0 }, {xAxis.x, yAxis.x, zAxis.x},
{ 0, yScale, 0, 0 }, {xAxis.y, yAxis.y, zAxis.y},
{ 0, 0, zf / (zf - zn), 1 }, {xAxis.z, yAxis.z, zAxis.z},
{ 0, 0, -zn * zf / (zf - zn), 0 } {trans.x, trans.y, trans.z}
}; };
} }
Vector3 Matrix::GetAxisX() const
{ Matrix Matrix::CreatePerspectiveFovLH(float fovy, float aspect, float zn, float zf) {
// const float yScale = 1.f / tanf(fovy / 2.f);
// const float xScale = yScale / aspect;
//
// return {
// {xScale, 0, 0, 0},
// {0, yScale, 0, 0},
// {0, 0, zf / (zf - zn), 1},
// {0, 0, -zn * zf / (zf - zn), 0}
// };
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]; return data[0];
} }
Vector3 Matrix::GetAxisY() const Vector3 Matrix::GetAxisY() const {
{
return data[1]; return data[1];
} }
Vector3 Matrix::GetAxisZ() const Vector3 Matrix::GetAxisZ() const {
{
return data[2]; return data[2];
} }
Vector3 Matrix::GetTranslation() const Vector3 Matrix::GetTranslation() const {
{
return data[3]; return data[3];
} }
Matrix Matrix::CreateTranslation(float x, float y, float z) Matrix Matrix::CreateTranslation(float x, float y, float z) {
{ return CreateTranslation({x, y, z});
return CreateTranslation({ x, y, z });
} }
Matrix Matrix::CreateTranslation(const Vector3& t) Matrix Matrix::CreateTranslation(const Vector3 &t) {
{ return {Vector3::UnitX, Vector3::UnitY, Vector3::UnitZ, t};
return { Vector3::UnitX, Vector3::UnitY, Vector3::UnitZ, t };
} }
Matrix Matrix::CreateRotationX(float pitch) Matrix Matrix::CreateRotationX(float pitch) {
{
return { return {
{1, 0, 0, 0}, {1, 0, 0, 0},
{0, cos(pitch), -sin(pitch), 0}, {0, cos(pitch), -sin(pitch), 0},
@@ -202,8 +203,7 @@ namespace dae {
}; };
} }
Matrix Matrix::CreateRotationY(float yaw) Matrix Matrix::CreateRotationY(float yaw) {
{
return { return {
{cos(yaw), 0, -sin(yaw), 0}, {cos(yaw), 0, -sin(yaw), 0},
{0, 1, 0, 0}, {0, 1, 0, 0},
@@ -212,8 +212,7 @@ namespace dae {
}; };
} }
Matrix Matrix::CreateRotationZ(float roll) Matrix Matrix::CreateRotationZ(float roll) {
{
return { return {
{cos(roll), sin(roll), 0, 0}, {cos(roll), sin(roll), 0, 0},
{-sin(roll), cos(roll), 0, 0}, {-sin(roll), cos(roll), 0, 0},
@@ -222,48 +221,40 @@ namespace dae {
}; };
} }
Matrix Matrix::CreateRotation(float pitch, float yaw, float roll) Matrix Matrix::CreateRotation(float pitch, float yaw, float roll) {
{ return CreateRotation({pitch, yaw, roll});
return CreateRotation({ pitch, yaw, roll });
} }
Matrix Matrix::CreateRotation(const Vector3& r) Matrix Matrix::CreateRotation(const Vector3 &r) {
{
return CreateRotationX(r[0]) * CreateRotationY(r[1]) * CreateRotationZ(r[2]); return CreateRotationX(r[0]) * CreateRotationY(r[1]) * CreateRotationZ(r[2]);
} }
Matrix Matrix::CreateScale(float sx, float sy, float sz) Matrix Matrix::CreateScale(float sx, float sy, float sz) {
{ return {{sx, 0, 0}, {0, sy, 0}, {0, 0, sz}, Vector3::Zero};
return { {sx, 0, 0}, {0, sy, 0}, {0, 0, sz}, Vector3::Zero };
} }
Matrix Matrix::CreateScale(const Vector3& s) Matrix Matrix::CreateScale(const Vector3 &s) {
{
return CreateScale(s[0], s[1], s[2]); return CreateScale(s[0], s[1], s[2]);
} }
#pragma region Operator Overloads #pragma region Operator Overloads
Vector4& Matrix::operator[](int index)
{ Vector4 &Matrix::operator[](int index) {
assert(index <= 3 && index >= 0); assert(index <= 3 && index >= 0);
return data[index]; return data[index];
} }
Vector4 Matrix::operator[](int index) const Vector4 Matrix::operator[](int index) const {
{
assert(index <= 3 && index >= 0); assert(index <= 3 && index >= 0);
return data[index]; return data[index];
} }
Matrix Matrix::operator*(const Matrix& m) const Matrix Matrix::operator*(const Matrix &m) const {
{
Matrix result{}; Matrix result{};
Matrix m_transposed = Transpose(m); Matrix m_transposed = Transpose(m);
for (int r{ 0 }; r < 4; ++r) for (int r{0}; r < 4; ++r) {
{ for (int c{0}; c < 4; ++c) {
for (int c{ 0 }; c < 4; ++c)
{
result[r][c] = Vector4::Dot(data[r], m_transposed[c]); result[r][c] = Vector4::Dot(data[r], m_transposed[c]);
} }
} }
@@ -271,15 +262,12 @@ namespace dae {
return result; return result;
} }
const Matrix& Matrix::operator*=(const Matrix& m) const Matrix &Matrix::operator*=(const Matrix &m) {
{ Matrix copy{*this};
Matrix copy{ *this };
Matrix m_transposed = Transpose(m); Matrix m_transposed = Transpose(m);
for (int r{ 0 }; r < 4; ++r) for (int r{0}; r < 4; ++r) {
{ for (int c{0}; c < 4; ++c) {
for (int c{ 0 }; c < 4; ++c)
{
data[r][c] = Vector4::Dot(copy[r], m_transposed[c]); data[r][c] = Vector4::Dot(copy[r], m_transposed[c]);
} }
} }
@@ -287,8 +275,7 @@ namespace dae {
return *this; return *this;
} }
bool Matrix::operator==(const Matrix& m) const bool Matrix::operator==(const Matrix &m) const {
{
return data[0] == m.data[0] return data[0] == m.data[0]
&& data[1] == m.data[1] && data[1] == m.data[1]
&& data[2] == m.data[2] && data[2] == m.data[2]

View File

@@ -1,11 +1,14 @@
//External includes //External includes
#include <iostream> #include <iostream>
#include <SDL.h>
#include <array>
#include "SDL_surface.h" #include "SDL_surface.h"
//Project includes //Project includes
#include "Renderer.h" #include "Renderer.h"
#include "Maths.h" #include "Maths.h"
#include "HitTest.h" #include "HitTest.h"
#include "utils.h"
using namespace dae; using namespace dae;
@@ -21,13 +24,16 @@ Renderer::Renderer(SDL_Window *pWindow) : m_pWindow(pWindow) {
m_pDepthBufferPixels = new float[m_Width * m_Height]; m_pDepthBufferPixels = new float[m_Width * m_Height];
//Initialize Camera //Initialize Camera
m_Camera.Initialize(60.f, {.0f, .0f, -10.f});
//Initialize Camera
m_Camera.Initialize(60.f, {.0f, .0f, -10.f});
m_aspectRatio = static_cast<float>(m_Width) / static_cast<float>(m_Height); m_aspectRatio = static_cast<float>(m_Width) / static_cast<float>(m_Height);
m_Camera.Initialize(45.f, {.0f, 5.0f, -64.f}, m_aspectRatio);
m_pTexture = Texture::LoadFromFile("./Resources/uv_grid_2.png"); m_currentDiffuse = Texture::LoadFromFile("./Resources/vehicle_diffuse.png");
m_currentGloss = Texture::LoadFromFile("./Resources/vehicle_gloss.png");
m_currentNormal = Texture::LoadFromFile("./Resources/vehicle_normal.png");
m_currentSpecular = Texture::LoadFromFile("./Resources/vehicle_specular.png");
Utils::ParseOBJ("./Resources/vehicle.obj", m_mesh.vertices, m_mesh.indices, false);
m_worldMeshes.push_back(m_mesh);
} }
Renderer::~Renderer() { Renderer::~Renderer() {
@@ -36,6 +42,11 @@ Renderer::~Renderer() {
void Renderer::Update(Timer *pTimer) { void Renderer::Update(Timer *pTimer) {
m_Camera.Update(pTimer); m_Camera.Update(pTimer);
//Rotate the mesh
if(m_isRotating){
m_worldMeshes[0].worldMatrix = Matrix::CreateRotationY(SDL_GetTicks() / 1000.f);
}
} }
void Renderer::Render() { void Renderer::Render() {
@@ -54,10 +65,11 @@ void Renderer::Render() {
constexpr int numVerticies = 3; constexpr int numVerticies = 3;
std::vector<Vertex> verticiesScreenSpace{}; std::vector<Vertex> verticiesScreenSpace{};
// VertexTransformationFunction(m_verticiesWorld, verticiesScreenSpace);
for (const Mesh &currentMesh: m_meshesWorldStrip) { for (const Mesh &currentMesh: m_worldMeshes) {
VertexTransformationFunction(currentMesh.vertices, verticiesScreenSpace);
const Matrix worldViewProjectionMatrix{ currentMesh.worldMatrix * m_Camera.viewMatrix * m_Camera.ProjectionMatrix };
VertexTransformationFunction(worldViewProjectionMatrix, currentMesh, currentMesh.vertices, verticiesScreenSpace);
int numTriangles{}; int numTriangles{};
@@ -97,6 +109,10 @@ void Renderer::Render() {
} }
break; 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 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 minY{std::min(vertex0.position.y, std::min(vertex1.position.y, vertex2.position.y))};
@@ -127,44 +143,31 @@ void Renderer::Render() {
Vector3 P{static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f}; Vector3 P{static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f};
const Vector3 cross0{Vector3::Cross(vertex2.position - vertex1.position, P - vertex1.position)}; auto sample{ HitTest::TriangleHitTest(P, vertex0, vertex1, vertex2) };
if (cross0.z < 0) {
continue; if (!sample.has_value()) {
}
const Vector3 cross1{Vector3::Cross(vertex0.position - vertex2.position, P - vertex2.position)};
if (cross1.z < 0) {
continue;
}
const Vector3 cross2{Vector3::Cross(vertex1.position - vertex0.position, P - vertex0.position)};
if (cross2.z < 0) {
continue; continue;
} }
const int depthBufferIndex{px + (py * m_Width)}; const Vector3 fragPos{ static_cast<float>(px) + 0.5f, static_cast<float>(py) + 0.5f, 1.f };
float totalWeight{cross0.z + cross1.z + cross2.z}; int depthBufferIndex{ px + (py * m_Width) };
Vector3 weights{
cross0.z / totalWeight,
cross1.z / totalWeight,
cross2.z / totalWeight,
};
const float currentDepth = float min{.985f};
1 / (weights.x / vertex0.position.z + float max{1.f};
weights.y / vertex1.position.z + float depthBuffer{(sample.value().depth - min) * (max - min)};
weights.z / vertex2.position.z); float currentDepth = sample.value().depth;
const Vector2 UvCoords = if (m_pDepthBufferPixels[depthBufferIndex] > currentDepth) {
vertex0.uv * currentDepth * weights.x / vertex0.position.z +
vertex1.uv * currentDepth * weights.y / vertex1.position.z +
vertex2.uv * currentDepth * weights.z / vertex2.position.z;
if (m_pDepthBufferPixels[depthBufferIndex] >= currentDepth) {
m_pDepthBufferPixels[depthBufferIndex] = currentDepth; m_pDepthBufferPixels[depthBufferIndex] = currentDepth;
//Update Color in Buffer if (m_isDepthBuffer) {
finalColor = m_pTexture->Sample(UvCoords); finalColor = ColorRGB{depthBuffer, depthBuffer, depthBuffer};
} else {
// finalColor = m_pTexture->Sample(UvCoords);
finalColor = shadePixel(sample.value());
}
finalColor.MaxToOne(); finalColor.MaxToOne();
m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format, m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format,
@@ -174,28 +177,14 @@ void Renderer::Render() {
} }
} }
} }
} }
} }
int x, y{0};
//For loop over all the pixels
for (int px{}; px < 100; ++px) {
for (int py{}; py < 100; ++py) {
//Get the pixel position
x = px;
y = py;
ColorRGB test = m_pTexture->Sample(Vector2{static_cast<float>(px) / 100, static_cast<float>(py) / 100});
m_pBackBufferPixels[x + (y * m_Width)] = SDL_MapRGB(m_pBackBuffer->format,
static_cast<uint8_t>(test.r * 255),
static_cast<uint8_t>(test.g * 255),
static_cast<uint8_t>(test.b * 255));
}
}
//RENDER LOGIC //RENDER LOGIC
@@ -205,20 +194,117 @@ void Renderer::Render() {
SDL_UpdateWindowSurface(m_pWindow); SDL_UpdateWindowSurface(m_pWindow);
} }
void Renderer::VertexTransformationFunction(const std::vector<Vertex> &vertices_in, void Renderer::VertexTransformationFunction(const Matrix& WorldViewProjectionMatrix, const Mesh& mesh, const std::vector<Vertex> &vertices_in,
std::vector<Vertex> &vertices_out) const { std::vector<Vertex> &vertices_out) const {
for (const Vertex &vert: vertices_in) { // vertices_out.clear();
Vector3 vertPos{m_Camera.invViewMatrix.TransformPoint(vert.position)}; for (const Vertex& vert : vertices_in)
{
Vertex vertex_out{};
vertPos.x = (vertPos.x / vertPos.z) / (m_aspectRatio * m_Camera.fov); Vector4 vertPos{ WorldViewProjectionMatrix.TransformPoint({vert.position.GetXYZ(), 1}) };
vertPos.y = (vertPos.y / vertPos.z) / m_Camera.fov;
vertPos.x = (vertPos.x + 1) / 2 * static_cast<float>(m_Width); const Vector3 normal{ mesh.worldMatrix.TransformVector(vert.normal) };
vertPos.y = (1 - vertPos.y) / 2 * static_cast<float>(m_Height); const Vector3 tangent{ mesh.worldMatrix.TransformVector(vert.tangent) };
vertices_out.push_back(Vertex{vertPos, vert.color, vert.uv});
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.color = vert.color;
vertex_out.uv = vert.uv;
vertex_out.normal = normal;
vertex_out.tangent = tangent;
vertex_out.viewDir = WorldViewProjectionMatrix.TransformVector(vert.viewDir);
vertex_out.valid = isValid;
vertices_out.push_back(vertex_out);
} }
} }
bool Renderer::SaveBufferToImage() const { bool Renderer::SaveBufferToImage() const {
return SDL_SaveBMP(m_pBackBuffer, "Rasterizer_ColorBuffer.bmp"); return SDL_SaveBMP(m_pBackBuffer, "Rasterizer_ColorBuffer.bmp");
} }
ColorRGB Renderer::shadePixel(const Sample &sample) {
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{ m_currentNormal->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{ m_currentDiffuse->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 *= m_currentGloss->Sample(sample.uv).r;
shininess *= m_currentSpecular->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;
}

View File

@@ -11,8 +11,16 @@
struct SDL_Window; struct SDL_Window;
struct SDL_Surface; struct SDL_Surface;
namespace dae { namespace dae {
enum class ShadeMode{
ObservedArea,
Diffuse,
Specular,
Combined
};
struct Mesh; struct Mesh;
class Timer; class Timer;
@@ -40,7 +48,48 @@ namespace dae {
bool SaveBufferToImage() const; bool SaveBufferToImage() const;
void void
VertexTransformationFunction(const std::vector<Vertex> &vertices_in, std::vector<Vertex> &vertices_out) const; VertexTransformationFunction(const Matrix& WorldViewProjectionMatrix, const Mesh& mesh, const std::vector<Vertex> &vertices_in, std::vector<Vertex> &vertices_out) const;
ColorRGB shadePixel(const Sample& sample);
void SwitchDepthBuffer(){
m_isDepthBuffer = !m_isDepthBuffer;
}
void SetShadeMode(ShadeMode mode) {
m_ShadeMode = mode;
}
void ToggleRotation(){
m_isRotating = !m_isRotating;
std::cout << "Rotation: " << m_isRotating << std::endl;
}
void ToggleNormals(){
m_useNormals = !m_useNormals;
std::cout << "Use Normals: " << m_useNormals << std::endl;
}
void 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;
}
}
private: private:
SDL_Window *m_pWindow{}; SDL_Window *m_pWindow{};
@@ -56,83 +105,22 @@ namespace dae {
float m_aspectRatio{}; float m_aspectRatio{};
Texture* m_pTexture{ nullptr }; Texture* m_currentDiffuse{ nullptr };
// Texture* m_currentGloss{ nullptr };
// std::vector<Vertex> m_verticiesWorld{ Texture* m_currentNormal{ nullptr };
// //Triangle 0 Texture* m_currentSpecular{ nullptr };
// {{0.f,2.f,0.f}, {1,0,0}},
// {{1.5f,-1.f,0.f}, {1,0,0}},
// {{-1.5f,-1.f,0.f}, {1,0,0}},
//
// //Triangle 1
// {{0.f,4.f,2.f}, {1,0,0}},
// {{3.f,-2.f,2.f}, {0,1,0}},
// {{-3.f,-2.f,2.f}, {0,0,1}}
// };
std::vector<Mesh> m_meshesWorldList
{
Mesh
{
{
Vertex{ {-3, 3, -2 }, { 1, 1, 1 }, { 0.0f, 0.0f } },
Vertex{ { 0, 3, -2 }, { 1, 1, 1 }, { 0.5f, 0.0f } },
Vertex{ { 3, 3, -2 }, { 1, 1, 1 }, { 1.0f, 0.0f } },
Vertex{ {-3, 0, -2 }, { 1, 1, 1 }, { 0.0f, 0.5f } },
Vertex{ { 0, 0, -2 }, { 1, 1, 1 }, { 0.5f, 0.5f } },
Vertex{ { 3, 0, -2 }, { 1, 1, 1 }, { 1.0f, 0.5f } },
Vertex{ {-3, -3, -2 }, { 1, 1, 1 }, { 0.0f, 1.0f } },
Vertex{ { 0, -3, -2 }, { 1, 1, 1 }, { 0.5f, 1.0f } },
Vertex{ { 3, -3, -2 }, { 1, 1, 1 }, { 1.0f, 1.0f } }
},
{
3, 0, 1, 1, 4, 3, 4, 1 ,2,
2, 5, 4, 6, 3, 4, 4, 7, 6,
7, 4, 5, 5, 8, 7
},
PrimitiveTopology::TriangleList
}
};
std::vector<Mesh> m_meshesWorldStrip ShadeMode m_ShadeMode{ ShadeMode::Combined };
{ bool m_isRotating{ true };
Mesh bool m_useNormals{ true };
{
std::vector<Vertex>{ Mesh m_mesh{};
{{-3, 3, -2}, {colors::White}, {0,0} },
{{0, 3, -2}, {colors::Red}, {0.5,0}}, bool m_isDepthBuffer{ false };
{{3, 3, -2}, {colors::Blue}, {1,0}},
{{-3, 0, -2}, {colors::Red}, {0,0.5}},
{{0, 0, -2}, {colors::Yellow}, {0.5, 0.5}}, std::vector<Mesh> m_worldMeshes{};
{{3, 0, -2}, {colors::White}, {1, 0.5}},
{{-3, -3, -2}, {colors::White}, {0,1}},
{{0, -3, -2}, {colors::White}, {0.5,1}},
{{3, -3, -2}, {colors::White}, {1,1}},
},
std::vector<uint32_t>{
3, 0, 4, 1, 5, 2,
2, 6,
6, 3, 7, 4, 8, 5,
},
PrimitiveTopology::TriangleStrip,
}
};
//square
std::vector<Mesh> testMesh{
Mesh{
std::vector<Vertex>{
{{-1, 1, 0}, {colors::White}, {0, 0}},
{{1, 1, 0}, {colors::White}, {1, 0}},
{{-1, -1, 0}, {colors::White}, {0, 1}},
{{1, -1, 0}, {colors::White}, {1, 1}},
},
std::vector<uint32_t>{
0, 1, 2, 1, 3, 2
},
PrimitiveTopology::TriangleList
}
};
// std::vector<Vertex> m_verticies_screenSpace{};
float* m_pDepthBufferPixels{}; float* m_pDepthBufferPixels{};

View File

@@ -4,7 +4,7 @@
#include "Maths.h" #include "Maths.h"
#include "DataTypes.h" #include "DataTypes.h"
#define DISABLE_OBJ //#define DISABLE_OBJ
namespace dae namespace dae
{ {
@@ -84,7 +84,7 @@ namespace dae
{ {
// OBJ format uses 1-based arrays // OBJ format uses 1-based arrays
file >> iPosition; file >> iPosition;
vertex.position = positions[iPosition - 1]; vertex.position = positions[iPosition - 1].ToVector4();
if ('/' == file.peek())//is next in buffer == '/' ? if ('/' == file.peek())//is next in buffer == '/' ?
{ {

View File

@@ -6,10 +6,10 @@ namespace dae
struct Vector3; struct Vector3;
struct Vector4 struct Vector4
{ {
float x; float x{};
float y; float y{};
float z; float z{};
float w; float w{};
Vector4() = default; Vector4() = default;
Vector4(float _x, float _y, float _z, float _w); Vector4(float _x, float _y, float _z, float _w);
@@ -20,8 +20,8 @@ namespace dae
float Normalize(); float Normalize();
Vector4 Normalized() const; Vector4 Normalized() const;
Vector2 GetXY() const; [[nodiscard]] Vector2 GetXY() const;
Vector3 GetXYZ() const; [[nodiscard]] Vector3 GetXYZ() const;
static float Dot(const Vector4& v1, const Vector4& v2); static float Dot(const Vector4& v1, const Vector4& v2);

View File

@@ -2,8 +2,10 @@
#ifdef ENABLE_VLD #ifdef ENABLE_VLD
#include "vld.h" #include "vld.h"
#endif #endif
#include "SDL.h" #include "SDL.h"
#include "SDL_surface.h" #include "SDL_surface.h"
#undef main #undef main
//Standard includes //Standard includes
@@ -15,17 +17,15 @@
using namespace dae; using namespace dae;
void ShutDown(SDL_Window* pWindow) void ShutDown(SDL_Window *pWindow) {
{
SDL_DestroyWindow(pWindow); SDL_DestroyWindow(pWindow);
SDL_Quit(); SDL_Quit();
} }
int main(int argc, char* args[]) int main(int argc, char *args[]) {
{
//Unreferenced parameters //Unreferenced parameters
(void)argc; (void) argc;
(void)args; (void) args;
//Create window + surfaces //Create window + surfaces
SDL_Init(SDL_INIT_VIDEO); SDL_Init(SDL_INIT_VIDEO);
@@ -33,8 +33,8 @@ int main(int argc, char* args[])
const uint32_t width = 640; const uint32_t width = 640;
const uint32_t height = 480; const uint32_t height = 480;
SDL_Window* pWindow = SDL_CreateWindow( SDL_Window *pWindow = SDL_CreateWindow(
"Rasterizer - **Insert Name**", "Rasterizer - Bram Verhulst",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height, 0); width, height, 0);
@@ -55,14 +55,11 @@ int main(int argc, char* args[])
float printTimer = 0.f; float printTimer = 0.f;
bool isLooping = true; bool isLooping = true;
bool takeScreenshot = false; bool takeScreenshot = false;
while (isLooping) while (isLooping) {
{
//--------- Get input events --------- //--------- Get input events ---------
SDL_Event e; SDL_Event e;
while (SDL_PollEvent(&e)) while (SDL_PollEvent(&e)) {
{ switch (e.type) {
switch (e.type)
{
case SDL_QUIT: case SDL_QUIT:
isLooping = false; isLooping = false;
break; break;
@@ -70,6 +67,21 @@ int main(int argc, char* args[])
if (e.key.keysym.scancode == SDL_SCANCODE_X) if (e.key.keysym.scancode == SDL_SCANCODE_X)
takeScreenshot = true; takeScreenshot = true;
break; break;
case SDL_KEYDOWN: {
auto key = e.key.keysym.scancode;
if (key == SDL_SCANCODE_F4) {
pRenderer->SwitchDepthBuffer();
}
if (key == SDL_SCANCODE_F5) {
pRenderer->ToggleRotation();
}
if (key == SDL_SCANCODE_F6) {
pRenderer->ToggleNormals();
}
if (key == SDL_SCANCODE_F7) {
pRenderer->CycleRenderingMode();
}
}
} }
} }
@@ -82,15 +94,13 @@ int main(int argc, char* args[])
//--------- Timer --------- //--------- Timer ---------
pTimer->Update(); pTimer->Update();
printTimer += pTimer->GetElapsed(); printTimer += pTimer->GetElapsed();
if (printTimer >= 1.f) if (printTimer >= 1.f) {
{
printTimer = 0.f; printTimer = 0.f;
std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl; std::cout << "dFPS: " << pTimer->GetdFPS() << std::endl;
} }
//Save screenshot after full render //Save screenshot after full render
if (takeScreenshot) if (takeScreenshot) {
{
if (!pRenderer->SaveBufferToImage()) if (!pRenderer->SaveBufferToImage())
std::cout << "Screenshot saved!" << std::endl; std::cout << "Screenshot saved!" << std::endl;
else else