Week10 [30/11] - [06/12]

Added active Variable to the Lights Classes
Added updated MD2Loader Class
Added Model Filename and Texture File Name to the Model Class
Added Active Flag to the Model Class
Added DrawMode to the Model Class
Added Texture and UV Variables to the Model Class
Added UV Coordinates to the Polygon3D Class
Added DrawString method to the Rasterizer to write text to the screen space
Added Interpolate and Lerp Methods to the Rasterizer
Added Select statement for drawing a current models draw mode
Added DrawTextured Method to the Rasterizer Class
Added UVCoord Class
Added Texture Class
Added = operator to the Vector3D Class
Added UVCoord to the Vertex Class
Moved Models and Texture Files into a subfolder
Fixed issue with textures not loading properly because of the vector address problem
This commit is contained in:
IDunnoDev
2021-12-11 20:31:39 +00:00
committed by iDunnoDev
parent df3c9fac81
commit cdb940f6aa
32 changed files with 1136 additions and 243 deletions

View File

@ -158,6 +158,8 @@
<ClCompile Include="Polygon3D.cpp" />
<ClCompile Include="Rasteriser.cpp" />
<ClCompile Include="SharedTools.cpp" />
<ClCompile Include="Texture.cpp" />
<ClCompile Include="UVCoord.cpp" />
<ClCompile Include="Vector3D.cpp" />
<ClCompile Include="Vertex.cpp" />
</ItemGroup>
@ -177,6 +179,8 @@
<ClInclude Include="Resource.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="SharedTools.h" />
<ClInclude Include="Texture.h" />
<ClInclude Include="UVCoord.h" />
<ClInclude Include="Vector3D.h" />
<ClInclude Include="Vertex.h" />
</ItemGroup>

View File

@ -60,6 +60,12 @@
<ClCompile Include="PointLight.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Texture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UVCoord.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Framework.h">
@ -113,6 +119,12 @@
<ClInclude Include="PointLight.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Texture.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UVCoord.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="Rasteriser.ico">

View File

@ -3,11 +3,13 @@
Light::Light()
{
SetLightIntensity(255, 255, 255);
_active = true;
}
Light::Light(int red, int green, int blue)
{
SetLightIntensity(red, green, blue);
_active = true;
}
Light::Light(const Light& other)
@ -95,6 +97,21 @@ int Light::GetBlueLightIntensity() const
return GetLightIntensity(ColRef::Blue);
}
bool Light::GetLightActive() const
{
return _active;
}
void Light::SetLightActive(bool active)
{
_active = active;
}
void Light::ToggleLightActive()
{
_active = !_active;
}
Light& Light::operator= (const Light& rhs)
{
if (this != &rhs)
@ -109,4 +126,5 @@ void Light::Copy(const Light& other)
_liRed = other.GetRedLightIntensity();
_liGreen = other.GetGreenLightIntensity();
_liBlue = other.GetBlueLightIntensity();
_active = other.GetLightActive();
}

View File

@ -26,6 +26,10 @@ public:
int GetGreenLightIntensity() const;
int GetBlueLightIntensity() const;
bool GetLightActive() const;
void SetLightActive(bool active);
void ToggleLightActive();
virtual COLORREF CalculateLight(const Model& currentModel, const Polygon3D& currentPolygon, COLORREF colorIn) = 0;
virtual COLORREF CalculateLight(const Model& currentModel, const Vertex& currentVertex, COLORREF colorIn) = 0;
@ -36,6 +40,8 @@ protected:
int _liGreen;
int _liBlue;
bool _active;
void Copy(const Light& other);
};

View File

@ -48,6 +48,13 @@ struct Md2Vertex
BYTE lightNormalIndex; // Index to a normal vector for the lighting
};
// Texture co-ordinates
struct Md2TextureCoord
{
short textureCoord[2];
};
struct Md2Frame
{
float scale[3]; // Scale values
@ -56,14 +63,139 @@ struct Md2Frame
Md2Vertex verts[1]; // First vertex of this frame
};
// ----------------------------------------------
// LoadModel() - load model from file.
// ----------------------------------------------
struct PcxHeader
{
BYTE ID;
BYTE Version;
BYTE Encoding;
BYTE BitsPerPixel;
short XMin;
short YMin;
short XMax;
short YMax;
short HRes;
short VRes;
BYTE ClrMap[16 * 3];
BYTE Reserved;
BYTE NumPlanes;
short BytesPerLine;
short Pal;
BYTE Filler[58];
};
bool MD2Loader::LoadModel(const char* md2Filename, Model& model, AddPolygon addPolygon, AddVertex addVertex)
MD2Loader::MD2Loader()
{
}
MD2Loader::~MD2Loader()
{
}
bool LoadPCX(const char* textureFilename, Texture& texture, const Md2Header* md2Header)
{
std::ifstream file;
BYTE * paletteIndices = texture.GetPaletteIndices();
COLORREF * palette = texture.GetPalette();
// Try to open file
file.open(textureFilename, std::ios::in | std::ios::binary);
if (file.fail())
{
return false;
}
// Read PCX header
PcxHeader header;
file.read(reinterpret_cast<char*>(&header), sizeof(PcxHeader));
// Verify that this is a valid PCX file
// We only handle those with 256 colour palette
if ((header.Version != 5) || (header.BitsPerPixel != 8) ||
(header.Encoding != 1) || (header.NumPlanes != 1) ||
(md2Header && (header.BytesPerLine != md2Header->skinWidth)))
{
// This is not valid supported PCX
file.close();
return false;
}
// Check dimensions
int xSize = header.XMax - header.XMin + 1;
int ySize = header.YMax - header.YMin + 1;
int size = xSize * ySize;
// Check that this matches our MD2 expected texture
// Note. valid size is <= because uses RLE (so potentially smaller)
if (md2Header && (size > (md2Header->skinHeight * md2Header->skinWidth)))
{
// Doesn't match expected MD2 skin size
file.close();
return false;
}
// Reading file data
BYTE processByte, colourByte;
int count = 0;
while (count < size)
{
file.read(reinterpret_cast<char*>(&processByte), 1);
// Run length encoding - test if byte is an RLE byte
if ((processByte & 192) == 192)
{
// Extract number of times repeated byte
processByte &= 63;
file.read(reinterpret_cast<char*>(&colourByte), 1);
for (int index = 0; index < processByte; ++index)
{
// repeatedly write colour
paletteIndices[count] = colourByte;
++count;
}
}
else
{
// Byte is the colour
paletteIndices[count] = processByte;
++count;
}
}
bool returnValue = false;
// read palette data...
file.seekg(-769, std::ios::end); // This offset from end of file
file.read(reinterpret_cast<char*>(&processByte), 1);
if (processByte == 12)
{
BYTE rawPalette[768];
file.read(reinterpret_cast<char*>(&rawPalette), 768);
// Build palette
for (int palIndex = 0; palIndex < 256; ++palIndex)
{
palette[palIndex] = RGB(rawPalette[palIndex * 3],
rawPalette[(palIndex * 3) + 1],
rawPalette[(palIndex * 3) + 2]);
}
returnValue = true;
}
file.close();
return returnValue;
}
// Load model from file.
bool MD2Loader::LoadModel(const char* md2Filename, const char * textureFilename, Model& model, AddPolygon addPolygon, AddVertex addVertex, AddTextureUV addTextureUV)
{
ifstream file;
Md2Header header;
bool bHasTexture = false;
// Try to open MD2 file
file.open(md2Filename, ios::in | ios::binary);
@ -87,6 +219,7 @@ bool MD2Loader::LoadModel(const char* md2Filename, Model& model, AddPolygon addP
// We are only interested in the first frame
BYTE* frameBuffer = new BYTE[header.frameSize];
Md2Frame* frame = reinterpret_cast<Md2Frame*>(frameBuffer);
Md2TextureCoord * textureCoords = new Md2TextureCoord[header.numTexCoords];
// Read polygon data...
file.seekg(header.offsetTriangles, ios::beg);
@ -96,16 +229,27 @@ bool MD2Loader::LoadModel(const char* md2Filename, Model& model, AddPolygon addP
file.seekg(header.offsetFrames, ios::beg);
file.read(reinterpret_cast<char*>(frame), header.frameSize);
// Read texture coordinate data
file.seekg(header.offsetTexCoords, std::ios::beg);
file.read(reinterpret_cast<char*>(textureCoords), sizeof(Md2TextureCoord) * header.numTexCoords);
// Close the file
file.close();
//----------------------------------------------------------------------------------------------
// Attempt to load any texture
if (textureFilename)
{
model.GetTexture().SetTextureSize(header.skinWidth, header.skinHeight);
bHasTexture = LoadPCX(textureFilename, model.GetTexture(), &header);
}
// 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]);
std::invoke(addPolygon, model,
triangles[i].vertexIndex[0], triangles[i].vertexIndex[1], triangles[i].vertexIndex[2],
triangles[i].uvIndex[0], triangles[i].uvIndex[1], triangles[i].uvIndex[2]);
}
// Vertex array initialization
@ -123,7 +267,14 @@ bool MD2Loader::LoadModel(const char* md2Filename, Model& model, AddPolygon addP
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]));
}
// Texture coordinates initialisation
if (bHasTexture)
{
for (int i = 0; i < header.numTexCoords; i++)
{
std::invoke(addTextureUV, model, textureCoords[i].textureCoord[0], textureCoords[i].textureCoord[1]);
}
}
// Free dynamically allocated memory
delete [] triangles; // NOTE: this is 'array' delete. Must be sure to use this
triangles = 0;
@ -132,5 +283,8 @@ bool MD2Loader::LoadModel(const char* md2Filename, Model& model, AddPolygon addP
frameBuffer = 0;
frame = 0;
delete[] textureCoords;
textureCoords = 0;
return true;
}

