diff --git a/Faceball2030.sln b/Faceball2030.sln
new file mode 100644
index 0000000..bef44aa
--- /dev/null
+++ b/Faceball2030.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33516.290
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Faceball2030", "Faceball2030\Faceball2030.vcxproj", "{735BD839-ABF4-49EC-8A84-FAD819015CCC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Debug|x64.ActiveCfg = Debug|x64
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Debug|x64.Build.0 = Debug|x64
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Debug|x86.ActiveCfg = Debug|Win32
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Debug|x86.Build.0 = Debug|Win32
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Release|x64.ActiveCfg = Release|x64
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Release|x64.Build.0 = Release|x64
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Release|x86.ActiveCfg = Release|Win32
+ {735BD839-ABF4-49EC-8A84-FAD819015CCC}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {518BE9CB-D573-4303-9DBB-D322A58CE88A}
+ EndGlobalSection
+EndGlobal
diff --git a/Faceball2030/Faceball2030.vcxproj b/Faceball2030/Faceball2030.vcxproj
new file mode 100644
index 0000000..ce74af2
--- /dev/null
+++ b/Faceball2030/Faceball2030.vcxproj
@@ -0,0 +1,138 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {735bd839-abf4-49ec-8a84-fad819015ccc}
+ Faceball2030
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Faceball2030/Faceball2030.vcxproj.filters b/Faceball2030/Faceball2030.vcxproj.filters
new file mode 100644
index 0000000..e77fe10
--- /dev/null
+++ b/Faceball2030/Faceball2030.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/Faceball2030/High.png b/Faceball2030/High.png
new file mode 100644
index 0000000..0a9d131
Binary files /dev/null and b/Faceball2030/High.png differ
diff --git a/Faceball2030/main.cpp b/Faceball2030/main.cpp
new file mode 100644
index 0000000..c3cd689
--- /dev/null
+++ b/Faceball2030/main.cpp
@@ -0,0 +1,673 @@
+#define OLC_PGE_APPLICATION
+#include "pixelGameEngine.h"
+#include
+#include
+
+using namespace olc;
+
+const float PI = 3.14159f;
+
+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;
+};
+
+struct mesh
+{
+ std::vector tris;
+ Decal* texture;
+
+ 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,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] });
+ }
+
+ }
+
+ return true;
+ }
+
+};
+
+struct mat4x4
+{
+ float m[4][4] = { 0 };
+};
+
+class olcEngine3D : public PixelGameEngine
+{
+
+public:
+
+ Decal* texture;
+ olcEngine3D()
+ {
+ sAppName = "3D Demo";
+ }
+
+
+private:
+ mesh meshCube;
+ mat4x4 matProj;
+
+ vec3d vCamera = { 0,0,0 };
+ vec3d vLookDir;
+
+ float zOffset = 2;
+
+ float fTheta = 0;
+ float fYaw = 0;
+ float pitch = -PI / 6;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ mat4x4 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;
+
+ }
+
+ 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;
+ }
+
+ vec3d Vector_Add(vec3d& v1, vec3d& v2)
+ {
+ return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
+ }
+
+ vec3d Vector_Sub(vec3d& v1, vec3d& v2)
+ {
+ return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
+ }
+
+ vec3d Vector_Mul(vec3d& v1, float k)
+ {
+ return { v1.x * k, v1.y * k, v1.z * k };
+ }
+
+ vec3d Vector_Div(vec3d& v1, float k)
+ {
+ return { v1.x / k, v1.y / k, v1.z / k };
+ }
+
+ float Vector_DotProduct(vec3d& v1, vec3d& v2)
+ {
+ return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
+ }
+
+ float Vector_Length(vec3d& v)
+ {
+ return sqrtf(Vector_DotProduct(v, v));
+ }
+
+ vec3d Vector_Normalise(vec3d& v)
+ {
+ float l = Vector_Length(v);
+ return { v.x / l, v.y / l, v.z / l };
+ }
+
+ 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;
+ }
+
+ vec3d 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);
+ }
+
+
+ int 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);
+
+ // 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;
+
+ // 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;
+
+ // 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
+ }
+ }
+
+
+public:
+ bool OnUserCreate() override
+ {
+ texture = new Decal(new Sprite("High.png"));
+ meshCube.LoadFromObjectFile("Artisans Hub.obj");
+
+ matProj = Matrix_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f);
+
+ return true;
+ }
+
+ bool OnUserUpdate(float fElapsedTime) override
+ {
+ if (GetKey(olc::DOWN).bHeld) {
+ pitch -= 1 * fElapsedTime;
+ }
+ if (GetKey(olc::UP).bHeld) {
+ pitch += 1 * fElapsedTime;
+ }
+ vec3d vForward = Vector_Mul(vLookDir, 20 * fElapsedTime);
+ 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;
+ }
+
+ // Set up rotation matrices
+ mat4x4 matRotZ, matRotX, matTrans, matWorld;
+
+ matRotZ = Matrix_MakeRotationZ(fTheta * 0.5f);
+ matRotX = Matrix_MakeRotationX(fTheta);
+
+ matTrans = Matrix_MakeTranslation(0.0f, 0.0f, 5.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& tri : meshCube.tris)
+ {
+ triangle triProjected, triTransformed, triViewed;
+
+ triTransformed.p[0] = Matrix_MultiplyVector(matWorld, tri.p[0]);
+ triTransformed.p[1] = Matrix_MultiplyVector(matWorld, tri.p[1]);
+ triTransformed.p[2] = Matrix_MultiplyVector(matWorld, tri.p[2]);
+ triTransformed.uv[0] = tri.uv[0];
+ triTransformed.uv[1] = tri.uv[1];
+ triTransformed.uv[2] = tri.uv[2];
+
+ 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(255 * dp * dp, 255 * dp * dp, 255 * 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();
+
+ 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) {
+
+ triangle clipped[2];
+ std::listlistTriangles;
+ listTriangles.push_back(triToRaster);
+ int nNewTriangles = 1;
+
+ for (int p = 0; p < 4; p++)
+ {
+ 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)
+ {
+ 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]);
+ }
+ nNewTriangles = listTriangles.size();
+ }
+
+ for (auto& t : listTriangles) {
+ // Rasterize triangle
+ SetDecalStructure(DecalStructure::LIST);
+ SetDecalMode(DecalMode::NORMAL);
+ DrawPolygonDecal(texture, {
+ {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},
+ },WHITE);*/
+ SetDecalStructure(DecalStructure::FAN);
+ triRenderCount++;
+ }
+ }
+
+ SetDecalMode(DecalMode::NORMAL);
+ DrawStringDecal({ 0,0 }, "Triangles: " + std::to_string(triRenderCount), WHITE, { 2,2 });
+
+
+ return true;
+ }
+
+};
+
+
+
+
+int main()
+{
+ olcEngine3D demo;
+ if (demo.Construct(1280, 720, 1, 1))
+ demo.Start();
+ return 0;
+}
diff --git a/Faceball2030/pixelGameEngine.h b/Faceball2030/pixelGameEngine.h
new file mode 100644
index 0000000..89bd0bf
--- /dev/null
+++ b/Faceball2030/pixelGameEngine.h
@@ -0,0 +1,6431 @@
+#pragma region license_and_help
+/*
+ olcPixelGameEngine.h
+
+ +-------------------------------------------------------------+
+ | OneLoneCoder Pixel Game Engine v2.19 |
+ | "What do you need? Pixels... Lots of Pixels..." - javidx9 |
+ +-------------------------------------------------------------+
+
+ What is this?
+ ~~~~~~~~~~~~~
+ olc::PixelGameEngine is a single file, cross platform graphics and userinput
+ framework used for games, visualisations, algorithm exploration and learning.
+ It was developed by YouTuber "javidx9" as an assistive tool for many of his
+ videos. The goal of this project is to provide high speed graphics with
+ minimal project setup complexity, to encourage new programmers, younger people,
+ and anyone else that wants to make fun things.
+
+ However, olc::PixelGameEngine is not a toy! It is a powerful and fast utility
+ capable of delivering high resolution, high speed, high quality applications
+ which behave the same way regardless of the operating system or platform.
+
+ This file provides the core utility set of the olc::PixelGameEngine, including
+ window creation, keyboard/mouse input, main game thread, timing, pixel drawing
+ routines, image/sprite loading and drawing routines, and a bunch of utility
+ types to make rapid development of games/visualisations possible.
+
+
+ License (OLC-3)
+ ~~~~~~~~~~~~~~~
+
+ Copyright 2018 - 2022 OneLoneCoder.com
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ 1. Redistributions or derivations of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions or derivative works in binary form must reproduce the above
+ copyright notice. This list of conditions and the following disclaimer must be
+ reproduced in the documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its contributors may
+ be used to endorse or promote products derived from this software without specific
+ prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Links
+ ~~~~~
+ YouTube: https://www.youtube.com/javidx9
+ https://www.youtube.com/javidx9extra
+ Discord: https://discord.gg/WhwHUMV
+ Twitter: https://www.twitter.com/javidx9
+ Twitch: https://www.twitch.tv/javidx9
+ GitHub: https://www.github.com/onelonecoder
+ Homepage: https://www.onelonecoder.com
+ Patreon: https://www.patreon.com/javidx9
+ Community: https://community.onelonecoder.com
+
+
+
+ Compiling in Linux
+ ~~~~~~~~~~~~~~~~~~
+ You will need a modern C++ compiler, so update yours!
+ To compile use the command:
+
+ g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng -lstdc++fs -std=c++17
+
+ On some Linux configurations, the frame rate is locked to the refresh
+ rate of the monitor. This engine tries to unlock it but may not be
+ able to, in which case try launching your program like this:
+
+ vblank_mode=0 ./YourProgName
+
+
+
+ Compiling in Code::Blocks on Windows
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Well I wont judge you, but make sure your Code::Blocks installation
+ is really up to date - you may even consider updating your C++ toolchain
+ to use MinGW32-W64.
+
+ Guide for installing recent GCC for Windows:
+ https://www.msys2.org/
+ Guide for configuring code::blocks:
+ https://solarianprogrammer.com/2019/11/05/install-gcc-windows/
+ https://solarianprogrammer.com/2019/11/16/install-codeblocks-gcc-windows-build-c-cpp-fortran-programs/
+
+ Add these libraries to "Linker Options":
+ user32 gdi32 opengl32 gdiplus Shlwapi dwmapi stdc++fs
+
+ Set these compiler options: -std=c++17
+
+
+
+ Compiling on Mac - EXPERIMENTAL! PROBABLY HAS BUGS
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ Yes yes, people use Macs for C++ programming! Who knew? Anyway, enough
+ arguing, thanks to Mumflr the PGE is now supported on Mac. Now I know nothing
+ about Mac, so if you need support, I suggest checking out the instructions
+ here: https://github.com/MumflrFumperdink/olcPGEMac
+
+ clang++ -arch x86_64 -std=c++17 -mmacosx-version-min=10.15 -Wall -framework OpenGL
+ -framework GLUT -framework Carbon -lpng YourSource.cpp -o YourProgName
+
+
+
+ Compiling with Emscripten (New & Experimental)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ Emscripten compiler will turn your awesome C++ PixelGameEngine project into WASM!
+ This means you can run your application in teh browser, great for distributing
+ and submission in to jams and things! It's a bit new at the moment.
+
+ em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 ./YourSource.cpp -o pge.html
+
+
+
+ Using stb_image.h
+ ~~~~~~~~~~~~~~~~~
+ The PGE will load png images by default (with help from libpng on non-windows systems).
+ However, the excellent "stb_image.h" can be used instead, supporting a variety of
+ image formats, and has no library dependence - something we like at OLC studios ;)
+ To use stb_image.h, make sure it's in your code base, and simply:
+
+ #define OLC_IMAGE_STB
+
+ Before including the olcPixelGameEngine.h header file. stb_image.h works on many systems
+ and can be downloaded here: https://github.com/nothings/stb/blob/master/stb_image.h
+
+
+
+ Multiple cpp file projects?
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ As a single header solution, the OLC_PGE_APPLICATION definition is used to
+ insert the engine implementation at a project location of your choosing.
+ The simplest way to setup multifile projects is to create a file called
+ "olcPixelGameEngine.cpp" which includes the following:
+
+ #define OLC_PGE_APPLICATION
+ #include "olcPixelGameEngine.h"
+
+ That's all it should include. You can also include PGEX includes and
+ defines in here too. With this in place, you dont need to
+ #define OLC_PGE_APPLICATION anywhere, and can simply include this
+ header file as an when you need to.
+
+
+
+ Ports
+ ~~~~~
+ olc::PixelGameEngine has been ported and tested with varying degrees of
+ success to: WinXP, Win7, Win8, Win10, Various Linux, Raspberry Pi,
+ Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are
+ interested in the details of these ports, come and visit the Discord!
+
+
+
+ Thanks
+ ~~~~~~
+ I'd like to extend thanks to Ian McKay, Bispoo, Eremiell, slavka, Kwizatz77, gurkanctn, Phantim,
+ IProgramInCPP, JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice,
+ dandistine, Ralakus, Gorbit99, raoul, joshinils, benedani, Moros1138, Alexio, SaladinAkara
+ & MagetzUb for advice, ideas and testing, and I'd like to extend my appreciation to the
+ 250K YouTube followers, 80+ Patreons, 4.8K Twitch followers and 10K Discord server members
+ who give me the motivation to keep going with all this :D
+
+ Significant Contributors: @Moros1138, @SaladinAkara, @MaGetzUb, @slavka,
+ @Dragoneye, @Gorbit99, @dandistine & @Mumflr
+
+ Special thanks to those who bring gifts!
+ GnarGnarHead.......Domina
+ Gorbit99...........Bastion, Ori & The Blind Forest, Terraria, Spelunky 2, Skully
+ Marti Morta........Gris
+ Danicron...........Terraria
+ SaladinAkara.......Aseprite, Inside, Quern: Undying Thoughts, Outer Wilds
+ AlterEgo...........Final Fantasy XII - The Zodiac Age
+ SlicEnDicE.........Noita, Inside
+ TGD................Voucher Gift
+
+ Special thanks to my Patreons too - I wont name you on here, but I've
+ certainly enjoyed my tea and flapjacks :D
+
+
+
+ Author
+ ~~~~~~
+ David Barr, aka javidx9, �OneLoneCoder 2018, 2019, 2020, 2021, 2022
+*/
+#pragma endregion
+
+#pragma region version_history
+/*
+ 2.01: Made renderer and platform static for multifile projects
+ 2.02: Added Decal destructor, optimised Pixel constructor
+ 2.03: Added FreeBSD flags, Added DrawStringDecal()
+ 2.04: Windows Full-Screen bug fixed
+ 2.05: +DrawPartialWarpedDecal() - draws a warped decal from a subset image
+ +DrawPartialRotatedDecal() - draws a rotated decal from a subset image
+ 2.06: +GetTextSize() - returns area occupied by multiline string
+ +GetWindowSize() - returns actual window size
+ +GetElapsedTime() - returns last calculated fElapsedTime
+ +GetWindowMouse() - returns actual mouse location in window
+ +DrawExplicitDecal() - bow-chikka-bow-bow
+ +DrawPartialDecal(pos, size) - draws a partial decal to specified area
+ +FillRectDecal() - draws a flat shaded rectangle as a decal
+ +GradientFillRectDecal() - draws a rectangle, with unique colour corners
+ +Modified DrawCircle() & FillCircle() - Thanks IanM-Matrix1 (#PR121)
+ +Gone someway to appeasing pedants
+ 2.07: +GetPixelSize() - returns user specified pixel size
+ +GetScreenPixelSize() - returns actual size in monitor pixels
+ +Pixel Cohesion Mode (flag in Construct()) - disallows arbitrary window scaling
+ +Working VSYNC in Windows windowed application - now much smoother
+ +Added string conversion for olc::vectors
+ +Added comparator operators for olc::vectors
+ +Added DestroyWindow() on windows platforms for serial PGE launches
+ +Added GetMousePos() to stop TarriestPython whinging
+ 2.08: Fix SetScreenSize() aspect ratio pre-calculation
+ Fix DrawExplicitDecal() - stupid oversight with multiple decals
+ Disabled olc::Sprite copy constructor
+ +olc::Sprite Duplicate() - produces a new clone of the sprite
+ +olc::Sprite Duplicate(pos, size) - produces a new sprite from the region defined
+ +Unary operators for vectors
+ +More pedant mollification - Thanks TheLandfill
+ +ImageLoader modules - user selectable image handling core, gdi+, libpng, stb_image
+ +Mac Support via GLUT - thanks Mumflr!
+ 2.09: Fix olc::Renderable Image load error - Thanks MaGetzUb & Zij-IT for finding and moaning about it
+ Fix file rejection in image loaders when using resource packs
+ Tidied Compiler defines per platform - Thanks slavka
+ +Pedant fixes, const correctness in parts
+ +DecalModes - Normal, Additive, Multiplicative blend modes
+ +Pixel Operators & Lerping
+ +Filtered Decals - If you hate pixels, then erase this file
+ +DrawStringProp(), GetTextSizeProp(), DrawStringPropDecal() - Draws non-monospaced font
+ 2.10: Fix PixelLerp() - oops my bad, lerped the wrong way :P
+ Fix "Shader" support for strings - thanks Megarev for crying about it
+ Fix GetTextSizeProp() - Height was just plain wrong...
+ +vec2d operator overloads (element wise *=, /=)
+ +vec2d comparison operators... :| yup... hmmmm...
+ +vec2d ceil(), floor(), min(), max() functions - surprising how often I do it manually
+ +DrawExplicitDecal(... uint32_t elements) - complete control over convex polygons and lines
+ +DrawPolygonDecal() - to keep Bispoo happy, required significant rewrite of EVERYTHING, but hey ho
+ +Complete rewrite of decal renderer
+ +OpenGL 3.3 Renderer (also supports Raspberry Pi)
+ +PGEX Break-In Hooks - with a push from Dandistine
+ +Wireframe Decal Mode - For debug overlays
+ 2.11: Made PGEX hooks optional - (provide true to super constructor)
+ 2.12: Fix for MinGW compiler non-compliance :( - why is its sdk structure different?? why???
+ 2.13: +GetFontSprite() - allows access to font data
+ 2.14: Fix WIN32 Definition reshuffle
+ Fix DrawPartialDecal() - messed up dimension during renderer experiment, didnt remove junk code, thanks Alexio
+ Fix? Strange error regarding GDI+ Image Loader not knowing about COM, SDK change?
+ 2.15: Big Reformat
+ +WASM Platform (via Emscripten) - Big Thanks to OLC Community - See Platform for details
+ +Sample Mode for Decals
+ +Made olc_ConfigureSystem() accessible
+ +Added OLC_----_CUSTOM_EX for externalised platforms, renderers and image loaders
+ =Refactored olc::Sprite pixel data store
+ -Deprecating LoadFromPGESprFile()
+ -Deprecating SaveToPGESprFile()
+ Fix Pixel -= operator (thanks Au Lit)
+ 2.16: FIX Emscripten JS formatting in VS IDE (thanks Moros)
+ +"Headless" Mode
+ +DrawLineDecal()
+ +Mouse Button Constants
+ +Move Constructor for olc::Renderable
+ +Polar/Cartesian conversion for v2d_generic
+ +DrawRotatedStringDecal()/DrawRotatedStringPropDecal() (thanks Oso-Grande/Sopadeoso (PR #209))
+ =Using olc::Renderable for layer surface
+ +Major Mac and GLUT Update (thanks Mumflr)
+ 2.17: +Clipping for DrawLine() functions
+ +Reintroduced sub-pixel decals
+ +Modified DrawPartialDecal() to quantise and correctly sample from tile atlasses
+ +olc::Sprite::GetPixel() - Clamp Mode
+ 2.18: +Option to not "dirty" layers with SetDrawTarget() - Thanks TerasKasi!
+ =Detection for Mac M1, fix for scroll wheel interrogation - Thanks ruarq!
+ 2.19: Textual Input(of)course Edition!
+ =Built in font is now olc::Renderable
+ +EnablePixelTransfer() - Gate if layer content transfers occur (speedup in decal only apps)
+ +TextEntryEnable() - Enables/Disables text entry mode
+ +TextEntryGetString() - Gets the current accumulated string in text entry mode
+ +TextEntryGetCursor() - Gets the current cursor position in text entry mode
+ +IsTextEntryEnabled() - Returns true if text entry mode is activated
+ +OnTextEntryComplete() - Override is called when user presses "ENTER" in text entry mode
+ +Potential for regional keyboard mappings - needs volunteers to do this
+ +ConsoleShow() - Opens built in command console
+ +ConsoleClear() - Clears built in command console output
+ +ConsoleOut() - Stream strings to command console output
+ +ConsoleCaptureStdOut() - Capture std::cout by redirecting to built-in console
+ +IsConsoleShowing() - Returns true if console is currently active
+ +OnConsoleCommand() - Override is called when command is entered into built in console
+
+ !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !!
+ !! Volunteers willing to help appreciated, though PRs are manually integrated with credit !!
+*/
+#pragma endregion
+
+#pragma region hello_world_example
+// O------------------------------------------------------------------------------O
+// | Example "Hello World" Program (main.cpp) |
+// O------------------------------------------------------------------------------O
+/*
+
+#define OLC_PGE_APPLICATION
+#include "olcPixelGameEngine.h"
+
+// Override base class with your custom functionality
+class Example : public olc::PixelGameEngine
+{
+public:
+ Example()
+ {
+ // Name your application
+ sAppName = "Example";
+ }
+
+public:
+ bool OnUserCreate() override
+ {
+ // Called once at the start, so create things here
+ return true;
+ }
+
+ bool OnUserUpdate(float fElapsedTime) override
+ {
+ // Called once per frame, draws random coloured pixels
+ for (int x = 0; x < ScreenWidth(); x++)
+ for (int y = 0; y < ScreenHeight(); y++)
+ Draw(x, y, olc::Pixel(rand() % 256, rand() % 256, rand() % 256));
+ return true;
+ }
+};
+
+int main()
+{
+ Example demo;
+ if (demo.Construct(256, 240, 4, 4))
+ demo.Start();
+ return 0;
+}
+
+*/
+#pragma endregion
+
+#ifndef OLC_PGE_DEF
+#define OLC_PGE_DEF
+
+#pragma region std_includes
+// O------------------------------------------------------------------------------O
+// | STANDARD INCLUDES |
+// O------------------------------------------------------------------------------O
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include