#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 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 verticies) { vector 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 pointArray; vector 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 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 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 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 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& 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& 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& 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; } } }