View File

@ -1,14 +1,17 @@
#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
// Declare typedefs used by the MD2Loader to call the methods to add a vertex,
// add a polygon and add a texture UV to the lists
typedef void (Model::*AddVertex)(float x, float y, float z);
typedef void (Model::*AddPolygon)(int i0, int i1, int i2);
typedef void (Model::*AddPolygon)(int i0, int i1, int i2, int uvIndex0, int uvIndex1, int uvIndex2);
typedef void (Model::*AddTextureUV)(float u, float v);
class MD2Loader
{
public:
static bool LoadModel(const char* md2Filename, Model& model, AddPolygon addPolygon, AddVertex addVertex);
MD2Loader();
~MD2Loader();
static bool LoadModel(const char* md2Filename, const char * textureFilename, Model& model, AddPolygon addPolygon, AddVertex addVertex, AddTextureUV addTextureUV);
};

View File

@ -1,5 +1,4 @@
#pragma once
#include "Vertex.h"
#include <initializer_list>

100
Model.cpp
View File

@ -5,10 +5,80 @@ Model::Model()
_kdRed = 1.0f;
_kdGreen = 1.0f;
_kdBlue = 1.0f;
_active = false;
_drawMethod = DrawMethod::Wireframe;
_modelMD2Filename = "";
_modelTextureFilename = "";
}
Model::Model(string MD2Filename, string textureFilename)
{
_kdRed = 1.0f;
_kdGreen = 1.0f;
_kdBlue = 1.0f;
_active = false;
_drawMethod = DrawMethod::Wireframe;
_modelMD2Filename = MD2Filename;
_modelTextureFilename = textureFilename;
}
Model::~Model()
{
_vertices.~vector();
_transformedVertices.~vector();
_polygons.~vector();
_pendingTransforms.~vector();
_uvCoords.~vector();
}
string Model::GetModelFilename() const
{
return _modelMD2Filename;
}
const char* Model::CGetModelFilename() const
{
return _modelMD2Filename.c_str();
}
string Model::GetTextureFilename() const
{
return _modelTextureFilename;
}
const char* Model::CGetTextureFilename() const
{
return _modelTextureFilename.c_str();
}
void Model::SetActive(bool value)
{
_active = value;
}
void Model::ToggleActive()
{
_active = !_active;
}
bool Model::GetActive() const
{
return _active;
}
void Model::SetDrawMethod(DrawMethod method)
{
_drawMethod = method;
}
DrawMethod Model::GetDrawMethod() const
{
return _drawMethod;
}
vector<Polygon3D>& Model::GetPolygons()
@ -21,6 +91,11 @@ vector<Vertex>& Model::GetVertices()
return _vertices;
}
vector<UVCoord>& Model::GetUVCoords()
{
return _uvCoords;
}
const vector<Matrix>& Model::GetPendingTransforms()
{
return _pendingTransforms;
@ -36,6 +111,11 @@ size_t Model::GetVerticesCount()
return _vertices.size();
}
size_t Model::GetUVCoordCount()
{
return _uvCoords.size();
}
size_t Model::GetPendingTransformCount()
{
return _pendingTransforms.size();
@ -47,9 +127,14 @@ void Model::AddVertex(float x, float y, float z)
_transformedVertices.push_back(Vertex(x, y, z));
}
void Model::AddPolygon(int index0, int index1, int index2)
void Model::AddPolygon(int index0, int index1, int index2, int uvIndex0, int uvIndex1, int uvIndex2)
{
_polygons.push_back(Polygon3D(index0, index1, index2));
_polygons.push_back(Polygon3D(index0, index1, index2, uvIndex0, uvIndex1, uvIndex2));
}
void Model::AddTextureUV(float u, float v)
{
_uvCoords.push_back(UVCoord(u, v));
}
void Model::EnqueueTransform(Matrix transform)
@ -62,6 +147,11 @@ void Model::ClearPendingTransforms()
_pendingTransforms.clear();
}
Texture& Model::GetTexture()
{
return _texture;
}
const Polygon3D& Model::GetPolygon(int index) const
{
return _polygons[index];
@ -77,6 +167,11 @@ const Vertex& Model::GetVertex(int index) const
return _transformedVertices[index];
}
const UVCoord& Model::GetUVCoord(int index) const
{
return _uvCoords[index];
}
vector<Vertex> Model::GetPolygonVertexArray(int index) const
{
vector<Vertex> polygonVerticies = {};
@ -234,6 +329,7 @@ void Model::CalculateVertexNormals()
{
_transformedVertices[_polygons[pi].GetIndex(i)].SetNormal(_transformedVertices[_polygons[pi].GetIndex(i)].GetNormal() + _polygons[pi].GetNormal());
_transformedVertices[_polygons[pi].GetIndex(i)].IncrementContributeCount();
_transformedVertices[_polygons[pi].GetIndex(i)].SetUVIndex(_polygons[pi].GetUVIndex(i));
}
}

35
Model.h
View File

@ -4,33 +4,56 @@
#include "Polygon3D.h"
#include "Matrix.h"
#include "Camera.h"
#include "Texture.h"
#include "UVCoord.h"
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
enum class DrawMethod { Wireframe, Flat, FlatRaster, Smooth, Textured };
class Model
{
public:
Model();
Model(string MD2Filename, string textureFilename);
~Model();
string GetModelFilename() const;
const char* CGetModelFilename() const;
string GetTextureFilename() const;
const char* CGetTextureFilename() const;
void SetActive(bool value);
void ToggleActive();
bool GetActive() const;
void SetDrawMethod(DrawMethod method);
DrawMethod GetDrawMethod() const;
vector<Polygon3D>& GetPolygons(void);
vector<Vertex>& GetVertices(void);
vector<UVCoord>& GetUVCoords(void);
const vector<Matrix>& GetPendingTransforms(void);
size_t GetPolygonCount(void);
size_t GetVerticesCount(void);
size_t GetUVCoordCount(void);
size_t GetPendingTransformCount(void);
void AddVertex(float x, float y, float z);
void AddPolygon(int index0, int index1, int index2);
void AddPolygon(int index0, int index1, int index2, int uvIndex0, int uvIndex1, int uvIndex2);
void AddTextureUV(float u, float v);
void EnqueueTransform(Matrix transform);
void ClearPendingTransforms();
Texture& GetTexture();
const Polygon3D& GetPolygon(int index) const;
const Vertex& GetVertex(int polygonIndex, int vertexPolygonIndex) const;
const Vertex& GetVertex(int index) const;
const UVCoord& GetUVCoord(int index) const;
vector<Vertex> GetPolygonVertexArray(int index) const;
void SetPolygonColor(int index, COLORREF color);
@ -61,8 +84,18 @@ private:
vector<Vertex> _transformedVertices;
vector<Matrix> _pendingTransforms;
vector<UVCoord> _uvCoords;
Texture _texture;
float _kdRed;
float _kdGreen;
float _kdBlue;
bool _active;
DrawMethod _drawMethod;
string _modelMD2Filename;
string _modelTextureFilename;
};

