generated from sigonasr2/CPlusPlusProjectTemplate
parent
7568ba124e
commit
2a1645a35c
After Width: | Height: | Size: 35 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
@ -0,0 +1,26 @@ |
|||||||
|
v 0 0 0 |
||||||
|
v 0 0 1 |
||||||
|
v 0 1 0 |
||||||
|
v 0 1 1 |
||||||
|
v 1 0 0 |
||||||
|
v 1 0 1 |
||||||
|
v 1 1 0 |
||||||
|
v 1 1 1 |
||||||
|
|
||||||
|
vt 0 0 #1 |
||||||
|
vt 0 1 #2 |
||||||
|
vt 1 0 #3 |
||||||
|
vt 1 1 #4 |
||||||
|
|
||||||
|
f 1/2 3/1 7/3 #South/0 |
||||||
|
f 1/2 7/3 5/4 #1 |
||||||
|
f 5/2 7/1 8/3 #East/2 |
||||||
|
f 5/2 8/3 6/4 #3 |
||||||
|
f 6/2 8/1 4/3 #North/4 |
||||||
|
f 6/2 4/3 2/4 #5 |
||||||
|
f 2/2 4/1 3/3 #West/6 |
||||||
|
f 2/2 3/3 1/4 #7 |
||||||
|
f 3/2 4/1 8/3 #Top/8 |
||||||
|
f 3/2 8/3 7/4 #9 |
||||||
|
f 6/2 2/1 1/3 #Bottom/10 |
||||||
|
f 6/2 1/3 5/4 #11 |
@ -0,0 +1,836 @@ |
|||||||
|
/*
|
||||||
|
olcPGEX_Graphics3D.h |
||||||
|
|
||||||
|
+-------------------------------------------------------------+ |
||||||
|
| OneLoneCoder Pixel Game Engine Extension | |
||||||
|
| 3D Rendering - v0.1 | |
||||||
|
+-------------------------------------------------------------+ |
||||||
|
|
||||||
|
What is this? |
||||||
|
~~~~~~~~~~~~~ |
||||||
|
This is an extension to the olcPixelGameEngine, which provides |
||||||
|
support for software rendering 3D graphics. |
||||||
|
|
||||||
|
NOTE!!! This file is under development and may change! |
||||||
|
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2018-2019 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
|
||||||
|
Discord: https://discord.gg/WhwHUMV
|
||||||
|
Twitter: https://www.twitter.com/javidx9
|
||||||
|
Twitch: https://www.twitch.tv/javidx9
|
||||||
|
GitHub: https://www.github.com/onelonecoder
|
||||||
|
Patreon: https://www.patreon.com/javidx9
|
||||||
|
Homepage: https://www.onelonecoder.com
|
||||||
|
|
||||||
|
Author |
||||||
|
~~~~~~ |
||||||
|
David Barr, aka javidx9, ©OneLoneCoder 2018 |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
#ifndef OLC_PGEX_GFX3D |
||||||
|
#define OLC_PGEX_GFX3D |
||||||
|
|
||||||
|
#include <algorithm> |
||||||
|
#include <vector> |
||||||
|
#include <list> |
||||||
|
#undef min |
||||||
|
#undef max |
||||||
|
|
||||||
|
namespace olc |
||||||
|
{ |
||||||
|
// Container class for Advanced 2D Drawing functions
|
||||||
|
class GFX3D : public olc::PGEX |
||||||
|
{ |
||||||
|
|
||||||
|
public: |
||||||
|
|
||||||
|
struct vec2d |
||||||
|
{ |
||||||
|
float x = 0; |
||||||
|
float y = 0; |
||||||
|
float z = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
struct vec3d |
||||||
|
{ |
||||||
|
float x = 0; |
||||||
|
float y = 0; |
||||||
|
float z = 0; |
||||||
|
float w = 1; // Need a 4th term to perform sensible matrix vector multiplication
|
||||||
|
}; |
||||||
|
|
||||||
|
struct triangle |
||||||
|
{ |
||||||
|
vec3d p[3]; |
||||||
|
vec2d t[3]; |
||||||
|
olc::Pixel col; |
||||||
|
}; |
||||||
|
|
||||||
|
struct mat4x4 |
||||||
|
{ |
||||||
|
float m[4][4] = { 0 }; |
||||||
|
}; |
||||||
|
|
||||||
|
struct mesh |
||||||
|
{ |
||||||
|
std::vector<triangle> tris; |
||||||
|
}; |
||||||
|
|
||||||
|
class Math |
||||||
|
{ |
||||||
|
public: |
||||||
|
inline Math(); |
||||||
|
public: |
||||||
|
inline static vec3d Mat_MultiplyVector(mat4x4 &m, vec3d &i); |
||||||
|
inline static mat4x4 Mat_MultiplyMatrix(mat4x4 &m1, mat4x4 &m2); |
||||||
|
inline static mat4x4 Mat_MakeIdentity(); |
||||||
|
inline static mat4x4 Mat_MakeRotationX(float fAngleRad); |
||||||
|
inline static mat4x4 Mat_MakeRotationY(float fAngleRad); |
||||||
|
inline static mat4x4 Mat_MakeRotationZ(float fAngleRad); |
||||||
|
inline static mat4x4 Mat_MakeScale(float x, float y, float z); |
||||||
|
inline static mat4x4 Mat_MakeTranslation(float x, float y, float z); |
||||||
|
inline static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); |
||||||
|
inline static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up); |
||||||
|
inline static mat4x4 Mat_QuickInverse(mat4x4 &m); // Only for Rotation/Translation Matrices
|
||||||
|
inline static mat4x4 Mat_Inverse(olc::GFX3D::mat4x4 &m); |
||||||
|
|
||||||
|
inline static vec3d Vec_Add(vec3d &v1, vec3d &v2); |
||||||
|
inline static vec3d Vec_Sub(vec3d &v1, vec3d &v2); |
||||||
|
inline static vec3d Vec_Mul(vec3d &v1, float k); |
||||||
|
inline static vec3d Vec_Div(vec3d &v1, float k); |
||||||
|
inline static float Vec_DotProduct(vec3d &v1, vec3d &v2); |
||||||
|
inline static float Vec_Length(vec3d &v); |
||||||
|
inline static vec3d Vec_Normalise(vec3d &v); |
||||||
|
inline static vec3d Vec_CrossProduct(vec3d &v1, vec3d &v2); |
||||||
|
inline static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t); |
||||||
|
|
||||||
|
inline static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2); |
||||||
|
}; |
||||||
|
|
||||||
|
enum RENDERFLAGS |
||||||
|
{ |
||||||
|
RENDER_WIRE = 0x01, |
||||||
|
RENDER_FLAT = 0x02, |
||||||
|
RENDER_TEXTURED = 0x04, |
||||||
|
RENDER_CULL_CW = 0x08, |
||||||
|
RENDER_CULL_CCW = 0x10, |
||||||
|
RENDER_DEPTH = 0x20, |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
class PipeLine |
||||||
|
{ |
||||||
|
public: |
||||||
|
PipeLine(); |
||||||
|
|
||||||
|
public: |
||||||
|
void SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight); |
||||||
|
void SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up); |
||||||
|
void SetTransform(olc::GFX3D::mat4x4 &transform); |
||||||
|
void SetTexture(olc::Sprite *texture); |
||||||
|
void SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col);
|
||||||
|
uint32_t Render(std::vector<olc::GFX3D::triangle> &triangles, uint32_t flags = RENDER_CULL_CW | RENDER_TEXTURED | RENDER_DEPTH); |
||||||
|
|
||||||
|
private: |
||||||
|
olc::GFX3D::mat4x4 matProj; |
||||||
|
olc::GFX3D::mat4x4 matView; |
||||||
|
olc::GFX3D::mat4x4 matWorld; |
||||||
|
olc::Sprite *sprTexture; |
||||||
|
float fViewX; |
||||||
|
float fViewY; |
||||||
|
float fViewW; |
||||||
|
float fViewH; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public: |
||||||
|
//static const int RF_TEXTURE = 0x00000001;
|
||||||
|
//static const int RF_ = 0x00000002;
|
||||||
|
|
||||||
|
inline static void ConfigureDisplay(); |
||||||
|
inline static void ClearDepth(); |
||||||
|
inline static void AddTriangleToScene(olc::GFX3D::triangle &tri); |
||||||
|
inline static void RenderScene(); |
||||||
|
|
||||||
|
inline static void DrawTriangleFlat(olc::GFX3D::triangle &tri); |
||||||
|
inline static void DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col = olc::WHITE); |
||||||
|
inline static void DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr); |
||||||
|
inline static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1, |
||||||
|
int x2, int y2, float u2, float v2, float w2, |
||||||
|
int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr); |
||||||
|
|
||||||
|
// Draws a sprite with the transform applied
|
||||||
|
//inline static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform);
|
||||||
|
|
||||||
|
private: |
||||||
|
static float* m_DepthBuffer; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace olc |
||||||
|
{ |
||||||
|
olc::GFX3D::Math::Math() |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Mat_MultiplyVector(olc::GFX3D::mat4x4 &m, olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeIdentity() |
||||||
|
{ |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationX(float fAngleRad) |
||||||
|
{ |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationY(float fAngleRad) |
||||||
|
{ |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationZ(float fAngleRad) |
||||||
|
{ |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeScale(float x, float y, float z) |
||||||
|
{ |
||||||
|
olc::GFX3D::mat4x4 matrix; |
||||||
|
matrix.m[0][0] = x; |
||||||
|
matrix.m[1][1] = y; |
||||||
|
matrix.m[2][2] = z; |
||||||
|
matrix.m[3][3] = 1.0f; |
||||||
|
return matrix; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeTranslation(float x, float y, float z) |
||||||
|
{ |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar) |
||||||
|
{ |
||||||
|
float fFovRad = 1.0f / tanf(fFovDegrees * 0.5f / 180.0f * 3.14159f); |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MultiplyMatrix(olc::GFX3D::mat4x4 &m1, olc::GFX3D::mat4x4 &m2) |
||||||
|
{ |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_PointAt(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &target, olc::GFX3D::vec3d &up) |
||||||
|
{ |
||||||
|
// Calculate new forward direction
|
||||||
|
olc::GFX3D::vec3d newForward = Vec_Sub(target, pos); |
||||||
|
newForward = Vec_Normalise(newForward); |
||||||
|
|
||||||
|
// Calculate new Up direction
|
||||||
|
olc::GFX3D::vec3d a = Vec_Mul(newForward, Vec_DotProduct(up, newForward)); |
||||||
|
olc::GFX3D::vec3d newUp = Vec_Sub(up, a); |
||||||
|
newUp = Vec_Normalise(newUp); |
||||||
|
|
||||||
|
// New Right direction is easy, its just cross product
|
||||||
|
olc::GFX3D::vec3d newRight = Vec_CrossProduct(newUp, newForward); |
||||||
|
|
||||||
|
// Construct Dimensioning and Translation Matrix
|
||||||
|
olc::GFX3D::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; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_QuickInverse(olc::GFX3D::mat4x4 &m) // Only for Rotation/Translation Matrices
|
||||||
|
{ |
||||||
|
olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_Inverse(olc::GFX3D::mat4x4 &m) |
||||||
|
{ |
||||||
|
double det; |
||||||
|
|
||||||
|
|
||||||
|
mat4x4 matInv; |
||||||
|
|
||||||
|
matInv.m[0][0] = m.m[1][1] * m.m[2][2] * m.m[3][3] - m.m[1][1] * m.m[2][3] * m.m[3][2] - m.m[2][1] * m.m[1][2] * m.m[3][3] + m.m[2][1] * m.m[1][3] * m.m[3][2] + m.m[3][1] * m.m[1][2] * m.m[2][3] - m.m[3][1] * m.m[1][3] * m.m[2][2]; |
||||||
|
matInv.m[1][0] = -m.m[1][0] * m.m[2][2] * m.m[3][3] + m.m[1][0] * m.m[2][3] * m.m[3][2] + m.m[2][0] * m.m[1][2] * m.m[3][3] - m.m[2][0] * m.m[1][3] * m.m[3][2] - m.m[3][0] * m.m[1][2] * m.m[2][3] + m.m[3][0] * m.m[1][3] * m.m[2][2]; |
||||||
|
matInv.m[2][0] = m.m[1][0] * m.m[2][1] * m.m[3][3] - m.m[1][0] * m.m[2][3] * m.m[3][1] - m.m[2][0] * m.m[1][1] * m.m[3][3] + m.m[2][0] * m.m[1][3] * m.m[3][1] + m.m[3][0] * m.m[1][1] * m.m[2][3] - m.m[3][0] * m.m[1][3] * m.m[2][1]; |
||||||
|
matInv.m[3][0] = -m.m[1][0] * m.m[2][1] * m.m[3][2] + m.m[1][0] * m.m[2][2] * m.m[3][1] + m.m[2][0] * m.m[1][1] * m.m[3][2] - m.m[2][0] * m.m[1][2] * m.m[3][1] - m.m[3][0] * m.m[1][1] * m.m[2][2] + m.m[3][0] * m.m[1][2] * m.m[2][1]; |
||||||
|
matInv.m[0][1] = -m.m[0][1] * m.m[2][2] * m.m[3][3] + m.m[0][1] * m.m[2][3] * m.m[3][2] + m.m[2][1] * m.m[0][2] * m.m[3][3] - m.m[2][1] * m.m[0][3] * m.m[3][2] - m.m[3][1] * m.m[0][2] * m.m[2][3] + m.m[3][1] * m.m[0][3] * m.m[2][2]; |
||||||
|
matInv.m[1][1] = m.m[0][0] * m.m[2][2] * m.m[3][3] - m.m[0][0] * m.m[2][3] * m.m[3][2] - m.m[2][0] * m.m[0][2] * m.m[3][3] + m.m[2][0] * m.m[0][3] * m.m[3][2] + m.m[3][0] * m.m[0][2] * m.m[2][3] - m.m[3][0] * m.m[0][3] * m.m[2][2]; |
||||||
|
matInv.m[2][1] = -m.m[0][0] * m.m[2][1] * m.m[3][3] + m.m[0][0] * m.m[2][3] * m.m[3][1] + m.m[2][0] * m.m[0][1] * m.m[3][3] - m.m[2][0] * m.m[0][3] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[2][3] + m.m[3][0] * m.m[0][3] * m.m[2][1]; |
||||||
|
matInv.m[3][1] = m.m[0][0] * m.m[2][1] * m.m[3][2] - m.m[0][0] * m.m[2][2] * m.m[3][1] - m.m[2][0] * m.m[0][1] * m.m[3][2] + m.m[2][0] * m.m[0][2] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[2][2] - m.m[3][0] * m.m[0][2] * m.m[2][1]; |
||||||
|
matInv.m[0][2] = m.m[0][1] * m.m[1][2] * m.m[3][3] - m.m[0][1] * m.m[1][3] * m.m[3][2] - m.m[1][1] * m.m[0][2] * m.m[3][3] + m.m[1][1] * m.m[0][3] * m.m[3][2] + m.m[3][1] * m.m[0][2] * m.m[1][3] - m.m[3][1] * m.m[0][3] * m.m[1][2]; |
||||||
|
matInv.m[1][2] = -m.m[0][0] * m.m[1][2] * m.m[3][3] + m.m[0][0] * m.m[1][3] * m.m[3][2] + m.m[1][0] * m.m[0][2] * m.m[3][3] - m.m[1][0] * m.m[0][3] * m.m[3][2] - m.m[3][0] * m.m[0][2] * m.m[1][3] + m.m[3][0] * m.m[0][3] * m.m[1][2]; |
||||||
|
matInv.m[2][2] = m.m[0][0] * m.m[1][1] * m.m[3][3] - m.m[0][0] * m.m[1][3] * m.m[3][1] - m.m[1][0] * m.m[0][1] * m.m[3][3] + m.m[1][0] * m.m[0][3] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[1][3] - m.m[3][0] * m.m[0][3] * m.m[1][1]; |
||||||
|
matInv.m[3][2] = -m.m[0][0] * m.m[1][1] * m.m[3][2] + m.m[0][0] * m.m[1][2] * m.m[3][1] + m.m[1][0] * m.m[0][1] * m.m[3][2] - m.m[1][0] * m.m[0][2] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[1][2] + m.m[3][0] * m.m[0][2] * m.m[1][1]; |
||||||
|
matInv.m[0][3] = -m.m[0][1] * m.m[1][2] * m.m[2][3] + m.m[0][1] * m.m[1][3] * m.m[2][2] + m.m[1][1] * m.m[0][2] * m.m[2][3] - m.m[1][1] * m.m[0][3] * m.m[2][2] - m.m[2][1] * m.m[0][2] * m.m[1][3] + m.m[2][1] * m.m[0][3] * m.m[1][2]; |
||||||
|
matInv.m[1][3] = m.m[0][0] * m.m[1][2] * m.m[2][3] - m.m[0][0] * m.m[1][3] * m.m[2][2] - m.m[1][0] * m.m[0][2] * m.m[2][3] + m.m[1][0] * m.m[0][3] * m.m[2][2] + m.m[2][0] * m.m[0][2] * m.m[1][3] - m.m[2][0] * m.m[0][3] * m.m[1][2]; |
||||||
|
matInv.m[2][3] = -m.m[0][0] * m.m[1][1] * m.m[2][3] + m.m[0][0] * m.m[1][3] * m.m[2][1] + m.m[1][0] * m.m[0][1] * m.m[2][3] - m.m[1][0] * m.m[0][3] * m.m[2][1] - m.m[2][0] * m.m[0][1] * m.m[1][3] + m.m[2][0] * m.m[0][3] * m.m[1][1]; |
||||||
|
matInv.m[3][3] = m.m[0][0] * m.m[1][1] * m.m[2][2] - m.m[0][0] * m.m[1][2] * m.m[2][1] - m.m[1][0] * m.m[0][1] * m.m[2][2] + m.m[1][0] * m.m[0][2] * m.m[2][1] + m.m[2][0] * m.m[0][1] * m.m[1][2] - m.m[2][0] * m.m[0][2] * m.m[1][1]; |
||||||
|
|
||||||
|
det = m.m[0][0] * matInv.m[0][0] + m.m[0][1] * matInv.m[1][0] + m.m[0][2] * matInv.m[2][0] + m.m[0][3] * matInv.m[3][0]; |
||||||
|
// if (det == 0) return false;
|
||||||
|
|
||||||
|
det = 1.0 / det; |
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) |
||||||
|
for (int j = 0; j < 4; j++) |
||||||
|
matInv.m[i][j] *= (float)det; |
||||||
|
|
||||||
|
return matInv; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Add(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) |
||||||
|
{ |
||||||
|
return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Sub(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) |
||||||
|
{ |
||||||
|
return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Mul(olc::GFX3D::vec3d &v1, float k) |
||||||
|
{ |
||||||
|
return { v1.x * k, v1.y * k, v1.z * k }; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Div(olc::GFX3D::vec3d &v1, float k) |
||||||
|
{ |
||||||
|
return { v1.x / k, v1.y / k, v1.z / k }; |
||||||
|
} |
||||||
|
|
||||||
|
float olc::GFX3D::Math::Vec_DotProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) |
||||||
|
{ |
||||||
|
return v1.x*v2.x + v1.y*v2.y + v1.z * v2.z; |
||||||
|
} |
||||||
|
|
||||||
|
float olc::GFX3D::Math::Vec_Length(olc::GFX3D::vec3d &v) |
||||||
|
{ |
||||||
|
return sqrtf(Vec_DotProduct(v, v)); |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Normalise(olc::GFX3D::vec3d &v) |
||||||
|
{ |
||||||
|
float l = Vec_Length(v); |
||||||
|
return { v.x / l, v.y / l, v.z / l }; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Vec_CrossProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::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; |
||||||
|
} |
||||||
|
|
||||||
|
olc::GFX3D::vec3d olc::GFX3D::Math::Vec_IntersectPlane(olc::GFX3D::vec3d &plane_p, olc::GFX3D::vec3d &plane_n, olc::GFX3D::vec3d &lineStart, olc::GFX3D::vec3d &lineEnd, float &t) |
||||||
|
{ |
||||||
|
plane_n = Vec_Normalise(plane_n); |
||||||
|
float plane_d = -Vec_DotProduct(plane_n, plane_p); |
||||||
|
float ad = Vec_DotProduct(lineStart, plane_n); |
||||||
|
float bd = Vec_DotProduct(lineEnd, plane_n); |
||||||
|
t = (-plane_d - ad) / (bd - ad); |
||||||
|
olc::GFX3D::vec3d lineStartToEnd = Vec_Sub(lineEnd, lineStart); |
||||||
|
olc::GFX3D::vec3d lineToIntersect = Vec_Mul(lineStartToEnd, t); |
||||||
|
return Vec_Add(lineStart, lineToIntersect); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int olc::GFX3D::Math::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 = Math::Vec_Normalise(plane_n); |
||||||
|
|
||||||
|
out_tri1.t[0] = in_tri.t[0]; |
||||||
|
out_tri2.t[0] = in_tri.t[0]; |
||||||
|
out_tri1.t[1] = in_tri.t[1]; |
||||||
|
out_tri2.t[1] = in_tri.t[1]; |
||||||
|
out_tri1.t[2] = in_tri.t[2]; |
||||||
|
out_tri2.t[2] = in_tri.t[2]; |
||||||
|
|
||||||
|
// Return signed shortest distance from point to plane, plane normal must be normalised
|
||||||
|
auto dist = [&](vec3d &p) |
||||||
|
{ |
||||||
|
vec3d n = Math::Vec_Normalise(p); |
||||||
|
return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Math::Vec_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.t[0]; } |
||||||
|
else { |
||||||
|
outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.t[0]; |
||||||
|
} |
||||||
|
if (d1 >= 0) { |
||||||
|
inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.t[1]; |
||||||
|
} |
||||||
|
else { |
||||||
|
outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.t[1]; |
||||||
|
} |
||||||
|
if (d2 >= 0) { |
||||||
|
inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.t[2]; |
||||||
|
} |
||||||
|
else { |
||||||
|
outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.t[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 = olc::MAGENTA;// in_tri.col;
|
||||||
|
|
||||||
|
// The inside point is valid, so keep that...
|
||||||
|
out_tri1.p[0] = *inside_points[0]; |
||||||
|
out_tri1.t[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] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); |
||||||
|
out_tri1.t[1].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; |
||||||
|
out_tri1.t[1].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; |
||||||
|
out_tri1.t[1].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; |
||||||
|
|
||||||
|
out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t); |
||||||
|
out_tri1.t[2].x = t * (outside_tex[1]->x - inside_tex[0]->x) + inside_tex[0]->x; |
||||||
|
out_tri1.t[2].y = t * (outside_tex[1]->y - inside_tex[0]->y) + inside_tex[0]->y; |
||||||
|
out_tri1.t[2].z = t * (outside_tex[1]->z - inside_tex[0]->z) + inside_tex[0]->z; |
||||||
|
|
||||||
|
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 = olc::GREEN;// in_tri.col;
|
||||||
|
out_tri2.col = olc::RED;// 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.t[0] = *inside_tex[0]; |
||||||
|
|
||||||
|
out_tri1.p[1] = *inside_points[1]; |
||||||
|
out_tri1.t[1] = *inside_tex[1]; |
||||||
|
|
||||||
|
float t; |
||||||
|
out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); |
||||||
|
out_tri1.t[2].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; |
||||||
|
out_tri1.t[2].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; |
||||||
|
out_tri1.t[2].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; |
||||||
|
|
||||||
|
// 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[1] = *inside_points[1]; |
||||||
|
out_tri2.t[1] = *inside_tex[1]; |
||||||
|
out_tri2.p[0] = out_tri1.p[2]; |
||||||
|
out_tri2.t[0] = out_tri1.t[2]; |
||||||
|
out_tri2.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t); |
||||||
|
out_tri2.t[2].x = t * (outside_tex[0]->x - inside_tex[1]->x) + inside_tex[1]->x; |
||||||
|
out_tri2.t[2].y = t * (outside_tex[0]->y - inside_tex[1]->y) + inside_tex[1]->y; |
||||||
|
out_tri2.t[2].z = t * (outside_tex[0]->z - inside_tex[1]->z) + inside_tex[1]->z; |
||||||
|
return 2; // Return two newly formed triangles which form a quad
|
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::DrawTriangleFlat(olc::GFX3D::triangle &tri) |
||||||
|
{ |
||||||
|
pge->FillTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, tri.col); |
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col) |
||||||
|
{ |
||||||
|
pge->DrawTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, col); |
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::TexturedTriangle(int x1, int y1, float u1, float v1, float w1, |
||||||
|
int x2, int y2, float u2, float v2, float w2, |
||||||
|
int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr) |
||||||
|
{ |
||||||
|
pge->FillTexturedTriangle({{float(x1),float(y1)},{float(x2),float(y2)},{float(x3),float(y3)}},{{u1,v1},{u2,v2},{u3,v3}},{WHITE,WHITE,WHITE},spr); |
||||||
|
} |
||||||
|
|
||||||
|
float* GFX3D::m_DepthBuffer = nullptr; |
||||||
|
|
||||||
|
void GFX3D::ConfigureDisplay() |
||||||
|
{ |
||||||
|
m_DepthBuffer = new float[pge->ScreenWidth() * pge->ScreenHeight()]{ 0 }; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void GFX3D::ClearDepth() |
||||||
|
{ |
||||||
|
memset(m_DepthBuffer, 0, pge->ScreenWidth() * pge->ScreenHeight() * sizeof(float)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GFX3D::PipeLine::PipeLine() |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::PipeLine::SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight) |
||||||
|
{ |
||||||
|
matProj = GFX3D::Math::Mat_MakeProjection(fFovDegrees, fAspectRatio, fNear, fFar); |
||||||
|
fViewX = fLeft; |
||||||
|
fViewY = fTop; |
||||||
|
fViewW = fWidth; |
||||||
|
fViewH = fHeight; |
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::PipeLine::SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up) |
||||||
|
{ |
||||||
|
matView = GFX3D::Math::Mat_PointAt(pos, lookat, up); |
||||||
|
matView = GFX3D::Math::Mat_QuickInverse(matView); |
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::PipeLine::SetTransform(olc::GFX3D::mat4x4 &transform) |
||||||
|
{ |
||||||
|
matWorld = transform; |
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::PipeLine::SetTexture(olc::Sprite *texture) |
||||||
|
{ |
||||||
|
sprTexture = texture; |
||||||
|
} |
||||||
|
|
||||||
|
void GFX3D::PipeLine::SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
uint32_t GFX3D::PipeLine::Render(std::vector<olc::GFX3D::triangle> &triangles, uint32_t flags) |
||||||
|
{ |
||||||
|
// Calculate Transformation Matrix
|
||||||
|
mat4x4 matWorldView = Math::Mat_MultiplyMatrix(matWorld, matView); |
||||||
|
//matWorldViewProj = Math::Mat_MultiplyMatrix(matWorldView, matProj);
|
||||||
|
|
||||||
|
// Store triangles for rastering later
|
||||||
|
std::vector<GFX3D::triangle> vecTrianglesToRaster; |
||||||
|
|
||||||
|
int nTriangleDrawnCount = 0; |
||||||
|
|
||||||
|
// Process Triangles
|
||||||
|
for (auto &tri : triangles) |
||||||
|
{ |
||||||
|
GFX3D::triangle triTransformed; |
||||||
|
|
||||||
|
// Just copy through texture coordinates
|
||||||
|
triTransformed.t[0] = { tri.t[0].x, tri.t[0].y, tri.t[0].z }; |
||||||
|
triTransformed.t[1] = { tri.t[1].x, tri.t[1].y, tri.t[1].z }; |
||||||
|
triTransformed.t[2] = { tri.t[2].x, tri.t[2].y, tri.t[2].z }; // Think!
|
||||||
|
|
||||||
|
// Transform Triangle from object into projected space
|
||||||
|
triTransformed.p[0] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[0]); |
||||||
|
triTransformed.p[1] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[1]); |
||||||
|
triTransformed.p[2] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[2]); |
||||||
|
|
||||||
|
// Calculate Triangle Normal in WorldView Space
|
||||||
|
GFX3D::vec3d normal, line1, line2; |
||||||
|
line1 = GFX3D::Math::Vec_Sub(triTransformed.p[1], triTransformed.p[0]); |
||||||
|
line2 = GFX3D::Math::Vec_Sub(triTransformed.p[2], triTransformed.p[0]); |
||||||
|
normal = GFX3D::Math::Vec_CrossProduct(line1, line2); |
||||||
|
normal = GFX3D::Math::Vec_Normalise(normal); |
||||||
|
|
||||||
|
// Cull triangles that face away from viewer
|
||||||
|
if (flags & RENDER_CULL_CW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) > 0.0f) continue; |
||||||
|
if (flags & RENDER_CULL_CCW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) < 0.0f) continue; |
||||||
|
|
||||||
|
// If Lighting, calculate shading
|
||||||
|
triTransformed.col = olc::WHITE; |
||||||
|
|
||||||
|
// Clip triangle against near plane
|
||||||
|
int nClippedTriangles = 0; |
||||||
|
triangle clipped[2]; |
||||||
|
nClippedTriangles = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triTransformed, clipped[0], clipped[1]); |
||||||
|
|
||||||
|
// This may yield two new triangles
|
||||||
|
for (int n = 0; n < nClippedTriangles; n++) |
||||||
|
{ |
||||||
|
triangle triProjected = clipped[n]; |
||||||
|
|
||||||
|
// Project new triangle
|
||||||
|
triProjected.p[0] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[0]); |
||||||
|
triProjected.p[1] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[1]); |
||||||
|
triProjected.p[2] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[2]); |
||||||
|
|
||||||
|
// Apply Projection to Verts
|
||||||
|
triProjected.p[0].x = triProjected.p[0].x / triProjected.p[0].w; |
||||||
|
triProjected.p[1].x = triProjected.p[1].x / triProjected.p[1].w; |
||||||
|
triProjected.p[2].x = triProjected.p[2].x / triProjected.p[2].w; |
||||||
|
|
||||||
|
triProjected.p[0].y = triProjected.p[0].y / triProjected.p[0].w; |
||||||
|
triProjected.p[1].y = triProjected.p[1].y / triProjected.p[1].w; |
||||||
|
triProjected.p[2].y = triProjected.p[2].y / triProjected.p[2].w; |
||||||
|
|
||||||
|
triProjected.p[0].z = triProjected.p[0].z / triProjected.p[0].w; |
||||||
|
triProjected.p[1].z = triProjected.p[1].z / triProjected.p[1].w; |
||||||
|
triProjected.p[2].z = triProjected.p[2].z / triProjected.p[2].w; |
||||||
|
|
||||||
|
// Apply Projection to Tex coords
|
||||||
|
triProjected.t[0].x = triProjected.t[0].x / triProjected.p[0].w; |
||||||
|
triProjected.t[1].x = triProjected.t[1].x / triProjected.p[1].w; |
||||||
|
triProjected.t[2].x = triProjected.t[2].x / triProjected.p[2].w; |
||||||
|
|
||||||
|
triProjected.t[0].y = triProjected.t[0].y / triProjected.p[0].w; |
||||||
|
triProjected.t[1].y = triProjected.t[1].y / triProjected.p[1].w; |
||||||
|
triProjected.t[2].y = triProjected.t[2].y / triProjected.p[2].w; |
||||||
|
|
||||||
|
triProjected.t[0].z = 1.0f / triProjected.p[0].w; |
||||||
|
triProjected.t[1].z = 1.0f / triProjected.p[1].w; |
||||||
|
triProjected.t[2].z = 1.0f / triProjected.p[2].w; |
||||||
|
|
||||||
|
// Clip against viewport in screen space
|
||||||
|
// Clip triangles against all four screen edges, this could yield
|
||||||
|
// a bunch of triangles, so create a queue that we traverse to
|
||||||
|
// ensure we only test new triangles generated against planes
|
||||||
|
triangle sclipped[2]; |
||||||
|
std::list<triangle> listTriangles; |
||||||
|
|
||||||
|
|
||||||
|
// Add initial triangle
|
||||||
|
listTriangles.push_back(triProjected); |
||||||
|
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 = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, -1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; |
||||||
|
case 1: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, +1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; |
||||||
|
case 2: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; |
||||||
|
case 3: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ +1.0f, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[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(sclipped[w]); |
||||||
|
} |
||||||
|
nNewTriangles = listTriangles.size(); |
||||||
|
} |
||||||
|
|
||||||
|
for (auto &triRaster : listTriangles) |
||||||
|
{ |
||||||
|
// Scale to viewport
|
||||||
|
/*triRaster.p[0].x *= -1.0f;
|
||||||
|
triRaster.p[1].x *= -1.0f; |
||||||
|
triRaster.p[2].x *= -1.0f; |
||||||
|
triRaster.p[0].y *= -1.0f; |
||||||
|
triRaster.p[1].y *= -1.0f; |
||||||
|
triRaster.p[2].y *= -1.0f;*/ |
||||||
|
vec3d vOffsetView = { 1,1,0 }; |
||||||
|
triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); |
||||||
|
triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); |
||||||
|
triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); |
||||||
|
triRaster.p[0].x *= 0.5f * fViewW; |
||||||
|
triRaster.p[0].y *= 0.5f * fViewH; |
||||||
|
triRaster.p[1].x *= 0.5f * fViewW; |
||||||
|
triRaster.p[1].y *= 0.5f * fViewH; |
||||||
|
triRaster.p[2].x *= 0.5f * fViewW; |
||||||
|
triRaster.p[2].y *= 0.5f * fViewH; |
||||||
|
vOffsetView = { fViewX,fViewY,0 }; |
||||||
|
triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); |
||||||
|
triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); |
||||||
|
triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); |
||||||
|
|
||||||
|
// For now, just draw triangle
|
||||||
|
|
||||||
|
if (flags & RENDER_TEXTURED) |
||||||
|
{ |
||||||
|
TexturedTriangle( |
||||||
|
triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, |
||||||
|
triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, |
||||||
|
triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, |
||||||
|
sprTexture); |
||||||
|
} |
||||||
|
|
||||||
|
if (flags & RENDER_WIRE) |
||||||
|
{ |
||||||
|
DrawTriangleWire(triRaster, olc::RED); |
||||||
|
} |
||||||
|
|
||||||
|
if (flags & RENDER_FLAT) |
||||||
|
{ |
||||||
|
DrawTriangleFlat(triRaster); |
||||||
|
} |
||||||
|
|
||||||
|
nTriangleDrawnCount++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nTriangleDrawnCount; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endif |
Binary file not shown.
Loading…
Reference in new issue