Files
Graphics-Rasterizer/Rasteriser.cpp
IDunnoDev eeea920e45 Week12 [14/12]
Added UVCheck texture file
Added UV perspective Variables to the Vertex Class
Added Texture Draw method to the Rasteriser
2021-12-14 13:50:09 +00:00

969 lines
28 KiB
C++

#include "Rasteriser.h"
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 = 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(50, 50, 50));
//_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(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;
return true;
}
void Rasteriser::SetCurrentCamera(int index)
{
if (index >= 0 && index < _cameras.size())
{
_currentCamera = index;
}
}
Camera& Rasteriser::GetCamera(int index)
{
return _cameras[index];
}
Camera& Rasteriser::GetCurrentCamera()
{
return GetCamera(_currentCamera);
}
void Rasteriser::CalculateLighting(Model& currentModel, bool fullLightRender)
{
{
for (int pi = 0; pi < currentModel.GetPolygonCount(); pi++)
{
if (!currentModel.GetPolygon(pi).GetCulled())
{
if (fullLightRender)
{
for (int i = 0; i < currentModel.GetPolygon(pi).GetPolygonVertexCount(); i++)
{
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);
}
}
else
{
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);
}
}
}
}
}
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 (1 - t) * a + t * b;
}
float Rasteriser::Lerp(int a, int b, float t)
{
return Lerp((float)a, (float)b, t);
}
int toDraw = 1;
int drawn = 0;
void Rasteriser::Update(const Bitmap& bitmap)
{
drawn = 0;
if (bitmap.GetWidth() == 0 || bitmap.GetHeight() == 0)
{
_screenMinimized = true;
}
else
{
_screenMinimized = false;
}
if (!_screenMinimized)
{
int currentRot = 0;// 45; // (_rotation % 360);
Vertex startPos = Vertex(0, 0, 20);
int currentZOff = 0;
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);
if ((currentModelIndex % 2) == 1)
{
currentZOff = 0;
}
else
{
currentZOff = 100;
}
startPos.SetZ((float)currentZOff);*/
currentModelIndex++;
}
}
_currentAspectRatio = (float)(bitmap.GetWidth() / (float)bitmap.GetHeight());
_currentPerspectiveMatrix = GetPerspectiveProjectionMatrix(1, _currentAspectRatio);
_currentViewMatrix = GetViewMatrix(1, bitmap.GetWidth(), bitmap.GetHeight());
if (_rotation == 360)
{
_rotation = 0;
}
else
{
_rotation += 1;
}
}
}
void Rasteriser::Render(const Bitmap& bitmap)
{
if (!_screenMinimized)
{
ClearViewport(bitmap);
SelectObject(bitmap.GetDC(), GetStockObject(DC_BRUSH));
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();
for (Matrix currentTransform : currentModel.GetPendingTransforms())
{
workingMatrix *= currentTransform;
}
currentModel.ApplyTransformToLocalVertices(workingMatrix);
currentModel.ApplyTransformToTransformedVertices(GetCurrentCamera().GetCurrentCameraTransformMatrix());
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);
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)
{
bitmap.Clear(RGB(0, 0, 0));
}
void Rasteriser::DrawSquare(HDC hDc, const vector<Vertex> verticies)
{
POINT pointArray[4];
for (int i = 0; i < 4; i++)
{
pointArray[i].x = (long) verticies[i].GetX();
pointArray[i].y = (long) verticies[i].GetY();
}
SetDCBrushColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256));
SetDCPenColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256));
Polygon(hDc, pointArray, 4);
}
void Rasteriser::DrawShape(HDC hDc, const vector<Vertex> verticies)
{
vector<POINT> pointArray;
for (int i = 0; i < verticies.size(); i++)
{
POINT newPoint;
newPoint.x = (long)verticies[i].GetX();
newPoint.y = (long)verticies[i].GetY();
pointArray.push_back(newPoint);
}
SetDCBrushColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256));
SetDCPenColor(hDc, RGB(rand() % 256, rand() % 256, rand() % 256));
Polygon(hDc, pointArray.data(), (int) verticies.size());
}
void Rasteriser::DrawWireFrame(HDC hDc, Model& model)
{
vector<POINT> pointArray;
vector<int> sizeArray;
int unculledPolyCount = 0;
int modelPolygonCount = (int) model.GetPolygonCount();
for (int i = 0; i < modelPolygonCount; i++)
{
if (!model.GetPolygon(i).GetCulled())
{
int currentPolygonVertexCount = (int)model.GetPolygon(i).GetPolygonVertexCount();
for (int j = 0; j < currentPolygonVertexCount; j++)
{
POINT newPoint;
newPoint.x = (long)model.GetVertex(i, j).GetX();
newPoint.y = (long)model.GetVertex(i, j).GetY();
pointArray.push_back(newPoint);
}
sizeArray.push_back(currentPolygonVertexCount);
unculledPolyCount++;
}
}
SetDCBrushColor(hDc, RGB(1,1,1));
SetDCPenColor(hDc, RGB(255,255,255));
PolyPolygon(hDc, pointArray.data(), sizeArray.data(), unculledPolyCount);
}
void Rasteriser::DrawSolidFlat(HDC hDc, Model& model)
{
int modelPolygonCount = (int)model.GetPolygonCount();
for (int i = 0; i < modelPolygonCount; i++)
{
if (!model.GetPolygon(i).GetCulled())
{
vector<POINT> pointArray;
int currentPolygonVertexCount = (int)model.GetPolygon(i).GetPolygonVertexCount();
for (int j = 0; j < currentPolygonVertexCount; j++)
{
POINT newPoint;
newPoint.x = (long)model.GetVertex(i, j).GetX();
newPoint.y = (long)model.GetVertex(i, j).GetY();
pointArray.push_back(newPoint);
}
SetDCBrushColor(hDc, model.GetPolygon(i).GetColor());
SetDCPenColor(hDc, model.GetPolygon(i).GetColor());
Polygon(hDc, pointArray.data(), currentPolygonVertexCount);
}
}
}
void Rasteriser::DrawRasterisedSolidFlat(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);
FillPolygonFlat(hDc, vertexArray, model.GetPolygon(i).GetColor());
}
}
}
void Rasteriser::DrawGouraud(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);
FillPolygonGouraud(hDc, vertexArray);
}
}
}
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();
}
void Rasteriser::FillPolygonFlat(HDC hDc, vector<Vertex>& verts, COLORREF colorIn)
{
sort(verts.begin(), verts.end(), VerticiesYCompareAsc);
if (verts[1].GetY() == verts[2].GetY())
{
FillFlatSideTriangle(hDc, verts[0], verts[1], verts[2], colorIn);
}
else if (verts[0].GetY() == verts[1].GetY())
{
FillFlatSideTriangle(hDc, verts[2], verts[0], verts[1], colorIn);
}
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());
if (verts[1].GetX() < temp.GetX())
{
FillFlatSideTriangle(hDc, verts[0], verts[1], temp, colorIn);
FillFlatSideTriangle(hDc, verts[2], verts[1], temp, colorIn);
}
else
{
FillFlatSideTriangle(hDc, verts[0], temp, verts[1], colorIn);
FillFlatSideTriangle(hDc, verts[2], temp, verts[1], colorIn);
}
}
}
void Rasteriser::FillFlatSideTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3, COLORREF colorIn)
{
Vertex tempA = Vertex(v1);
Vertex tempB = Vertex(v1);
bool changed1 = false;
bool changed2 = false;
int dx1 = (int)ceil(abs(v2.GetX() - v1.GetX()));
int dy1 = (int)ceil(abs(v2.GetY() - v1.GetY()));
int dx2 = (int)ceil(abs(v3.GetX() - v1.GetX()));
int dy2 = (int)ceil(abs(v3.GetY() - v1.GetY()));
int signx1 = (int)ceil(sgn(v2.GetX() - v1.GetX()));
int signx2 = (int)ceil(sgn(v3.GetX() - v1.GetX()));
int signy1 = (int)ceil(sgn(v2.GetY() - v1.GetY()));
int signy2 = (int)ceil(sgn(v3.GetY() - v1.GetY()));
if (dy1 > dx1)
{
int tempInt = dx1;
dx1 = dy1;
dy1 = tempInt;
changed1 = true;
}
if (dy2 > dx2)
{
int tempInt = dx2;
dx2 = dy2;
dy2 = tempInt;
changed2 = true;
}
int e1 = 2 * dy1 - dx1;
int e2 = 2 * dy2 - dx2;
for (int i = 0; i <= dx1; i++)
{
float leftEndPoint;
float rightEndPoint;
if (tempA.GetX() < tempB.GetX())
{
leftEndPoint = tempA.GetX() - 1.0f;
rightEndPoint = tempB.GetX() + 1.0f;
}
else
{
leftEndPoint = tempB.GetX() - 1.0f;
rightEndPoint = tempA.GetX() + 1.0f;
}
for (int xi = (int)ceil(leftEndPoint); xi <= (int)ceil(rightEndPoint); xi++)
{
SetPixel(hDc, xi, tempA.GetYInt(), colorIn);
}
while (e1 >= 0)
{
if (changed1)
{
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
else
{
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
e1 = e1 - 2 * dx1;
}
if (changed1)
{
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
else
{
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
e1 = e1 + 2 * dy1;
while (tempB.GetYInt() != tempA.GetYInt())
{
while (e2 >= 0)
{
if (changed2)
{
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
}
else
{
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
}
e2 = e2 - 2 * dx2;
}
if (changed2)
{
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
}
else
{
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
}
e2 = e2 + 2 * dy2;
}
}
}
void Rasteriser::FillPolygonGouraud(HDC hDc, vector<Vertex>& verts)
{
sort(verts.begin(), verts.end(), VerticiesYCompareAsc);
if (verts[1].GetY() == verts[2].GetY())
{
FillGouraudSideTriangle(hDc, verts[0], verts[1], verts[2]);
}
else if (verts[0].GetY() == verts[1].GetY())
{
FillGouraudSideTriangle(hDc, verts[2], verts[0], verts[1]);
}
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 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())
{
FillGouraudSideTriangle(hDc, verts[0], verts[1], temp);
FillGouraudSideTriangle(hDc, verts[2], verts[1], temp);
}
else
{
FillGouraudSideTriangle(hDc, verts[0], temp, verts[1]);
FillGouraudSideTriangle(hDc, verts[2], temp, verts[1]);
}
}
}
void Rasteriser::FillGouraudSideTriangle(HDC hDc, const Vertex& v1, const Vertex& v2, const Vertex& v3)
{
Vertex tempA = Vertex(v1);
Vertex tempB = Vertex(v1);
bool changed1 = false;
bool changed2 = false;
int dx1 = (int)ceil(abs(v2.GetX() - v1.GetX()));
int dy1 = (int)ceil(abs(v2.GetY() - v1.GetY()));
int dx2 = (int)ceil(abs(v3.GetX() - v1.GetX()));
int dy2 = (int)ceil(abs(v3.GetY() - v1.GetY()));
int signx1 = (int)ceil(sgn(v2.GetX() - v1.GetX()));
int signx2 = (int)ceil(sgn(v3.GetX() - v1.GetX()));
int signy1 = (int)ceil(sgn(v2.GetY() - v1.GetY()));
int signy2 = (int)ceil(sgn(v3.GetY() - v1.GetY()));
if (dy1 > dx1)
{
int tempDx = dx1;
dx1 = dy1;
dy1 = tempDx;
changed1 = true;
}
if (dy2 > dx2)
{
int tempDx = dx2;
dx2 = dy2;
dy2 = tempDx;
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;
if (tempA.GetX() < tempB.GetX())
{
leftEndPoint = tempA.GetX();
rightEndPoint = tempB.GetX() + 1.0f;
}
else
{
leftEndPoint = tempB.GetX();
rightEndPoint = tempA.GetX() + 1.0f;
}
//float iRedA = Interpolate(tempA.GetY(), (float)v1.GetR(), (float)v2.GetR(), v1.GetY(), v2.GetY());
//float iRedB = Interpolate(tempA.GetY(), (float)v1.GetR(), (float)v3.GetR(), v1.GetY(), v3.GetY());
//float iGreenA = Interpolate(tempA.GetY(), (float)v1.GetG(), (float)v2.GetG(), v1.GetY(), v2.GetY());
//float iGreenB = Interpolate(tempA.GetY(), (float)v1.GetG(), (float)v3.GetG(), v1.GetY(), v3.GetY());
//float iBlueA = Interpolate(tempA.GetY(), (float)v1.GetB(), (float)v2.GetB(), v1.GetY(), v2.GetY());
//float iBlueB = Interpolate(tempA.GetY(), (float)v1.GetB(), (float)v3.GetB(), v1.GetY(), v3.GetY());
// Interpolate the Edge Colors of the 3 Vertex, Lerping seems to give better results given the
// non precise nature of converting the floats into ints since it works on the start and end, and
// interpolates fixed between those values (regular interpolation would sometimes overflow and cause
// a value higher then 255 to be used.
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)leftEndPoint; xi <= (int)rightEndPoint; xi++)
{
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++;
}
while (e1 >= 0)
{
if (changed1)
{
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
else
{
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
e1 = e1 - 2 * dx1;
}
if (changed1)
{
tempA.SetY((float)tempA.GetY() + (float)signy1);
}
else
{
tempA.SetX((float)tempA.GetX() + (float)signx1);
}
e1 = e1 + 2 * dy1;
while (tempB.GetYInt() != tempA.GetYInt())
{
while (e2 >= 0)
{
if (changed2)
{
tempB.SetX((float)tempB.GetX() + (float)signx2);
}
else
{
tempB.SetY((float)tempB.GetY() + (float)signy2);
}
e2 = e2 - 2 * dx2;
}
if (changed2)
{
tempB.SetY((float)tempB.GetY() + (float)signy2);
}
else
{
tempB.SetX((float)tempB.GetX() + (float)signx2);
}
e2 = e2 + 2 * dy2;
}
}
}
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());
//model.GetUVCoord(verts[1].GetUVIndex()).GetU() + ((model.GetUVCoord(verts[1].GetUVIndex()).GetV() - model.GetUVCoord(verts[0].GetUVIndex()).GetV()) / (model.GetUVCoord(verts[2].GetUVIndex()).GetV() - model.GetUVCoord(verts[0].GetUVIndex()).GetV())) * (model.GetUVCoord(verts[2].GetUVIndex()).GetU() - model.GetUVCoord(verts[0].GetUVIndex()).GetU());
float uc0 = model.GetUVCoord(verts[0].GetUVIndex()).GetU();
float vc0 = model.GetUVCoord(verts[0].GetUVIndex()).GetV();
float uc1 = model.GetUVCoord(verts[1].GetUVIndex()).GetU();
float vc1 = model.GetUVCoord(verts[1].GetUVIndex()).GetV();
float uc2 = model.GetUVCoord(verts[2].GetUVIndex()).GetU();
float vc2 = model.GetUVCoord(verts[2].GetUVIndex()).GetV();
float tempU = uc0 + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (uc2 - uc0);
float tempV = vc0 + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (vc2 - vc0);
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 (drawn < toDraw + 100)
{
if (verts[1].GetX() < temp.GetX())
{
FillTexturedSideTriangle(hDc, model, verts[0], verts[1], temp, model.GetUVCoord(verts[0].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), tempCoords);
FillTexturedSideTriangle(hDc, model, verts[2], verts[1], temp, model.GetUVCoord(verts[2].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), tempCoords);
drawn++;
}
else
{
FillTexturedSideTriangle(hDc, model, verts[0], temp, verts[1], model.GetUVCoord(verts[0].GetUVIndex()), tempCoords, model.GetUVCoord(verts[1].GetUVIndex()));
FillTexturedSideTriangle(hDc, model, verts[2], temp, verts[1], model.GetUVCoord(verts[2].GetUVIndex()), tempCoords, model.GetUVCoord(verts[1].GetUVIndex()));
drawn++;
}
}
}
}
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;
changed1 = true;
}
if (dy2 > dx2)
{
int tempDx = dx2;
dx2 = dy2;
dy2 = tempDx;
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 leftU;
float rightU;
float leftV;
float rightV;
if (tempA.GetX() < tempB.GetX())
{
leftEndPoint = tempA.GetX() - 1.0f;
rightEndPoint = tempB.GetX() + 1.0f;
leftU = tempUVA.GetU();
rightU = tempUVB.GetU();
leftV = tempUVA.GetV();
rightV = tempUVB.GetV();
}
else
{
leftEndPoint = tempB.GetX() - 1.0f;
rightEndPoint = tempA.GetX() + 1.0f;
leftU = tempUVB.GetU();
rightU = tempUVA.GetU();
leftV = tempUVB.GetV();
rightV = tempUVA.GetV();
}
float uy1 = Lerp(uv1.GetV(), uv2.GetV(), (float)i / (float)dx1);
float uy2 = Lerp(uv1.GetV(), uv3.GetV(), (float)i / (float)dx1);
//x0 + (y - y0) * ((x1 - x0) / (y1 - y0))
//a + (b - a) * t
float UCoordA = Interpolate(tempA.GetY(), uv1.GetU(), uv2.GetU(), v1.GetY(), v2.GetY());
float UCoordB = Interpolate(tempA.GetY(), uv1.GetU(), uv3.GetU(), v1.GetY(), v3.GetY());
float VCoordA = Interpolate(tempA.GetY(), uv1.GetV(), uv2.GetV(), v1.GetY(), v2.GetY());
float VCoordB = Interpolate(tempA.GetY(), uv1.GetV(), uv3.GetV(), v1.GetY(), v3.GetY());
float UCoord = (rightU - leftU) / (rightEndPoint - leftEndPoint);
float VCoord = (rightV - leftV) / (rightEndPoint - leftEndPoint);
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;
if (i < 10000)
{
for (int xi = (int)ceil(leftEndPoint); xi <= (int)ceil(rightEndPoint); xi++)
{
float ti = (float)ci / (float)xLength;
float UCoordTmp = Lerp(UCoordA, UCoordB, ti);
float VCoordTmp = Lerp(VCoordA, VCoordB, 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)VCoordTmp);
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;
}
}
}