cpp_drawing/renderers/pgm_renderer.cpp
2025-09-26 15:42:44 +02:00

107 lines
2.9 KiB
C++

#include "pgm_renderer.hpp"
#include <cmath>
#include <stdexcept>
PgmRenderer::PgmRenderer(const std::filesystem::path& path, size_t width, size_t height)
: m_file(path), m_bitmap(width, height, Color{0xFF})
{
if (m_file.bad())
{
throw std::runtime_error("Could not open file for writing: " + path.string());
}
}
void PgmRenderer::DrawLine(const math::Vector& p0, const math::Vector& p1)
{
RasterizeLine(static_cast<int>(p0.x), static_cast<int>(p0.y), static_cast<int>(p1.x), static_cast<int>(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;
PgmRenderer::DrawLine(pA, pB);
PgmRenderer::DrawLine(pB, pC);
PgmRenderer::DrawLine(pC, pD);
PgmRenderer::DrawLine(pD, pA);
}
void PgmRenderer::DrawCircle(const math::Vector& center, float radius)
{
RasterizeCircle(center.x, center.y, radius);
}
void PgmRenderer::Flush()
{
m_file << "P2" << std::endl;
m_file << "# KIV/CPP" << std::endl;
m_file << m_bitmap.GetWidth() << ' ' << m_bitmap.GetHeight() << std::endl;
m_file << 255 << std::endl;
for (size_t y = 0; y < m_bitmap.GetHeight(); ++y)
{
for (size_t x = 0; x < m_bitmap.GetWidth(); ++x)
{
m_file << static_cast<int>(m_bitmap[y][x].l) << ' ';
}
m_file << std::endl;
}
}
void PgmRenderer::RasterizeLine(int x0, int y0, int x1, int y1)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2; /* error value e_xy */
for (;;)
{ /* loop */
m_bitmap[y0][x0].l = 0x00;
if (x0 == x1 && y0 == y1)
break;
e2 = 2 * err;
if (e2 >= dy)
{
err += dy;
x0 += sx;
} /* e_xy+e_x > 0 */
if (e2 <= dx)
{
err += dx;
y0 += sy;
} /* e_xy+e_y < 0 */
}
}
void PgmRenderer::RasterizeCircle(int xm, int ym, int r)
{
int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */
do
{
m_bitmap[ym + y][xm - x].l = 0x00;
m_bitmap[ym - x][xm - y].l = 0x00;
m_bitmap[ym - y][xm + x].l = 0x00;
m_bitmap[ym + x][xm + y].l = 0x00;
// setPixel(xm - x, ym + y); /* I. Quadrant */
// setPixel(xm - y, ym - x); /* II. Quadrant */
// setPixel(xm + x, ym - y); /* III. Quadrant */
// setPixel(xm + y, ym + x); /* IV. Quadrant */
r = err;
if (r <= y)
err += ++y * 2 + 1; /* e_xy+e_y < 0 */
if (r > x || err > y)
err += ++x * 2 + 1; /* e_xy+e_x > 0 or no 2nd y-step */
} while (x < 0);
}