
Added active Variable to the Lights Classes Added updated MD2Loader Class Added Model Filename and Texture File Name to the Model Class Added Active Flag to the Model Class Added DrawMode to the Model Class Added Texture and UV Variables to the Model Class Added UV Coordinates to the Polygon3D Class Added DrawString method to the Rasterizer to write text to the screen space Added Interpolate and Lerp Methods to the Rasterizer Added Select statement for drawing a current models draw mode Added DrawTextured Method to the Rasterizer Class Added UVCoord Class Added Texture Class Added = operator to the Vector3D Class Added UVCoord to the Vertex Class Moved Models and Texture Files into a subfolder Fixed issue with textures not loading properly because of the vector address problem
934 lines
26 KiB
C++
934 lines
26 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, 0), 150, 150, 150));
|
|
_lights.push_back(new PointLight(Vertex(0, 0, -10), 0, 1, 0.01f, 150, 0, 0));
|
|
_cameras.push_back(Camera(0.0f, 0.0f, 0.0f, Vertex(0.0f, 0.0f, -50.0f)));
|
|
|
|
_screenMinimized = false;
|
|
|
|
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 a + (b - a) * t;
|
|
}
|
|
|
|
float Rasteriser::Lerp(int a, int b, float t)
|
|
{
|
|
return Lerp((float)a, (float)b, t);
|
|
}
|
|
|
|
void Rasteriser::Update(const Bitmap& bitmap)
|
|
{
|
|
if (bitmap.GetWidth() == 0 || bitmap.GetHeight() == 0)
|
|
{
|
|
_screenMinimized = true;
|
|
}
|
|
else
|
|
{
|
|
_screenMinimized = false;
|
|
}
|
|
|
|
if (!_screenMinimized)
|
|
{
|
|
int currentRot = (_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() - 1.0f;
|
|
rightEndPoint = tempB.GetX() + 1.0f;
|
|
}
|
|
else
|
|
{
|
|
leftEndPoint = tempB.GetX() - 1.0f;
|
|
rightEndPoint = tempA.GetX() + 1.0f;
|
|
}
|
|
|
|
float iRedA = Lerp(v1.GetR(), v2.GetR(), (float)i / (float)dx1);
|
|
float iRedB = Lerp(v1.GetR(), v3.GetR(), (float)i / (float)dx1);
|
|
float iGreenA = Lerp(v1.GetG(), v2.GetG(), (float)i / (float)dx1);
|
|
float iGreenB = Lerp(v1.GetG(), v3.GetG(), (float)i / (float)dx1);
|
|
float iBlueA = Lerp(v1.GetB(), v2.GetB(), (float)i / (float)dx1);
|
|
float iBlueB = Lerp(v1.GetB(), v3.GetB(), (float)i / (float)dx1);
|
|
|
|
int xLength = (int)ceil(rightEndPoint) - (int)ceil(leftEndPoint);
|
|
int ci = 0;
|
|
|
|
for (int xi = (int)ceil(leftEndPoint); xi <= (int)ceil(rightEndPoint); xi++)
|
|
{
|
|
float ti = (float)ci / (float)xLength;
|
|
float 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.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::FillPolygonTextured(HDC hDc, Model& model, vector<Vertex>& verts)
|
|
{
|
|
sort(verts.begin(), verts.end(), VerticiesYCompareAsc);
|
|
if (verts[1].GetY() == verts[2].GetY())
|
|
{
|
|
FillTexturedSideTriangle(hDc, model, verts[0], verts[1], verts[2], model.GetUVCoord(verts[0].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), model.GetUVCoord(verts[2].GetUVIndex()));
|
|
}
|
|
else if (verts[0].GetY() == verts[1].GetY())
|
|
{
|
|
FillTexturedSideTriangle(hDc, model, verts[2], verts[0], verts[1], model.GetUVCoord(verts[2].GetUVIndex()), model.GetUVCoord(verts[0].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()));
|
|
}
|
|
else
|
|
{
|
|
Vertex temp = Vertex(verts[0].GetX() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetX() - verts[0].GetX()), verts[1].GetY(), verts[1].GetZ());
|
|
temp.SetNormal(verts[1].GetNormal());
|
|
|
|
float tempU = model.GetUVCoord(verts[0].GetUVIndex()).GetU() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (model.GetUVCoord(verts[2].GetUVIndex()).GetU() - model.GetUVCoord(verts[0].GetUVIndex()).GetU());
|
|
float tempV = model.GetUVCoord(verts[0].GetUVIndex()).GetV() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (model.GetUVCoord(verts[2].GetUVIndex()).GetV() - model.GetUVCoord(verts[0].GetUVIndex()).GetV());
|
|
|
|
UVCoord tempCoords = UVCoord(tempU, tempV);
|
|
|
|
float cRed = verts[0].GetR() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetR() - verts[0].GetR());
|
|
float cGreen = verts[0].GetG() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetG() - verts[0].GetG());
|
|
float cBlue = verts[0].GetB() + ((verts[1].GetY() - verts[0].GetY()) / (verts[2].GetY() - verts[0].GetY())) * (verts[2].GetB() - verts[0].GetB());
|
|
temp.SetColor(BoundsCheck(0, 255, (int)cRed), BoundsCheck(0, 255, (int)cGreen), BoundsCheck(0, 255, (int)cBlue));
|
|
|
|
if (verts[1].GetX() <= temp.GetX())
|
|
{
|
|
temp.SetUVIndex(verts[2].GetUVIndex());
|
|
FillTexturedSideTriangle(hDc, model, verts[0], verts[1], temp, model.GetUVCoord(verts[0].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), tempCoords);
|
|
temp.SetUVIndex(verts[0].GetUVIndex());
|
|
FillTexturedSideTriangle(hDc, model, verts[2], verts[1], temp, model.GetUVCoord(verts[2].GetUVIndex()), model.GetUVCoord(verts[1].GetUVIndex()), tempCoords);
|
|
}
|
|
else
|
|
{
|
|
temp.SetUVIndex(verts[2].GetUVIndex());
|
|
FillTexturedSideTriangle(hDc, model, verts[0], temp, verts[1], model.GetUVCoord(verts[0].GetUVIndex()), tempCoords, model.GetUVCoord(verts[1].GetUVIndex()));
|
|
temp.SetUVIndex(verts[0].GetUVIndex());
|
|
FillTexturedSideTriangle(hDc, model, verts[2], temp, verts[1], model.GetUVCoord(verts[2].GetUVIndex()), tempCoords, model.GetUVCoord(verts[1].GetUVIndex()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Rasteriser::FillTexturedSideTriangle(HDC hDc, Model& model, const Vertex& v1, const Vertex& v2, const Vertex& v3, const UVCoord& uv1, const UVCoord& uv2, const UVCoord& uv3)
|
|
{
|
|
Vertex tempA = Vertex(v1);
|
|
Vertex tempB = Vertex(v1);
|
|
UVCoord tempUVA = UVCoord(uv1);
|
|
UVCoord tempUVB = UVCoord(uv1);
|
|
|
|
bool changed1 = false;
|
|
bool changed2 = false;
|
|
|
|
float uc0 = uv1.GetU();
|
|
float vc0 = uv1.GetV();
|
|
float uc1 = uv2.GetU();
|
|
float vc1 = uv2.GetV();
|
|
float uc2 = uv3.GetU();
|
|
float vc2 = uv3.GetV();
|
|
|
|
int dx1 = (int)ceil(abs(v2.GetX() - v1.GetX()));
|
|
int dy1 = (int)ceil(abs(v2.GetY() - v1.GetY()));
|
|
int du1 = (int)ceil(abs(uc1 - uc0));
|
|
int dv1 = (int)ceil(abs(vc1 - vc0));
|
|
|
|
int dx2 = (int)ceil(abs(v3.GetX() - v1.GetX()));
|
|
int dy2 = (int)ceil(abs(v3.GetY() - v1.GetY()));
|
|
int du2 = (int)ceil(abs(uc2 - uc0));
|
|
int dv2 = (int)ceil(abs(vc2 - vc0));
|
|
|
|
int signx1 = (int)ceil(sgn(v2.GetX() - v1.GetX()));
|
|
int signx2 = (int)ceil(sgn(v3.GetX() - v1.GetX()));
|
|
int signu1 = (int)ceil(sgn(uc1 - uc0));
|
|
int signu2 = (int)ceil(sgn(uc2 - uc0));
|
|
|
|
int signy1 = (int)ceil(sgn(v2.GetY() - v1.GetY()));
|
|
int signy2 = (int)ceil(sgn(v3.GetY() - v1.GetY()));
|
|
int signv1 = (int)ceil(sgn(vc1 - vc0));
|
|
int signv2 = (int)ceil(sgn(vc2 - vc0));
|
|
|
|
if (dy1 > dx1)
|
|
{
|
|
int tempDx = dx1;
|
|
dx1 = dy1;
|
|
dy1 = tempDx;
|
|
|
|
int tempDu = du1;
|
|
du1 = dv1;
|
|
dv1 = tempDu;
|
|
|
|
changed1 = true;
|
|
}
|
|
|
|
if (dy2 > dx2)
|
|
{
|
|
int tempDx = dx2;
|
|
dx2 = dy2;
|
|
dy2 = tempDx;
|
|
|
|
int tempDu = du2;
|
|
du2 = dv2;
|
|
dv2 = tempDu;
|
|
|
|
changed2 = true;
|
|
}
|
|
|
|
int e1 = 2 * (int)dy1 - (int)dx1;
|
|
int e2 = 2 * (int)dy2 - (int)dx2;
|
|
|
|
for (int i = 0; i <= (int)dx1; i++)
|
|
{
|
|
float leftEndPoint;
|
|
float rightEndPoint;
|
|
float leftUV;
|
|
float rightUV;
|
|
|
|
if (tempA.GetX() < tempB.GetX())
|
|
{
|
|
leftEndPoint = tempA.GetX() - 1.0f;
|
|
rightEndPoint = tempB.GetX() + 1.0f;
|
|
leftUV = tempUVA.GetU();
|
|
rightUV = tempUVB.GetU();
|
|
}
|
|
else
|
|
{
|
|
leftEndPoint = tempB.GetX() - 1.0f;
|
|
rightEndPoint = tempA.GetX() + 1.0f;
|
|
leftUV = tempUVB.GetU();
|
|
rightUV = tempUVA.GetU();
|
|
}
|
|
|
|
|
|
float UCoordA = Interpolate(uv1.GetV() + i, uv1.GetU(), uv2.GetU(), uv1.GetV(), uv2.GetV());
|
|
float UCoordB = Interpolate(uv1.GetV() + i, uv1.GetU(), uv3.GetU(), uv1.GetV(), uv3.GetV());
|
|
|
|
float iRedA = Lerp(v1.GetR(), v2.GetR(), (float)i / (float)dx1);
|
|
float iRedB = Lerp(v1.GetR(), v3.GetR(), (float)i / (float)dx1);
|
|
float iGreenA = Lerp(v1.GetG(), v2.GetG(), (float)i / (float)dx1);
|
|
float iGreenB = Lerp(v1.GetG(), v3.GetG(), (float)i / (float)dx1);
|
|
float iBlueA = Lerp(v1.GetB(), v2.GetB(), (float)i / (float)dx1);
|
|
float iBlueB = Lerp(v1.GetB(), v3.GetB(), (float)i / (float)dx1);
|
|
|
|
int xLength = (int)ceil(rightEndPoint) - (int)ceil(leftEndPoint);
|
|
int ci = 0;
|
|
|
|
for (int xi = (int)ceil(leftEndPoint); xi <= (int)ceil(rightEndPoint); xi++)
|
|
{
|
|
float ti = (float)ci / (float)xLength;
|
|
float UCoordTmp = Lerp(leftUV, rightUV, ti);
|
|
float redTmp = Lerp(iRedA, iRedB, ti) / 100;
|
|
float greenTmp = Lerp(iGreenA, iGreenB, ti) / 100;
|
|
float blueTmp = Lerp(iBlueA, iBlueB, ti) / 100;
|
|
|
|
COLORREF textureColor = model.GetTexture().GetTextureValue((int)UCoordTmp, (int)tempUVA.GetV());
|
|
COLORREF currentColor = RGB(BoundsCheck(0, 255, (int)(GetRValue(textureColor) * redTmp)), BoundsCheck(0, 255, (int)(GetGValue(textureColor) * greenTmp)), BoundsCheck(0, 255, (int)(GetBValue(textureColor) * blueTmp)));
|
|
|
|
SetPixel(hDc, xi, tempA.GetYInt(), currentColor);
|
|
ci++;
|
|
}
|
|
|
|
|
|
while (e1 >= 0)
|
|
{
|
|
if (changed1)
|
|
{
|
|
tempA.SetX((float)tempA.GetXInt() + (float)signx1);
|
|
tempUVA.SetU((float)tempUVA.GetU() + (float)signu1);
|
|
}
|
|
else
|
|
{
|
|
tempA.SetY((float)tempA.GetYInt() + (float)signy1);
|
|
tempUVA.SetV((float)tempUVA.GetV() + (float)signv1);
|
|
}
|
|
e1 = e1 - 2 * dx1;
|
|
}
|
|
|
|
if (changed1)
|
|
{
|
|
tempA.SetY((float)tempA.GetYInt() + (float)signy1);
|
|
tempUVA.SetV((float)tempUVA.GetV() + (float)signv1);
|
|
}
|
|
else
|
|
{
|
|
tempA.SetX((float)tempA.GetXInt() + (float)signx1);
|
|
tempUVA.SetU((float)tempUVA.GetU() + (float)signu1);
|
|
}
|
|
|
|
e1 = e1 + 2 * dy1;
|
|
|
|
while (tempB.GetYInt(true) != tempA.GetYInt(true))
|
|
{
|
|
while (e2 >= 0)
|
|
{
|
|
if (changed2)
|
|
{
|
|
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
|
|
tempUVB.SetU((float)tempUVB.GetU() + (float)signu2);
|
|
}
|
|
else
|
|
{
|
|
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
|
|
tempUVB.SetV((float)tempUVB.GetV() + (float)signv2);
|
|
}
|
|
e2 = e2 - 2 * dx2;
|
|
}
|
|
|
|
if (changed2)
|
|
{
|
|
tempB.SetY((float)tempB.GetYInt() + (float)signy2);
|
|
tempUVB.SetV((float)tempUVB.GetV() + (float)signv2);
|
|
}
|
|
else
|
|
{
|
|
tempB.SetX((float)tempB.GetXInt() + (float)signx2);
|
|
tempUVB.SetU((float)tempUVB.GetU() + (float)signu2);
|
|
}
|
|
e2 = e2 + 2 * dy2;
|
|
}
|
|
}
|
|
} |