#include "pgm_renderer.hpp" #include #include #include PgmRenderer::PgmRenderer(size_t width, size_t height) : m_bitmap(width, height, Color{0xFF}) {} void PgmRenderer::DrawLine(const math::Vector& p0, const math::Vector& p1) { RasterizeLine(static_cast(p0.x), static_cast(p0.y), static_cast(p1.x), static_cast(p1.y)); } void PgmRenderer::DrawRectangle(const math::Vector& pos, const math::Vector& size, float angle) { const float sina = std::sin(angle); const float cosa = std::cos(angle); const math::Vector bX{cosa, sina}; const math::Vector bY{-sina, cosa}; const auto& pD = pos; const auto pA = pD + bY * size.y; const auto pB = pA + bX * size.x; const auto pC = pD + bX * size.x; DrawLine(pA, pB); DrawLine(pB, pC); DrawLine(pC, pD); DrawLine(pD, pA); } void PgmRenderer::DrawCircle(const math::Vector& center, float radius) { // TODO: cast RasterizeCircle(center.x, center.y, radius); } void PgmRenderer::Save(const std::filesystem::path& path) { std::ofstream file{path}; if (!file.is_open()) { throw std::runtime_error{"Cannot open file for writing: " + path.string()}; } file << "P2" << std::endl; file << "# KIV/CPP" << std::endl; file << m_bitmap.GetWidth() << ' ' << m_bitmap.GetHeight() << std::endl; file << 255 << std::endl; for (size_t y = 0; y < m_bitmap.GetHeight(); ++y) { for (size_t x = 0; x < m_bitmap.GetWidth(); ++x) { file << static_cast(m_bitmap[y][x].l) << ' '; } file << std::endl; } } void PgmRenderer::RasterizeLine(int x0, int y0, int x1, int y1) { // TODO: fix const Color lineColor{0x00}; float w = 2.0f; int dx = abs(x1 - x0); int dy = abs(y1 - y0); int sx = (x0 < x1) ? 1 : -1; int sy = (y0 < y1) ? 1 : -1; int err = dx - dy; // perpendicular offsets for thickness int ox = 0, oy = 0; if (dx > dy) { oy = 1; } else { ox = 1; } while (true) { // draw a square of pixels for thickness for (int i = -w / 2; i <= w / 2; i++) { for (int j = -w / 2; j <= w / 2; j++) { m_bitmap.Put(x0 + i * ox, y0 + j * oy, lineColor, 0xFF); } } if (x0 == x1 && y0 == y1) break; int e2 = 2 * err; if (e2 > -dy) { err -= dy; x0 += sx; } if (e2 < dx) { err += dx; y0 += sy; } } } void PgmRenderer::RasterizeCircle(int cx, int cy, int r) { // TODO: fix const Color circleColor{0x00}; float w = 2.0f; int r_outer = r + w / 2; int r_inner = r - w / 2; if (r_inner < 0) r_inner = 0; for (int y = -r_outer; y <= r_outer; y++) { for (int x = -r_outer; x <= r_outer; x++) { int dist2 = x * x + y * y; if (dist2 <= r_outer * r_outer && dist2 >= r_inner * r_inner) { m_bitmap.Put(cx + x, cy + y, circleColor, 0xFF); } } } }