//External includes #include #include "SDL_surface.h" //Project includes #include "Renderer.h" #include "Maths.h" #include "HitTest.h" using namespace dae; Renderer::Renderer(SDL_Window *pWindow) : m_pWindow(pWindow) { //Initialize SDL_GetWindowSize(pWindow, &m_Width, &m_Height); //Create Buffers m_pFrontBuffer = SDL_GetWindowSurface(pWindow); m_pBackBuffer = SDL_CreateRGBSurface(0, m_Width, m_Height, 32, 0, 0, 0, 0); m_pBackBufferPixels = (uint32_t *) m_pBackBuffer->pixels; m_pDepthBufferPixels = new float[m_Width * m_Height]; //Initialize Camera m_Camera.Initialize(60.f, {.0f, .0f, -10.f}); //Initialize Camera m_Camera.Initialize(60.f, {.0f, .0f, -10.f}); m_aspectRatio = static_cast(m_Width) / static_cast(m_Height); m_pTexture = Texture::LoadFromFile("./Resources/uv_grid_2.png"); } Renderer::~Renderer() { delete[] m_pDepthBufferPixels; } void Renderer::Update(Timer *pTimer) { m_Camera.Update(pTimer); } void Renderer::Render() { //@START //Lock BackBuffer //Random color SDL_FillRect(m_pBackBuffer, nullptr, m_ClearColor); SDL_LockSurface(m_pBackBuffer); std::fill_n(m_pDepthBufferPixels, m_Width * m_Height, std::numeric_limits::max()); //Clear SDL_FillRect(m_pBackBuffer, nullptr, m_ClearColor); ColorRGB finalColor{}; constexpr int numVerticies = 3; std::vector verticiesScreenSpace{}; // VertexTransformationFunction(m_verticiesWorld, verticiesScreenSpace); for (const Mesh ¤tMesh: m_meshesWorldStrip) { VertexTransformationFunction(currentMesh.vertices, verticiesScreenSpace); int numTriangles{}; switch (currentMesh.primitiveTopology) { case PrimitiveTopology::TriangleList: numTriangles = static_cast(currentMesh.indices.size()) / numVerticies; break; case PrimitiveTopology::TriangleStrip: numTriangles = static_cast(currentMesh.indices.size()) - 2; break; } for (int triangleIndex{}; triangleIndex < numTriangles; ++triangleIndex) { Vertex vertex0, vertex1, vertex2; switch (currentMesh.primitiveTopology) { case PrimitiveTopology::TriangleList: vertex0 = verticiesScreenSpace[currentMesh.indices[triangleIndex * numVerticies + 0]]; vertex1 = verticiesScreenSpace[currentMesh.indices[triangleIndex * numVerticies + 1]]; vertex2 = verticiesScreenSpace[currentMesh.indices[triangleIndex * numVerticies + 2]]; break; case PrimitiveTopology::TriangleStrip: vertex0 = verticiesScreenSpace[currentMesh.indices[triangleIndex + 0]]; vertex1 = verticiesScreenSpace[currentMesh.indices[triangleIndex + 1]]; vertex2 = verticiesScreenSpace[currentMesh.indices[triangleIndex + 2]]; if (triangleIndex % 2 == 1) { std::swap(vertex1, vertex2); } if (vertex0.position == vertex1.position || vertex0.position == vertex2.position || vertex1.position == vertex2.position) { continue; } break; } const float minX{std::min(vertex0.position.x, std::min(vertex1.position.x, vertex2.position.x))}; const float minY{std::min(vertex0.position.y, std::min(vertex1.position.y, vertex2.position.y))}; const float maxX{std::max(vertex0.position.x, std::max(vertex1.position.x, vertex2.position.x))}; const float maxY{std::max(vertex0.position.y, std::max(vertex1.position.y, vertex2.position.y))}; const Vector3 side1{vertex1.position - vertex0.position}; const Vector3 side2{vertex2.position - vertex0.position}; const float totalArea{Vector3::Cross(side1, side2).z}; const int startX = std::max(0, static_cast(minX)) - 1; const int endX = std::min(m_Width - 1, static_cast(maxX)) + 1; const int startY = std::max(0, static_cast(minY)) - 1; const int endY = std::min(m_Height - 1, static_cast(maxY)) + 1; for (int px{startX}; px < endX; ++px) { for (int py{startY}; py < endY; ++py) { if (px < 0 || px >= m_Width || py < 0 || py >= m_Height) { //TEMP fix for out of bounds //This is to remove triangles having an incorrect edge on their bounding box continue; } Vector3 P{static_cast(px) + 0.5f, static_cast(py) + 0.5f, 1.f}; const Vector3 cross0{Vector3::Cross(vertex2.position - vertex1.position, P - vertex1.position)}; if (cross0.z < 0) { continue; } const Vector3 cross1{Vector3::Cross(vertex0.position - vertex2.position, P - vertex2.position)}; if (cross1.z < 0) { continue; } const Vector3 cross2{Vector3::Cross(vertex1.position - vertex0.position, P - vertex0.position)}; if (cross2.z < 0) { continue; } const int depthBufferIndex{px + (py * m_Width)}; float totalWeight{cross0.z + cross1.z + cross2.z}; Vector3 weights{ cross0.z / totalWeight, cross1.z / totalWeight, cross2.z / totalWeight, }; const float currentDepth = 1 / (weights.x / vertex0.position.z + weights.y / vertex1.position.z + weights.z / vertex2.position.z); const Vector2 UvCoords = vertex0.uv * currentDepth * weights.x / vertex0.position.z + vertex1.uv * currentDepth * weights.y / vertex1.position.z + vertex2.uv * currentDepth * weights.z / vertex2.position.z; if (m_pDepthBufferPixels[depthBufferIndex] >= currentDepth) { m_pDepthBufferPixels[depthBufferIndex] = currentDepth; //Update Color in Buffer finalColor = m_pTexture->Sample(UvCoords); finalColor.MaxToOne(); m_pBackBufferPixels[px + (py * m_Width)] = SDL_MapRGB(m_pBackBuffer->format, static_cast(finalColor.r * 255), static_cast(finalColor.g * 255), static_cast(finalColor.b * 255)); } } } } } int x, y{0}; //For loop over all the pixels for (int px{}; px < 100; ++px) { for (int py{}; py < 100; ++py) { //Get the pixel position x = px; y = py; ColorRGB test = m_pTexture->Sample(Vector2{static_cast(px) / 100, static_cast(py) / 100}); m_pBackBufferPixels[x + (y * m_Width)] = SDL_MapRGB(m_pBackBuffer->format, static_cast(test.r * 255), static_cast(test.g * 255), static_cast(test.b * 255)); } } //RENDER LOGIC SDL_UnlockSurface(m_pBackBuffer); SDL_BlitSurface(m_pBackBuffer, nullptr, m_pFrontBuffer, nullptr); SDL_UpdateWindowSurface(m_pWindow); } void Renderer::VertexTransformationFunction(const std::vector &vertices_in, std::vector &vertices_out) const { for (const Vertex &vert: vertices_in) { Vector3 vertPos{m_Camera.invViewMatrix.TransformPoint(vert.position)}; vertPos.x = (vertPos.x / vertPos.z) / (m_aspectRatio * m_Camera.fov); vertPos.y = (vertPos.y / vertPos.z) / m_Camera.fov; vertPos.x = (vertPos.x + 1) / 2 * static_cast(m_Width); vertPos.y = (1 - vertPos.y) / 2 * static_cast(m_Height); vertices_out.push_back(Vertex{vertPos, vert.color, vert.uv}); } } bool Renderer::SaveBufferToImage() const { return SDL_SaveBMP(m_pBackBuffer, "Rasterizer_ColorBuffer.bmp"); }