1274 lines
36 KiB
C++
1274 lines
36 KiB
C++
#include "Rasteriser.h"
|
|
|
|
Rasteriser app;
|
|
|
|
Rasteriser::~Rasteriser()
|
|
{
|
|
_lights.~vector();
|
|
_sceneModels.~vector();
|
|
}
|
|
|
|
void Rasteriser::DrawString(HDC hDc, int x, int y, LPCTSTR text, int fontSize, COLORREF textColor, COLORREF backgroundColor)
|
|
{
|
|
HFONT hFont, hOldFont;
|
|
|
|
// Retrieve a handle to the variable stock font.
|
|
hFont = hFont = CreateFont(fontSize, 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;
|
|
|
|
//Set the current Time for the automation
|
|
time(&_startTime);
|
|
time(&_currentTime);
|
|
_currentState = 0;
|
|
_maxStates = 5;
|
|
for (int i = 0; i < (sizeof _counters / sizeof _counters[0]); i++)
|
|
{
|
|
_counters[i] = 0;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void Rasteriser::Update(const Bitmap& bitmap)
|
|
{
|
|
if (bitmap.GetWidth() == 0 || bitmap.GetHeight() == 0)
|
|
{
|
|
_screenMinimized = true;
|
|
}
|
|
else
|
|
{
|
|
_screenMinimized = false;
|
|
}
|
|
|
|
int duration = 0;
|
|
switch (_currentState)
|
|
{
|
|
case -1:
|
|
duration = -1;
|
|
case 0:
|
|
duration = 10;
|
|
break;
|
|
case 1:
|
|
duration = 10;
|
|
break;
|
|
case 2:
|
|
duration = 10;
|
|
break;
|
|
case 3:
|
|
duration = 10;
|
|
break;
|
|
case 4:
|
|
duration = 10;
|
|
break;
|
|
}
|
|
|
|
if (!_screenMinimized)
|
|
{
|
|
for (Model& currentModel : _sceneModels)
|
|
{
|
|
if (currentModel.GetActive())
|
|
{
|
|
switch (_currentState)
|
|
{
|
|
case -1:
|
|
|
|
break;
|
|
case 0:
|
|
currentModel.SetDrawMethod(DrawMethod::Wireframe);
|
|
break;
|
|
case 1:
|
|
currentModel.SetDrawMethod(DrawMethod::Flat);
|
|
break;
|
|
case 2:
|
|
currentModel.SetDrawMethod(DrawMethod::FlatRaster);
|
|
break;
|
|
case 3:
|
|
currentModel.SetDrawMethod(DrawMethod::Smooth);
|
|
break;
|
|
case 4:
|
|
currentModel.SetDrawMethod(DrawMethod::Textured);
|
|
break;
|
|
}
|
|
|
|
//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);*/
|
|
|
|
}
|
|
}
|
|
|
|
_currentAspectRatio = (float)(bitmap.GetWidth() / (float)bitmap.GetHeight());
|
|
_currentPerspectiveMatrix = GetPerspectiveProjectionMatrix(1, _currentAspectRatio);
|
|
_currentViewMatrix = GetViewMatrix(1, bitmap.GetWidth(), bitmap.GetHeight());
|
|
|
|
}
|
|
|
|
if (((int)_currentTime > (int)_startTime + duration) && (duration != -1))
|
|
{
|
|
if (_currentState == _maxStates)
|
|
{
|
|
_currentState = 0;
|
|
}
|
|
else
|
|
{
|
|
_currentState++;
|
|
}
|
|
time(&_startTime);
|
|
}
|
|
time(&_currentTime);
|
|
}
|
|
|
|
void Rasteriser::Render(const Bitmap& bitmap)
|
|
{
|
|
bool titleDrawn = false;
|
|
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):
|
|
if (!titleDrawn)
|
|
{
|
|
DrawString(bitmap.GetDC(), 10, 10, _T("Wireframe"));
|
|
titleDrawn = true;
|
|
}
|
|
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
|
|
currentModel.DehomogenizeAllVertices();
|
|
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
|
|
DrawWireFrame(bitmap.GetDC(), currentModel);
|
|
break;
|
|
case (DrawMethod::Flat):
|
|
if (!titleDrawn)
|
|
{
|
|
DrawString(bitmap.GetDC(), 10, 10, TEXT("Flat Polygon"));
|
|
titleDrawn = true;
|
|
}
|
|
currentModel.CalculateVertexNormals();
|
|
CalculateLighting(currentModel, false);
|
|
|
|
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
|
|
currentModel.DehomogenizeAllVertices();
|
|
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
|
|
DrawSolidFlat(bitmap.GetDC(), currentModel);
|
|
break;
|
|
case (DrawMethod::FlatRaster):
|
|
if (!titleDrawn)
|
|
{
|
|
DrawString(bitmap.GetDC(), 10, 10, _T("Flat Raster"));
|
|
titleDrawn = true;
|
|
}
|
|
currentModel.CalculateVertexNormals();
|
|
CalculateLighting(currentModel, false);
|
|
|
|
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
|
|
currentModel.DehomogenizeAllVertices();
|
|
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
|
|
DrawRasterisedSolidFlat(bitmap.GetDC(), currentModel);
|
|
break;
|
|
case (DrawMethod::Smooth):
|
|
if (!titleDrawn)
|
|
{
|
|
DrawString(bitmap.GetDC(), 10, 10, _T("Gouraud Shading"));
|
|
titleDrawn = true;
|
|
}
|
|
currentModel.CalculateVertexNormals();
|
|
CalculateLighting(currentModel, true);
|
|
|
|
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
|
|
currentModel.DehomogenizeAllVertices();
|
|
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
|
|
DrawGouraud(bitmap.GetDC(), currentModel);
|
|
break;
|
|
case (DrawMethod::Textured):
|
|
if (!titleDrawn)
|
|
{
|
|
DrawString(bitmap.GetDC(), 10, 10, _T("Textured"));
|
|
titleDrawn = true;
|
|
}
|
|
currentModel.CalculateVertexNormals();
|
|
CalculateLighting(currentModel, true);
|
|
|
|
currentModel.ApplyTransformToTransformedVertices(_currentPerspectiveMatrix);
|
|
currentModel.DehomogenizeAllVertices();
|
|
currentModel.ApplyTransformToTransformedVertices(_currentViewMatrix);
|
|
DrawSolidTextured(bitmap.GetDC(), currentModel);
|
|
break;
|
|
}
|
|
currentModel.ClearPendingTransforms();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
model.CalculateUVPerspective();
|
|
|
|
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)
|
|
{
|
|
// Check if any of the vertices match and dont draw the triangle if they do, this should stop the infinite loop that can happen with small vertex float numbers
|
|
if ((v1.GetXInt() == v2.GetXInt() && v1.GetYInt() == v2.GetYInt()) || (v1.GetXInt() == v3.GetXInt() && v1.GetYInt() == v3.GetYInt()) || (v2.GetXInt() == v3.GetXInt() && v3.GetYInt() == v2.GetYInt()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vertex tempA = Vertex(v1);
|
|
Vertex tempB = Vertex(v1);
|
|
|
|
bool changed1 = false;
|
|
bool changed2 = false;
|
|
|
|
int dx1 = (int)abs(v2.GetXInt() - v1.GetXInt());
|
|
int dy1 = (int)abs(v2.GetYInt() - v1.GetYInt());
|
|
int dx2 = (int)abs(v3.GetXInt() - v1.GetXInt());
|
|
int dy2 = (int)abs(v3.GetYInt() - v1.GetYInt());
|
|
|
|
int signx1 = (int)sgn(v2.GetXInt() - v1.GetXInt());
|
|
int signx2 = (int)sgn(v3.GetXInt() - v1.GetXInt());
|
|
int signy1 = (int)sgn(v2.GetYInt() - v1.GetYInt());
|
|
int signy2 = (int)sgn(v3.GetYInt() - v1.GetYInt());
|
|
|
|
if (dy1 > dx1)
|
|
{
|
|
swap(dx1, dy1);
|
|
changed1 = true;
|
|
}
|
|
|
|
if (dy2 > dx2)
|
|
{
|
|
swap(dx2, dy2);
|
|
changed2 = true;
|
|
}
|
|
|
|
int e1 = 2 * dy1 - dx1;
|
|
int e2 = 2 * dy2 - dx2;
|
|
|
|
for (int i = 0; i <= dx1; i++)
|
|
{
|
|
int leftEndPoint;
|
|
int rightEndPoint;
|
|
|
|
if (tempA.GetXInt() < tempB.GetXInt())
|
|
{
|
|
leftEndPoint = tempA.GetXInt();
|
|
rightEndPoint = tempB.GetXInt();
|
|
}
|
|
else
|
|
{
|
|
leftEndPoint = tempB.GetXInt();
|
|
rightEndPoint = tempA.GetXInt();
|
|
}
|
|
|
|
for (int xi = leftEndPoint; xi < rightEndPoint; xi++)
|
|
{
|
|
SetPixel(hDc, xi, tempA.GetYInt(), colorIn);
|
|
}
|
|
|
|
while (e1 >= 0)
|
|
{
|
|
if (changed1)
|
|
{
|
|
tempA.SetX((float)(tempA.GetXInt() + signx1));
|
|
}
|
|
else
|
|
{
|
|
tempA.SetY((float)(tempA.GetYInt() + signy1));
|
|
}
|
|
e1 = e1 - 2 * dx1;
|
|
}
|
|
|
|
if (changed1)
|
|
{
|
|
tempA.SetY((float)(tempA.GetYInt() + signy1));
|
|
}
|
|
else
|
|
{
|
|
tempA.SetX((float)(tempA.GetXInt() + signx1));
|
|
}
|
|
|
|
e1 = e1 + 2 * dy1;
|
|
|
|
while (tempB.GetYInt(true) != tempA.GetYInt(true))
|
|
{
|
|
while (e2 >= 0)
|
|
{
|
|
if (changed2)
|
|
{
|
|
tempB.SetX((float)(tempB.GetXInt() + signx2));
|
|
}
|
|
else
|
|
{
|
|
tempB.SetY((float)(tempB.GetYInt() + signy2));
|
|
}
|
|
e2 = e2 - 2 * dx2;
|
|
}
|
|
|
|
if (changed2)
|
|
{
|
|
tempB.SetY((float)(tempB.GetYInt() + signy2));
|
|
}
|
|
else
|
|
{
|
|
tempB.SetX((float)(tempB.GetXInt() + 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)
|
|
{
|
|
// Check if any of the vertices match and dont draw the triangle if they do, this should stop the infinite loop that can happen with small vertex float numbers
|
|
if ((v1.GetXInt() == v2.GetXInt() && v1.GetYInt() == v2.GetYInt()) || (v1.GetXInt() == v3.GetXInt() && v1.GetYInt() == v3.GetYInt()) || (v2.GetXInt() == v3.GetXInt() && v3.GetYInt() == v2.GetYInt()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vertex tempA = Vertex(v1);
|
|
Vertex tempB = Vertex(v1);
|
|
|
|
bool changed1 = false;
|
|
bool changed2 = false;
|
|
|
|
int dx1 = (int)abs(v2.GetXInt() - v1.GetXInt());
|
|
int dy1 = (int)abs(v2.GetYInt() - v1.GetYInt());
|
|
int dx2 = (int)abs(v3.GetXInt() - v1.GetXInt());
|
|
int dy2 = (int)abs(v3.GetYInt() - v1.GetYInt());
|
|
|
|
int signx1 = (int)sgn(v2.GetXInt() - v1.GetXInt());
|
|
int signx2 = (int)sgn(v3.GetXInt() - v1.GetXInt());
|
|
int signy1 = (int)sgn(v2.GetYInt() - v1.GetYInt());
|
|
int signy2 = (int)sgn(v3.GetYInt() - v1.GetYInt());
|
|
|
|
if (dy1 > dx1)
|
|
{
|
|
swap(dx1, dy1);
|
|
changed1 = true;
|
|
}
|
|
|
|
if (dy2 > dx2)
|
|
{
|
|
swap(dx2, dy2);
|
|
changed2 = true;
|
|
}
|
|
|
|
int e1 = 2 * dy1 - dx1;
|
|
int e2 = 2 * dy2 - dx2;
|
|
|
|
for (int i = 0; i <= dx1; i++)
|
|
{
|
|
int leftEndPoint;
|
|
int rightEndPoint;
|
|
int sideFix;
|
|
|
|
if (tempA.GetXInt() < tempB.GetXInt())
|
|
{
|
|
leftEndPoint = tempA.GetXInt();
|
|
rightEndPoint = tempB.GetXInt();
|
|
sideFix = 0;
|
|
}
|
|
else
|
|
{
|
|
leftEndPoint = tempB.GetXInt();
|
|
rightEndPoint = tempA.GetXInt();
|
|
sideFix = 1;
|
|
}
|
|
|
|
// 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 = rightEndPoint - leftEndPoint;
|
|
int ci = xLength * sideFix;
|
|
|
|
for (int xi = leftEndPoint; xi < 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);
|
|
if (sideFix == 1)
|
|
{
|
|
ci--;
|
|
}
|
|
else
|
|
{
|
|
ci++;
|
|
}
|
|
}
|
|
|
|
while (e1 >= 0)
|
|
{
|
|
if (changed1)
|
|
{
|
|
tempA.SetX((float)(tempA.GetXInt() + signx1));
|
|
}
|
|
else
|
|
{
|
|
tempA.SetY((float)(tempA.GetYInt() + signy1));
|
|
}
|
|
e1 = e1 - 2 * dx1;
|
|
}
|
|
|
|
if (changed1)
|
|
{
|
|
tempA.SetY((float)(tempA.GetYInt() + signy1));
|
|
}
|
|
else
|
|
{
|
|
tempA.SetX((float)(tempA.GetXInt() + signx1));
|
|
}
|
|
|
|
e1 = e1 + 2 * dy1;
|
|
|
|
while (tempB.GetYInt(true) != tempA.GetYInt(true))
|
|
{
|
|
while (e2 >= 0)
|
|
{
|
|
if (changed2)
|
|
{
|
|
tempB.SetX((float)(tempB.GetXInt() + signx2));
|
|
}
|
|
else
|
|
{
|
|
tempB.SetY((float)(tempB.GetYInt() + signy2));
|
|
}
|
|
e2 = e2 - 2 * dx2;
|
|
}
|
|
|
|
if (changed2)
|
|
{
|
|
tempB.SetY((float)(tempB.GetYInt() + signy2));
|
|
}
|
|
else
|
|
{
|
|
tempB.SetX((float)(tempB.GetXInt() + 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]);
|
|
}
|
|
else if (verts[0].GetY() == verts[1].GetY())
|
|
{
|
|
FillTexturedSideTriangle(hDc, model, verts[2], verts[0], verts[1]);
|
|
}
|
|
else
|
|
{
|
|
Vertex temp = verts[1];
|
|
temp.SetX(verts[0].GetX() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetX() - verts[0].GetX()));
|
|
|
|
float tempZr = verts[0].GetZRecip() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetZRecip() - verts[0].GetZRecip());
|
|
temp.SetZRecip(tempZr);
|
|
|
|
float tempU = verts[0].GetUOverZ() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetUOverZ() - verts[0].GetUOverZ());
|
|
float tempV = verts[0].GetVOverZ() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetVOverZ() - verts[0].GetVOverZ());
|
|
temp.SetUOverZ(tempU);
|
|
temp.SetVOverZ(tempV);
|
|
|
|
// Get the RGB value at the new vertex point
|
|
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())
|
|
{
|
|
FillTexturedSideTriangle(hDc, model, verts[0], verts[1], temp);
|
|
FillTexturedSideTriangle(hDc, model, verts[2], verts[1], temp);
|
|
}
|
|
else
|
|
{
|
|
FillTexturedSideTriangle(hDc, model, verts[0], temp, verts[1]);
|
|
FillTexturedSideTriangle(hDc, model, verts[2], temp, verts[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Rasteriser::FillTexturedSideTriangle(HDC hDc, Model& model, const Vertex& v1, const Vertex& v2, const Vertex& v3)
|
|
{
|
|
// Check if any of the vertices match and dont draw the triangle if they do, this should stop the infinite loop that can happen with small vertex float numbers
|
|
if ((v1.GetXInt() == v2.GetXInt() && v1.GetYInt() == v2.GetYInt()) || (v1.GetXInt() == v3.GetXInt() && v1.GetYInt() == v3.GetYInt()) || (v2.GetXInt() == v3.GetXInt() && v3.GetYInt() == v2.GetYInt()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vertex tempA = Vertex(v1);
|
|
Vertex tempB = Vertex(v1);
|
|
|
|
bool changed1 = false;
|
|
bool changed2 = false;
|
|
|
|
int dx1 = (int)abs(v2.GetXInt() - v1.GetXInt());
|
|
int dy1 = (int)abs(v2.GetYInt() - v1.GetYInt());
|
|
int dx2 = (int)abs(v3.GetXInt() - v1.GetXInt());
|
|
int dy2 = (int)abs(v3.GetYInt() - v1.GetYInt());
|
|
|
|
int signx1 = (int)sgn(v2.GetXInt() - v1.GetXInt());
|
|
int signx2 = (int)sgn(v3.GetXInt() - v1.GetXInt());
|
|
int signy1 = (int)sgn(v2.GetYInt() - v1.GetYInt());
|
|
int signy2 = (int)sgn(v3.GetYInt() - v1.GetYInt());
|
|
|
|
if (dy1 > dx1)
|
|
{
|
|
swap(dx1, dy1);
|
|
changed1 = true;
|
|
}
|
|
|
|
if (dy2 > dx2)
|
|
{
|
|
swap(dx2, dy2);
|
|
changed2 = true;
|
|
}
|
|
|
|
int e1 = 2 * dy1 - dx1;
|
|
int e2 = 2 * dy2 - dx2;
|
|
|
|
for (int i = 0; i <= dx1; i++)
|
|
{
|
|
int leftEndPoint;
|
|
int rightEndPoint;
|
|
int sideFix;
|
|
|
|
if (tempA.GetXInt() < tempB.GetXInt())
|
|
{
|
|
leftEndPoint = tempA.GetXInt();
|
|
rightEndPoint = tempB.GetXInt();
|
|
sideFix = 0;
|
|
}
|
|
else
|
|
{
|
|
leftEndPoint = tempB.GetXInt();
|
|
rightEndPoint = tempA.GetXInt();
|
|
sideFix = 1;
|
|
}
|
|
|
|
float currentPoint = (float)i / (float)dx1;
|
|
float UCoordA = Interpolate(tempA.GetY(), v1.GetUOverZ(), v2.GetUOverZ(), v1.GetY(), v2.GetY());
|
|
float UCoordB = Interpolate(tempA.GetY(), v1.GetUOverZ(), v3.GetUOverZ(), v1.GetY(), v3.GetY());
|
|
float VCoordA = Interpolate(tempA.GetY(), v1.GetVOverZ(), v2.GetVOverZ(), v1.GetY(), v2.GetY());
|
|
float VCoordB = Interpolate(tempA.GetY(), v1.GetVOverZ(), v3.GetVOverZ(), v1.GetY(), v3.GetY());
|
|
float ZRecipA = Interpolate(tempA.GetY(), v1.GetZRecip(), v2.GetZRecip(), v1.GetY(), v2.GetY());
|
|
float ZRecipB = Interpolate(tempA.GetY(), v1.GetZRecip(), v3.GetZRecip(), v1.GetY(), v3.GetY());
|
|
|
|
float iRedA = Lerp(v1.GetR(), v2.GetR(), currentPoint);
|
|
float iRedB = Lerp(v1.GetR(), v3.GetR(), currentPoint);
|
|
float iGreenA = Lerp(v1.GetG(), v2.GetG(), currentPoint);
|
|
float iGreenB = Lerp(v1.GetG(), v3.GetG(), currentPoint);
|
|
float iBlueA = Lerp(v1.GetB(), v2.GetB(), currentPoint);
|
|
float iBlueB = Lerp(v1.GetB(), v3.GetB(), currentPoint);
|
|
|
|
int xLength = rightEndPoint - leftEndPoint;
|
|
int ci = xLength * sideFix;
|
|
|
|
for (int xi = leftEndPoint; xi < rightEndPoint; xi++)
|
|
{
|
|
float ti = ((float)ci / (float)xLength);
|
|
|
|
float UCoordTmp = Lerp(UCoordA, UCoordB, ti);
|
|
float VCoordTmp = Lerp(VCoordA, VCoordB, ti);
|
|
float ZRecipTmp = Lerp(ZRecipA, ZRecipB, ti);
|
|
float redTmp = Lerp(iRedA, iRedB, ti) / 100;
|
|
float greenTmp = Lerp(iGreenA, iGreenB, ti) / 100;
|
|
float blueTmp = Lerp(iBlueA, iBlueB, ti) / 100;
|
|
|
|
float uFinal = UCoordTmp / ZRecipTmp;
|
|
float vFinal = VCoordTmp / ZRecipTmp;
|
|
|
|
COLORREF textureColor = model.GetTexture().GetTextureValue((int)uFinal, (int)vFinal);
|
|
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);
|
|
if (sideFix == 1)
|
|
{
|
|
ci--;
|
|
}
|
|
else
|
|
{
|
|
ci++;
|
|
}
|
|
}
|
|
|
|
while (e1 >= 0)
|
|
{
|
|
if (changed1)
|
|
{
|
|
tempA.SetX((float)(tempA.GetXInt() + signx1));
|
|
}
|
|
else
|
|
{
|
|
tempA.SetY((float)(tempA.GetYInt() + signy1));
|
|
}
|
|
e1 = e1 - 2 * dx1;
|
|
}
|
|
|
|
if (changed1)
|
|
{
|
|
tempA.SetY((float)(tempA.GetYInt() + signy1));
|
|
}
|
|
else
|
|
{
|
|
tempA.SetX((float)(tempA.GetXInt() + signx1));
|
|
}
|
|
|
|
e1 = e1 + 2 * dy1;
|
|
|
|
while (tempB.GetYInt(true) != tempA.GetYInt(true))
|
|
{
|
|
while (e2 >= 0)
|
|
{
|
|
if (changed2)
|
|
{
|
|
tempB.SetX((float)(tempB.GetXInt() + signx2));
|
|
}
|
|
else
|
|
{
|
|
tempB.SetY((float)(tempB.GetYInt() + signy2));
|
|
}
|
|
e2 = e2 - 2 * dx2;
|
|
}
|
|
|
|
if (changed2)
|
|
{
|
|
tempB.SetY((float)(tempB.GetYInt() + signy2));
|
|
}
|
|
else
|
|
{
|
|
tempB.SetX((float)(tempB.GetXInt() + signx2));
|
|
}
|
|
e2 = e2 + 2 * dy2;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void Rasteriser::FillPolygonTexturedA(HDC hDc, Model& model, vector<Vertex>& verts)
|
|
{
|
|
sort(verts.begin(), verts.end(), VerticiesYCompareAsc);
|
|
|
|
if (verts[1].GetY() == verts[2].GetY())
|
|
{
|
|
FillTexturedBottomFlatTriangle(hDc, model, verts[0], verts[1], verts[2]);
|
|
}
|
|
else if (verts[0].GetY() == verts[1].GetY())
|
|
{
|
|
FillTexturedTopFlatTriangle(hDc, model, verts[0], verts[1], verts[2]);
|
|
}
|
|
else
|
|
{
|
|
Vertex temp = verts[1];
|
|
temp.SetX(verts[0].GetX() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetX() - verts[0].GetX()));
|
|
|
|
float tempZr = verts[1].GetZOriginal() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetZOriginal() - verts[0].GetZOriginal());
|
|
temp.SetZOriginal(tempZr);
|
|
|
|
float uc1 = model.GetUVCoord(verts[0].GetUVIndex()).GetU();
|
|
float vc1 = model.GetUVCoord(verts[0].GetUVIndex()).GetV();
|
|
float uc2 = model.GetUVCoord(verts[1].GetUVIndex()).GetU();
|
|
float vc2 = model.GetUVCoord(verts[1].GetUVIndex()).GetV();
|
|
float uc3 = model.GetUVCoord(verts[2].GetUVIndex()).GetU();
|
|
float vc3 = model.GetUVCoord(verts[2].GetUVIndex()).GetV();
|
|
|
|
float tempU = Interpolate(verts[1].GetY(), uc1, uc3, verts[0].GetY(), verts[2].GetY()); // uc1 + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (uc3 - uc1);
|
|
float tempV = Interpolate(verts[1].GetY(), vc1, vc3, verts[0].GetY(), verts[2].GetY()); // vc2 + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (vc3 - vc2);
|
|
temp.UVCorrect(tempU, tempV);
|
|
//temp.SetUOverZ(tempU);
|
|
//temp.SetVOverZ(tempV);
|
|
|
|
//x0 + (y - y0) * ((x1 - x0) / (y1 - y0));
|
|
|
|
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));
|
|
|
|
FillTexturedBottomFlatTriangle(hDc, model, verts[0], verts[1], temp);
|
|
FillTexturedTopFlatTriangle(hDc, model, verts[1], temp, verts[2]);
|
|
|
|
}
|
|
}
|
|
|
|
void Rasteriser::FillTexturedBottomFlatTriangle(HDC hDc, Model& model, const Vertex& v1, const Vertex& v2, const Vertex& v3)
|
|
{
|
|
float slope1 = (v2.GetX() - v1.GetX()) / (v2.GetY() - v1.GetY());
|
|
float slope2 = (v3.GetX() - v1.GetX()) / (v3.GetY() - v1.GetY());
|
|
|
|
float x1 = v1.GetX() - 1.0f;
|
|
float x2 = v1.GetX() + 1.0f;
|
|
|
|
float v2v1Diff = (v2.GetY() - v1.GetY());
|
|
float colorSlopeBlue1 = (v2.GetB() - v1.GetB()) / v2v1Diff;
|
|
float colorSlopeRed1 = (v2.GetR() - v1.GetR()) / v2v1Diff;
|
|
float colorSlopeGreen1 = (v2.GetG() - v1.GetG()) / v2v1Diff;
|
|
float uSlope1 = (v2.GetUOverZ() - v1.GetUOverZ()) / v2v1Diff;
|
|
float vSlope1 = (v2.GetVOverZ() - v1.GetVOverZ()) / v2v1Diff;
|
|
float zrSlope1 = (v2.GetZRecip() - v1.GetZRecip()) / v2v1Diff;
|
|
|
|
float v3v1Diff = (v3.GetY() - v1.GetY());
|
|
float colorSlopeBlue2 = (v3.GetB() - v1.GetB()) / v3v1Diff;
|
|
float colorSlopeRed2 = (v3.GetR() - v1.GetR()) / v3v1Diff;
|
|
float colorSlopeGreen2 = (v3.GetG() - v1.GetG()) / v3v1Diff;
|
|
float uSlope2 = (v3.GetUOverZ() - v1.GetUOverZ()) / v3v1Diff;
|
|
float vSlope2 = (v3.GetVOverZ() - v1.GetVOverZ()) / v3v1Diff;
|
|
float zrSlope2 = (v3.GetZRecip() - v1.GetZRecip()) / v3v1Diff;
|
|
|
|
float cBlue1 = (float)v1.GetB();
|
|
float cRed1 = (float)v1.GetR();
|
|
float cGreen1 = (float)v1.GetG();
|
|
float uc1 = v1.GetUOverZ();
|
|
float vc1 = v1.GetVOverZ();
|
|
float zr1 = v1.GetZRecip();
|
|
float cBlue2 = (float)v1.GetB();
|
|
float cRed2 = (float)v1.GetR();
|
|
float cGreen2 = (float)v1.GetG();
|
|
float uc2 = v1.GetUOverZ();
|
|
float vc2 = v1.GetVOverZ();
|
|
float zr2 = v1.GetZRecip();
|
|
|
|
if (slope2 < slope1)
|
|
{
|
|
float slopeTmp = slope1;
|
|
slope1 = slope2;
|
|
slope2 = slopeTmp;
|
|
|
|
slopeTmp = colorSlopeRed1;
|
|
colorSlopeRed1 = colorSlopeRed2;
|
|
colorSlopeRed2 = slopeTmp;
|
|
|
|
slopeTmp = colorSlopeGreen1;
|
|
colorSlopeGreen1 = colorSlopeGreen2;
|
|
colorSlopeGreen2 = slopeTmp;
|
|
|
|
slopeTmp = colorSlopeBlue1;
|
|
colorSlopeBlue1 = colorSlopeBlue2;
|
|
colorSlopeBlue2 = slopeTmp;
|
|
|
|
slopeTmp = uSlope1;
|
|
uSlope1 = uSlope2;
|
|
uSlope2 = slopeTmp;
|
|
|
|
slopeTmp = vSlope1;
|
|
vSlope1 = vSlope2;
|
|
vSlope2 = slopeTmp;
|
|
|
|
slopeTmp = zrSlope1;
|
|
zrSlope1 = zrSlope2;
|
|
zrSlope2 = slopeTmp;
|
|
}
|
|
|
|
for (float scanlineY = v1.GetY(); scanlineY < v2.GetY() + 0.5f; scanlineY++)
|
|
{
|
|
for (int xPos = (int)ceil(x1); xPos < (int)x2; xPos++)
|
|
{
|
|
float t = (xPos - x1) / (x2 - x1);
|
|
|
|
float redTmp = Lerp(cRed1, cRed2, t) / 100;
|
|
float greenTmp = Lerp(cGreen1, cGreen2, t) / 100;
|
|
float blueTmp = Lerp(cBlue1, cBlue2, t) / 100;
|
|
|
|
float UCoordTmp = Lerp(uc1, uc2, t);
|
|
float VCoordTmp = Lerp(vc1, vc2, t);
|
|
float ZRecipTmp = Lerp(zr1, zr2, t);
|
|
|
|
float uFinal = UCoordTmp / ZRecipTmp;
|
|
float vFinal = VCoordTmp / ZRecipTmp;
|
|
|
|
COLORREF textureColor = model.GetTexture().GetTextureValue((int)uFinal, (int)vFinal);
|
|
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, xPos, (int)scanlineY, currentColor);
|
|
}
|
|
|
|
x1 += slope1;
|
|
x2 += slope2;
|
|
|
|
cRed1 += colorSlopeRed1;
|
|
cGreen1 += colorSlopeGreen1;
|
|
cBlue1 += colorSlopeBlue1;
|
|
uc1 += uSlope1;
|
|
vc1 += vSlope1;
|
|
zr1 += zrSlope1;
|
|
|
|
cRed2 += colorSlopeRed2;
|
|
cGreen2 += colorSlopeGreen2;
|
|
cBlue2 += colorSlopeBlue2;
|
|
uc2 += uSlope2;
|
|
vc2 += vSlope2;
|
|
zr2 += zrSlope2;
|
|
}
|
|
}
|
|
|
|
void Rasteriser::FillTexturedTopFlatTriangle(HDC hDc, Model& model, const Vertex& v1, const Vertex& v2, const Vertex& v3)
|
|
{
|
|
float slope1 = (v3.GetX() - v1.GetX()) / (v3.GetY() - v1.GetY());
|
|
float slope2 = (v3.GetX() - v2.GetX()) / (v3.GetY() - v2.GetY());
|
|
|
|
float x1 = v3.GetX() - 1.0f;
|
|
float x2 = v3.GetX() + 1.0f;
|
|
|
|
float v3v1Diff = (v3.GetY() - v1.GetY());
|
|
float colorSlopeBlue1 = (v3.GetB() - v1.GetB()) / v3v1Diff;
|
|
float colorSlopeRed1 = (v3.GetR() - v1.GetR()) / v3v1Diff;
|
|
float colorSlopeGreen1 = (v3.GetG() - v1.GetG()) / v3v1Diff;
|
|
float uSlope1 = (v3.GetUOverZ() - v1.GetUOverZ()) / v3v1Diff;
|
|
float vSlope1 = (v3.GetVOverZ() - v1.GetVOverZ()) / v3v1Diff;
|
|
float zrSlope1 = (v3.GetZRecip() - v1.GetZRecip()) / v3v1Diff;
|
|
|
|
float v3v2Diff = (v3.GetY() - v2.GetY());
|
|
float colorSlopeBlue2 = (v3.GetB() - v2.GetB()) / v3v2Diff;
|
|
float colorSlopeRed2 = (v3.GetR() - v2.GetR()) / v3v2Diff;
|
|
float colorSlopeGreen2 = (v3.GetG() - v2.GetG()) / v3v2Diff;
|
|
float uSlope2 = (v3.GetUOverZ() - v2.GetUOverZ()) / v3v2Diff;
|
|
float vSlope2 = (v3.GetVOverZ() - v2.GetVOverZ()) / v3v2Diff;
|
|
float zrSlope2 = (v3.GetZRecip() - v2.GetZRecip()) / v3v2Diff;
|
|
|
|
float cBlue1 = (float)v3.GetB();
|
|
float cRed1 = (float)v3.GetR();
|
|
float cGreen1 = (float)v3.GetG();
|
|
float uc1 = v3.GetUOverZ();
|
|
float vc1 = v3.GetVOverZ();
|
|
float zr1 = v3.GetZRecip();
|
|
float cBlue2 = (float)v3.GetB();
|
|
float cRed2 = (float)v3.GetR();
|
|
float cGreen2 = (float)v3.GetG();
|
|
float uc2 = v3.GetUOverZ();
|
|
float vc2 = v3.GetVOverZ();
|
|
float zr2 = v3.GetZRecip();
|
|
|
|
if (slope1 < slope2)
|
|
{
|
|
float slopeTmp = slope1;
|
|
slope1 = slope2;
|
|
slope2 = slopeTmp;
|
|
|
|
slopeTmp = colorSlopeRed1;
|
|
colorSlopeRed1 = colorSlopeRed2;
|
|
colorSlopeRed2 = slopeTmp;
|
|
|
|
slopeTmp = colorSlopeGreen1;
|
|
colorSlopeGreen1 = colorSlopeGreen2;
|
|
colorSlopeGreen2 = slopeTmp;
|
|
|
|
slopeTmp = colorSlopeBlue1;
|
|
colorSlopeBlue1 = colorSlopeBlue2;
|
|
colorSlopeBlue2 = slopeTmp;
|
|
|
|
slopeTmp = uSlope1;
|
|
uSlope1 = uSlope2;
|
|
uSlope2 = slopeTmp;
|
|
|
|
slopeTmp = vSlope1;
|
|
vSlope1 = vSlope2;
|
|
vSlope2 = slopeTmp;
|
|
|
|
slopeTmp = zrSlope1;
|
|
zrSlope1 = zrSlope2;
|
|
zrSlope2 = slopeTmp;
|
|
}
|
|
|
|
for (float scanlineY = v3.GetY(); scanlineY > v1.GetY(); scanlineY--)
|
|
{
|
|
for (int xPos = (int)ceil(x1); xPos < (int)x2; xPos++)
|
|
{
|
|
float t = (xPos - x1) / (x2 - x1);
|
|
|
|
float redTmp = Lerp(cRed1, cRed2, t) / 100;
|
|
float greenTmp = Lerp(cGreen1, cGreen2, t) / 100;
|
|
float blueTmp = Lerp(cBlue1, cBlue2, t) / 100;
|
|
|
|
float UCoordTmp = Lerp(uc1, uc2, t);
|
|
float VCoordTmp = Lerp(vc1, vc2, t);
|
|
float ZRecipTmp = Lerp(zr1, zr2, t);
|
|
|
|
float uFinal = UCoordTmp / ZRecipTmp;
|
|
float vFinal = VCoordTmp / ZRecipTmp;
|
|
|
|
COLORREF textureColor = model.GetTexture().GetTextureValue((int)uFinal, (int)vFinal);
|
|
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, xPos, (int)scanlineY, currentColor);
|
|
}
|
|
|
|
x1 -= slope1;
|
|
x2 -= slope2;
|
|
|
|
cRed1 -= colorSlopeRed1;
|
|
cGreen1 -= colorSlopeGreen1;
|
|
cBlue1 -= colorSlopeBlue1;
|
|
uc1 -= uSlope1;
|
|
vc1 -= vSlope1;
|
|
zr1 -= zrSlope1;
|
|
|
|
cRed2 -= colorSlopeRed2;
|
|
cGreen2 -= colorSlopeGreen2;
|
|
cBlue2 -= colorSlopeBlue2;
|
|
uc2 -= uSlope2;
|
|
vc2 -= vSlope2;
|
|
zr2 -= zrSlope2;
|
|
}
|
|
}
|