View File

@ -1,19 +1,30 @@
#include "Polygon3D.h"
Polygon3D::Polygon3D() : _indices{ 0 }
Polygon3D::Polygon3D() : _indices{ 0 }, _uvIndices { 0 }
{
_depth = 0.0f;
_color = RGB(0, 0, 0);
_r = 0;
_g = 0;
_b = 0;
_culled = false;
}
Polygon3D::Polygon3D(int index0, int index1, int index2)
Polygon3D::Polygon3D(int index0, int index1, int index2, int uvIndex0, int uvIndex1, int uvIndex2)
{
_indices[0] = index0;
_indices[1] = index1;
_indices[2] = index2;
_uvIndices[0] = uvIndex0;
_uvIndices[1] = uvIndex1;
_uvIndices[2] = uvIndex2;
_depth = 0.0f;
_color = RGB(0, 0, 0);
_r = 0;
_g = 0;
_b = 0;
_culled = false;
}
@ -24,6 +35,7 @@ Polygon3D::Polygon3D(const Polygon3D& other)
Polygon3D::~Polygon3D()
{
}
size_t Polygon3D::GetPolygonVertexCount() const
@ -31,11 +43,21 @@ size_t Polygon3D::GetPolygonVertexCount() const
return sizeof(_indices) / sizeof(_indices[0]);
}
size_t Polygon3D::GetPolygonUVCount() const
{
return sizeof(_uvIndices) / sizeof(_uvIndices[0]);
}
int Polygon3D::GetIndex(const int index) const
{
return _indices[index];
}
int Polygon3D::GetUVIndex(const int index) const
{
return _uvIndices[index];
}
void Polygon3D::SetNormal(const Vector3D& normal)
{
_normal = normal;
@ -53,21 +75,51 @@ void Polygon3D::NormalizeNormal()
void Polygon3D::SetColor(int red, int green, int blue)
{
int redChecked = BoundsCheck(0, 255, red);
int greenChecked = BoundsCheck(0, 255, green);
int blueChecked = BoundsCheck(0, 255, blue);
_color = RGB(redChecked, greenChecked, blueChecked);
_r = red;
_g = green;
_b = blue;
}
void Polygon3D::SetColor(const COLORREF color)
{
_color = color;
_r = GetRValue(color);
_g = GetGValue(color);
_b = GetBValue(color);
}
int Polygon3D::GetR() const
{
return _r;
}
void Polygon3D::SetR(const int r)
{
_r = r;
}
int Polygon3D::GetG() const
{
return _g;
}
void Polygon3D::SetG(const int g)
{
_g = g;
}
int Polygon3D::GetB() const
{
return _b;
}
void Polygon3D::SetB(const int b)
{
_b = b;
}
COLORREF Polygon3D::GetColor() const
{
return _color;
return RGB(_r, _g, _b);
}
void Polygon3D::SetDepth(float depth)
@ -105,8 +157,17 @@ void Polygon3D::Copy(const Polygon3D& other)
{
_indices[i] = other.GetIndex(i);
}
for (int i = 0; i < sizeof(_uvIndices) / sizeof(_uvIndices[0]); i++)
{
_uvIndices[i] = other.GetUVIndex(i);
}
_normal = other.GetNormal();
_culled = other.GetCulled();
_depth = other.GetDepth();
_color = other.GetColor();
_r = other.GetR();
_g = other.GetG();
_b = other.GetB();
}

View File

@ -1,22 +1,21 @@
#pragma once
#include "Vector3D.h"
#include "SharedTools.h"
#include "windows.h"
using namespace SharedTools;
class Polygon3D
{
public:
Polygon3D();
Polygon3D(int index0, int index1, int index2);
Polygon3D(int index0, int index1, int index2, int uvIndex0, int uvIndex1, int uvIndex2);
Polygon3D(const Polygon3D& other);
~Polygon3D();
size_t GetPolygonVertexCount() const;
size_t GetPolygonUVCount() const;
int GetIndex(int index) const;
int GetUVIndex(int index) const;
void SetNormal(const Vector3D& normal);
const Vector3D& GetNormal() const;
@ -24,6 +23,14 @@ public:
void SetColor(int red, int green, int blue);
void SetColor(const COLORREF color);
int GetR() const;
void SetR(const int r);
int GetG() const;
void SetG(const int g);
int GetB() const;
void SetB(const int b);
COLORREF GetColor() const;
void SetDepth(float depth);
@ -35,10 +42,15 @@ public:
private:
int _indices[3];
int _uvIndices[3];
Vector3D _normal;
float _depth;
bool _culled;
COLORREF _color;
int _r;
int _g;
int _b;
void Copy(const Polygon3D& other);
};

View File

