2018-05-16 16:51:28 +00:00
|
|
|
#include "Rasterizer.hpp"
|
2018-05-21 11:46:41 +00:00
|
|
|
#include <ExPolygon.hpp>
|
|
|
|
|
2018-05-17 16:17:15 +00:00
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
// For rasterizing
|
|
|
|
#include <agg/agg_basics.h>
|
|
|
|
#include <agg/agg_rendering_buffer.h>
|
|
|
|
#include <agg/agg_pixfmt_gray.h>
|
|
|
|
#include <agg/agg_pixfmt_rgb.h>
|
|
|
|
#include <agg/agg_renderer_base.h>
|
|
|
|
#include <agg/agg_renderer_scanline.h>
|
|
|
|
|
|
|
|
#include <agg/agg_scanline_p.h>
|
|
|
|
#include <agg/agg_rasterizer_scanline_aa.h>
|
|
|
|
#include <agg/agg_path_storage.h>
|
2018-05-16 16:51:28 +00:00
|
|
|
|
2018-05-21 11:46:41 +00:00
|
|
|
// For png compression
|
2018-05-18 16:11:29 +00:00
|
|
|
#include <png/writer.hpp>
|
2018-05-16 16:51:28 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
|
|
|
class Raster::Impl {
|
2018-05-17 16:17:15 +00:00
|
|
|
public:
|
2018-05-18 13:08:18 +00:00
|
|
|
using TPixelRenderer = agg::pixfmt_gray8; // agg::pixfmt_rgb24;
|
2018-05-17 16:17:15 +00:00
|
|
|
using TRawRenderer = agg::renderer_base<TPixelRenderer>;
|
|
|
|
using TPixel = TPixelRenderer::color_type;
|
|
|
|
using TRawBuffer = agg::rendering_buffer;
|
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
using TBuffer = std::vector<TPixelRenderer::pixel_type>;
|
|
|
|
|
2018-05-17 16:17:15 +00:00
|
|
|
using TRendererAA = agg::renderer_scanline_aa_solid<TRawRenderer>;
|
|
|
|
|
|
|
|
static const TPixel ColorWhite;
|
|
|
|
static const TPixel ColorBlack;
|
|
|
|
|
2018-07-18 07:46:55 +00:00
|
|
|
using Origin = Raster::Origin;
|
|
|
|
|
2018-05-17 16:17:15 +00:00
|
|
|
private:
|
|
|
|
Raster::Resolution resolution_;
|
|
|
|
Raster::PixelDim pxdim_;
|
|
|
|
TBuffer buf_;
|
|
|
|
TRawBuffer rbuf_;
|
|
|
|
TPixelRenderer pixfmt_;
|
|
|
|
TRawRenderer raw_renderer_;
|
2018-05-18 13:08:18 +00:00
|
|
|
TRendererAA renderer_;
|
2018-07-18 07:46:55 +00:00
|
|
|
Origin o_;
|
2018-07-25 15:27:02 +00:00
|
|
|
std::function<void(agg::path_storage&)> flipy_ = [](agg::path_storage&) {};
|
2018-05-17 16:17:15 +00:00
|
|
|
public:
|
2018-07-18 07:46:55 +00:00
|
|
|
inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd,
|
2018-07-25 15:27:02 +00:00
|
|
|
Origin o):
|
2018-05-17 16:17:15 +00:00
|
|
|
resolution_(res), pxdim_(pd),
|
|
|
|
buf_(res.pixels()),
|
2018-05-18 13:08:18 +00:00
|
|
|
rbuf_(reinterpret_cast<TPixelRenderer::value_type*>(buf_.data()),
|
|
|
|
res.width_px, res.height_px,
|
|
|
|
res.width_px*TPixelRenderer::num_components),
|
2018-05-17 16:17:15 +00:00
|
|
|
pixfmt_(rbuf_),
|
2018-05-18 13:08:18 +00:00
|
|
|
raw_renderer_(pixfmt_),
|
2018-07-18 07:46:55 +00:00
|
|
|
renderer_(raw_renderer_),
|
|
|
|
o_(o)
|
2018-05-17 16:17:15 +00:00
|
|
|
{
|
2018-05-18 13:08:18 +00:00
|
|
|
renderer_.color(ColorWhite);
|
|
|
|
|
|
|
|
// If we would like to play around with gamma
|
|
|
|
// ras.gamma(agg::gamma_power(1.0));
|
|
|
|
|
2018-05-17 16:17:15 +00:00
|
|
|
clear();
|
2018-07-25 15:27:02 +00:00
|
|
|
|
|
|
|
if(o_ == Origin::TOP_LEFT) flipy_ = [this](agg::path_storage& path) {
|
|
|
|
path.flip_y(0, resolution_.height_px);
|
|
|
|
};
|
2018-05-17 16:17:15 +00:00
|
|
|
}
|
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
void draw(const ExPolygon &poly) {
|
2018-05-17 16:17:15 +00:00
|
|
|
agg::rasterizer_scanline_aa<> ras;
|
|
|
|
agg::scanline_p8 scanlines;
|
|
|
|
|
2018-05-21 11:46:41 +00:00
|
|
|
auto&& path = to_path(poly.contour);
|
2018-07-25 15:27:02 +00:00
|
|
|
flipy_(path);
|
2018-05-21 11:46:41 +00:00
|
|
|
ras.add_path(path);
|
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
for(auto h : poly.holes) {
|
2018-05-21 11:46:41 +00:00
|
|
|
auto&& holepath = to_path(h);
|
2018-07-25 15:27:02 +00:00
|
|
|
flipy_(holepath);
|
2018-05-21 11:46:41 +00:00
|
|
|
ras.add_path(holepath);
|
2018-05-17 16:17:15 +00:00
|
|
|
}
|
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
agg::render_scanlines(ras, scanlines, renderer_);
|
2018-05-17 16:17:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void clear() {
|
|
|
|
raw_renderer_.clear(ColorBlack);
|
|
|
|
}
|
|
|
|
|
2018-05-18 16:11:29 +00:00
|
|
|
inline TBuffer& buffer() { return buf_; }
|
2018-05-17 16:17:15 +00:00
|
|
|
|
|
|
|
inline const Raster::Resolution resolution() { return resolution_; }
|
2018-05-18 13:08:18 +00:00
|
|
|
|
2018-07-25 15:27:02 +00:00
|
|
|
inline Origin origin() const /*noexcept*/ { return o_; }
|
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
private:
|
|
|
|
double getPx(const Point& p) {
|
|
|
|
return p.x * SCALING_FACTOR/pxdim_.w_mm;
|
|
|
|
}
|
|
|
|
|
|
|
|
double getPy(const Point& p) {
|
|
|
|
return p.y * SCALING_FACTOR/pxdim_.h_mm;
|
|
|
|
}
|
|
|
|
|
|
|
|
agg::path_storage to_path(const Polygon& poly) {
|
|
|
|
agg::path_storage path;
|
|
|
|
auto it = poly.points.begin();
|
|
|
|
path.move_to(getPx(*it), getPy(*it));
|
|
|
|
while(++it != poly.points.end())
|
|
|
|
path.line_to(getPx(*it), getPy(*it));
|
|
|
|
|
|
|
|
path.line_to(getPx(poly.points.front()), getPy(poly.points.front()));
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2018-05-16 16:51:28 +00:00
|
|
|
};
|
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255);
|
|
|
|
const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0);
|
2018-05-17 16:17:15 +00:00
|
|
|
|
2018-07-18 07:46:55 +00:00
|
|
|
Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o):
|
|
|
|
impl_(new Impl(r, pd, o)) {}
|
2018-05-16 16:51:28 +00:00
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
Raster::Raster() {}
|
|
|
|
|
2018-05-16 16:51:28 +00:00
|
|
|
Raster::~Raster() {}
|
|
|
|
|
|
|
|
Raster::Raster(Raster &&m):
|
2018-05-17 16:17:15 +00:00
|
|
|
impl_(std::move(m.impl_)) {}
|
2018-05-16 16:51:28 +00:00
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd)
|
|
|
|
{
|
2018-08-17 13:11:30 +00:00
|
|
|
// Free up the unnecessary memory and make sure it stays clear after
|
2018-05-22 13:13:07 +00:00
|
|
|
// an exception
|
2018-07-25 15:27:02 +00:00
|
|
|
auto o = impl_? impl_->origin() : Origin::TOP_LEFT;
|
|
|
|
reset(r, pd, o);
|
|
|
|
}
|
2018-05-22 13:13:07 +00:00
|
|
|
|
2018-07-25 15:27:02 +00:00
|
|
|
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
|
|
|
|
Raster::Origin o)
|
|
|
|
{
|
|
|
|
impl_.reset();
|
|
|
|
impl_.reset(new Impl(r, pd, o));
|
2018-05-18 13:08:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Raster::reset()
|
|
|
|
{
|
|
|
|
impl_.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
Raster::Resolution Raster::resolution() const
|
|
|
|
{
|
|
|
|
if(impl_) return impl_->resolution();
|
|
|
|
|
|
|
|
return Resolution(0, 0);
|
|
|
|
}
|
|
|
|
|
2018-05-16 16:51:28 +00:00
|
|
|
void Raster::clear()
|
|
|
|
{
|
2018-05-18 13:08:18 +00:00
|
|
|
assert(impl_);
|
2018-05-17 16:17:15 +00:00
|
|
|
impl_->clear();
|
2018-05-16 16:51:28 +00:00
|
|
|
}
|
|
|
|
|
2018-05-18 13:08:18 +00:00
|
|
|
void Raster::draw(const ExPolygon &poly)
|
2018-05-16 16:51:28 +00:00
|
|
|
{
|
2018-05-18 13:08:18 +00:00
|
|
|
assert(impl_);
|
2018-05-17 16:17:15 +00:00
|
|
|
impl_->draw(poly);
|
2018-05-16 16:51:28 +00:00
|
|
|
}
|
|
|
|
|
2018-05-17 16:17:15 +00:00
|
|
|
void Raster::save(std::ostream& stream, Compression comp)
|
2018-05-16 16:51:28 +00:00
|
|
|
{
|
2018-05-18 13:08:18 +00:00
|
|
|
assert(impl_);
|
2018-05-17 16:17:15 +00:00
|
|
|
switch(comp) {
|
2018-05-18 16:11:29 +00:00
|
|
|
case Compression::PNG: {
|
|
|
|
|
|
|
|
png::writer<std::ostream> wr(stream);
|
|
|
|
|
|
|
|
wr.set_bit_depth(8);
|
|
|
|
wr.set_color_type(png::color_type_gray);
|
|
|
|
wr.set_width(resolution().width_px);
|
|
|
|
wr.set_height(resolution().height_px);
|
|
|
|
wr.set_compression_type(png::compression_type_default);
|
|
|
|
|
|
|
|
wr.write_info();
|
|
|
|
|
|
|
|
auto& b = impl_->buffer();
|
|
|
|
auto ptr = reinterpret_cast<png::byte*>( b.data() );
|
|
|
|
unsigned stride =
|
|
|
|
sizeof(Impl::TBuffer::value_type) * resolution().width_px;
|
|
|
|
|
|
|
|
for(unsigned r = 0; r < resolution().height_px; r++, ptr+=stride) {
|
|
|
|
wr.write_row(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Compression::RAW: {
|
2018-05-18 13:08:18 +00:00
|
|
|
stream << "P5 "
|
2018-05-17 16:17:15 +00:00
|
|
|
<< impl_->resolution().width_px << " "
|
|
|
|
<< impl_->resolution().height_px << " "
|
|
|
|
<< "255 ";
|
2018-05-22 15:37:39 +00:00
|
|
|
|
2018-05-18 16:11:29 +00:00
|
|
|
stream.write(reinterpret_cast<const char*>(impl_->buffer().data()),
|
|
|
|
impl_->buffer().size()*sizeof(Impl::TBuffer::value_type));
|
|
|
|
}
|
2018-05-17 16:17:15 +00:00
|
|
|
}
|
2018-05-16 16:51:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|