22 #include "gl/compiler.h" |
22 #include "gl/compiler.h" |
23 #include "documentmanager.h" |
23 #include "documentmanager.h" |
24 #include "invert.h" |
24 #include "invert.h" |
25 #include "ring.h" |
25 #include "ring.h" |
26 |
26 |
|
27 gl::Compiler::Compiler(QObject* parent) : |
|
28 QObject{parent} |
|
29 { |
|
30 } |
|
31 |
27 gl::Compiler::~Compiler() |
32 gl::Compiler::~Compiler() |
28 { |
33 { |
29 |
34 |
30 } |
35 } |
|
36 |
|
37 void gl::Compiler::build(Model* model, DocumentManager* context) |
|
38 { |
|
39 if (not this->initialized) |
|
40 { |
|
41 this->initializeVbo(); |
|
42 } |
|
43 std::vector<GLfloat> vboData[gl::numVbos]; |
|
44 const std::vector<gl::Polygon> polygons = model->getPolygons(context); |
|
45 for (const gl::Polygon& polygon : polygons) |
|
46 { |
|
47 this->buildPolygon(polygon, vboData); |
|
48 } |
|
49 for (int i = 0; i < gl::numVbos; i += 1) |
|
50 { |
|
51 this->upload(i, vboData[i]); |
|
52 } |
|
53 } |
|
54 |
|
55 gl::VboClass classifyPolygon(const gl::Polygon& polygon) |
|
56 { |
|
57 switch (polygon.type) |
|
58 { |
|
59 case gl::Polygon::EdgeLine: |
|
60 return gl::VboClass::Lines; |
|
61 case gl::Polygon::Triangle: |
|
62 return gl::VboClass::Triangles; |
|
63 case gl::Polygon::Quadrilateral: |
|
64 return gl::VboClass::Quads; |
|
65 case gl::Polygon::ConditionalEdge: |
|
66 return gl::VboClass::ConditionalLines; |
|
67 } |
|
68 return gl::VboClass::Lines; |
|
69 } |
|
70 |
|
71 QColor colorFromId(linetypes::Id id) |
|
72 { |
|
73 // Calculate a color based from this index. This method caters for |
|
74 // 16777216 objects. I don't think that will be exceeded anytime soon. |
|
75 const int r = (id.value / 0x10000) % 0x100; |
|
76 const int g = (id.value / 0x100) % 0x100; |
|
77 const int b = id.value % 0x100; |
|
78 return {r, g, b}; |
|
79 } |
|
80 |
|
81 void writeVertex(std::vector<GLfloat>& data, const Point3D& point) |
|
82 { |
|
83 data.push_back(point.x); |
|
84 data.push_back(point.y); |
|
85 data.push_back(point.z); |
|
86 } |
|
87 |
|
88 void gl::Compiler::buildPolygon(gl::Polygon polygon, std::vector<GLfloat>* vboData) |
|
89 { |
|
90 const gl::VboClass vboClass = classifyPolygon(polygon); |
|
91 auto vboBuffer = [&](VboSubclass subclass) -> std::vector<GLfloat>& |
|
92 { |
|
93 return vboData[gl::vboIndex({vboClass, subclass})]; |
|
94 }; |
|
95 auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices()); |
|
96 for (int i = 0; i < polygon.numPolygonVertices(); i += 1) |
|
97 { |
|
98 const Point3D& v1 = vertexRing[i - 1]; |
|
99 const Point3D& v2 = vertexRing[i]; |
|
100 const Point3D& v3 = vertexRing[i + 1]; |
|
101 const QVector3D normal = QVector3D::crossProduct(v3 - v2, v1 - v2).normalized(); |
|
102 std::vector<GLfloat>& data = vboBuffer(VboSubclass::Normals); |
|
103 for (const GLfloat coord : {normal.x(), normal.y(), normal.z()}) |
|
104 data.push_back(coord); |
|
105 } |
|
106 vboBuffer(VboSubclass::Surfaces).reserve(vboBuffer(VboSubclass::Surfaces).size() + polygon.numPolygonVertices()); |
|
107 // Transform vertices so that they're suitable for GL rendering |
|
108 for (int i = 0; i < polygon.numPolygonVertices(); i += 1) |
|
109 { |
|
110 polygon.vertices[i].y = -polygon.vertices[i].y; |
|
111 polygon.vertices[i].z = -polygon.vertices[i].z; |
|
112 #if 0 |
|
113 // Add these vertices to the bounding box (unless we're going to do it over |
|
114 // from scratch afterwards anyway) |
|
115 if (not this->needBoundingBoxRebuild) |
|
116 { |
|
117 this->boundingBox.consider(poly.vertices[i]); |
|
118 } |
|
119 #endif |
|
120 writeVertex(vboBuffer(VboSubclass::Surfaces), polygon.vertices[i]); |
|
121 } |
|
122 this->writeColor(vboData, polygon, VboSubclass::RegularColors); |
|
123 this->writeColor(vboData, polygon, VboSubclass::PickColors); |
|
124 this->writeColor(vboData, polygon, VboSubclass::BfcFrontColors); |
|
125 this->writeColor(vboData, polygon, VboSubclass::BfcBackColors); |
|
126 } |
|
127 |
|
128 QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon, VboSubclass subclass) |
|
129 { |
|
130 QColor color; |
|
131 |
|
132 switch (subclass) |
|
133 { |
|
134 case VboSubclass::Surfaces: |
|
135 case VboSubclass::Normals: |
|
136 case VboSubclass::InvertedNormals: |
|
137 // Surface and normal VBOs contain vertex data, not colors. So we can't return anything meaningful. |
|
138 return {}; |
|
139 case VboSubclass::BfcFrontColors: |
|
140 // Use the constant green color for BFC front colors |
|
141 return {64, 192, 80}; |
|
142 case VboSubclass::BfcBackColors: |
|
143 // Use the constant red color for BFC back colors |
|
144 return {208, 64, 64}; |
|
145 case VboSubclass::PickColors: |
|
146 // For the picking scene, use unique picking colors provided by the model. |
|
147 return colorFromId(polygon.id); |
|
148 case VboSubclass::RandomColors: |
|
149 // For the random color scene, the owner object has rolled up a random color. Use that. |
|
150 color = {255, 64, 255}; // polygonOwner->randomColor(); |
|
151 break; |
|
152 case VboSubclass::RegularColors: |
|
153 // For normal colors, use the polygon's color. |
|
154 if (polygon.color == colors::main) |
|
155 { |
|
156 color = {255, 255, 64}; // mainColorRepresentation(); |
|
157 } |
|
158 else if (polygon.color == colors::edge) |
|
159 { |
|
160 // Edge color is black, unless we have a dark background, in which case lines need to be bright. |
|
161 color = Qt::black; //luma(config::backgroundColor()) > 40 ? Qt::black : Qt::white; |
|
162 } |
|
163 else |
|
164 { |
|
165 // Not main or edge color, use the polygon's color as is. |
|
166 color = {255, 255, 64}; //polygon.color.faceColor(); |
|
167 } |
|
168 break; |
|
169 } |
|
170 |
|
171 if (color.isValid()) |
|
172 { |
|
173 // We may wish to apply blending on the color to indicate selection or highlight. |
|
174 /* |
|
175 const double blendAlpha = 0.0; |
|
176 if (blendAlpha != 0.0) |
|
177 { |
|
178 QColor selectedColor = config::selectColorBlend(); |
|
179 double denominator = blendAlpha + 1.0; |
|
180 color.setRed((color.red() + (selectedColor.red() * blendAlpha)) / denominator); |
|
181 color.setGreen((color.green() + (selectedColor.green() * blendAlpha)) / denominator); |
|
182 color.setBlue((color.blue() + (selectedColor.blue() * blendAlpha)) / denominator); |
|
183 } |
|
184 */ |
|
185 } |
|
186 else |
|
187 { |
|
188 if (polygon.numPolygonVertices() == 2) |
|
189 color = Qt::black; |
|
190 else |
|
191 color = {255, 255, 64}; |
|
192 } |
|
193 |
|
194 return color; |
|
195 } |
|
196 |
|
197 void gl::Compiler::writeColor(std::vector<GLfloat>* data, const gl::Polygon& polygon, VboSubclass subclass) |
|
198 { |
|
199 std::vector<GLfloat>& buffer = data[gl::vboIndex({classifyPolygon(polygon), subclass})]; |
|
200 const QColor color = this->getColorForPolygon(polygon, subclass); |
|
201 buffer.reserve(data->size() + 4 * polygon.numPolygonVertices()); |
|
202 for (int i = 0; i < polygon.numPolygonVertices(); i += 1) |
|
203 { |
|
204 buffer.push_back(color.redF() / 255.0f); |
|
205 buffer.push_back(color.greenF() / 255.0f); |
|
206 buffer.push_back(color.blueF() / 255.0f); |
|
207 buffer.push_back(color.alphaF() / 255.0f); |
|
208 } |
|
209 } |
|
210 |
|
211 void gl::Compiler::initializeVbo() |
|
212 { |
|
213 this->initializeOpenGLFunctions(); |
|
214 glGenBuffers(countof(this->storedVbo), &this->storedVbo[0]); |
|
215 this->initialized = true; |
|
216 } |
|
217 |
|
218 /// |
|
219 /// \brief Uploads data to a vbo |
|
220 /// \param vboAddress Which vbo to upload to |
|
221 /// \param data Data to upload to vbo |
|
222 /// |
|
223 void gl::Compiler::upload(const int vboIndex, const std::vector<GLfloat>& data) |
|
224 { |
|
225 glBindBuffer(GL_ARRAY_BUFFER, this->storedVbo[vboIndex]); |
|
226 glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof data[0], data.data(), GL_STATIC_DRAW); |
|
227 glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
228 this->storedVboSizes[vboIndex] = data.size(); |
|
229 } |
|
230 |
|
231 GLuint gl::Compiler::vbo(const VboAddress vboAddress) const |
|
232 { |
|
233 return this->storedVbo[gl::vboIndex(vboAddress)]; |
|
234 } |
|
235 |
|
236 int gl::Compiler::vboSize(const VboAddress vboAddress) const |
|
237 { |
|
238 return this->storedVboSizes[gl::vboIndex(vboAddress)]; |
|
239 } |
|
240 |
|
241 int gl::vboIndex(const VboAddress vboAddress) |
|
242 { |
|
243 return static_cast<std::uint8_t>(vboAddress.vboClass) * gl::numVboSubclasses |
|
244 + static_cast<std::uint8_t>(vboAddress.vboSubclass); |
|
245 } |