@ -2,23 +2,60 @@
Rasteriser app;
Rasteriser::~Rasteriser()
{
_lights.~vector();
_sceneModels.~vector();
}
void Rasteriser::DrawString(HDC hDc, int x, int y, LPCTSTR text, COLORREF textColor, COLORREF backgroundColor)
{
HFONT hFont, hOldFont;
// Retrieve a handle to the variable stock font.
hFont = hFont = CreateFont(48, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Myfont"));
// Select the variable stock font into the specified device context.
if (hOldFont = (HFONT)SelectObject(hDc, hFont))
{
SetTextColor(hDc, textColor);
SetBkColor(hDc, backgroundColor);
// Display the text string.
TextOut(hDc, x, y, text, lstrlen(text));
// Restore the original font.
SelectObject(hDc, hOldFont);
}
DeleteObject(hFont);
}
bool Rasteriser::Initialise()
{
Model modelA;
if (MD2Loader::LoadModel(".\\marvin.MD2", modelA, &Model::AddPolygon, &Model::AddVertex))
{
Model modelA = Model(_modelDataLocation + "cube.MD2", _modelDataLocation + "lines.pcx");
// Changed to adding the model to the vector first because doing it once the model has been loaded
// caused the texture pointers to be at incorrect addresses.............
_sceneModels.push_back(modelA);
for (Model& currentModel : _sceneModels)
{
if (MD2Loader::LoadModel(currentModel.CGetModelFilename(), currentModel.CGetTextureFilename(), currentModel, &Model::AddPolygon, &Model::AddVertex, &Model::AddTextureUV))
{
currentModel.SetDrawMethod(DrawMethod::Textured);
currentModel.SetActive(true);
}
else
{
return false;
}
}
_lights.push_back(new AmbientLight(150, 150, 150));
//_lights.push_back(new AmbientLight(255, 255, 255));
_lights.push_back(new DirectionalLight(Vector3D(-1, 0, -1), 150, 150, 150));
//_lights.push_back(new PointLight(Vertex(-10, 0, 10), 0, 1, 0, 100, 0, 0));
//_lights.push_back(new AmbientLight(50, 50, 50));
_lights.push_back(new AmbientLight(255, 255, 255));
//_lights.push_back(new DirectionalLight(Vector3D(-1, 0, 0), 150, 150, 150));
_lights.push_back(new PointLight(Vertex(0, 0, -10), 0, 1, 0.01f, 150, 0, 0));
_cameras.push_back(Camera(0.0f, 0.0f, 0.0f, Vertex(0.0f, 0.0f, -50.0f)));
_screenMinimized = false;
@ -57,9 +94,12 @@ void Rasteriser::CalculateLighting(Model& currentModel, bool fullLightRender)
{
COLORREF colorWorking = RGB(0, 0, 0);
for (Light* currentLight : _lights)
{
if (currentLight->GetLightActive())
{
colorWorking = currentLight->CalculateLight(currentModel, currentModel.GetVertex(pi, i), colorWorking);
}
}
currentModel.SetVertexColor(pi, i, colorWorking);
}
}
@ -67,9 +107,12 @@ void Rasteriser::CalculateLighting(Model& currentModel, bool fullLightRender)
{
COLORREF colorWorking = RGB(0, 0, 0);
for (Light* currentLight : _lights)
{
if (currentLight->GetLightActive())
{
colorWorking = currentLight->CalculateLight(currentModel, currentModel.GetPolygon(pi), colorWorking);
}
}
currentModel.SetPolygonColor(pi, colorWorking);
}
}
@ -77,6 +120,26 @@ void Rasteriser::CalculateLighting(Model& currentModel, bool fullLightRender)
}
}
float Rasteriser::Interpolate(float y, float x0, float x1, float y0, float y1)
{
return x0 + (y - y0) * ((x1 - x0) / (y1 - y0));
}
float Rasteriser::Interpolate(int y, int x0, int x1, int y0, int y1)
{
return Interpolate((float)y, (float)x0, (float)x1, (float)y0, (float)y1);
}
float Rasteriser::Lerp(float a, float b, float t)
{
return a + (b - a) * t;
}
float Rasteriser::Lerp(int a, int b, float t)
{
return Lerp((float)a, (float)b, t);
}
void Rasteriser::Update(const Bitmap& bitmap)
{
if (bitmap.GetWidth() == 0 || bitmap.GetHeight() == 0)
@ -96,10 +159,12 @@ void Rasteriser::Update(const Bitmap& bitmap)
int currentModelIndex = 0;
for (Model& currentModel : _sceneModels)
{
if (currentModel.GetActive())
{
currentModel.EnqueueTransform(GetTranslateMatrix(startPos));
currentModel.EnqueueTransform(GetRotationMatrix(Axis::Y, (float)currentRot));
//startPos.SetX(startPos.GetX() + 100);
/*startPos.SetX(startPos.GetX() + 100);
if ((currentModelIndex % 2) == 1)
{
currentZOff = 0;
@ -108,9 +173,10 @@ void Rasteriser::Update(const Bitmap& bitmap)
{
currentZOff = 100;
}
//startPos.SetZ((float)currentZOff);
startPos.SetZ((float)currentZOff);*/
currentModelIndex++;
}
}
_currentAspectRatio = (float)(bitmap.GetWidth() / (float)bitmap.GetHeight());
_currentPerspectiveMatrix = GetPerspectiveProjectionMatrix(1, _currentAspectRatio);
@ -136,6 +202,8 @@ void Rasteriser::Render(const Bitmap& bitmap)
SelectObject(bitmap.GetDC(), GetStockObject(DC_PEN));
for (Model& currentModel : _sceneModels)
{
if (currentModel.GetActive())
{
currentModel.SetReflectionCoefficient(0.5f, 0.5f, 0.5f);
Matrix workingMatrix = workingMatrix.IdentityMatrix();
@ -149,20 +217,57 @@ void Rasteriser::Render(const Bitmap& bitmap)
currentModel.CalculateBackfaces(GetCurrentCamera());
currentModel.Sort();
switch (currentModel.GetDrawMethod())
{
case (DrawMethod::Wireframe):
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
currentModel.DehomogenizeAllVertices();
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
DrawWireFrame(bitmap.GetDC(), currentModel);
break;
case (DrawMethod::Flat):
currentModel.CalculateVertexNormals();
CalculateLighting(currentModel, false);
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
currentModel.DehomogenizeAllVertices();
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
DrawSolidFlat(bitmap.GetDC(), currentModel);
break;
case (DrawMethod::FlatRaster):
currentModel.CalculateVertexNormals();
CalculateLighting(currentModel, false);
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
currentModel.DehomogenizeAllVertices();
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
DrawRasterisedSolidFlat(bitmap.GetDC(), currentModel);
break;
case (DrawMethod::Smooth):
currentModel.CalculateVertexNormals();
CalculateLighting(currentModel, true);
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
currentModel.DehomogenizeAllVertices();
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
//DrawWireFrame(bitmap.GetDC(), currentModel);
//DrawSolidFlat(bitmap.GetDC(), currentModel);
//DrawRasterisedSolidFlat(bitmap.GetDC(), currentModel);
DrawGouraud(bitmap.GetDC(), currentModel);
break;
case (DrawMethod::Textured):
currentModel.CalculateVertexNormals();
CalculateLighting(currentModel, true);
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
currentModel.DehomogenizeAllVertices();
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
DrawSolidTextured(bitmap.GetDC(), currentModel);
break;
}
currentModel.ClearPendingTransforms();
}
}
DrawString(bitmap.GetDC(), 10, 10, _T("Hello World"));
}
}
void Rasteriser::ClearViewport(const Bitmap& bitmap)
@ -179,8 +284,8 @@ void Rasteriser::DrawSquare(HDC hDc, const vector<Vertex> verticies)
pointArray[i].y = (long) verticies[i].GetY();
}
SetDCBrushColor(hDc, RGB(255, 0, 255));
SetDCPenColor(hDc, RGB(0, 0, 255));
SetDCBrushColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256));
SetDCPenColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256));
Polygon(hDc, pointArray, 4);
}
@ -225,6 +330,8 @@ void Rasteriser::DrawWireFrame(HDC hDc, Model& model)
}
}
SetDCBrushColor(hDc, RGB(1,1,1));
SetDCPenColor(hDc, RGB(255,255,255));
PolyPolygon(hDc, pointArray.data(), sizeArray.data(), unculledPolyCount);
}
@ -280,6 +387,20 @@ void Rasteriser::DrawGouraud(HDC hDc, Model& model)
}
}
void Rasteriser::DrawSolidTextured(HDC hDc, Model& model)
{
int modelPolygonCount = (int)model.GetPolygonCount();
for (int i = 0; i < modelPolygonCount; i++)
{
if (!model.GetPolygon(i).GetCulled())
{
vector<Vertex> vertexArray = model.GetPolygonVertexArray(i);
FillPolygonTextured(hDc, model, vertexArray);
}
}
}
bool VerticiesYCompareAsc(Vertex& v1, Vertex& v2)
{
return v1.GetY() < v2.GetY();
@ -326,11 +447,11 @@ void Rasteriser::FillFlatSideTriangle(HDC hDc, const Vertex& v1, const Vertex& v
int dx2 = (int)ceil(abs(v3.GetX() - v1.GetX()));
int dy2 = (int)ceil(abs(v3.GetY() - v1.GetY()));
int signx1 = (int)sgn(v2.GetX() - v1.GetX());
int signx2 = (int)sgn(v3.GetX() - v1.GetX());
int signx1 = (int)ceil(sgn(v2.GetX() - v1.GetX()));
int signx2 = (int)ceil(sgn(v3.GetX() - v1.GetX()));
int signy1 = (int)sgn(v2.GetY() - v1.GetY());
int signy2 = (int)sgn(v3.GetY() - v1.GetY());
int signy1 = (int)ceil(sgn(v2.GetY() - v1.GetY()));
int signy2 = (int)ceil(sgn(v3.GetY() - v1.GetY()));
if (dy1 > dx1)
{
@ -353,72 +474,73 @@ void Rasteriser::FillFlatSideTriangle(HDC hDc, const Vertex& v1, const Vertex& v
for (int i = 0; i <= dx1; i++)
{
int startPoint;
int endPoint;
float leftEndPoint;
float rightEndPoint;
if (tempA.GetXInt() < tempB.GetXInt())
if (tempA.GetX() < tempB.GetX())
{
startPoint = tempA.GetXInt();
endPoint = tempB.GetXInt();
leftEndPoint = tempA.GetX() - 1.0f;
rightEndPoint = tempB.GetX() + 1.0f;
}
else
{
startPoint = tempB.GetXInt();
endPoint = tempA.GetXInt();
leftEndPoint = tempB.GetX() - 1.0f;
rightEndPoint = tempA.GetX() + 1.0f;
}
for (int xi = (int)ceil(startPoint); xi <= endPoint; xi++)
for (int xi = (int)ceil(leftEndPoint); xi <= (int)ceil(rightEndPoint); xi++)
{
SetPixel(hDc, xi, tempA.GetYInt(), colorIn);
}
while (e1 >= 0)
{
if (changed1)
{
tempA.SetX(tempA.GetX() + signx1);
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
else
{
tempA.SetY(tempA.GetY() + signy1);
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
e1 = e1 - 2 * dx1;
}
if (changed1)
{
tempA.SetY(tempA.GetY() + signy1);
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
else
{
tempA.SetX(tempA.GetX() + signx1);
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
e1 = e1 + 2 * dy1;
while (tempB.GetY() != tempA.GetY())
while (tempB.GetYInt() != tempA.GetYInt())
{
while (e2 >= 0)
{
if (changed2)
{
tempB.SetX(tempB.GetX() + signx2);
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
}
else
{
tempB.SetY(tempB.GetY() + signy2);
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
}
e2 = e2 - 2 * dx2;
}
if (changed2)
{
tempB.SetY(tempB.GetY() + signy2);
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
}
else
{
tempB.SetX(tempB.GetX() + signx2);
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
}
e2 = e2 + 2 * dy2;
}
@ -426,112 +548,6 @@ void Rasteriser::FillFlatSideTriangle(HDC hDc, const Vertex& v1, const Vertex& v
}
void Rasteriser::FillPolygonGouraud(HDC hDc, vector<Vertex>& verts)
{
sort(verts.begin(), verts.end(), VerticiesYCompareAsc);
if (verts[1].GetY() == verts[2].GetY())
{
FillGouraudBottomFlatTriangle(hDc, verts[0], verts[1], verts[2]);
}
else if (verts[0].GetY() == verts[1].GetY())
{
FillGouraudTopFlatTriangle(hDc, verts[0], verts[1], verts[2]);
}
else
{
Vertex temp = Vertex(verts[0].GetX() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetX() - verts[0].GetX()), verts[1].GetY(), verts[1].GetZ());
temp.SetNormal(verts[1].GetNormal());
float cRed = GetRValue(verts[0].GetColor()) + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (GetRValue(verts[2].GetColor()) - GetRValue(verts[0].GetColor()));
float cGreen = GetGValue(verts[0].GetColor()) + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (GetGValue(verts[2].GetColor()) - GetGValue(verts[0].GetColor()));
float cBlue = GetBValue(verts[0].GetColor()) + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (GetBValue(verts[2].GetColor()) - GetBValue(verts[0].GetColor()));
temp.SetColor(RGB((int)cRed, (int)cGreen, (int)cBlue));
temp.SetColor(verts[1].GetColor());
FillGouraudBottomFlatTriangle(hDc, verts[0], verts[1], temp);
FillGouraudTopFlatTriangle(hDc, verts[1], temp, verts[2]);
}
}
void Rasteriser::FillGouraudBottomFlatTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3)
{
float slope1 = (float)(v2.GetX() - v1.GetX()) / (float)(v2.GetY() - v1.GetY());
float slope2 = (float)(v3.GetX() - v1.GetX()) / (float)(v3.GetY() - v1.GetY());
float x1 = (float)v1.GetX();
float x2 = (float)v1.GetX() + 0.5f;
if (slope2 < slope1)
{
float slopeTmp = slope1;
slope1 = slope2;
slope2 = slopeTmp;
}
for (int scanlineY = (int)v1.GetY(); scanlineY <= (int)v2.GetY(); scanlineY++)
{
float iRedA = (scanlineY - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetR() + (v1.GetY() - scanlineY) / (v1.GetY() - v2.GetY()) * v2.GetR();
float iRedB = (scanlineY - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetR() + (v1.GetY() - scanlineY) / (v1.GetY() - v3.GetY()) * v3.GetR();
float iGreenA = (scanlineY - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetG() + (v1.GetY() - scanlineY) / (v1.GetY() - v2.GetY()) * v2.GetG();
float iGreenB = (scanlineY - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetG() + (v1.GetY() - scanlineY) / (v1.GetY() - v3.GetY()) * v3.GetG();
float iBlueA = (scanlineY - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetB() + (v1.GetY() - scanlineY) / (v1.GetY() - v2.GetY()) * v2.GetB();
float iBlueB = (scanlineY - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetB() + (v1.GetY() - scanlineY) / (v1.GetY() - v3.GetY()) * v3.GetB();
for (int xi = (int)ceil(x1); xi < (int)x2; xi++)
{
float redTmp = (x2 - xi) / (x2 - x1) * iRedA + (xi - x1) / (x2 - x1) * iRedB;
float greenTmp = (x2 - xi) / (x2 - x1) * iGreenA + (xi - x1) / (x2 - x1) * iGreenB;
float blueTmp = (x2 - xi) / (x2 - x1) * iBlueA + (xi - x1) / (x2 - x1) * iBlueB;
COLORREF currentColor = RGB(BoundsCheck(0, 255, (int)redTmp), BoundsCheck(0, 255, (int)greenTmp), BoundsCheck(0, 255, (int)blueTmp));
SetPixel(hDc, xi, scanlineY, currentColor);
}
x1 += slope1;
x2 += slope2;
}
}
void Rasteriser::FillGouraudTopFlatTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3)
{
float slope1 = (float)(v3.GetX() - v1.GetX()) / (float)(v3.GetY() - v1.GetY());
float slope2 = (float)(v3.GetX() - v2.GetX()) / (float)(v3.GetY() - v2.GetY());
float x1 = (float)v3.GetX();
float x2 = (float)v3.GetX() + 0.5f;
if (slope1 < slope2)
{
float slopeTmp = slope1;
slope1 = slope2;
slope2 = slopeTmp;
}
for (int scanlineY = (int)v3.GetY(); scanlineY > (int)v1.GetY(); scanlineY--)
{
float iRedA = (scanlineY - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetR() + (v1.GetY() - scanlineY) / (v1.GetY() - v2.GetY()) * v2.GetR();
float iRedB = (scanlineY - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetR() + (v1.GetY() - scanlineY) / (v1.GetY() - v3.GetY()) * v3.GetR();
float iGreenA = (scanlineY - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetG() + (v1.GetY() - scanlineY) / (v1.GetY() - v2.GetY()) * v2.GetG();
float iGreenB = (scanlineY - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetG() + (v1.GetY() - scanlineY) / (v1.GetY() - v3.GetY()) * v3.GetG();
float iBlueA = (scanlineY - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetB() + (v1.GetY() - scanlineY) / (v1.GetY() - v2.GetY()) * v2.GetB();
float iBlueB = (scanlineY - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetB() + (v1.GetY() - scanlineY) / (v1.GetY() - v3.GetY()) * v3.GetB();
for (int xi = (int)ceil(x1); xi < (int)x2; xi++)
{
float redTmp = (x2 - xi) / (x2 - x1) * iRedA - (xi - x1) / (x2 - x1) * iRedB;
float greenTmp = (x2 - xi) / (x2 - x1) * iGreenA - (xi - x1) / (x2 - x1) * iGreenB;
float blueTmp = (x2 - xi) / (x2 - x1) * iBlueA - (xi - x1) / (x2 - x1) * iBlueB;
COLORREF currentColor = RGB(BoundsCheck(0, 255, (int)redTmp), BoundsCheck(0, 255, (int)greenTmp), BoundsCheck(0, 255, (int)blueTmp));
SetPixel(hDc, xi, scanlineY, currentColor);
}
x1 -= slope1;
x2 -= slope2;
}
}
void Rasteriser::FillPolygonGouraudInt(HDC hDc, vector<Vertex>& verts)
{
sort(verts.begin(), verts.end(), VerticiesYCompareAsc);
if (verts[1].GetY() == verts[2].GetY())
@ -547,12 +563,13 @@ void Rasteriser::FillPolygonGouraudInt(HDC hDc, vector<Vertex>& verts)
Vertex temp = Vertex(verts[0].GetX() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetX() - verts[0].GetX()), verts[1].GetY(), verts[1].GetZ());
temp.SetNormal(verts[1].GetNormal());
float cRed = verts[0].GetR() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetR() - verts[0].GetR());
float cGreen = verts[0].GetG() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetG() - verts[0].GetG());
float cBlue = verts[0].GetB() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetB() - verts[0].GetB());
float vDiff = ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY()));
float cRed = Lerp(verts[0].GetR(), verts[2].GetR(), vDiff);
float cGreen = Lerp(verts[0].GetG(), verts[2].GetG(), vDiff);
float cBlue = Lerp(verts[0].GetB(), verts[2].GetB(), vDiff);
temp.SetColor(BoundsCheck(0, 255, (int)cRed), BoundsCheck(0, 255, (int)cGreen), BoundsCheck(0, 255, (int)cBlue));
if (verts[1].GetX() < temp.GetX())
if (verts[1].GetX() <= temp.GetX())
{
FillGouraudSideTriangle(hDc, verts[0], verts[1], temp);
FillGouraudSideTriangle(hDc, verts[2], verts[1], temp);
@ -611,30 +628,35 @@ void Rasteriser::FillGouraudSideTriangle(HDC hDc, const Vertex& v1, const Vertex
if (tempA.GetX() < tempB.GetX())
{
leftEndPoint = tempA.GetX();
rightEndPoint = tempB.GetX();
leftEndPoint = tempA.GetX() - 1.0f;
rightEndPoint = tempB.GetX() + 1.0f;
}
else
{
leftEndPoint = tempB.GetX();
rightEndPoint = tempA.GetX();
leftEndPoint = tempB.GetX() - 1.0f;
rightEndPoint = tempA.GetX() + 1.0f;
}
float iRedA = (tempA.GetY() - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetR() + (v1.GetY() - tempA.GetY()) / (v1.GetY() - v2.GetY()) * v2.GetR();
float iRedB = (tempA.GetY() - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetR() + (v1.GetY() - tempA.GetY()) / (v1.GetY() - v3.GetY()) * v3.GetR();
float iGreenA = (tempA.GetY() - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetG() + (v1.GetY() - tempA.GetY()) / (v1.GetY() - v2.GetY()) * v2.GetG();
float iGreenB = (tempA.GetY() - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetG() + (v1.GetY() - tempA.GetY()) / (v1.GetY() - v3.GetY()) * v3.GetG();
float iBlueA = (tempA.GetY() - v2.GetY()) / (v1.GetY() - v2.GetY()) * v1.GetB() + (v1.GetY() - tempA.GetY()) / (v1.GetY() - v2.GetY()) * v2.GetB();
float iBlueB = (tempA.GetY() - v3.GetY()) / (v1.GetY() - v3.GetY()) * v1.GetB() + (v1.GetY() - tempA.GetY()) / (v1.GetY() - v3.GetY()) * v3.GetB();
float iRedA = Lerp(v1.GetR(), v2.GetR(), (float)i / (float)dx1);
float iRedB = Lerp(v1.GetR(), v3.GetR(), (float)i / (float)dx1);
float iGreenA = Lerp(v1.GetG(), v2.GetG(), (float)i / (float)dx1);
float iGreenB = Lerp(v1.GetG(), v3.GetG(), (float)i / (float)dx1);
float iBlueA = Lerp(v1.GetB(), v2.GetB(), (float)i / (float)dx1);
float iBlueB = Lerp(v1.GetB(), v3.GetB(), (float)i / (float)dx1);
for (int xi = (int)ceil(leftEndPoint); xi <= (int)rightEndPoint; xi++)
int xLength = (int)ceil(rightEndPoint) - (int)ceil(leftEndPoint);
int ci = 0;
for (int xi = (int)ceil(leftEndPoint); xi <= (int)ceil(rightEndPoint); xi++)
{
float redTmp = (rightEndPoint - xi) / (rightEndPoint - leftEndPoint) * iRedA + (xi - leftEndPoint) / (rightEndPoint - leftEndPoint) * iRedB;
float greenTmp = (rightEndPoint - xi) / (rightEndPoint - leftEndPoint) * iGreenA + (xi - leftEndPoint) / (rightEndPoint - leftEndPoint) * iGreenB;
float blueTmp = (rightEndPoint - xi) / (rightEndPoint - leftEndPoint) * iBlueA + (xi - leftEndPoint) / (rightEndPoint - leftEndPoint) * iBlueB;
float ti = (float)ci / (float)xLength;
float redTmp = Lerp(iRedA, iRedB, ti);
float greenTmp = Lerp(iGreenA, iGreenB, ti);
float blueTmp = Lerp(iBlueA, iBlueB, ti);
COLORREF currentColor = RGB(BoundsCheck(0, 255, (int)redTmp), BoundsCheck(0, 255, (int)greenTmp), BoundsCheck(0, 255, (int)blueTmp));
SetPixel(hDc, xi, tempA.GetYInt(), currentColor);
ci++;
}
@ -642,27 +664,27 @@ void Rasteriser::FillGouraudSideTriangle(HDC hDc, const Vertex& v1, const Vertex
{
if (changed1)
{
tempA.SetX((float)tempA.GetXInt() + (float)signx1);
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
else
{
tempA.SetY((float)tempA.GetYInt() + (float)signy1);
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
e1 = e1 - 2 * dx1;
}
if (changed1)
{
tempA.SetY((float)tempA.GetYInt() + (float)signy1);
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
else
{
tempA.SetX((float)tempA.GetXInt() + (float)signx1);
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
e1 = e1 + 2 * dy1;
while (tempB.GetY() < tempA.GetY() && tempB.GetY() > tempA.GetY())
while (tempB.GetYInt() != tempA.GetYInt())
{
while (e2 >= 0)
{
@ -689,3 +711,224 @@ void Rasteriser::FillGouraudSideTriangle(HDC hDc, const Vertex& v1, const Vertex
}
}
}
void Rasteriser::FillPolygonTextured(HDC hDc, Model& model, vector<Vertex>& verts)
{
sort(verts.begin(), verts.end(), VerticiesYCompareAsc);
if (verts[1].GetY() == verts[2].GetY())
{
FillTexturedSideTriangle(hDc, model, verts[0], verts[1], verts[2], model.GetUVCoord(verts[0].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), model.GetUVCoord(verts[2].GetUVIndex()));
}
else if (verts[0].GetY() == verts[1].GetY())
{
FillTexturedSideTriangle(hDc, model, verts[2], verts[0], verts[1], model.GetUVCoord(verts[2].GetUVIndex()), model.GetUVCoord(verts[0].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()));
}
else
{
Vertex temp = Vertex(verts[0].GetX() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetX() - verts[0].GetX()), verts[1].GetY(), verts[1].GetZ());
temp.SetNormal(verts[1].GetNormal());
float tempU = model.GetUVCoord(verts[0].GetUVIndex()).GetU() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (model.GetUVCoord(verts[2].GetUVIndex()).GetU() - model.GetUVCoord(verts[0].GetUVIndex()).GetU());
float tempV = model.GetUVCoord(verts[0].GetUVIndex()).GetV() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (model.GetUVCoord(verts[2].GetUVIndex()).GetV() - model.GetUVCoord(verts[0].GetUVIndex()).GetV());
UVCoord tempCoords = UVCoord(tempU, tempV);
float cRed = verts[0].GetR() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetR() - verts[0].GetR());
float cGreen = verts[0].GetG() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetG() - verts[0].GetG());
float cBlue = verts[0].GetB() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetB() - verts[0].GetB());
temp.SetColor(BoundsCheck(0, 255, (int)cRed), BoundsCheck(0, 255, (int)cGreen), BoundsCheck(0, 255, (int)cBlue));
if (verts[1].GetX() <= temp.GetX())
{
temp.SetUVIndex(verts[2].GetUVIndex());
FillTexturedSideTriangle(hDc, model, verts[0], verts[1], temp, model.GetUVCoord(verts[0].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), tempCoords);
temp.SetUVIndex(verts[0].GetUVIndex());
FillTexturedSideTriangle(hDc, model, verts[2], verts[1], temp, model.GetUVCoord(verts[2].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), tempCoords);
}
else
{
temp.SetUVIndex(verts[2].GetUVIndex());
FillTexturedSideTriangle(hDc, model, verts[0], temp, verts[1], model.GetUVCoord(verts[0].GetUVIndex()), tempCoords, model.GetUVCoord(verts[1].GetUVIndex()));
temp.SetUVIndex(verts[0].GetUVIndex());
FillTexturedSideTriangle(hDc, model, verts[2], temp, verts[1], model.GetUVCoord(verts[2].GetUVIndex()), tempCoords, model.GetUVCoord(verts[1].GetUVIndex()));
}
}
}
void Rasteriser::FillTexturedSideTriangle(HDC hDc, Model& model, const Vertex& v1, const Vertex& v2, const Vertex& v3, const UVCoord& uv1, const UVCoord& uv2, const UVCoord& uv3)
{
Vertex tempA = Vertex(v1);
Vertex tempB = Vertex(v1);
UVCoord tempUVA = UVCoord(uv1);
UVCoord tempUVB = UVCoord(uv1);
bool changed1 = false;
bool changed2 = false;
float uc0 = uv1.GetU();
float vc0 = uv1.GetV();
float uc1 = uv2.GetU();
float vc1 = uv2.GetV();
float uc2 = uv3.GetU();
float vc2 = uv3.GetV();
int dx1 = (int)ceil(abs(v2.GetX() - v1.GetX()));
int dy1 = (int)ceil(abs(v2.GetY() - v1.GetY()));
int du1 = (int)ceil(abs(uc1 - uc0));
int dv1 = (int)ceil(abs(vc1 - vc0));
int dx2 = (int)ceil(abs(v3.GetX() - v1.GetX()));
int dy2 = (int)ceil(abs(v3.GetY() - v1.GetY()));
int du2 = (int)ceil(abs(uc2 - uc0));
int dv2 = (int)ceil(abs(vc2 - vc0));
int signx1 = (int)ceil(sgn(v2.GetX() - v1.GetX()));
int signx2 = (int)ceil(sgn(v3.GetX() - v1.GetX()));
int signu1 = (int)ceil(sgn(uc1 - uc0));
int signu2 = (int)ceil(sgn(uc2 - uc0));
int signy1 = (int)ceil(sgn(v2.GetY() - v1.GetY()));
int signy2 = (int)ceil(sgn(v3.GetY() - v1.GetY()));
int signv1 = (int)ceil(sgn(vc1 - vc0));
int signv2 = (int)ceil(sgn(vc2 - vc0));
if (dy1 > dx1)
{
int tempDx = dx1;
dx1 = dy1;
dy1 = tempDx;
int tempDu = du1;
du1 = dv1;
dv1 = tempDu;
changed1 = true;
}
if (dy2 > dx2)
{
int tempDx = dx2;
dx2 = dy2;
dy2 = tempDx;
int tempDu = du2;
du2 = dv2;
dv2 = tempDu;
changed2 = true;
}
int e1 = 2 * (int)dy1 - (int)dx1;
int e2 = 2 * (int)dy2 - (int)dx2;
for (int i = 0; i <= (int)dx1; i++)
{
float leftEndPoint;
float rightEndPoint;
float leftUV;
float rightUV;
if (tempA.GetX() < tempB.GetX())
{
leftEndPoint = tempA.GetX() - 1.0f;
rightEndPoint = tempB.GetX() + 1.0f;
leftUV = tempUVA.GetU();
rightUV = tempUVB.GetU();
}
else
{
leftEndPoint = tempB.GetX() - 1.0f;
rightEndPoint = tempA.GetX() + 1.0f;
leftUV = tempUVB.GetU();
rightUV = tempUVA.GetU();
}
float UCoordA = Interpolate(uv1.GetV() + i, uv1.GetU(), uv2.GetU(), uv1.GetV(), uv2.GetV());
float UCoordB = Interpolate(uv1.GetV() + i, uv1.GetU(), uv3.GetU(), uv1.GetV(), uv3.GetV());
float iRedA = Lerp(v1.GetR(), v2.GetR(), (float)i / (float)dx1);
float iRedB = Lerp(v1.GetR(), v3.GetR(), (float)i / (float)dx1);
float iGreenA = Lerp(v1.GetG(), v2.GetG(), (float)i / (float)dx1);
float iGreenB = Lerp(v1.GetG(), v3.GetG(), (float)i / (float)dx1);
float iBlueA = Lerp(v1.GetB(), v2.GetB(), (float)i / (float)dx1);
float iBlueB = Lerp(v1.GetB(), v3.GetB(), (float)i / (float)dx1);
int xLength = (int)ceil(rightEndPoint) - (int)ceil(leftEndPoint);
int ci = 0;
for (int xi = (int)ceil(leftEndPoint); xi <= (int)ceil(rightEndPoint); xi++)
{
float ti = (float)ci / (float)xLength;
float UCoordTmp = Lerp(leftUV, rightUV, ti);
float redTmp = Lerp(iRedA, iRedB, ti) / 100;
float greenTmp = Lerp(iGreenA, iGreenB, ti) / 100;
float blueTmp = Lerp(iBlueA, iBlueB, ti) / 100;
COLORREF textureColor = model.GetTexture().GetTextureValue((int)UCoordTmp, (int)tempUVA.GetV());
COLORREF currentColor = RGB(BoundsCheck(0, 255, (int)(GetRValue(textureColor) * redTmp)), BoundsCheck(0, 255, (int)(GetGValue(textureColor) * greenTmp)), BoundsCheck(0, 255, (int)(GetBValue(textureColor) * blueTmp)));
SetPixel(hDc, xi, tempA.GetYInt(), currentColor);
ci++;
}
while (e1 >= 0)
{
if (changed1)
{
tempA.SetX((float)tempA.GetXInt() + (float)signx1);
tempUVA.SetU((float)tempUVA.GetU() + (float)signu1);
}
else
{
tempA.SetY((float)tempA.GetYInt() + (float)signy1);
tempUVA.SetV((float)tempUVA.GetV() + (float)signv1);
}
e1 = e1 - 2 * dx1;
}
if (changed1)
{
tempA.SetY((float)tempA.GetYInt() + (float)signy1);
tempUVA.SetV((float)tempUVA.GetV() + (float)signv1);
}
else
{
tempA.SetX((float)tempA.GetXInt() + (float)signx1);
tempUVA.SetU((float)tempUVA.GetU() + (float)signu1);
}
e1 = e1 + 2 * dy1;
while (tempB.GetYInt(true) != tempA.GetYInt(true))
{
while (e2 >= 0)
{
if (changed2)
{
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
tempUVB.SetU((float)tempUVB.GetU() + (float)signu2);
}
else
{
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
tempUVB.SetV((float)tempUVB.GetV() + (float)signv2);
}
e2 = e2 - 2 * dx2;
}
if (changed2)
{
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
tempUVB.SetV((float)tempUVB.GetV() + (float)signv2);
}
else
{
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
tempUVB.SetU((float)tempUVB.GetU() + (float)signu2);
}
e2 = e2 + 2 * dy2;
}
}
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <vector>
#include <string>
#include <tchar.h>
#include "Framework.h"
#include "Vector3D.h"
#include "Vertex.h"
@ -23,13 +25,23 @@ public:
void Update(const Bitmap& bitmap);
void Render(const Bitmap& bitmap);
void ClearViewport(const Bitmap& bitmap);
void DrawString(HDC hDc, int x, int y, LPCTSTR text, COLORREF textColor = 0x00FFFFFF, COLORREF backgroundColor = 0x00000000);
~Rasteriser();
void SetCurrentCamera(int index);
Camera& GetCamera(int index);
Camera& GetCurrentCamera();
// Calculate the Lighting for the scene, fullLightRender sets the method to calculate the
// light values of all verticies otherwise light values are calculated at the polygon level
void CalculateLighting(Model& currentModel, bool fullLightRender);
float Interpolate(float y, float x0, float x1, float y0, float y1);
float Interpolate(int y, int x0, int x1, int y0, int y1);
float Lerp(float a, float b, float t);
float Lerp(int a, int b, float t);
void DrawSquare(HDC hDc, const vector<Vertex> verticies);
void DrawShape(HDC hDc, const vector<Vertex> verticies);
@ -37,17 +49,17 @@ public:
void DrawSolidFlat(HDC hDc, Model& model);
void DrawRasterisedSolidFlat(HDC hDc, Model& model);
void DrawGouraud(HDC hDc, Model& model);
void DrawSolidTextured(HDC hDc, Model& model);
void FillPolygonFlat(HDC hDc, vector<Vertex>& verticies, COLORREF colorIn);
void FillFlatSideTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3, COLORREF colorIn);
void FillPolygonGouraud(HDC hDc, vector<Vertex>& verticies);
void FillGouraudTopFlatTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3);
void FillGouraudBottomFlatTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3);
void FillPolygonGouraudInt(HDC hDc, vector<Vertex>& verticies);
void FillGouraudSideTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3);
void FillPolygonTextured(HDC hDc, Model& model, vector<Vertex>& verticies);
void FillTexturedSideTriangle(HDC hDc, Model& model, const Vertex& v1, const Vertex& v2, const Vertex& v3, const UVCoord& uv1, const UVCoord& uv2, const UVCoord& uv3);
private:
vector<Model> _sceneModels;
vector<Light*> _lights;
@ -60,6 +72,9 @@ private:
float _currentAspectRatio = 0.0f;
int _rotation = 0;
int _currentDrawMode = 0;
bool _screenMinimized = false;
string _modelDataLocation = ".//model_data/";
};

View File

@ -1,4 +1,5 @@
#pragma once
#include "Vertex.h"
#include "Matrix.h"
#include <cmath>
@ -9,6 +10,7 @@ template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
namespace SharedTools
{
const float PI = (float)acos(-1);

80
Texture.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "Texture.h"
Texture::Texture()
{
_width = 0;
_height = 0;
_paletteIndices = nullptr;
_palette = nullptr;
}
Texture::~Texture()
{
if (_paletteIndices != nullptr)
{
delete[] _paletteIndices;
_paletteIndices = nullptr;
}
if (_palette != nullptr)
{
delete[] _palette;
_palette = nullptr;
}
}
void Texture::SetTextureSize(int width, int height)
{
_width = width;
_height = height;
if (_paletteIndices != nullptr)
{
delete[] _paletteIndices;
}
_paletteIndices = new BYTE[_width * _height];
if (_palette != nullptr)
{
delete[] _palette;
}
_palette = new COLORREF[256];
}
COLORREF Texture::GetTextureValue(int u, int v) const
{
if (v < 0)
{
v = 0;
}
if (v >= _height)
{
v = _height - 1;
}
if (u < 0)
{
u = 0;
}
if (u >= _width)
{
u = _width - 1;
}
return _palette[_paletteIndices[v * _width + u]];
}
BYTE * Texture::GetPaletteIndices()
{
return _paletteIndices;
}
COLORREF * Texture::GetPalette()
{
return _palette;
}
int Texture::GetWidth() const
{
return _width;
}
int Texture::GetHeight() const
{
return _height;
}

22
Texture.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "windows.h"
class Texture
{
public:
Texture();
~Texture();
void SetTextureSize(int width, int height);
COLORREF GetTextureValue(int u, int v) const;
BYTE * GetPaletteIndices();
COLORREF * GetPalette();
int GetWidth() const;
int GetHeight() const;
private:
BYTE * _paletteIndices;
COLORREF * _palette;
int _width;
int _height;
};

57
UVCoord.cpp Normal file
View File

@ -0,0 +1,57 @@
#include "UVCoord.h"
UVCoord::UVCoord()
{
_u = 0.0f;
_v = 0.0f;
}
UVCoord::UVCoord(float u, float v)
{
_u = u;
_v = v;
}
UVCoord::UVCoord(const UVCoord& other)
{
Copy(other);
}
UVCoord::~UVCoord()
{
}
float UVCoord::GetU() const
{
return _u;
}
void UVCoord::SetU(const float u)
{
_u = u;
}
float UVCoord::GetV() const
{
return _v;
}
void UVCoord::SetV(const float v)
{
_v = v;
}
UVCoord& UVCoord::operator= (const UVCoord& rhs)
{
if (this != &rhs)
{
Copy(rhs);
}
return *this;
}
void UVCoord::Copy(const UVCoord& other)
{
_u = other.GetU();
_v = other.GetV();
}

26
UVCoord.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
class UVCoord
{
public:
UVCoord();
UVCoord(float u, float v);
UVCoord(const UVCoord& other);
~UVCoord();
float GetU() const;
void SetU(const float u);
float GetV() const;
void SetV(const float v);
UVCoord& operator= (const UVCoord& rhs);
private:
float _u;
float _v;
void Copy(const UVCoord& other);
};

View File

@ -81,6 +81,14 @@ Vector3D Vector3D::CrossProduct(const Vector3D v1, const Vector3D v2)
return Vector3D(v1.GetY() * v2.GetZ() - v1.GetZ() * v2.GetY(), v1.GetZ() * v2.GetX() - v1.GetX() * v2.GetZ(), v1.GetX() * v2.GetY() - v1.GetY() * v2.GetX());
}
Vector3D& Vector3D::operator= (const Vector3D& rhs)
{
if (this != &rhs)
{
Copy(rhs);
}
return *this;
}
const Vector3D Vector3D::operator+ (const Vector3D& rhs) const
{

View File

@ -24,6 +24,8 @@ public:
static float Length(const Vector3D v1, const Vector3D v2);
static Vector3D CrossProduct(const Vector3D v1, const Vector3D v2);
Vector3D& operator= (const Vector3D& rhs);
const Vector3D operator+ (const Vector3D& rhs) const;
const Vector3D operator/ (const int rhs) const;
const Vector3D operator/ (const float rhs) const;

View File

@ -140,16 +140,31 @@ int Vertex::GetR() const
return _r;
}
void Vertex::SetR(const int r)
{
_r = r;
}
int Vertex::GetG() const
{
return _g;
}
void Vertex::SetG(const int g)
{
_g = g;
}
int Vertex::GetB() const
{
return _b;
}
void Vertex::SetB(const int b)
{
_b = b;
}
void Vertex::SetColor(int r, int g, int b)
{
_r = r;
@ -162,6 +177,16 @@ void Vertex::SetColor(const COLORREF colorIn)
SetColor((int)GetRValue(colorIn), (int)GetGValue(colorIn), (int)GetBValue(colorIn));
}
int Vertex::GetUVIndex() const
{
return _uvIndex;
}
void Vertex::SetUVIndex(const int index)
{
_uvIndex = index;
}
int Vertex::GetXInt(bool forceRoundUp) const
{
if (forceRoundUp)
@ -261,7 +286,11 @@ void Vertex::Copy(const Vertex& other)
_w = other.GetW();
_contributeCount = other.GetContributeCount();
SetNormal(other.GetNormal());
_normal = other.GetNormal();
SetColor(other.GetR(), other.GetG(), other.GetB());
_r = other.GetR();
_g = other.GetG();
_b = other.GetB();
_uvIndex = other.GetUVIndex();
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "Vector3D.h"
#include "UVCoord.h"
#include "windows.h"
class Vertex
@ -32,12 +33,18 @@ public:
const COLORREF GetColor() const;
int GetR() const;
void SetR(const int r);
int GetG() const;
void SetG(const int g);
int GetB() const;
void SetB(const int b);
void SetColor(const int r, const int g, const int b);
void SetColor(const COLORREF colorIn);
// Accessor Methods for returning the private x, y, z and w values as integeres instead of floats
int GetUVIndex() const;
void SetUVIndex(const int index);
// Accessors for returning the private x, y, z and w values as integeres instead of floats
// the ceil function to round the number up by defaults but using providing a false param will
// use the floor function instead to round the number down
int GetXInt(bool forceRoundUp = false) const;
@ -61,6 +68,8 @@ private:
float _z;
float _w;
float _zOriginal;
int _contributeCount;
Vector3D _normal;
@ -68,6 +77,8 @@ private:
int _g;
int _b;
int _uvIndex;
void Copy(const Vertex& other);
};

BIN
model_data/lines.pcx Normal file

Binary file not shown.

BIN
model_data/marvin.pcx Normal file

Binary file not shown.