From 3b374c1e17b4a17ea99cb18de81a0b26b07a1f8f Mon Sep 17 00:00:00 2001 From: IDunnoDev Date: Sat, 11 Dec 2021 13:24:09 +0000 Subject: [PATCH] Week5 [26/10] Added the Z Access to the Matrix class Added the Identity Matrix Method to the Matrix Class Added MD2Loader Class Added Model Class Added Polygon Class Added Clear Viewport Method to Rasterizer Added Z Axis to the Vertex Class Updated Transformation Matrices to pass a matrix back so that we can do the multiplication at once --- BaseFramework.vcxproj | 6 ++ BaseFramework.vcxproj.filters | 18 +++++ MD2Loader.cpp | 136 ++++++++++++++++++++++++++++++++++ MD2Loader.h | 14 ++++ Matrix.cpp | 25 ++++++- Matrix.h | 6 +- Model.cpp | 39 ++++++++++ Model.h | 29 ++++++++ Polygon3D.cpp | 43 +++++++++++ Polygon3D.h | 20 +++++ Rasteriser.cpp | 80 ++++++++++++-------- Rasteriser.h | 18 +++-- Vertex.cpp | 42 ++++++++--- Vertex.h | 8 +- cube.md2 | Bin 0 -> 4792 bytes 15 files changed, 432 insertions(+), 52 deletions(-) create mode 100644 MD2Loader.cpp create mode 100644 MD2Loader.h create mode 100644 Model.cpp create mode 100644 Model.h create mode 100644 Polygon3D.cpp create mode 100644 Polygon3D.h create mode 100644 cube.md2 diff --git a/BaseFramework.vcxproj b/BaseFramework.vcxproj index 64ce85e..5fe775d 100644 --- a/BaseFramework.vcxproj +++ b/BaseFramework.vcxproj @@ -148,6 +148,9 @@ + + + @@ -155,6 +158,9 @@ + + + diff --git a/BaseFramework.vcxproj.filters b/BaseFramework.vcxproj.filters index 9484823..bf48fe3 100644 --- a/BaseFramework.vcxproj.filters +++ b/BaseFramework.vcxproj.filters @@ -30,6 +30,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -53,6 +62,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + diff --git a/MD2Loader.cpp b/MD2Loader.cpp new file mode 100644 index 0000000..3aac28c --- /dev/null +++ b/MD2Loader.cpp @@ -0,0 +1,136 @@ +#include "MD2Loader.h" + +// File reading +#include +#include + +using namespace std; + +// BYTE added in case Windows.h is not included. +typedef unsigned char BYTE; + +// Magic number for MD2 files "IDP2" or 844121161 +const int MD2_IDENT = (('2'<<24) + ('P'<<16) + ('D'<<8) + 'I'); + +// MS2 version +const int MD2_VERSION = 8; + +struct Md2Header +{ + int indent; // The magic number used to identify the file. + int version; // The file version number (must be 8). + int skinWidth; // The width in pixels of our image. + int skinHeight; // The height in pixels of our image. + int frameSize; // The size in bytes the frames are. + int numSkins; // The number of skins associated with the model. + int numVertices; // The number of vertices. + int numTexCoords; // The number of texture coordinates. + int numTriangles; // The number of faces (polygons). + int numGlCommands; // The number of gl commands. + int numFrames; // The number of animated frames. + int offsetSkins; // The offset in the file for the skin data. + int offsetTexCoords; // The offset in the file for the texture data. + int offsetTriangles; // The offset in the file for the face data. + int offsetFrames; // The offset in the file for the frames data. + int offsetGlCommands; // The offset in the file for the gl commands data. + int offsetEnd; // The end of the file offset. +}; + +struct Md2Triangle +{ + short vertexIndex[3]; // Vertex indices of the triangle + short uvIndex[3]; // Texture coordinate indices +}; + +struct Md2Vertex +{ + BYTE v[3]; // Compressed vertex (x, y, z) coordinates + BYTE lightNormalIndex; // Index to a normal vector for the lighting +}; + +struct Md2Frame +{ + float scale[3]; // Scale values + float translate[3]; // Translation vector + char name[16]; // Frame name + Md2Vertex verts[1]; // First vertex of this frame +}; + +// ---------------------------------------------- +// LoadModel() - load model from file. +// ---------------------------------------------- + +bool MD2Loader::LoadModel(const char* md2Filename, Model& model, AddPolygon addPolygon, AddVertex addVertex) +{ + ifstream file; + Md2Header header; + + // Try to open MD2 file + file.open(md2Filename, ios::in | ios::binary); + if (file.fail()) + { + return false; + } + // Read file header + file.read(reinterpret_cast(&header), sizeof(Md2Header)); + + // Verify that this is a MD2 file (check for the magic number and version number) + if ((header.indent != MD2_IDENT) && (header.version != MD2_VERSION)) + { + // This is not a MD2 model + file.close(); + return false; + } + + // Allocate the memory we need + Md2Triangle* triangles = new Md2Triangle[header.numTriangles]; + // We are only interested in the first frame + BYTE* frameBuffer = new BYTE[header.frameSize]; + Md2Frame* frame = reinterpret_cast(frameBuffer); + + // Read polygon data... + file.seekg(header.offsetTriangles, ios::beg); + file.read(reinterpret_cast(triangles), sizeof(Md2Triangle) * header.numTriangles); + + // Read frame data... + file.seekg(header.offsetFrames, ios::beg); + file.read(reinterpret_cast(frame), header.frameSize); + + // Close the file + file.close(); + + //---------------------------------------------------------------------------------------------- + + // Polygon array initialization + for ( int i = 0; i < header.numTriangles; ++i ) + { + // Call supplied member function to add a new polygon to the list + std::invoke(addPolygon, model, triangles[i].vertexIndex[0], triangles[i].vertexIndex[1], triangles[i].vertexIndex[2]); + } + + // Vertex array initialization + for( int i = 0; i < header.numVertices; ++i ) + { + // The following are the expressions needed to access each of the co-ordinates. + // + // X co-ordinate: frame->verts[i].v[0] * frame->scale[0] + frame->translate[0] + // Y co-ordinate: frame->verts[i].v[2] * frame->scale[2] + frame->translate[2] + // Z co-ordinate: frame->verts[i].v[1] * frame->scale[1] + frame->translate[1] + // + // NOTE: We have to swap Y and Z over because Z is up in MD2 and we have Y as up-axis + std::invoke(addVertex, model, + static_cast((frame->verts[i].v[0] * frame->scale[0]) + frame->translate[0]), + static_cast((frame->verts[i].v[2] * frame->scale[2]) + frame->translate[2]), + static_cast((frame->verts[i].v[1] * frame->scale[1]) + frame->translate[1])); + } + + // Free dynamically allocated memory + delete [] triangles; // NOTE: this is 'array' delete. Must be sure to use this + triangles = 0; + + delete [] frameBuffer; + frameBuffer = 0; + frame = 0; + + return true; +} diff --git a/MD2Loader.h b/MD2Loader.h new file mode 100644 index 0000000..3d9ada9 --- /dev/null +++ b/MD2Loader.h @@ -0,0 +1,14 @@ +#pragma once +#include "Model.h" + +// Declare typedefs used by the MD2Loader to call the methods to add a vertex and +// add a polygon to the lists + +typedef void (Model::*AddVertex)(float x, float y, float z); +typedef void (Model::*AddPolygon)(int i0, int i1, int i2); + +class MD2Loader +{ + public: + static bool LoadModel(const char* md2Filename, Model& model, AddPolygon addPolygon, AddVertex addVertex); +}; diff --git a/Matrix.cpp b/Matrix.cpp index e5a23ed..549fe5c 100644 --- a/Matrix.cpp +++ b/Matrix.cpp @@ -119,12 +119,31 @@ const Vertex Matrix::operator*(const Vertex& other) const { Vertex newVertex(other); - newVertex.SetX(_matrix[0][0] * other.GetX() + _matrix[0][1] * other.GetY() + _matrix[0][2] * other.GetW()); - newVertex.SetY(_matrix[1][0] * other.GetX() + _matrix[1][1] * other.GetY() + _matrix[1][2] * other.GetW()); - newVertex.SetW(_matrix[2][0] * other.GetX() + _matrix[2][1] * other.GetY() + _matrix[2][2] * other.GetW()); + newVertex.SetX(_matrix[0][0] * other.GetX() + _matrix[0][1] * other.GetY() + _matrix[0][2] * other.GetZ() + _matrix[0][3] * other.GetW()); + newVertex.SetY(_matrix[1][0] * other.GetX() + _matrix[1][1] * other.GetY() + _matrix[1][2] * other.GetZ() + _matrix[1][3] * other.GetW()); + newVertex.SetZ(_matrix[2][0] * other.GetX() + _matrix[2][1] * other.GetY() + _matrix[2][2] * other.GetZ() + _matrix[2][3] * other.GetW()); + newVertex.SetW(_matrix[3][0] * other.GetX() + _matrix[3][1] * other.GetY() + _matrix[3][2] * other.GetZ() + _matrix[3][3] * other.GetW()); return newVertex; } +Matrix Matrix::IdentityMatrix() +{ + for (int i = 0; i < ROWS; i++) + { + for (int j = 0; j < COLS; j++) + { + float currentValue = 0.0f; + if (j == i) + { + currentValue = 1.0f; + } + _matrix[i][j] = currentValue; + } + } + + return _matrix; +} + void Matrix::Copy(const Matrix& other) { for (int i = 0; i < ROWS; i++) diff --git a/Matrix.h b/Matrix.h index 334d3e7..31f03d5 100644 --- a/Matrix.h +++ b/Matrix.h @@ -4,8 +4,8 @@ #include // Size of the matrix -const int COLS = 3; -const int ROWS = 3; +const int COLS = 4; +const int ROWS = 4; class Matrix { @@ -25,6 +25,8 @@ public: void SetMatrixCell(const int row, const int column, const float value); void FromArray(const float arrayIn[ROWS][COLS]); + Matrix IdentityMatrix(); + Matrix& operator= (const Matrix& rhs); bool operator==(const Matrix& other) const; diff --git a/Model.cpp b/Model.cpp new file mode 100644 index 0000000..b6706aa --- /dev/null +++ b/Model.cpp @@ -0,0 +1,39 @@ +#include "Model.h" + +Model::Model() +{ +} + +Model::~Model() +{ +} + +const vector& Model::GetPolygons() +{ + return _polygons; +} + +const vector& Model::GetVertices() +{ + return _vertices; +} + +size_t Model::GetPolygonCount() +{ + return _polygons.size(); +} + +size_t Model::GetVerticesCount() +{ + return _vertices.size(); +} + +void Model::AddVertex(float x, float y, float z) +{ + _vertices.push_back(Vertex(x, y, z)); +} + +void Model::AddPolygon(int index0, int index1, int index2) +{ + _polygons.push_back(Polygon3D(index0, index1, index2)); +} \ No newline at end of file diff --git a/Model.h b/Model.h new file mode 100644 index 0000000..593164c --- /dev/null +++ b/Model.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Polygon3D.h" +#include "Vertex.h" +#include + +using namespace std; + +class Model +{ +public: + Model(); + + ~Model(); + + const vector& GetPolygons(); + const vector& GetVertices(); + + size_t GetPolygonCount(); + size_t GetVerticesCount(); + + void AddVertex(float x, float y, float z); + void AddPolygon(int index0, int index1, int index2); + +private: + vector _polygons; + vector _vertices; +}; + diff --git a/Polygon3D.cpp b/Polygon3D.cpp new file mode 100644 index 0000000..63f3a8a --- /dev/null +++ b/Polygon3D.cpp @@ -0,0 +1,43 @@ +#include "Polygon3D.h" + +Polygon3D::Polygon3D() : _indices{ 0 } +{ +} + +Polygon3D::Polygon3D(int index0, int index1, int index2) +{ + _indices[0] = index0; + _indices[1] = index1; + _indices[2] = index2; +} + +Polygon3D::Polygon3D(const Polygon3D& other) +{ + Copy(other); +} + +Polygon3D::~Polygon3D() +{ +} + +int Polygon3D::GetIndex(const int index) const +{ + return _indices[index]; +} + +Polygon3D& Polygon3D::operator= (const Polygon3D& rhs) +{ + if (this != &rhs) + { + Copy(rhs); + } + return *this; +} + +void Polygon3D::Copy(const Polygon3D& other) +{ + for (int i = 0; i < sizeof(_indices)/sizeof(_indices[0]); i++) + { + _indices[i] = other.GetIndex(i); + } +} \ No newline at end of file diff --git a/Polygon3D.h b/Polygon3D.h new file mode 100644 index 0000000..b6cdaef --- /dev/null +++ b/Polygon3D.h @@ -0,0 +1,20 @@ +#pragma once +class Polygon3D +{ +public: + Polygon3D(); + Polygon3D(int index0, int index1, int index2); + Polygon3D(const Polygon3D& other); + + ~Polygon3D(); + + int GetIndex(int index) const; + + Polygon3D& operator= (const Polygon3D& rhs); + +private: + int _indices[3]; + + void Copy(const Polygon3D& other); +}; + diff --git a/Rasteriser.cpp b/Rasteriser.cpp index a63fb12..d35fa65 100644 --- a/Rasteriser.cpp +++ b/Rasteriser.cpp @@ -7,58 +7,76 @@ Rasteriser app; bool Rasteriser::Initialise() { - //_vertexArray.push_back(Vertex(175, 175, 1)); - //_vertexArray.push_back(Vertex(225, 175, 1)); - //_vertexArray.push_back(Vertex(225, 225, 1)); - //_vertexArray.push_back(Vertex(175, 225, 1)); + //_initialVertexArray.push_back(Vertex(175, 175, 0, 1)); + //_initialVertexArray.push_back(Vertex(225, 175, 0, 1)); + //_initialVertexArray.push_back(Vertex(225, 225, 0, 1)); + //_initialVertexArray.push_back(Vertex(175, 225, 0, 1)); - _vertexArray.push_back(Vertex(150, 200, 1)); - _vertexArray.push_back(Vertex(187.5f, 187.5f, 1)); - _vertexArray.push_back(Vertex(200, 150, 1)); - _vertexArray.push_back(Vertex(212.5f, 187.5f, 1)); - _vertexArray.push_back(Vertex(250, 200, 1)); - _vertexArray.push_back(Vertex(212.5f, 212.5f, 1)); - _vertexArray.push_back(Vertex(200, 250, 1)); - _vertexArray.push_back(Vertex(187.5, 212.5f, 1)); + _initialVertexArray.push_back(Vertex(150, 200, 1)); + _initialVertexArray.push_back(Vertex(187.5f, 187.5f, 1)); + _initialVertexArray.push_back(Vertex(200, 150, 1)); + _initialVertexArray.push_back(Vertex(212.5f, 187.5f, 1)); + _initialVertexArray.push_back(Vertex(250, 200, 1)); + _initialVertexArray.push_back(Vertex(212.5f, 212.5f, 1)); + _initialVertexArray.push_back(Vertex(200, 250, 1)); + _initialVertexArray.push_back(Vertex(187.5, 212.5f, 1)); + _currentVertexArray = _initialVertexArray; + return true; } void Rasteriser::Update(const Bitmap& bitmap) -{ - for (int i = 0; i < _vertexArray.size(); i++) { - _vertexArray[i] = Translate(_vertexArray[i], 2, 0); - _vertexArray[i] = Rotate(_vertexArray[i], 1); - _vertexArray[i] = Scale(_vertexArray[i], 1.001f, 1.001f); +{ + int currentRot = (_rotation % 360); + for (int i = 0; i < _initialVertexArray.size(); i++) { + Matrix currentTransfomation = GetRotationMatrixFromPoint(Axis::Z, (float) currentRot, _initialVertexArray[0].GetX(), _initialVertexArray[0].GetY(), 0); + _currentVertexArray[i] = currentTransfomation * _initialVertexArray[i]; } - + _rotation += 1; } void Rasteriser::Render(const Bitmap& bitmap) { - bitmap.Clear(RGB(255, 255, 255)); + ClearViewport(bitmap); SelectObject(bitmap.GetDC(), GetStockObject(DC_BRUSH)); - //DrawSquare(bitmap.GetDC(), _vertexArray); - DrawShape(bitmap.GetDC(), _vertexArray); + //DrawSquare(bitmap.GetDC(), _initialVertexArray); + DrawShape(bitmap.GetDC(), _currentVertexArray); } -Vertex Rasteriser::Translate(const Vertex vertexIn, const float moveXBy, const float moveYBy) +void Rasteriser::ClearViewport(const Bitmap& bitmap) +{ + bitmap.Clear(RGB(255, 255, 255)); +} + +Matrix Rasteriser::GetTranslateMatrix(const float x, const float y, const float z) +{ + return Matrix({ 1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1 }); +} + +Matrix Rasteriser::GetScaleMatrix(const float x, const float y, const float z) { - Matrix translationMatrix = Matrix({ 1, 0, moveXBy, 0, 1, moveYBy, 0, 0, 1 }); - return translationMatrix * vertexIn; + return Matrix({ x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 }); } -Vertex Rasteriser::Scale(const Vertex vertexIn, const float scaleXBy, const float scaleYBy) +Matrix Rasteriser::GetRotationMatrix(const Axis rotAxis, const float rotDegrees) { - Matrix scaleFactorMatrix = Matrix({ scaleXBy, 0, 0, 0, scaleYBy, 0, 0, 0, 1 }); - return scaleFactorMatrix * vertexIn; + float rotationRadian = DegreesToRadians(rotDegrees); + switch (rotAxis) + { + case (Axis::X): + return Matrix({ 1, 0, 0, 0, 0, cos(rotationRadian), -sin(rotationRadian), 0, 0, sin(rotationRadian), cos(rotationRadian), 0, 0, 0, 0, 1 }); + case (Axis::Y): + return Matrix({ cos(rotationRadian), 0, sin(rotationRadian), 0, 0, 1, 0, 0, -sin(rotationRadian), 0, cos(rotationRadian), 0, 0, 0, 0, 1 }); + default: + case (Axis::Z): + return Matrix({ cos(rotationRadian), -sin(rotationRadian), 0, 0, sin(rotationRadian), cos(rotationRadian), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }); + } } -Vertex Rasteriser::Rotate(const Vertex vertexIn, const float rotationDegrees) +Matrix Rasteriser::GetRotationMatrixFromPoint(const Axis rotAxis, const float rotDegrees, const float x, const float y, const float z) { - float rotationRadian = DegreesToRadians(rotationDegrees); - Matrix rotationFactorMatrix = Matrix({ cos(rotationRadian), -sin(rotationRadian), 0, sin(rotationRadian), cos(rotationRadian), 0, 0, 0, 1}); - return rotationFactorMatrix * vertexIn; + return GetTranslateMatrix(x, y, z) * GetRotationMatrix(rotAxis, rotDegrees) * GetTranslateMatrix(-x, -y, -z); } float Rasteriser::DegreesToRadians(const float degrees) diff --git a/Rasteriser.h b/Rasteriser.h index 9ec46d6..8c331b1 100644 --- a/Rasteriser.h +++ b/Rasteriser.h @@ -4,24 +4,30 @@ #include "Matrix.h" #include +enum class Axis { X, Y, Z }; + class Rasteriser : public Framework { -public: +public: bool Initialise(); void Update(const Bitmap& bitmap); void Render(const Bitmap& bitmap); + void ClearViewport(const Bitmap& bitmap); void DrawSquare(HDC hDc, const vector verticies); void DrawShape(HDC hDc, const vector verticies); - Vertex Translate(const Vertex vertexIn, const float moveXBy, const float moveYBy); - Vertex Scale(const Vertex vertexIn, const float scaleXBy, const float scaleYBy); - Vertex Rotate(const Vertex vertexIn, const float rotationDegrees); - + Matrix GetTranslateMatrix(const float x, const float y, const float z); + Matrix GetScaleMatrix(const float x, const float y, const float z); + Matrix GetRotationMatrix(const Axis rotAxis, const float rotDegrees); + Matrix GetRotationMatrixFromPoint(const Axis rotAxis, const float rotDegrees, const float x, const float y, const float z); + float DegreesToRadians(const float degrees); private: - vector _vertexArray; + vector _initialVertexArray; + vector _currentVertexArray; const float _PI = (float) acos(-1); + int _rotation; }; diff --git a/Vertex.cpp b/Vertex.cpp index e889f49..739f89c 100644 --- a/Vertex.cpp +++ b/Vertex.cpp @@ -4,21 +4,29 @@ Vertex::Vertex() { _x = 0.0f; _y = 0.0f; + _z = 0.0f; _w = 0.0f; } -Vertex::Vertex(float x, float y, float w) +Vertex::Vertex(const float x, const float y, const float z) { _x = x; _y = y; + _z = z; + _w = 1.0f; +} + +Vertex::Vertex(const float x, const float y, const float z, const float w) +{ + _x = x; + _y = y; + _z = z; _w = w; } Vertex::Vertex(const Vertex & other) { - _x = other.GetX(); - _y = other.GetY(); - _w = other.GetW(); + Copy(other); } float Vertex::GetX() const @@ -41,6 +49,16 @@ void Vertex::SetY(const float y) _y = y; } +float Vertex::GetZ() const +{ + return _z; +} + +void Vertex::SetZ(const float z) +{ + _z = z; +} + float Vertex::GetW() const { return _w; @@ -57,9 +75,7 @@ Vertex& Vertex::operator=(const Vertex& rhs) // to ourselves if (this != &rhs) { - _x = rhs.GetX(); - _y = rhs.GetY(); - _w = rhs.GetW(); + Copy(rhs); } return *this; } @@ -69,7 +85,7 @@ Vertex& Vertex::operator=(const Vertex& rhs) bool Vertex::operator==(const Vertex& rhs) const { - return (_x == rhs.GetX() && _y == rhs.GetY() && _w == rhs.GetW()); + return (_x == rhs.GetX() && _y == rhs.GetY() && _z == rhs.GetZ() && _w == rhs.GetW()); } // You can see three different uses of 'const' here: @@ -80,5 +96,13 @@ bool Vertex::operator==(const Vertex& rhs) const const Vertex Vertex::operator+(const Vertex& rhs) const { - return Vertex(_x + rhs.GetX(), _y + rhs.GetY(), _w + rhs.GetW()); + return Vertex(_x + rhs.GetX(), _y + rhs.GetY(), _z + rhs.GetZ(), _w + rhs.GetW()); +} + +void Vertex::Copy(const Vertex& other) +{ + _x = other.GetX(); + _y = other.GetY(); + _z = other.GetZ(); + _w = other.GetW(); } diff --git a/Vertex.h b/Vertex.h index e206585..0782a1e 100644 --- a/Vertex.h +++ b/Vertex.h @@ -3,7 +3,8 @@ class Vertex { public: Vertex(); - Vertex(float x, float y, float w); + Vertex(const float x, const float y, const float z); + Vertex(const float x, const float y, const float z, const float w); Vertex(const Vertex& other); // Accessors @@ -11,6 +12,8 @@ public: void SetX(const float x); float GetY() const; void SetY(const float y); + float GetZ() const; + void SetZ(const float z); float GetW() const; void SetW(const float w); @@ -24,6 +27,9 @@ public: private: float _x; float _y; + float _z; float _w; + + void Copy(const Vertex& other); }; diff --git a/cube.md2 b/cube.md2 new file mode 100644 index 0000000000000000000000000000000000000000..ec7354c26d87815914b3235ecf1f9467aa42b7e2 GIT binary patch literal 4792 zcmd5=J5Iwu5FIBtU-EN^Lj%eYvYYU0aFd3P!WW_Se`=*nPVnoj=7LIPK3;HDrAl` zA#0KBoWsQiF;gL z&1xi(`M@uhc`GUNSg&4?pl5nqUdy>_+MMtnvWv%hZOcm{)8p!Oox6_B`5mXsW4)f` vC6VcIdB4v)Ni?uL!u!iE9_tM)k9%Cb(77AgobYb*SC4tDH@3VaDtdkZ!}6ci literal 0 HcmV?d00001