107 lines
2.9 KiB
C++
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);
|
|
}
|