1 #include <cstring> |
|
2 #include "gldata.h" |
|
3 #include "ldtypes.h" |
|
4 #include "colors.h" |
|
5 #include "document.h" |
|
6 #include "misc.h" |
|
7 #include "gldraw.h" |
|
8 #include <QDate> |
|
9 |
|
10 #define DEBUG_PRINT(...) fprint (stdout, __VA_ARGS__) |
|
11 |
|
12 extern_cfg (Bool, gl_blackedges); |
|
13 static QList<short> g_warnedColors; |
|
14 VertexCompiler g_vertexCompiler; |
|
15 |
|
16 // ============================================================================= |
|
17 // ----------------------------------------------------------------------------- |
|
18 VertexCompiler::VertexCompiler() : |
|
19 m_file (null) |
|
20 { |
|
21 needMerge(); |
|
22 } |
|
23 |
|
24 VertexCompiler::~VertexCompiler() {} |
|
25 |
|
26 // ============================================================================= |
|
27 // Note: we use the top level object's color but the draw object's vertices. |
|
28 // This is so that the index color is generated correctly - it has to reference |
|
29 // the top level object's ID. This is crucial for picking to work. |
|
30 // ----------------------------------------------------------------------------- |
|
31 void VertexCompiler::compilePolygon (LDObject* drawobj, LDObject* trueobj, QList< VertexCompiler::CompiledTriangle >& data) |
|
32 { |
|
33 const QColor pickColor = getObjectColor (trueobj, PickColor); |
|
34 LDObject::Type type = drawobj->getType(); |
|
35 LDObjectList objs; |
|
36 |
|
37 assert (type != LDObject::ESubfile); |
|
38 |
|
39 if (type == LDObject::EQuad) |
|
40 { |
|
41 for (LDTriangle* t : static_cast<LDQuad*> (drawobj)->splitToTriangles()) |
|
42 objs << t; |
|
43 } |
|
44 else |
|
45 objs << drawobj; |
|
46 |
|
47 for (LDObject* obj : objs) |
|
48 { |
|
49 const LDObject::Type objtype = obj->getType(); |
|
50 const bool isline = (objtype == LDObject::ELine || objtype == LDObject::ECondLine); |
|
51 const int verts = isline ? 2 : obj->vertices(); |
|
52 QColor normalColor = getObjectColor (obj, Normal); |
|
53 |
|
54 assert (isline || objtype == LDObject::ETriangle); |
|
55 |
|
56 CompiledTriangle a; |
|
57 a.rgb = getColorRGB (normalColor); |
|
58 a.pickrgb = getColorRGB (pickColor); |
|
59 a.numVerts = verts; |
|
60 a.obj = trueobj; |
|
61 a.isCondLine = (objtype == LDObject::ECondLine); |
|
62 |
|
63 for (int i = 0; i < verts; ++i) |
|
64 { |
|
65 a.verts[i] = obj->getVertex (i); |
|
66 a.verts[i].y() = -a.verts[i].y(); |
|
67 a.verts[i].z() = -a.verts[i].z(); |
|
68 } |
|
69 |
|
70 data << a; |
|
71 } |
|
72 } |
|
73 |
|
74 // ============================================================================= |
|
75 // ----------------------------------------------------------------------------- |
|
76 void VertexCompiler::compileObject (LDObject* obj) |
|
77 { |
|
78 initObject (obj); |
|
79 QList<CompiledTriangle> data; |
|
80 QTime t0; |
|
81 |
|
82 t0 = QTime::currentTime(); |
|
83 for (int i = 0; i < GL::ENumArrays; ++i) |
|
84 m_objArrays[obj][i].clear(); |
|
85 DEBUG_PRINT ("INIT: %1ms\n", t0.msecsTo (QTime::currentTime())); |
|
86 |
|
87 t0 = QTime::currentTime(); |
|
88 compileSubObject (obj, obj, data); |
|
89 DEBUG_PRINT ("COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime())); |
|
90 |
|
91 t0 = QTime::currentTime(); |
|
92 |
|
93 for (int i = 0; i < GL::ENumArrays; ++i) |
|
94 { |
|
95 GL::VAOType type = (GL::VAOType) i; |
|
96 const bool islinearray = (type == GL::EEdgeArray || type == GL::EEdgePickArray); |
|
97 |
|
98 for (const CompiledTriangle & poly : data) |
|
99 { |
|
100 if (poly.isCondLine) |
|
101 { |
|
102 // Conditional lines go to the edge pick array and the array |
|
103 // specifically designated for conditional lines and nowhere else. |
|
104 if (type != GL::EEdgePickArray && type != GL::ECondEdgeArray) |
|
105 continue; |
|
106 } |
|
107 else |
|
108 { |
|
109 // Lines and only lines go to the line array and only to the line array. |
|
110 if ( (poly.numVerts == 2) ^ islinearray) |
|
111 continue; |
|
112 |
|
113 // Only conditional lines go into the conditional line array |
|
114 if (type == GL::ECondEdgeArray) |
|
115 continue; |
|
116 } |
|
117 |
|
118 Array* verts = postprocess (poly, type); |
|
119 m_objArrays[obj][type] += *verts; |
|
120 delete verts; |
|
121 } |
|
122 } |
|
123 |
|
124 DEBUG_PRINT ("POST-PROCESS: %1ms\n", t0.msecsTo (QTime::currentTime())); |
|
125 |
|
126 needMerge(); |
|
127 } |
|
128 |
|
129 // ============================================================================= |
|
130 // ----------------------------------------------------------------------------- |
|
131 void VertexCompiler::compileSubObject (LDObject* obj, LDObject* topobj, VertexCompiler::PolygonList& data) |
|
132 { |
|
133 LDObjectList objs; |
|
134 |
|
135 switch (obj->getType()) |
|
136 { |
|
137 case LDObject::ETriangle: |
|
138 case LDObject::ELine: |
|
139 case LDObject::ECondLine: |
|
140 { |
|
141 compilePolygon (obj, topobj, data); |
|
142 } break; |
|
143 |
|
144 case LDObject::EQuad: |
|
145 { |
|
146 QTime t0 = QTime::currentTime(); |
|
147 for (LDTriangle* triangle : static_cast<LDQuad*> (obj)->splitToTriangles()) |
|
148 compilePolygon (triangle, topobj, data); |
|
149 DEBUG_PRINT ("\t- QUAD COMPILE: %1ms\n", t0.msecsTo (QTime::currentTime())); |
|
150 } break; |
|
151 |
|
152 case LDObject::ESubfile: |
|
153 { |
|
154 QTime t0 = QTime::currentTime(); |
|
155 objs = static_cast<LDSubfile*> (obj)->inlineContents (LDSubfile::RendererInline | LDSubfile::DeepCacheInline); |
|
156 DEBUG_PRINT ("\t- INLINE: %1ms\n", t0.msecsTo (QTime::currentTime())); |
|
157 DEBUG_PRINT ("\t- %1 objects\n", objs.size()); |
|
158 |
|
159 t0 = QTime::currentTime(); |
|
160 |
|
161 for (LDObject* obj : objs) |
|
162 { |
|
163 compileSubObject (obj, topobj, data); |
|
164 obj->deleteSelf(); |
|
165 } |
|
166 |
|
167 DEBUG_PRINT ("\t- SUB-COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime())); |
|
168 } break; |
|
169 |
|
170 default: |
|
171 {} break; |
|
172 } |
|
173 } |
|
174 |
|
175 // ============================================================================= |
|
176 // ----------------------------------------------------------------------------- |
|
177 void VertexCompiler::compileDocument() |
|
178 { |
|
179 for (LDObject * obj : m_file->getObjects()) |
|
180 compileObject (obj); |
|
181 } |
|
182 |
|
183 // ============================================================================= |
|
184 // ----------------------------------------------------------------------------- |
|
185 void VertexCompiler::forgetObject (LDObject* obj) |
|
186 { |
|
187 auto it = m_objArrays.find (obj); |
|
188 |
|
189 if (it != m_objArrays.end()) |
|
190 delete *it; |
|
191 |
|
192 m_objArrays.remove (obj); |
|
193 } |
|
194 |
|
195 // ============================================================================= |
|
196 // ----------------------------------------------------------------------------- |
|
197 void VertexCompiler::setFile (LDDocument* file) |
|
198 { |
|
199 m_file = file; |
|
200 } |
|
201 |
|
202 // ============================================================================= |
|
203 // ----------------------------------------------------------------------------- |
|
204 const VertexCompiler::Array* VertexCompiler::getMergedBuffer (GL::VAOType type) |
|
205 { |
|
206 // If there are objects staged for compilation, compile them now. |
|
207 if (m_staged.size() > 0) |
|
208 { |
|
209 for (LDObject * obj : m_staged) |
|
210 compileObject (obj); |
|
211 |
|
212 m_staged.clear(); |
|
213 } |
|
214 |
|
215 assert (type < GL::ENumArrays); |
|
216 |
|
217 if (m_changed[type]) |
|
218 { |
|
219 m_changed[type] = false; |
|
220 m_mainArrays[type].clear(); |
|
221 |
|
222 for (LDObject* obj : m_file->getObjects()) |
|
223 { |
|
224 if (!obj->isScemantic()) |
|
225 continue; |
|
226 |
|
227 auto it = m_objArrays.find (obj); |
|
228 |
|
229 if (it != m_objArrays.end()) |
|
230 m_mainArrays[type] += (*it)[type]; |
|
231 } |
|
232 |
|
233 DEBUG_PRINT ("merged array %1: %2 entries\n", (int) type, m_mainArrays[type].size()); |
|
234 } |
|
235 |
|
236 return &m_mainArrays[type]; |
|
237 } |
|
238 |
|
239 // ============================================================================= |
|
240 // This turns a compiled triangle into usable VAO vertices |
|
241 // ----------------------------------------------------------------------------- |
|
242 VertexCompiler::Array* VertexCompiler::postprocess (const CompiledTriangle& poly, GLRenderer::VAOType type) |
|
243 { |
|
244 Array* va = new Array; |
|
245 QList<Vertex> verts; |
|
246 |
|
247 for (int i = 0; i < poly.numVerts; ++i) |
|
248 { |
|
249 alias v0 = poly.verts[i]; |
|
250 Vertex v; |
|
251 v.x = v0.x(); |
|
252 v.y = v0.y(); |
|
253 v.z = v0.z(); |
|
254 |
|
255 switch (type) |
|
256 { |
|
257 case GL::ESurfaceArray: |
|
258 case GL::EEdgeArray: |
|
259 case GL::ECondEdgeArray: |
|
260 { |
|
261 v.color = poly.rgb; |
|
262 } break; |
|
263 |
|
264 case GL::EPickArray: |
|
265 case GL::EEdgePickArray: |
|
266 { |
|
267 v.color = poly.pickrgb; |
|
268 } break; |
|
269 |
|
270 case GL::EBFCArray: |
|
271 case GL::ENumArrays: |
|
272 break; // handled separately |
|
273 } |
|
274 |
|
275 verts << v; |
|
276 } |
|
277 |
|
278 if (type == GL::EBFCArray) |
|
279 { |
|
280 int32 rgb = getColorRGB (getObjectColor (poly.obj, BFCFront)); |
|
281 |
|
282 for (Vertex v : verts) |
|
283 { |
|
284 v.color = rgb; |
|
285 *va << v; |
|
286 } |
|
287 |
|
288 rgb = getColorRGB (getObjectColor (poly.obj, BFCBack)); |
|
289 |
|
290 for (int i = verts.size() - 1; i >= 0; --i) |
|
291 { |
|
292 Vertex v = verts[i]; |
|
293 v.color = rgb; |
|
294 *va << v; |
|
295 } |
|
296 } |
|
297 else |
|
298 { |
|
299 for (Vertex v : verts) |
|
300 *va << v; |
|
301 } |
|
302 |
|
303 return va; |
|
304 } |
|
305 |
|
306 // ============================================================================= |
|
307 // ----------------------------------------------------------------------------- |
|
308 uint32 VertexCompiler::getColorRGB (const QColor& color) |
|
309 { |
|
310 return |
|
311 (color.red() & 0xFF) << 0x00 | |
|
312 (color.green() & 0xFF) << 0x08 | |
|
313 (color.blue() & 0xFF) << 0x10 | |
|
314 (color.alpha() & 0xFF) << 0x18; |
|
315 } |
|
316 |
|
317 // ============================================================================= |
|
318 // ----------------------------------------------------------------------------- |
|
319 QColor VertexCompiler::getObjectColor (LDObject* obj, ColorType colotype) const |
|
320 { |
|
321 QColor qcol; |
|
322 |
|
323 if (!obj->isColored()) |
|
324 return QColor(); |
|
325 |
|
326 if (colotype == PickColor) |
|
327 { |
|
328 // Make the color by the object's ID if we're picking, so we can make the |
|
329 // ID again from the color we get from the picking results. Be sure to use |
|
330 // the top level parent's index since we want a subfile's children point |
|
331 // to the subfile itself. |
|
332 long i = obj->topLevelParent()->getID(); |
|
333 |
|
334 // Calculate a color based from this index. This method caters for |
|
335 // 16777216 objects. I don't think that'll be exceeded anytime soon. :) |
|
336 // ATM biggest is 53588.dat with 12600 lines. |
|
337 int r = (i / 0x10000) % 0x100, |
|
338 g = (i / 0x100) % 0x100, |
|
339 b = i % 0x100; |
|
340 |
|
341 return QColor (r, g, b); |
|
342 } |
|
343 |
|
344 if ( (colotype == BFCFront || colotype == BFCBack) && |
|
345 obj->getType() != LDObject::ELine && |
|
346 obj->getType() != LDObject::ECondLine |
|
347 ) |
|
348 { |
|
349 if (colotype == BFCFront) |
|
350 qcol = QColor (40, 192, 0); |
|
351 else |
|
352 qcol = QColor (224, 0, 0); |
|
353 } |
|
354 else |
|
355 { |
|
356 if (obj->getColor() == maincolor) |
|
357 qcol = GL::getMainColor(); |
|
358 else |
|
359 { |
|
360 LDColor* col = getColor (obj->getColor()); |
|
361 |
|
362 if (col) |
|
363 qcol = col->faceColor; |
|
364 } |
|
365 |
|
366 if (obj->getColor() == edgecolor) |
|
367 { |
|
368 qcol = QColor (32, 32, 32); // luma (m_bgcolor) < 40 ? QColor (64, 64, 64) : Qt::black; |
|
369 LDColor* col; |
|
370 |
|
371 if (!gl_blackedges && obj->getParent() && (col = getColor (obj->getParent()->getColor()))) |
|
372 qcol = col->edgeColor; |
|
373 } |
|
374 |
|
375 if (qcol.isValid() == false) |
|
376 { |
|
377 // The color was unknown. Use main color to make the object at least |
|
378 // not appear pitch-black. |
|
379 if (obj->getColor() != edgecolor) |
|
380 qcol = GL::getMainColor(); |
|
381 else |
|
382 qcol = Qt::black; |
|
383 |
|
384 // Warn about the unknown color, but only once. |
|
385 for (short i : g_warnedColors) |
|
386 if (obj->getColor() == i) |
|
387 return qcol; |
|
388 |
|
389 log ("%1: Unknown color %2!\n", __func__, obj->getColor()); |
|
390 g_warnedColors << obj->getColor(); |
|
391 return qcol; |
|
392 } |
|
393 } |
|
394 |
|
395 if (obj->topLevelParent()->isSelected()) |
|
396 { |
|
397 // Brighten it up if selected. |
|
398 const int add = 51; |
|
399 |
|
400 qcol.setRed (min (qcol.red() + add, 255)); |
|
401 qcol.setGreen (min (qcol.green() + add, 255)); |
|
402 qcol.setBlue (min (qcol.blue() + add, 255)); |
|
403 } |
|
404 |
|
405 return qcol; |
|
406 } |
|
407 |
|
408 // ============================================================================= |
|
409 // ----------------------------------------------------------------------------- |
|
410 void VertexCompiler::needMerge() |
|
411 { |
|
412 // Set all of m_changed to true |
|
413 memset (m_changed, 0xFF, sizeof m_changed); |
|
414 } |
|
415 |
|
416 // ============================================================================= |
|
417 // ----------------------------------------------------------------------------- |
|
418 void VertexCompiler::initObject (LDObject* obj) |
|
419 { |
|
420 if (m_objArrays.find (obj) == m_objArrays.end()) |
|
421 m_objArrays[obj] = new Array[GL::ENumArrays]; |
|
422 } |
|
423 |
|
424 // ============================================================================= |
|
425 // ----------------------------------------------------------------------------- |
|
426 void VertexCompiler::stageForCompilation (LDObject* obj) |
|
427 { |
|
428 m_staged << obj; |
|
429 removeDuplicates (m_staged); |
|
430 } |
|
431 |
|