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
This commit is contained in:
IDunnoDev
2021-12-11 13:24:09 +00:00
committed by iDunnoDev
parent 7c62126ede
commit 3b374c1e17
15 changed files with 432 additions and 52 deletions

View File

@ -148,6 +148,9 @@
<ClCompile Include="Bitmap.cpp" />
<ClCompile Include="Framework.cpp" />
<ClCompile Include="Matrix.cpp" />
<ClCompile Include="MD2Loader.cpp" />
<ClCompile Include="Model.cpp" />
<ClCompile Include="Polygon3D.cpp" />
<ClCompile Include="Rasteriser.cpp" />
<ClCompile Include="Vertex.cpp" />
</ItemGroup>
@ -155,6 +158,9 @@
<ClInclude Include="Bitmap.h" />
<ClInclude Include="Framework.h" />
<ClInclude Include="Matrix.h" />
<ClInclude Include="MD2Loader.h" />
<ClInclude Include="Model.h" />
<ClInclude Include="Polygon3D.h" />
<ClInclude Include="Rasteriser.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="targetver.h" />

View File

@ -30,6 +30,15 @@
<ClCompile Include="Vertex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Polygon3D.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Model.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MD2Loader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Framework.h">
@ -53,6 +62,15 @@
<ClInclude Include="Vertex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Polygon3D.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Model.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MD2Loader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="Rasteriser.ico">

136
MD2Loader.cpp Normal file
View File

@ -0,0 +1,136 @@
#include "MD2Loader.h"
// File reading
#include <iostream>
#include <fstream>
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<char*>(&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<Md2Frame*>(frameBuffer);
// Read polygon data...
file.seekg(header.offsetTriangles, ios::beg);
file.read(reinterpret_cast<char*>(triangles), sizeof(Md2Triangle) * header.numTriangles);
// Read frame data...
file.seekg(header.offsetFrames, ios::beg);
file.read(reinterpret_cast<char*>(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<float>((frame->verts[i].v[0] * frame->scale[0]) + frame->translate[0]),
static_cast<float>((frame->verts[i].v[2] * frame->scale[2]) + frame->translate[2]),
static_cast<float>((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;
}

14
MD2Loader.h Normal file
View File

@ -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);
};

View File

@ -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++)

View File

@ -4,8 +4,8 @@
#include <initializer_list>
// 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;

39
Model.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "Model.h"
Model::Model()
{
}
Model::~Model()
{
}
const vector<Polygon3D>& Model::GetPolygons()
{
return _polygons;
}
const vector<Vertex>& 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));
}

29
Model.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include "Polygon3D.h"
#include "Vertex.h"
#include <vector>
using namespace std;
class Model
{
public:
Model();
~Model();
const vector<Polygon3D>& GetPolygons();
const vector<Vertex>& 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<Polygon3D> _polygons;
vector<Vertex> _vertices;
};

43
Polygon3D.cpp Normal file
View File

@ -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);
}
}

20
Polygon3D.h Normal file
View File

@ -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);
};

View File

@ -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)

View File

@ -4,24 +4,30 @@
#include "Matrix.h"
#include <vector>
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<Vertex> verticies);
void DrawShape(HDC hDc, const vector<Vertex> 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<Vertex> _vertexArray;
vector<Vertex> _initialVertexArray;
vector<Vertex> _currentVertexArray;
const float _PI = (float) acos(-1);
int _rotation;
};

View File

@ -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();
}

View File

@ -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);
};

BIN
cube.md2 Normal file

Binary file not shown.