Unravel Engine C++ Reference
Loading...
Searching...
No Matches
svg_writer.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <map>
3#include <memory>
4#include <sstream>
5
6#include "svg_writer.hpp"
7
8using namespace generator;
9
10namespace
11{
12
13std::string toColor(const gml::dvec3& c)
14{
15 std::stringstream ss;
16 auto fn = [](double c)
17 {
18 c = gml::clamp(c, 0.0, 1.0);
19 return static_cast<int>(255 * c);
20 };
21
22 ss << "rgb(" << fn(c[0]) << "," << fn(c[1]) << "," << fn(c[2]) << ")";
23
24 return ss.str();
25}
26} // namespace
27
28svg_writer_t::BaseElem::BaseElem(double z, const gml::dvec3& color) : z_{z}, color_{color}
29{
30}
31
32svg_writer_t::BaseElem::~BaseElem()
33{
34}
35
36svg_writer_t::VertexElem::VertexElem(const gml::dvec3& p, const gml::dvec3& color) : BaseElem{p[2], color}, p_{p}
37{
38}
39
40void svg_writer_t::VertexElem::stream(std::ostream& os) const
41{
42 os << "<circle "
43 << "cx=\"" << p_[0] << "\" cy=\"" << p_[1] << "\" "
44 << "r=\"3\" style=\"fill: " << toColor(color_) << "\" />\n";
45}
46
47svg_writer_t::LineElem::LineElem(const gml::dvec3& p1, const gml::dvec3& p2, const gml::dvec3& color)
48 : BaseElem{(p1[2] + p2[2]) / 2.0, color}
49 , p1_(p1)
50 , p2_(p2)
51{
52}
53
54void svg_writer_t::LineElem::stream(std::ostream& os) const
55{
56 os << "<line "
57 << "x1=\"" << p1_[0] << "\" y1=\"" << p1_[1] << "\" "
58 << "x2=\"" << p2_[0] << "\" y2=\"" << p2_[1] << "\" "
59 << "style=\"stroke: " << toColor(color_) << ";\" />\n";
60}
61
62svg_writer_t::TriangleElem::TriangleElem(const gml::dvec3& p1,
63 const gml::dvec3& p2,
64 const gml::dvec3& p3,
65 const gml::dvec3& color)
66 : BaseElem{(p1[2] + p2[2] + p3[2]) / 3.0, color}
67 , p_{{p1, p2, p3}}
68{
69}
70
71void svg_writer_t::TriangleElem::stream(std::ostream& os) const
72{
73 os << "<polygon "
74 << "points=\"";
75 for(gml::dvec3 p : p_)
76 {
77 os << p[0] << "," << p[1] << " ";
78 }
79 os << "\" ";
80 os << "style=\"fill: " << toColor(color_) << ";\" />\n";
81}
82
83gml::dvec3 svg_writer_t::project(const gml::dvec3& p) const
84{
85 auto temp = gml::project(p, viewProjMatrix_, viewportOrigin_, viewportSize_);
86 temp[1] = size_[1] - temp[1];
87 return temp;
88}
89
90gml::dvec3 svg_writer_t::normalToColor(const gml::dvec3& normal) const
91{
92 double d = gml::dot(normal, lightDir_);
93 d = gml::clamp(d, 0.0, 1.0);
94 d = 0.1 + 0.8 * d;
95 return {d, d, d};
96}
97
98svg_writer_t::svg_writer_t(int width, int height)
99 : size_{width, height}
100 , viewMatrix_{1.0}
101 , projMatrix_{1.0}
102 , viewProjMatrix_{1.0}
103 , viewportOrigin_{0, 0}
104 , viewportSize_{width, height}
105 , lightDir_{1.0, 2.0, 3.0}
106 , cullface_{true}
107 , elems_{}
108{
109 lightDir_ = normalize(lightDir_);
110}
111
112void svg_writer_t::modelView(const gml::dmat4& matrix)
113{
114 viewMatrix_ = matrix;
115 viewProjMatrix_ = projMatrix_ * viewMatrix_;
116}
117
118void svg_writer_t::perspective(double fovy, double aspect, double zNear, double zFar)
119{
120 projMatrix_ = gml::perspective(fovy, aspect, zNear, zFar);
121 viewProjMatrix_ = projMatrix_ * viewMatrix_;
122}
123
124void svg_writer_t::ortho(double left, double right, double bottom, double top)
125{
126 projMatrix_ = gml::ortho2D(left, right, bottom, top);
127 viewProjMatrix_ = projMatrix_ * viewMatrix_;
128}
129
130void svg_writer_t::viewport(int x, int y, int width, int height)
131{
132 viewportOrigin_ = gml::ivec2{x, y};
133 viewportSize_ = gml::ivec2{width, height};
134}
135
136void svg_writer_t::cullface(bool cullface)
137{
138 cullface_ = cullface;
139}
140
141void svg_writer_t::writePoint(const gml::dvec3& p, const gml::dvec3& color)
142{
143 elems_.push_back(std::unique_ptr<BaseElem>{new VertexElem{project(p), color}});
144}
145
146void svg_writer_t::writeLine(const gml::dvec3& p1, const gml::dvec3& p2, const gml::dvec3& color)
147{
148 if(p1 == p2)
149 return;
150 elems_.push_back(std::unique_ptr<BaseElem>{new LineElem{project(p1), project(p2), color}});
151}
152
153void svg_writer_t::writeTriangle(const gml::dvec3& p1,
154 const gml::dvec3& p2,
155 const gml::dvec3& p3,
156 const gml::dvec3& color)
157{
158 if(p1 == p2 || p2 == p3 || p1 == p3)
159 return;
160
161 auto pp1 = project(p1);
162 auto pp2 = project(p2);
163 auto pp3 = project(p3);
164
165 if(cullface_ && gml::normal(pp1, pp2, pp3)[2] > 0.0)
166 return;
167
168 elems_.push_back(std::unique_ptr<BaseElem>{new TriangleElem(pp1, pp2, pp3, color)});
169}
170
171void svg_writer_t::writeTriangle(const gml::dvec3& p1, const gml::dvec3& p2, const gml::dvec3& p3)
172{
173 writeTriangle(p1, p2, p3, normalToColor(gml::normal(p1, p2, p3)));
174}
175
176std::string svg_writer_t::str() const
177{
178 std::stringstream ss;
179
180 ss << "<svg "
181 << "width=\"" << size_[0] << "\" height=\"" << size_[1] << "\" "
182 << "version=\"1.1\" "
183 << "xmlns=\"http://www.w3.org/2000/svg\""
184 << ">\n";
185
186 ss << "<rect "
187 << "width=\"" << size_[0] << "\" height=\"" << size_[1] << "\" "
188 << "style=\"fill:white\""
189 << "/>\n";
190
191 std::stable_sort(elems_.begin(),
192 elems_.end(),
193 [](const std::unique_ptr<BaseElem>& e1, const std::unique_ptr<BaseElem>& e2)
194 {
195 return e1->z_ > e2->z_;
196 });
197
198 for(const auto& elem : elems_)
199 elem->stream(ss);
200
201 ss << "</svg>\n";
202
203 return ss.str();
204}
btVector3 normal
void viewport(int x, int y, int width, int height)
Sets the viewport. Default fills the whole image.
void modelView(const gml::dmat4 &matrix)
Sets the model view matrix. Default is the identity matrix.
void writeTriangle(const gml::dvec3 &p1, const gml::dvec3 &p2, const gml::dvec3 &p3, const gml::dvec3 &color)
Write one triangle.
svg_writer_t(int width, int height)
void writeLine(const gml::dvec3 &p1, const gml::dvec3 &p2, const gml::dvec3 &color={0.0, 0.0, 0.0})
Write one line.
void perspective(double fovy, double aspect, double zNear, double zFar)
void ortho(double left, double right, double bottom, double top)
std::string str() const
Generates svg xml from the data written so far.
void writePoint(const gml::dvec3 &p, const gml::dvec3 &color={0.0, 0.0, 0.0})
Write one point. Drawn as a circle.
void cullface(bool cullface)
Sets if backfacing triangles should be culled. Default is true.
glm::tvec3< T > normal(const glm::tvec3< T > &p1, const glm::tvec3< T > &p2, const glm::tvec3< T > &p3)
Definition math.hpp:131
glm::tmat4x4< T > ortho2D(const T &left, const T &right, const T &bottom, const T &top)
Definition math.hpp:161
glm::tvec3< T > project(const glm::tvec3< T > &v, const glm::tmat4x4< T > &modelViewProj, const glm::tvec2< TI > &viewportOrigin, const glm::tvec2< TS > &viewportSize)
Definition math.hpp:137
float y
float x
float z