From 725853c0b2118edd78471bfc933de77ee50d34ea Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Sat, 8 Apr 2023 14:22:08 -0500 Subject: [PATCH] Refactor game into multiple files. --- Faceball2030/Editor.cpp | 0 Faceball2030/Editor.h | 11 + Faceball2030/Faceball2030.vcxproj | 3 + Faceball2030/Faceball2030.vcxproj.filters | 9 + Faceball2030/MapFormat.txt | 23 + Faceball2030/assets/map/map1.map | 0 Faceball2030/main.cpp | 1359 +++++++++------------ Faceball2030/main.h | 185 +++ 8 files changed, 839 insertions(+), 751 deletions(-) create mode 100644 Faceball2030/Editor.cpp create mode 100644 Faceball2030/Editor.h create mode 100644 Faceball2030/MapFormat.txt create mode 100644 Faceball2030/assets/map/map1.map create mode 100644 Faceball2030/main.h diff --git a/Faceball2030/Editor.cpp b/Faceball2030/Editor.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Faceball2030/Editor.h b/Faceball2030/Editor.h new file mode 100644 index 0000000..fdb07d5 --- /dev/null +++ b/Faceball2030/Editor.h @@ -0,0 +1,11 @@ +#pragma once +#include "pixelGameEngine.h" +using namespace olc; + +class Editor { + std::string filename; + vi2d MAP_SIZE; + void Update(float fElapsedTime) { + + } +}; \ No newline at end of file diff --git a/Faceball2030/Faceball2030.vcxproj b/Faceball2030/Faceball2030.vcxproj index ce74af2..88cc5d0 100644 --- a/Faceball2030/Faceball2030.vcxproj +++ b/Faceball2030/Faceball2030.vcxproj @@ -127,9 +127,12 @@ + + + diff --git a/Faceball2030/Faceball2030.vcxproj.filters b/Faceball2030/Faceball2030.vcxproj.filters index e77fe10..65b2820 100644 --- a/Faceball2030/Faceball2030.vcxproj.filters +++ b/Faceball2030/Faceball2030.vcxproj.filters @@ -18,10 +18,19 @@ Source Files + + Source Files + Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/Faceball2030/MapFormat.txt b/Faceball2030/MapFormat.txt new file mode 100644 index 0000000..fc4bb7a --- /dev/null +++ b/Faceball2030/MapFormat.txt @@ -0,0 +1,23 @@ + +Map Format: +Width +Height + +Width*Height 16-bit values + +16 bits + Dir + vv +0000 0000 0000 0000 +^ ^ En ID^ ^^^^ +| ^^^ NESW +| Wave 321 +Blink + +Armor +Speed +Shot +Camo +Stop +Shield +Map \ No newline at end of file diff --git a/Faceball2030/assets/map/map1.map b/Faceball2030/assets/map/map1.map new file mode 100644 index 0000000..e69de29 diff --git a/Faceball2030/main.cpp b/Faceball2030/main.cpp index 75034d9..48cefa8 100644 --- a/Faceball2030/main.cpp +++ b/Faceball2030/main.cpp @@ -2,857 +2,714 @@ #include "pixelGameEngine.h" #include #include +#include "main.h" using namespace olc; -const float PI = 3.14159f; -enum Direction { - NORTH=1, - EAST=2, - SOUTH=4, - WEST=8 -}; - -struct vec2d +vec3d +FaceBall::Matrix_MultiplyVector(mat4x4& m, vec3d& i) { - float u = 0; - float v = 0; - float w = 1; + vec3d v; + v.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + i.w * m.m[3][0]; + v.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + i.w * m.m[3][1]; + v.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + i.w * m.m[3][2]; + v.w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + i.w * m.m[3][3]; + return v; }; - -struct vec3d +mat4x4 FaceBall::Matrix_MakeIdentity() { - float x = 0; - float y = 0; - float z = 0; - float w = 1; + mat4x4 matrix; + matrix.m[0][0] = 1.0f; + matrix.m[1][1] = 1.0f; + matrix.m[2][2] = 1.0f; + matrix.m[3][3] = 1.0f; + return matrix; }; -struct Triangle +mat4x4 FaceBall::Matrix_MakeRotationX(float fAngleRad) { - vec3d p[3]; - vec2d uv[3]; - Pixel col; - Decal* tex; -}; - -struct MapSquare { - Decal*wallN=NULL; - Decal* wallE=NULL; - Decal* wallS=NULL; - Decal* wallW=NULL; -}; + mat4x4 matrix; + matrix.m[0][0] = 1.0f; + matrix.m[1][1] = cosf(fAngleRad); + matrix.m[1][2] = sinf(fAngleRad); + matrix.m[2][1] = -sinf(fAngleRad); + matrix.m[2][2] = cosf(fAngleRad); + matrix.m[3][3] = 1.0f; + return matrix; +} -struct Mesh +mat4x4 FaceBall::Matrix_MakeRotationY(float fAngleRad) { - std::vector tris; - Decal* texture=NULL; - - Mesh() {} - - Mesh(std::string filename,Decal*tex) - :texture(tex){ - LoadFromObjectFile(filename); - } - - private: - void Parse(std::string str, int& v, int& uv) { - std::cout << str << "\n"; - std::stringstream s(str.substr(0, str.find("/") + 1)); - s >> v; - str.erase(0, str.find("/") + 1); - std::stringstream s2(str.substr(0, str.find("/") + 1)); - s2 >> uv; - //std::cout<<" "< verts; - std::vector uvs; - - std::string data; - while (f.good()) { - f >> data; - if (data == "v") { - float x, y, z; - f >> x >> y >> z; - verts.push_back({ x,y,z }); - std::cout<> u >> v; - uvs.push_back({ u,1-v }); - std::cout<> t1 >> t2 >> t3; - int v1, v2, v3, uv1, uv2, uv3; - Parse(t1, v1, uv1); - Parse(t2, v2, uv2); - Parse(t3, v3, uv3); - tris.push_back({ verts[v1 - 1],verts[v2 - 1],verts[v3 - 1], - uvs[uv1 - 1],uvs[uv2 - 1],uvs[uv3 - 1],WHITE }); - } - - } - - return true; - } - -}; + mat4x4 matrix; + matrix.m[0][0] = cosf(fAngleRad); + matrix.m[0][2] = sinf(fAngleRad); + matrix.m[2][0] = -sinf(fAngleRad); + matrix.m[1][1] = 1.0f; + matrix.m[2][2] = cosf(fAngleRad); + matrix.m[3][3] = 1.0f; + return matrix; +} -struct Object { - Mesh mesh; - vf2d pos = { 0,0 }; - float rot = 0; -}; +mat4x4 FaceBall::Matrix_MakeRotationZ(float fAngleRad) +{ + mat4x4 matrix; + matrix.m[0][0] = cosf(fAngleRad); + matrix.m[0][1] = sinf(fAngleRad); + matrix.m[1][0] = -sinf(fAngleRad); + matrix.m[1][1] = cosf(fAngleRad); + matrix.m[2][2] = 1.0f; + matrix.m[3][3] = 1.0f; + return matrix; +} -struct mat4x4 +mat4x4 FaceBall::Matrix_MakeTranslation(float x, float y, float z) { - float m[4][4] = { 0 }; -}; + mat4x4 matrix; + matrix.m[0][0] = 1.0f; + matrix.m[1][1] = 1.0f; + matrix.m[2][2] = 1.0f; + matrix.m[3][3] = 1.0f; + matrix.m[3][0] = x; + matrix.m[3][1] = y; + matrix.m[3][2] = z; + return matrix; +} -class FaceBall : public PixelGameEngine +mat4x4 FaceBall::Matrix_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar) { + float fFovRad = 1.0f / tanf(fFovDegrees * 0.5f / 180.0f * 3.14159f); + mat4x4 matrix; + matrix.m[0][0] = fAspectRatio * fFovRad; + matrix.m[1][1] = fFovRad; + matrix.m[2][2] = fFar / (fFar - fNear); + matrix.m[3][2] = (-fFar * fNear) / (fFar - fNear); + matrix.m[2][3] = 1.0f; + matrix.m[3][3] = 0.0f; + return matrix; +} -public: +mat4x4 FaceBall::Matrix_MultiplyMatrix(mat4x4& m1, mat4x4& m2) +{ + mat4x4 matrix; + for (int c = 0; c < 4; c++) + for (int r = 0; r < 4; r++) + matrix.m[r][c] = m1.m[r][0] * m2.m[0][c] + m1.m[r][1] * m2.m[1][c] + m1.m[r][2] * m2.m[2][c] + m1.m[r][3] * m2.m[3][c]; + return matrix; +} - bool freeRoam=false; - FaceBall() - { - sAppName = "3D Demo"; - } +mat4x4 FaceBall::Matrix_PointAt(vec3d& pos, vec3d& target, vec3d& up) +{ + // Calculate new forward direction + vec3d newForward = Vector_Sub(target, pos); + newForward = Vector_Normalise(newForward); + + // Calculate new Up direction + vec3d a = Vector_Mul(newForward, Vector_DotProduct(up, newForward)); + vec3d newUp = Vector_Sub(up, a); + newUp = Vector_Normalise(newUp); + + // New Right direction is easy, its just cross product + vec3d newRight = Vector_CrossProduct(newUp, newForward); + + // Construct Dimensioning and Translation Matrix + mat4x4 matrix; + matrix.m[0][0] = newRight.x; matrix.m[0][1] = newRight.y; matrix.m[0][2] = newRight.z; matrix.m[0][3] = 0.0f; + matrix.m[1][0] = newUp.x; matrix.m[1][1] = newUp.y; matrix.m[1][2] = newUp.z; matrix.m[1][3] = 0.0f; + matrix.m[2][0] = newForward.x; matrix.m[2][1] = newForward.y; matrix.m[2][2] = newForward.z; matrix.m[2][3] = 0.0f; + matrix.m[3][0] = pos.x; matrix.m[3][1] = pos.y; matrix.m[3][2] = pos.z; matrix.m[3][3] = 1.0f; + return matrix; +} -private: - Mesh mapMesh; - mat4x4 matProj; +mat4x4 FaceBall::Matrix_QuickInverse(mat4x4& m) // Only for Rotation/Translation Matrices +{ + mat4x4 matrix; + matrix.m[0][0] = m.m[0][0]; matrix.m[0][1] = m.m[1][0]; matrix.m[0][2] = m.m[2][0]; matrix.m[0][3] = 0.0f; + matrix.m[1][0] = m.m[0][1]; matrix.m[1][1] = m.m[1][1]; matrix.m[1][2] = m.m[2][1]; matrix.m[1][3] = 0.0f; + matrix.m[2][0] = m.m[0][2]; matrix.m[2][1] = m.m[1][2]; matrix.m[2][2] = m.m[2][2]; matrix.m[2][3] = 0.0f; + matrix.m[3][0] = -(m.m[3][0] * matrix.m[0][0] + m.m[3][1] * matrix.m[1][0] + m.m[3][2] * matrix.m[2][0]); + matrix.m[3][1] = -(m.m[3][0] * matrix.m[0][1] + m.m[3][1] * matrix.m[1][1] + m.m[3][2] * matrix.m[2][1]); + matrix.m[3][2] = -(m.m[3][0] * matrix.m[0][2] + m.m[3][1] * matrix.m[1][2] + m.m[3][2] * matrix.m[2][2]); + matrix.m[3][3] = 1.0f; + return matrix; +} - vec3d vCamera = { 5,0.5,5 }; - vec3d vLookDir; +vec3d FaceBall::Vector_Add(vec3d& v1, vec3d& v2) +{ + return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; +} - float zOffset = 2; +vec3d FaceBall::Vector_Sub(vec3d& v1, vec3d& v2) +{ + return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; +} - float fTheta = 0; - float fYaw = 0; - float pitch = -PI / 6; +vec3d FaceBall::Vector_Mul(vec3d& v1, float k) +{ + return { v1.x * k, v1.y * k, v1.z * k }; +} - vec3d - Matrix_MultiplyVector(mat4x4& m, vec3d& i) - { - vec3d v; - v.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + i.w * m.m[3][0]; - v.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + i.w * m.m[3][1]; - v.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + i.w * m.m[3][2]; - v.w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + i.w * m.m[3][3]; - return v; - } +vec3d FaceBall::Vector_Div(vec3d& v1, float k) +{ + return { v1.x / k, v1.y / k, v1.z / k }; +} - mat4x4 Matrix_MakeIdentity() - { - mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } +float FaceBall::Vector_DotProduct(vec3d& v1, vec3d& v2) +{ + return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; +} - mat4x4 Matrix_MakeRotationX(float fAngleRad) - { - mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[1][2] = sinf(fAngleRad); - matrix.m[2][1] = -sinf(fAngleRad); - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } +float FaceBall::Vector_Length(vec3d& v) +{ + return sqrtf(Vector_DotProduct(v, v)); +} - mat4x4 Matrix_MakeRotationY(float fAngleRad) - { - mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][2] = sinf(fAngleRad); - matrix.m[2][0] = -sinf(fAngleRad); - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } +vec3d FaceBall::Vector_Normalise(vec3d& v) +{ + float l = Vector_Length(v); + return { v.x / l, v.y / l, v.z / l }; +} - mat4x4 Matrix_MakeRotationZ(float fAngleRad) - { - mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][1] = sinf(fAngleRad); - matrix.m[1][0] = -sinf(fAngleRad); - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } +vec3d FaceBall::Vector_CrossProduct(vec3d& v1, vec3d& v2) +{ + vec3d v; + v.x = v1.y * v2.z - v1.z * v2.y; + v.y = v1.z * v2.x - v1.x * v2.z; + v.z = v1.x * v2.y - v1.y * v2.x; + return v; +} - mat4x4 Matrix_MakeTranslation(float x, float y, float z) - { - mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - matrix.m[3][0] = x; - matrix.m[3][1] = y; - matrix.m[3][2] = z; - return matrix; - } +vec3d FaceBall::Vector_IntersectPlane(vec3d& plane_p, vec3d& plane_n, vec3d& lineStart, vec3d& lineEnd, float& t) +{ + plane_n = Vector_Normalise(plane_n); + float plane_d = -Vector_DotProduct(plane_n, plane_p); + float ad = Vector_DotProduct(lineStart, plane_n); + float bd = Vector_DotProduct(lineEnd, plane_n); + t = (-plane_d - ad) / (bd - ad); + vec3d lineStartToEnd = Vector_Sub(lineEnd, lineStart); + vec3d lineToIntersect = Vector_Mul(lineStartToEnd, t); + return Vector_Add(lineStart, lineToIntersect); +} - mat4x4 Matrix_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar) - { - float fFovRad = 1.0f / tanf(fFovDegrees * 0.5f / 180.0f * 3.14159f); - mat4x4 matrix; - matrix.m[0][0] = fAspectRatio * fFovRad; - matrix.m[1][1] = fFovRad; - matrix.m[2][2] = fFar / (fFar - fNear); - matrix.m[3][2] = (-fFar * fNear) / (fFar - fNear); - matrix.m[2][3] = 1.0f; - matrix.m[3][3] = 0.0f; - return matrix; - } - mat4x4 Matrix_MultiplyMatrix(mat4x4& m1, mat4x4& m2) - { - mat4x4 matrix; - for (int c = 0; c < 4; c++) - for (int r = 0; r < 4; r++) - matrix.m[r][c] = m1.m[r][0] * m2.m[0][c] + m1.m[r][1] * m2.m[1][c] + m1.m[r][2] * m2.m[2][c] + m1.m[r][3] * m2.m[3][c]; - return matrix; - } +int FaceBall::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& in_tri, Triangle& out_tri1, Triangle& out_tri2) +{ + // Make sure plane normal is indeed normal + plane_n = Vector_Normalise(plane_n); - mat4x4 Matrix_PointAt(vec3d& pos, vec3d& target, vec3d& up) + // Return signed shortest distance from point to plane, plane normal must be normalised + auto dist = [&](vec3d& p) { - // Calculate new forward direction - vec3d newForward = Vector_Sub(target, pos); - newForward = Vector_Normalise(newForward); - - // Calculate new Up direction - vec3d a = Vector_Mul(newForward, Vector_DotProduct(up, newForward)); - vec3d newUp = Vector_Sub(up, a); - newUp = Vector_Normalise(newUp); - - // New Right direction is easy, its just cross product - vec3d newRight = Vector_CrossProduct(newUp, newForward); - - // Construct Dimensioning and Translation Matrix - mat4x4 matrix; - matrix.m[0][0] = newRight.x; matrix.m[0][1] = newRight.y; matrix.m[0][2] = newRight.z; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = newUp.x; matrix.m[1][1] = newUp.y; matrix.m[1][2] = newUp.z; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = newForward.x; matrix.m[2][1] = newForward.y; matrix.m[2][2] = newForward.z; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = pos.x; matrix.m[3][1] = pos.y; matrix.m[3][2] = pos.z; matrix.m[3][3] = 1.0f; - return matrix; - + vec3d n = Vector_Normalise(p); + return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Vector_DotProduct(plane_n, plane_p)); + }; + + // Create two temporary storage arrays to classify points either side of plane + // If distance sign is positive, point lies on "inside" of plane + vec3d* inside_points[3]; int nInsidePointCount = 0; + vec3d* outside_points[3]; int nOutsidePointCount = 0; + vec2d* inside_tex[3]; int nInsideTexCount = 0; + vec2d* outside_tex[3]; int nOutsideTexCount = 0; + + + // Get signed distance of each point in triangle to plane + float d0 = dist(in_tri.p[0]); + float d1 = dist(in_tri.p[1]); + float d2 = dist(in_tri.p[2]); + + if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.uv[0]; } + else { + outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.uv[0]; } - - mat4x4 Matrix_QuickInverse(mat4x4& m) // Only for Rotation/Translation Matrices - { - mat4x4 matrix; - matrix.m[0][0] = m.m[0][0]; matrix.m[0][1] = m.m[1][0]; matrix.m[0][2] = m.m[2][0]; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = m.m[0][1]; matrix.m[1][1] = m.m[1][1]; matrix.m[1][2] = m.m[2][1]; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = m.m[0][2]; matrix.m[2][1] = m.m[1][2]; matrix.m[2][2] = m.m[2][2]; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = -(m.m[3][0] * matrix.m[0][0] + m.m[3][1] * matrix.m[1][0] + m.m[3][2] * matrix.m[2][0]); - matrix.m[3][1] = -(m.m[3][0] * matrix.m[0][1] + m.m[3][1] * matrix.m[1][1] + m.m[3][2] * matrix.m[2][1]); - matrix.m[3][2] = -(m.m[3][0] * matrix.m[0][2] + m.m[3][1] * matrix.m[1][2] + m.m[3][2] * matrix.m[2][2]); - matrix.m[3][3] = 1.0f; - return matrix; + if (d1 >= 0) { + inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.uv[1]; } - - vec3d Vector_Add(vec3d& v1, vec3d& v2) - { - return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; + else { + outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.uv[1]; } - - vec3d Vector_Sub(vec3d& v1, vec3d& v2) - { - return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; + if (d2 >= 0) { + inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.uv[2]; } - - vec3d Vector_Mul(vec3d& v1, float k) - { - return { v1.x * k, v1.y * k, v1.z * k }; + else { + outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.uv[2]; } - vec3d Vector_Div(vec3d& v1, float k) - { - return { v1.x / k, v1.y / k, v1.z / k }; - } + // Now classify triangle points, and break the input triangle into + // smaller output triangles if required. There are four possible + // outcomes... - float Vector_DotProduct(vec3d& v1, vec3d& v2) + if (nInsidePointCount == 0) { - return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; - } + // All points lie on the outside of plane, so clip whole triangle + // It ceases to exist - float Vector_Length(vec3d& v) - { - return sqrtf(Vector_DotProduct(v, v)); + return 0; // No returned triangles are valid } - vec3d Vector_Normalise(vec3d& v) + if (nInsidePointCount == 3) { - float l = Vector_Length(v); - return { v.x / l, v.y / l, v.z / l }; - } + // All points lie on the inside of plane, so do nothing + // and allow the triangle to simply pass through + out_tri1 = in_tri; - vec3d Vector_CrossProduct(vec3d& v1, vec3d& v2) - { - vec3d v; - v.x = v1.y * v2.z - v1.z * v2.y; - v.y = v1.z * v2.x - v1.x * v2.z; - v.z = v1.x * v2.y - v1.y * v2.x; - return v; + return 1; // Just the one returned original triangle is valid } - vec3d Vector_IntersectPlane(vec3d& plane_p, vec3d& plane_n, vec3d& lineStart, vec3d& lineEnd, float& t) + if (nInsidePointCount == 1 && nOutsidePointCount == 2) { - plane_n = Vector_Normalise(plane_n); - float plane_d = -Vector_DotProduct(plane_n, plane_p); - float ad = Vector_DotProduct(lineStart, plane_n); - float bd = Vector_DotProduct(lineEnd, plane_n); - t = (-plane_d - ad) / (bd - ad); - vec3d lineStartToEnd = Vector_Sub(lineEnd, lineStart); - vec3d lineToIntersect = Vector_Mul(lineStartToEnd, t); - return Vector_Add(lineStart, lineToIntersect); + // Triangle should be clipped. As two points lie outside + // the plane, the triangle simply becomes a smaller triangle + + // Copy appearance info to new triangle + out_tri1.col = in_tri.col; + out_tri1.tex = in_tri.tex; + + // The inside point is valid, so keep that... + out_tri1.p[0] = *inside_points[0]; + out_tri1.uv[0] = *inside_tex[0]; + + // but the two new points are at the locations where the + // original sides of the triangle (lines) intersect with the plane + float t; + out_tri1.p[1] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); + out_tri1.uv[1].u = t * (outside_tex[0]->u - inside_tex[0]->u) + inside_tex[0]->u; + out_tri1.uv[1].v = t * (outside_tex[0]->v - inside_tex[0]->v) + inside_tex[0]->v; + out_tri1.uv[1].w = t * (outside_tex[0]->w - inside_tex[0]->w) + inside_tex[0]->w; + + out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t); + out_tri1.uv[2].u = t * (outside_tex[1]->u - inside_tex[0]->u) + inside_tex[0]->u; + out_tri1.uv[2].v = t * (outside_tex[1]->v - inside_tex[0]->v) + inside_tex[0]->v; + out_tri1.uv[2].w = t * (outside_tex[1]->w - inside_tex[0]->w) + inside_tex[0]->w; + + return 1; // Return the newly formed single triangle } - - int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& in_tri, Triangle& out_tri1, Triangle& out_tri2) + if (nInsidePointCount == 2 && nOutsidePointCount == 1) { - // Make sure plane normal is indeed normal - plane_n = Vector_Normalise(plane_n); - - // Return signed shortest distance from point to plane, plane normal must be normalised - auto dist = [&](vec3d& p) - { - vec3d n = Vector_Normalise(p); - return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Vector_DotProduct(plane_n, plane_p)); - }; - - // Create two temporary storage arrays to classify points either side of plane - // If distance sign is positive, point lies on "inside" of plane - vec3d* inside_points[3]; int nInsidePointCount = 0; - vec3d* outside_points[3]; int nOutsidePointCount = 0; - vec2d* inside_tex[3]; int nInsideTexCount = 0; - vec2d* outside_tex[3]; int nOutsideTexCount = 0; - - - // Get signed distance of each point in triangle to plane - float d0 = dist(in_tri.p[0]); - float d1 = dist(in_tri.p[1]); - float d2 = dist(in_tri.p[2]); - - if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.uv[0]; } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.uv[0]; - } - if (d1 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.uv[1]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.uv[1]; - } - if (d2 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.uv[2]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.uv[2]; - } - - // Now classify triangle points, and break the input triangle into - // smaller output triangles if required. There are four possible - // outcomes... - - if (nInsidePointCount == 0) - { - // All points lie on the outside of plane, so clip whole triangle - // It ceases to exist - - return 0; // No returned triangles are valid - } - - if (nInsidePointCount == 3) - { - // All points lie on the inside of plane, so do nothing - // and allow the triangle to simply pass through - out_tri1 = in_tri; - - return 1; // Just the one returned original triangle is valid - } - - if (nInsidePointCount == 1 && nOutsidePointCount == 2) - { - // Triangle should be clipped. As two points lie outside - // the plane, the triangle simply becomes a smaller triangle - - // Copy appearance info to new triangle - out_tri1.col = in_tri.col; - out_tri1.tex = in_tri.tex; - - // The inside point is valid, so keep that... - out_tri1.p[0] = *inside_points[0]; - out_tri1.uv[0] = *inside_tex[0]; - - // but the two new points are at the locations where the - // original sides of the triangle (lines) intersect with the plane - float t; - out_tri1.p[1] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.uv[1].u = t * (outside_tex[0]->u - inside_tex[0]->u) + inside_tex[0]->u; - out_tri1.uv[1].v = t * (outside_tex[0]->v - inside_tex[0]->v) + inside_tex[0]->v; - out_tri1.uv[1].w = t * (outside_tex[0]->w - inside_tex[0]->w) + inside_tex[0]->w; - - out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t); - out_tri1.uv[2].u = t * (outside_tex[1]->u - inside_tex[0]->u) + inside_tex[0]->u; - out_tri1.uv[2].v = t * (outside_tex[1]->v - inside_tex[0]->v) + inside_tex[0]->v; - out_tri1.uv[2].w = t * (outside_tex[1]->w - inside_tex[0]->w) + inside_tex[0]->w; - - return 1; // Return the newly formed single triangle - } - - if (nInsidePointCount == 2 && nOutsidePointCount == 1) - { - // Triangle should be clipped. As two points lie inside the plane, - // the clipped triangle becomes a "quad". Fortunately, we can - // represent a quad with two new triangles - - // Copy appearance info to new triangles - out_tri1.col = in_tri.col; - out_tri2.col = in_tri.col; - out_tri1.tex = in_tri.tex; - out_tri2.tex = in_tri.tex; - - // The first triangle consists of the two inside points and a new - // point determined by the location where one side of the triangle - // intersects with the plane - out_tri1.p[0] = *inside_points[0]; - out_tri1.p[1] = *inside_points[1]; - out_tri1.uv[0] = *inside_tex[0]; - out_tri1.uv[1] = *inside_tex[1]; - - float t; - out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.uv[2].u = t * (outside_tex[0]->u - inside_tex[0]->u) + inside_tex[0]->u; - out_tri1.uv[2].v = t * (outside_tex[0]->v - inside_tex[0]->v) + inside_tex[0]->v; - out_tri1.uv[2].w = t * (outside_tex[0]->w - inside_tex[0]->w) + inside_tex[0]->w; - - // The second triangle is composed of one of he inside points, a - // new point determined by the intersection of the other side of the - // triangle and the plane, and the newly created point above - out_tri2.p[0] = *inside_points[1]; - out_tri2.uv[0] = *inside_tex[1]; - out_tri2.p[1] = out_tri1.p[2]; - out_tri2.uv[1] = out_tri1.uv[2]; - out_tri2.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t); - out_tri2.uv[2].u = t * (outside_tex[0]->u - inside_tex[1]->u) + inside_tex[1]->u; - out_tri2.uv[2].v = t * (outside_tex[0]->v - inside_tex[1]->v) + inside_tex[1]->v; - out_tri2.uv[2].w = t * (outside_tex[0]->w - inside_tex[1]->w) + inside_tex[1]->w; - return 2; // Return two newly formed triangles which form a quad - } + // Triangle should be clipped. As two points lie inside the plane, + // the clipped triangle becomes a "quad". Fortunately, we can + // represent a quad with two new triangles + + // Copy appearance info to new triangles + out_tri1.col = in_tri.col; + out_tri2.col = in_tri.col; + out_tri1.tex = in_tri.tex; + out_tri2.tex = in_tri.tex; + + // The first triangle consists of the two inside points and a new + // point determined by the location where one side of the triangle + // intersects with the plane + out_tri1.p[0] = *inside_points[0]; + out_tri1.p[1] = *inside_points[1]; + out_tri1.uv[0] = *inside_tex[0]; + out_tri1.uv[1] = *inside_tex[1]; + + float t; + out_tri1.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); + out_tri1.uv[2].u = t * (outside_tex[0]->u - inside_tex[0]->u) + inside_tex[0]->u; + out_tri1.uv[2].v = t * (outside_tex[0]->v - inside_tex[0]->v) + inside_tex[0]->v; + out_tri1.uv[2].w = t * (outside_tex[0]->w - inside_tex[0]->w) + inside_tex[0]->w; + + // The second triangle is composed of one of he inside points, a + // new point determined by the intersection of the other side of the + // triangle and the plane, and the newly created point above + out_tri2.p[0] = *inside_points[1]; + out_tri2.uv[0] = *inside_tex[1]; + out_tri2.p[1] = out_tri1.p[2]; + out_tri2.uv[1] = out_tri1.uv[2]; + out_tri2.p[2] = Vector_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t); + out_tri2.uv[2].u = t * (outside_tex[0]->u - inside_tex[1]->u) + inside_tex[1]->u; + out_tri2.uv[2].v = t * (outside_tex[0]->v - inside_tex[1]->v) + inside_tex[1]->v; + out_tri2.uv[2].w = t * (outside_tex[0]->w - inside_tex[1]->w) + inside_tex[1]->w; + return 2; // Return two newly formed triangles which form a quad } +} - void RenderWorld() { - // Set up rotation matrices - mat4x4 matRotZ, matRotX, matWorld; - - matRotZ = Matrix_MakeRotationZ(fTheta * 0.5f); - matRotX = Matrix_MakeRotationX(fTheta); - - //matTrans = Matrix_MakeTranslation(0.0f, 0.0f, 0.0f); - matWorld = Matrix_MakeIdentity(); - matWorld = Matrix_MultiplyMatrix(matRotZ, matRotX); - //matWorld = Matrix_MultiplyMatrix(matWorld, matTrans); - - vec3d vUp = { 0,1,0 }; - vec3d vTarget = { 0,sinf(pitch),cosf(pitch) }; - mat4x4 matCameraRot = Matrix_MakeRotationY(fYaw); - vLookDir = Matrix_MultiplyVector(matCameraRot, vTarget); - vTarget = Vector_Add(vCamera, vLookDir); - mat4x4 matCamera = Matrix_PointAt(vCamera, vTarget, vUp); - mat4x4 matView = Matrix_QuickInverse(matCamera); - - std::vectorvecTrianglesToRaster; - - // Draw Triangles - for (auto& obj : objects) { - for (auto& tri : obj.mesh.tris){ - Triangle triProjected, triTransformed, triViewed; - //mat4x4 matTrans = Matrix_MakeTranslation(-mesh.size.x/2, 0, -mesh.size.x/2); - mat4x4 localMat = Matrix_MakeIdentity(); - //localMat = Matrix_MultiplyMatrix(localMat, matTrans); - mat4x4 rotMat = Matrix_MakeRotationY(obj.rot); - localMat = Matrix_MultiplyMatrix(localMat, rotMat); - mat4x4 matTrans = Matrix_MakeTranslation(obj.pos.x, 0, obj.pos.y); - localMat = Matrix_MultiplyMatrix(localMat, matTrans); - - triTransformed.p[0] = Matrix_MultiplyVector(localMat, tri.p[0]); - triTransformed.p[1] = Matrix_MultiplyVector(localMat, tri.p[1]); - triTransformed.p[2] = Matrix_MultiplyVector(localMat, tri.p[2]); - triTransformed.uv[0] = tri.uv[0]; - triTransformed.uv[1] = tri.uv[1]; - triTransformed.uv[2] = tri.uv[2]; - triTransformed.col = tri.col; - - vec3d normal, line1, line2; - line1 = Vector_Sub(triTransformed.p[1], triTransformed.p[0]); - line2 = Vector_Sub(triTransformed.p[2], triTransformed.p[0]); - - normal = Vector_CrossProduct(line1, line2); - normal = Vector_Normalise(normal); - - vec3d vCameraRay = Vector_Sub(triTransformed.p[0], vCamera); - - if (Vector_DotProduct(normal, vCameraRay) < 0) { - vec3d light_dir = Vector_Mul(vLookDir, -1); - light_dir = Vector_Normalise(light_dir); - - float dp = std::max(0.7f, Vector_DotProduct(light_dir, normal)); - - triViewed.p[0] = Matrix_MultiplyVector(matView, triTransformed.p[0]); - triViewed.p[1] = Matrix_MultiplyVector(matView, triTransformed.p[1]); - triViewed.p[2] = Matrix_MultiplyVector(matView, triTransformed.p[2]); - triViewed.uv[0] = triTransformed.uv[0]; - triViewed.uv[1] = triTransformed.uv[1]; - triViewed.uv[2] = triTransformed.uv[2]; - triViewed.col = Pixel(triTransformed.col.r * dp * dp, triTransformed.col.g * dp * dp, triTransformed.col.b * dp * dp); - - int nClippedTriangles = 0; - Triangle clipped[2]; - nClippedTriangles = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triViewed, clipped[0], clipped[1]); - - for (int n = 0; n < nClippedTriangles; n++) { - // Project triangles from 3D --> 2D - triProjected.p[0] = Matrix_MultiplyVector(matProj, clipped[n].p[0]); - triProjected.p[1] = Matrix_MultiplyVector(matProj, clipped[n].p[1]); - triProjected.p[2] = Matrix_MultiplyVector(matProj, clipped[n].p[2]); - triProjected.col = clipped[n].col; - triProjected.uv[0] = clipped[n].uv[0]; - triProjected.uv[1] = clipped[n].uv[1]; - triProjected.uv[2] = clipped[n].uv[2]; - triProjected.uv[0].u = triProjected.uv[0].u / triProjected.p[0].w; - triProjected.uv[1].u = triProjected.uv[1].u / triProjected.p[1].w; - triProjected.uv[2].u = triProjected.uv[2].u / triProjected.p[2].w; - - triProjected.uv[0].v = triProjected.uv[0].v / triProjected.p[0].w; - triProjected.uv[1].v = triProjected.uv[1].v / triProjected.p[1].w; - triProjected.uv[2].v = triProjected.uv[2].v / triProjected.p[2].w; - - triProjected.uv[0].w = 1.0f / triProjected.p[0].w; - triProjected.uv[1].w = 1.0f / triProjected.p[1].w; - triProjected.uv[2].w = 1.0f / triProjected.p[2].w; - - - triProjected.p[0] = Vector_Div(triProjected.p[0], triProjected.p[0].w); - triProjected.p[1] = Vector_Div(triProjected.p[1], triProjected.p[1].w); - triProjected.p[2] = Vector_Div(triProjected.p[2], triProjected.p[2].w); - - triProjected.p[0].x *= -1.0f; - triProjected.p[1].x *= -1.0f; - triProjected.p[2].x *= -1.0f; - triProjected.p[0].y *= -1.0f; - triProjected.p[1].y *= -1.0f; - triProjected.p[2].y *= -1.0f; - - // Scale into view - vec3d vOffsetView = { 1,1,0 }; - triProjected.p[0] = Vector_Add(triProjected.p[0], vOffsetView); - triProjected.p[1] = Vector_Add(triProjected.p[1], vOffsetView); - triProjected.p[2] = Vector_Add(triProjected.p[2], vOffsetView); - triProjected.p[0].x *= 0.5f * (float)ScreenWidth(); - triProjected.p[0].y *= 0.5f * (float)ScreenHeight(); - triProjected.p[1].x *= 0.5f * (float)ScreenWidth(); - triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); - triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); - triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); - triProjected.tex = obj.mesh.texture; - - vecTrianglesToRaster.push_back(triProjected); - } +void FaceBall::RenderWorld() { + // Set up rotation matrices + mat4x4 matRotZ, matRotX, matWorld; + + matRotZ = Matrix_MakeRotationZ(fTheta * 0.5f); + matRotX = Matrix_MakeRotationX(fTheta); + + //matTrans = Matrix_MakeTranslation(0.0f, 0.0f, 0.0f); + matWorld = Matrix_MakeIdentity(); + matWorld = Matrix_MultiplyMatrix(matRotZ, matRotX); + //matWorld = Matrix_MultiplyMatrix(matWorld, matTrans); + + vec3d vUp = { 0,1,0 }; + vec3d vTarget = { 0,sinf(pitch),cosf(pitch) }; + mat4x4 matCameraRot = Matrix_MakeRotationY(fYaw); + vLookDir = Matrix_MultiplyVector(matCameraRot, vTarget); + vTarget = Vector_Add(vCamera, vLookDir); + mat4x4 matCamera = Matrix_PointAt(vCamera, vTarget, vUp); + mat4x4 matView = Matrix_QuickInverse(matCamera); + + std::vectorvecTrianglesToRaster; + + // Draw Triangles + for (auto& obj : objects) { + for (auto& tri : obj.mesh.tris) { + Triangle triProjected, triTransformed, triViewed; + //mat4x4 matTrans = Matrix_MakeTranslation(-mesh.size.x/2, 0, -mesh.size.x/2); + mat4x4 localMat = Matrix_MakeIdentity(); + //localMat = Matrix_MultiplyMatrix(localMat, matTrans); + mat4x4 rotMat = Matrix_MakeRotationY(obj.rot); + localMat = Matrix_MultiplyMatrix(localMat, rotMat); + mat4x4 matTrans = Matrix_MakeTranslation(obj.pos.x, 0, obj.pos.y); + localMat = Matrix_MultiplyMatrix(localMat, matTrans); + + triTransformed.p[0] = Matrix_MultiplyVector(localMat, tri.p[0]); + triTransformed.p[1] = Matrix_MultiplyVector(localMat, tri.p[1]); + triTransformed.p[2] = Matrix_MultiplyVector(localMat, tri.p[2]); + triTransformed.uv[0] = tri.uv[0]; + triTransformed.uv[1] = tri.uv[1]; + triTransformed.uv[2] = tri.uv[2]; + triTransformed.col = tri.col; + + vec3d normal, line1, line2; + line1 = Vector_Sub(triTransformed.p[1], triTransformed.p[0]); + line2 = Vector_Sub(triTransformed.p[2], triTransformed.p[0]); + + normal = Vector_CrossProduct(line1, line2); + normal = Vector_Normalise(normal); + + vec3d vCameraRay = Vector_Sub(triTransformed.p[0], vCamera); + + if (Vector_DotProduct(normal, vCameraRay) < 0) { + vec3d light_dir = Vector_Mul(vLookDir, -1); + light_dir = Vector_Normalise(light_dir); + + float dp = std::max(0.7f, Vector_DotProduct(light_dir, normal)); + + triViewed.p[0] = Matrix_MultiplyVector(matView, triTransformed.p[0]); + triViewed.p[1] = Matrix_MultiplyVector(matView, triTransformed.p[1]); + triViewed.p[2] = Matrix_MultiplyVector(matView, triTransformed.p[2]); + triViewed.uv[0] = triTransformed.uv[0]; + triViewed.uv[1] = triTransformed.uv[1]; + triViewed.uv[2] = triTransformed.uv[2]; + triViewed.col = Pixel(triTransformed.col.r * dp * dp, triTransformed.col.g * dp * dp, triTransformed.col.b * dp * dp); + + int nClippedTriangles = 0; + Triangle clipped[2]; + nClippedTriangles = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triViewed, clipped[0], clipped[1]); + + for (int n = 0; n < nClippedTriangles; n++) { + // Project triangles from 3D --> 2D + triProjected.p[0] = Matrix_MultiplyVector(matProj, clipped[n].p[0]); + triProjected.p[1] = Matrix_MultiplyVector(matProj, clipped[n].p[1]); + triProjected.p[2] = Matrix_MultiplyVector(matProj, clipped[n].p[2]); + triProjected.col = clipped[n].col; + triProjected.uv[0] = clipped[n].uv[0]; + triProjected.uv[1] = clipped[n].uv[1]; + triProjected.uv[2] = clipped[n].uv[2]; + triProjected.uv[0].u = triProjected.uv[0].u / triProjected.p[0].w; + triProjected.uv[1].u = triProjected.uv[1].u / triProjected.p[1].w; + triProjected.uv[2].u = triProjected.uv[2].u / triProjected.p[2].w; + + triProjected.uv[0].v = triProjected.uv[0].v / triProjected.p[0].w; + triProjected.uv[1].v = triProjected.uv[1].v / triProjected.p[1].w; + triProjected.uv[2].v = triProjected.uv[2].v / triProjected.p[2].w; + + triProjected.uv[0].w = 1.0f / triProjected.p[0].w; + triProjected.uv[1].w = 1.0f / triProjected.p[1].w; + triProjected.uv[2].w = 1.0f / triProjected.p[2].w; + + + triProjected.p[0] = Vector_Div(triProjected.p[0], triProjected.p[0].w); + triProjected.p[1] = Vector_Div(triProjected.p[1], triProjected.p[1].w); + triProjected.p[2] = Vector_Div(triProjected.p[2], triProjected.p[2].w); + + triProjected.p[0].x *= -1.0f; + triProjected.p[1].x *= -1.0f; + triProjected.p[2].x *= -1.0f; + triProjected.p[0].y *= -1.0f; + triProjected.p[1].y *= -1.0f; + triProjected.p[2].y *= -1.0f; + + // Scale into view + vec3d vOffsetView = { 1,1,0 }; + triProjected.p[0] = Vector_Add(triProjected.p[0], vOffsetView); + triProjected.p[1] = Vector_Add(triProjected.p[1], vOffsetView); + triProjected.p[2] = Vector_Add(triProjected.p[2], vOffsetView); + triProjected.p[0].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[0].y *= 0.5f * (float)ScreenHeight(); + triProjected.p[1].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); + triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); + triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); + triProjected.tex = obj.mesh.texture; + + vecTrianglesToRaster.push_back(triProjected); } } } + } - //std::sort(vecTrianglesToRaster.begin(),vecTrianglesToRaster.end(),[](triangle&t1,triangle&t2){return (t1.p[0].z+t1.p[1].z+t1.p[2].z)/3.0f>(t2.p[0].z+t2.p[1].z+t2.p[2].z)/3.0f;}); - ClearBuffer(BLACK, true); - int triRenderCount = 0; - for (auto& triToRaster : vecTrianglesToRaster) { + //std::sort(vecTrianglesToRaster.begin(),vecTrianglesToRaster.end(),[](triangle&t1,triangle&t2){return (t1.p[0].z+t1.p[1].z+t1.p[2].z)/3.0f>(t2.p[0].z+t2.p[1].z+t2.p[2].z)/3.0f;}); + ClearBuffer(BLACK, true); + int triRenderCount = 0; + for (auto& triToRaster : vecTrianglesToRaster) { - Triangle clipped[2]; - std::listlistTriangles; - listTriangles.push_back(triToRaster); - int nNewTriangles = 1; + Triangle clipped[2]; + std::listlistTriangles; + listTriangles.push_back(triToRaster); + int nNewTriangles = 1; - for (int p = 0; p < 4; p++) + for (int p = 0; p < 4; p++) + { + int nTrisToAdd = 0; + while (nNewTriangles > 0) { - int nTrisToAdd = 0; - while (nNewTriangles > 0) + // Take triangle from front of queue + Triangle test = listTriangles.front(); + listTriangles.pop_front(); + nNewTriangles--; + + // Clip it against a plane. We only need to test each + // subsequent plane, against subsequent new triangles + // as all triangles after a plane clip are guaranteed + // to lie on the inside of the plane. I like how this + // comment is almost completely and utterly justified + switch (p) { - // Take triangle from front of queue - Triangle test = listTriangles.front(); - listTriangles.pop_front(); - nNewTriangles--; - - // Clip it against a plane. We only need to test each - // subsequent plane, against subsequent new triangles - // as all triangles after a plane clip are guaranteed - // to lie on the inside of the plane. I like how this - // comment is almost completely and utterly justified - switch (p) - { - case 0: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, clipped[0], clipped[1]); break; - case 1: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, (float)ScreenHeight() - 1, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, clipped[0], clipped[1]); break; - case 2: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; - case 3: nTrisToAdd = Triangle_ClipAgainstPlane({ (float)ScreenWidth() - 1, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; - } - - // Clipping may yield a variable number of triangles, so - // add these new ones to the back of the queue for subsequent - // clipping against next planes - for (int w = 0; w < nTrisToAdd; w++) - listTriangles.push_back(clipped[w]); + case 0: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, clipped[0], clipped[1]); break; + case 1: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, (float)ScreenHeight() - 1, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, clipped[0], clipped[1]); break; + case 2: nTrisToAdd = Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; + case 3: nTrisToAdd = Triangle_ClipAgainstPlane({ (float)ScreenWidth() - 1, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, clipped[0], clipped[1]); break; } - nNewTriangles = listTriangles.size(); - } - std::mapcoords; - - for (auto& t : listTriangles) { - // Rasterize triangle - SetDecalStructure(DecalStructure::LIST); - SetDecalMode(DecalMode::NORMAL); - DrawPolygonDecal(t.tex, { - {t.p[0].x, t.p[0].y}, - {t.p[1].x, t.p[1].y}, - {t.p[2].x, t.p[2].y} - }, { - {t.uv[0].u,t.uv[0].v}, - {t.uv[1].u,t.uv[1].v}, - {t.uv[2].u,t.uv[2].v}, - }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { t.col,t.col,t.col }); - /*SetDecalMode(DecalMode::WIREFRAME); - DrawPolygonDecal(nullptr,{ - {t.p[0].x, t.p[0].y}, - {t.p[1].x, t.p[1].y}, - {t.p[2].x, t.p[2].y} - },{ - {0,0}, - {0,0}, - {0,0}, - }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { BLACK,BLACK,BLACK });*/ - SetDecalStructure(DecalStructure::FAN); - triRenderCount++; + // Clipping may yield a variable number of triangles, so + // add these new ones to the back of the queue for subsequent + // clipping against next planes + for (int w = 0; w < nTrisToAdd; w++) + listTriangles.push_back(clipped[w]); } + nNewTriangles = listTriangles.size(); + } - for (const auto&key:coords){ - vf2d coord = key.first; - vf2d val = key.second; - DrawStringDecal({ coord.x,coord.y }, val.str()); - } + std::mapcoords; + + for (auto& t : listTriangles) { + // Rasterize triangle + SetDecalStructure(DecalStructure::LIST); + SetDecalMode(DecalMode::NORMAL); + DrawPolygonDecal(t.tex, { + {t.p[0].x, t.p[0].y}, + {t.p[1].x, t.p[1].y}, + {t.p[2].x, t.p[2].y} + }, { + {t.uv[0].u,t.uv[0].v}, + {t.uv[1].u,t.uv[1].v}, + {t.uv[2].u,t.uv[2].v}, + }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { t.col,t.col,t.col }); + /*SetDecalMode(DecalMode::WIREFRAME); + DrawPolygonDecal(nullptr,{ + {t.p[0].x, t.p[0].y}, + {t.p[1].x, t.p[1].y}, + {t.p[2].x, t.p[2].y} + },{ + {0,0}, + {0,0}, + {0,0}, + }, { t.uv[0].w,t.uv[1].w,t.uv[2].w }, { t.p[0].z,t.p[1].z,t.p[2].z }, { BLACK,BLACK,BLACK });*/ + SetDecalStructure(DecalStructure::FAN); + triRenderCount++; } - SetDecalMode(DecalMode::NORMAL); - DrawStringDecal({ 0,0 }, "Triangles: " + std::to_string(triRenderCount), WHITE, { 2,2 }); + for (const auto& key : coords) { + vf2d coord = key.first; + vf2d val = key.second; + DrawStringDecal({ coord.x,coord.y }, val.str()); + } } - void HandleKeys(float fElapsedTime) { - vec3d vForward = Vector_Mul(vLookDir, 2 * fElapsedTime); - if (freeRoam) { - if (GetKey(olc::DOWN).bHeld) { - pitch -= 1 * fElapsedTime; - } - if (GetKey(olc::UP).bHeld) { - pitch += 1 * fElapsedTime; - } - } - else { - pitch = 0; - } - if (GetKey(olc::W).bHeld) { - vCamera = Vector_Add(vCamera, vForward); - } - if (GetKey(olc::S).bHeld) { - vCamera = Vector_Sub(vCamera, vForward); - } - if (GetKey(olc::A).bHeld) { - fYaw -= 2 * fElapsedTime; - } - if (GetKey(olc::D).bHeld) { - fYaw += 2 * fElapsedTime; + SetDecalMode(DecalMode::NORMAL); + DrawStringDecal({ 0,0 }, "Triangles: " + std::to_string(triRenderCount), WHITE, { 2,2 }); +} + +void FaceBall::HandleKeys(float fElapsedTime) { + vec3d vForward = Vector_Mul(vLookDir, 2 * fElapsedTime); + if (freeRoam) { + if (GetKey(olc::DOWN).bHeld) { + pitch -= 1 * fElapsedTime; } - if (GetKey(olc::F1).bPressed) { - freeRoam = !freeRoam; + if (GetKey(olc::UP).bHeld) { + pitch += 1 * fElapsedTime; } } + else { + pitch = 0; + } + if (GetKey(olc::W).bHeld) { + vCamera = Vector_Add(vCamera, vForward); + } + if (GetKey(olc::S).bHeld) { + vCamera = Vector_Sub(vCamera, vForward); + } + if (GetKey(olc::A).bHeld) { + fYaw -= 2 * fElapsedTime; + } + if (GetKey(olc::D).bHeld) { + fYaw += 2 * fElapsedTime; + } + if (GetKey(olc::F1).bPressed) { + freeRoam = !freeRoam; + } +} - void AddWall(Direction dir,vi2d gridSquare) { - if (dir & NORTH) { - map[gridSquare.y][gridSquare.x].wallN = dot; - if (gridSquare.y > 0) { - map[gridSquare.y - 1][gridSquare.x].wallS = dot; - } +void FaceBall::AddWall(Direction dir, vi2d gridSquare) { + if (dir & NORTH) { + map[gridSquare.y][gridSquare.x].wallN = dot; + if (gridSquare.y > 0) { + map[gridSquare.y - 1][gridSquare.x].wallS = dot; } - if (dir & WEST) { - map[gridSquare.y][gridSquare.x].wallW = dot; - if (gridSquare.x > 0) { - map[gridSquare.y][gridSquare.x-1].wallE = dot; - } + } + if (dir & WEST) { + map[gridSquare.y][gridSquare.x].wallW = dot; + if (gridSquare.x > 0) { + map[gridSquare.y][gridSquare.x - 1].wallE = dot; } - if (dir & SOUTH) { - map[gridSquare.y][gridSquare.x].wallS = dot; - if (gridSquare.y>map; - std::vectorobjects; +bool FaceBall::OnUserCreate() +{ + game = this; + sAppName = "Faceball 2030"; + matProj = Matrix_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f); + dot = new Decal(new Sprite("assets/dot.png")); + enemy_ShootMe_tex = new Decal(new Sprite("assets/enemies/ShootMe.png")); + + Mesh testEnemy("assets/enemies/ShootMe.obj", enemy_ShootMe_tex); + mapMesh.texture = dot; + for (int i = 0; i < 75; i++) { + Object newEnemy({ testEnemy,{ float(rand() % 20),float(rand() % 20) }, (rand() % 1000) / 1000.f * 2 * PI }); + objects.push_back(newEnemy); + } -public: - bool OnUserCreate() override - { - sAppName = "Faceball 2030"; - matProj = Matrix_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f); - dot = new Decal(new Sprite("assets/dot.png")); - enemy_ShootMe_tex = new Decal(new Sprite("assets/enemies/ShootMe.png")); - - Mesh testEnemy("assets/enemies/ShootMe.obj", enemy_ShootMe_tex); - mapMesh.texture = dot; - for (int i = 0; i < 75; i++) { - Object newEnemy({ testEnemy,{ float(rand() % 20),float(rand() % 20) }, (rand() % 1000) / 1000.f * 2 * PI }); - objects.push_back(newEnemy); + for (int y = 0; y < MAP_SIZE.y; y++) { + std::vectorrow; + for (int x = 0; x < MAP_SIZE.x; x++) { + row.push_back({}); + mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},BLUE }); + mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y + 1}},{{0,0},{1,0},{0,1}},BLUE }); } + map.push_back(row); + } - for (int y = 0; y < MAP_SIZE.y; y++) { - std::vectorrow; - for (int x = 0; x < MAP_SIZE.x; x++) { - row.push_back({}); - mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},BLUE }); - mapMesh.tris.push_back({ {{(float)x+1,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y+1}},{{0,0},{1,0},{0,1}},BLUE }); + for (int y = 0; y < MAP_SIZE.y; y++) { + for (int x = 0; x < MAP_SIZE.x; x++) { + switch (rand() % 16) { + case 0: {//No Wall. + + }break; + case 1: {//North Wall. + AddWall(NORTH, { x,y }); + }break; + case 2: {//East Wall. + AddWall(EAST, { x,y }); + }break; + case 3: {//South Wall. + AddWall(SOUTH, { x,y }); + }break; + case 4: {//West Wall. + AddWall(WEST, { x,y }); + }break; + case 5: {//NE Wall. + AddWall(Direction(NORTH | EAST), { x,y }); + }break; + case 6: { + AddWall(Direction(NORTH | WEST), { x,y }); + }break; + case 7: { + AddWall(Direction(SOUTH | EAST), { x,y }); + }break; + case 8: { + AddWall(Direction(SOUTH | WEST), { x,y }); + }break; + case 9: { + AddWall(Direction(NORTH | SOUTH), { x,y }); + }break; + case 10: { + AddWall(Direction(EAST | WEST), { x,y }); + }break; + case 11: { + AddWall(Direction(NORTH | WEST | EAST), { x,y }); + }break; + case 12: { + AddWall(Direction(NORTH | WEST | SOUTH), { x,y }); + }break; + case 13: { + AddWall(Direction(WEST | SOUTH | EAST), { x,y }); + }break; + case 14: { + AddWall(Direction(SOUTH | EAST | NORTH), { x,y }); + }break; + case 15: { + AddWall(Direction(SOUTH | EAST | NORTH | WEST), { x,y }); + }break; } - map.push_back(row); } + } + AddWall(Direction(SOUTH | EAST | NORTH | WEST), { 0,0 }); - for (int y = 0; y < MAP_SIZE.y; y++) { - for (int x = 0; x < MAP_SIZE.x; x++) { - switch (rand() % 16) { - case 0: {//No Wall. - - }break; - case 1: {//North Wall. - AddWall(NORTH,{x,y}); - }break; - case 2: {//East Wall. - AddWall(EAST, { x,y }); - }break; - case 3: {//South Wall. - AddWall(SOUTH, { x,y }); - }break; - case 4: {//West Wall. - AddWall(WEST, { x,y }); - }break; - case 5: {//NE Wall. - AddWall(Direction(NORTH|EAST), { x,y }); - }break; - case 6: { - AddWall(Direction(NORTH|WEST), { x,y }); - }break; - case 7: { - AddWall(Direction(SOUTH|EAST), { x,y }); - }break; - case 8: { - AddWall(Direction(SOUTH|WEST), { x,y }); - }break; - case 9: { - AddWall(Direction(NORTH|SOUTH), { x,y }); - }break; - case 10: { - AddWall(Direction(EAST|WEST), { x,y }); - }break; - case 11: { - AddWall(Direction(NORTH|WEST|EAST), { x,y }); - }break; - case 12: { - AddWall(Direction(NORTH|WEST|SOUTH), { x,y }); - }break; - case 13: { - AddWall(Direction(WEST|SOUTH|EAST), { x,y }); - }break; - case 14: { - AddWall(Direction(SOUTH|EAST|NORTH), { x,y }); - }break; - case 15: { - AddWall(Direction(SOUTH | EAST | NORTH|WEST), { x,y }); - }break; - } + for (int y = 0; y < MAP_SIZE.y; y++) { + for (int x = 0; x < MAP_SIZE.x; x++) { + if (map[y][x].wallN != NULL) { + mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); + mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x + 1,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); } - } - AddWall(Direction(SOUTH | EAST | NORTH | WEST), { 0,0 }); - - for (int y = 0; y < MAP_SIZE.y; y++) { - for (int x = 0; x < MAP_SIZE.x; x++) { - if (map[y][x].wallN!=NULL) { - mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); - mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x+1,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},YELLOW }); - } - if (map[y][x].wallS != NULL) { - mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y+1},{(float)x,0,(float)y+1},{(float)x,1,(float)y + 1}},{{0,0},{1,0},{0,1}},DARK_RED }); - mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y+1},{(float)x + 1,0,(float)y+1},{(float)x,0,(float)y+1}},{{0,0},{1,0},{0,1}},DARK_RED }); - } - if (map[y][x].wallW != NULL) { - mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,1,(float)y+1}, {(float)x,0,(float)y + 1}},{{0,0},{1,0},{0,1}},MAGENTA }); - mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,1,(float)y}, {(float)x,0,(float)y + 1}}, {{0,0},{1,0},{0,1}},MAGENTA }); - } - if (map[y][x].wallE != NULL) { - mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1},{(float)x+1,1,(float)y + 1},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); - mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1} ,{(float)x+1,1,(float)y},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); - } + if (map[y][x].wallS != NULL) { + mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x,0,(float)y + 1},{(float)x,1,(float)y + 1}},{{0,0},{1,0},{0,1}},DARK_RED }); + mapMesh.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x + 1,0,(float)y + 1},{(float)x,0,(float)y + 1}},{{0,0},{1,0},{0,1}},DARK_RED }); + } + if (map[y][x].wallW != NULL) { + mapMesh.tris.push_back({ {{(float)x,1,(float)y},{(float)x,1,(float)y + 1}, {(float)x,0,(float)y + 1}},{{0,0},{1,0},{0,1}},MAGENTA }); + mapMesh.tris.push_back({ {{(float)x,0,(float)y},{(float)x,1,(float)y}, {(float)x,0,(float)y + 1}}, {{0,0},{1,0},{0,1}},MAGENTA }); + } + if (map[y][x].wallE != NULL) { + mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1},{(float)x + 1,1,(float)y + 1},{(float)x + 1,1,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); + mapMesh.tris.push_back({ {{(float)x + 1,0,(float)y + 1} ,{(float)x + 1,1,(float)y},{(float)x + 1,0,(float)y}},{{0,0},{1,0},{0,1}},CYAN }); } } + } - //objects.push_back(mapMesh); + //objects.push_back(mapMesh); - return true; - } + return true; +} - bool OnUserUpdate(float fElapsedTime) override - { +bool FaceBall::OnUserUpdate(float fElapsedTime) +{ + switch (mode) { + case GAME: { for (Object& o : objects) { o.rot += PI / 8 * fElapsedTime; } HandleKeys(fElapsedTime); RenderWorld(); - return true; - } + }break; + case EDITOR: { -}; + }break; + } + return true; +} diff --git a/Faceball2030/main.h b/Faceball2030/main.h new file mode 100644 index 0000000..06c9810 --- /dev/null +++ b/Faceball2030/main.h @@ -0,0 +1,185 @@ +#pragma once +#include "pixelGameEngine.h" +using namespace olc; + +const float PI = 3.14159f; + +enum GAMEMODE { + GAME, + EDITOR +}; + +enum Direction { + NORTH = 1, + EAST = 2, + SOUTH = 4, + WEST = 8 +}; + +struct vec2d +{ + float u = 0; + float v = 0; + float w = 1; +}; + + +struct vec3d +{ + float x = 0; + float y = 0; + float z = 0; + float w = 1; +}; + +struct Triangle +{ + vec3d p[3]; + vec2d uv[3]; + Pixel col; + Decal* tex; +}; + +struct MapSquare { + Decal* wallN = NULL; + Decal* wallE = NULL; + Decal* wallS = NULL; + Decal* wallW = NULL; +}; + +struct Mesh +{ + std::vector tris; + Decal* texture = NULL; + + Mesh() {} + + Mesh(std::string filename, Decal* tex) + :texture(tex) { + LoadFromObjectFile(filename); + } + +private: + void Parse(std::string str, int& v, int& uv) { + std::cout << str << "\n"; + std::stringstream s(str.substr(0, str.find("/") + 1)); + s >> v; + str.erase(0, str.find("/") + 1); + std::stringstream s2(str.substr(0, str.find("/") + 1)); + s2 >> uv; + //std::cout<<" "< verts; + std::vector uvs; + + std::string data; + while (f.good()) { + f >> data; + if (data == "v") { + float x, y, z; + f >> x >> y >> z; + verts.push_back({ x,y,z }); + std::cout << x << " " << y << " " << z << "\n"; + } + else + if (data == "vt") { + float u, v; + f >> u >> v; + uvs.push_back({ u,1 - v }); + std::cout << u << " " << v << "\n"; + } + else + if (data == "f") { + //std::cout<<"face\n"; + std::string t1, t2, t3; + f >> t1 >> t2 >> t3; + int v1, v2, v3, uv1, uv2, uv3; + Parse(t1, v1, uv1); + Parse(t2, v2, uv2); + Parse(t3, v3, uv3); + tris.push_back({ verts[v1 - 1],verts[v2 - 1],verts[v3 - 1], + uvs[uv1 - 1],uvs[uv2 - 1],uvs[uv3 - 1],WHITE }); + } + + } + + return true; + } + +}; + +struct Object { + Mesh mesh; + vf2d pos = { 0,0 }; + float rot = 0; +}; + +struct mat4x4 +{ + float m[4][4] = { 0 }; +}; + +class FaceBall : public PixelGameEngine +{ + bool freeRoam = false; + public: + FaceBall() + { + sAppName = "3D Demo"; + } + private: + Mesh mapMesh; + + Decal* dot, * enemy_ShootMe_tex; + vi2d MAP_SIZE = { 10,10 }; + std::vector>map; + std::vectorobjects; + GAMEMODE mode=GAMEMODE::GAME; + + + mat4x4 matProj; + + vec3d vCamera = { 5,0.5,5 }; + vec3d vLookDir; + + float zOffset = 2; + + float fTheta = 0; + float fYaw = 0; + float pitch = -PI / 6; + + vec3d Matrix_MultiplyVector(mat4x4& m, vec3d& i); + mat4x4 Matrix_MakeIdentity(); + mat4x4 Matrix_MakeRotationX(float fAngleRad); + mat4x4 Matrix_MakeRotationY(float fAngleRad); + mat4x4 Matrix_MakeRotationZ(float fAngleRad); + mat4x4 Matrix_MakeTranslation(float x, float y, float z); + mat4x4 Matrix_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); + mat4x4 Matrix_MultiplyMatrix(mat4x4& m1, mat4x4& m2); + mat4x4 Matrix_PointAt(vec3d& pos, vec3d& target, vec3d& up); + mat4x4 Matrix_QuickInverse(mat4x4& m); + vec3d Vector_Add(vec3d& v1, vec3d& v2); + vec3d Vector_Sub(vec3d& v1, vec3d& v2); + vec3d Vector_Mul(vec3d& v1, float k); + vec3d Vector_Div(vec3d& v1, float k); + float Vector_DotProduct(vec3d& v1, vec3d& v2); + float Vector_Length(vec3d& v); + vec3d Vector_Normalise(vec3d& v); + vec3d Vector_CrossProduct(vec3d& v1, vec3d& v2); + vec3d Vector_IntersectPlane(vec3d& plane_p, vec3d& plane_n, vec3d& lineStart, vec3d& lineEnd, float& t); + int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, Triangle& in_tri, Triangle& out_tri1, Triangle& out_tri2); + void RenderWorld(); + void HandleKeys(float fElapsedTime); + void AddWall(Direction dir, vi2d gridSquare); + bool OnUserCreate() override; + bool OnUserUpdate(float fElapsedTime) override; +}; +FaceBall* game; \ No newline at end of file