
Added UVCheck texture file Added UV perspective Variables to the Vertex Class Added Texture Draw method to the Rasteriser
969 lines
28 KiB
C++
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;
|
|
}
|
|
}
|
|
} |