Mon, 20 Jan 2014 16:42:18 +0200
- now compiles again
668 | 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::Array::Array() : | |
19 | m_data (null) | |
20 | { | |
21 | clear(); | |
22 | } | |
23 | ||
24 | // ============================================================================= | |
25 | // ----------------------------------------------------------------------------- | |
26 | VertexCompiler::Array::~Array() | |
27 | { | |
28 | delete[] m_data; | |
29 | } | |
30 | ||
31 | // ============================================================================= | |
32 | // ----------------------------------------------------------------------------- | |
33 | void VertexCompiler::Array::clear() | |
34 | { | |
35 | delete[] m_data; | |
36 | ||
37 | m_data = new Vertex[64]; | |
38 | m_size = 64; | |
39 | m_ptr = &m_data[0]; | |
40 | } | |
41 | ||
42 | // ============================================================================= | |
43 | // ----------------------------------------------------------------------------- | |
44 | void VertexCompiler::Array::resizeToFit (Size newSize) | |
45 | { | |
46 | if (allocatedSize() >= newSize) | |
47 | return; | |
48 | ||
49 | int32 cachedWriteSize = writtenSize(); | |
50 | ||
51 | // Add some lee-way space to reduce the amount of resizing. | |
52 | newSize += 256; | |
53 | ||
54 | const Size oldSize = allocatedSize(); | |
55 | ||
56 | // We need to back up the data first | |
57 | Vertex* copy = new Vertex[oldSize]; | |
58 | memcpy (copy, m_data, oldSize); | |
59 | ||
60 | // Re-create the buffer | |
61 | delete[] m_data; | |
62 | m_data = new Vertex[newSize]; | |
63 | m_size = newSize; | |
64 | m_ptr = &m_data[cachedWriteSize / sizeof (Vertex)]; | |
65 | ||
66 | // Copy the data back | |
67 | memcpy (m_data, copy, oldSize); | |
68 | delete[] copy; | |
69 | } | |
70 | ||
71 | // ============================================================================= | |
72 | // ----------------------------------------------------------------------------- | |
73 | const VertexCompiler::Vertex* VertexCompiler::Array::data() const | |
74 | { | |
75 | return m_data; | |
76 | } | |
77 | ||
78 | // ============================================================================= | |
79 | // ----------------------------------------------------------------------------- | |
80 | const VertexCompiler::Array::Size& VertexCompiler::Array::allocatedSize() const | |
81 | { | |
82 | return m_size; | |
83 | } | |
84 | ||
85 | // ============================================================================= | |
86 | // ----------------------------------------------------------------------------- | |
87 | VertexCompiler::Array::Size VertexCompiler::Array::writtenSize() const | |
88 | { | |
89 | return (m_ptr - m_data) * sizeof (Vertex); | |
90 | } | |
91 | ||
92 | // ============================================================================= | |
93 | // ----------------------------------------------------------------------------- | |
94 | void VertexCompiler::Array::write (const Vertex& f) | |
95 | { | |
96 | // Ensure there's enoughspace for the new vertex | |
97 | resizeToFit (writtenSize() + sizeof f); | |
98 | ||
99 | // Write the float in | |
100 | *m_ptr++ = f; | |
101 | } | |
102 | ||
103 | // ============================================================================= | |
104 | // ----------------------------------------------------------------------------- | |
105 | void VertexCompiler::Array::merge (Array* other) | |
106 | { | |
107 | // Ensure there's room for both buffers | |
108 | resizeToFit (writtenSize() + other->writtenSize()); | |
109 | ||
110 | memcpy (m_ptr, other->data(), other->writtenSize()); | |
111 | m_ptr += other->writtenSize() / sizeof (Vertex); | |
112 | } | |
113 | ||
114 | // ============================================================================= | |
115 | // ----------------------------------------------------------------------------- | |
116 | VertexCompiler::VertexCompiler() : | |
117 | m_file (null) | |
118 | { | |
119 | needMerge(); | |
120 | } | |
121 | ||
122 | VertexCompiler::~VertexCompiler() {} | |
123 | ||
124 | // ============================================================================= | |
125 | // Note: we use the top level object's color but the draw object's vertices. | |
126 | // This is so that the index color is generated correctly - it has to reference | |
127 | // the top level object's ID. This is crucial for picking to work. | |
128 | // ----------------------------------------------------------------------------- | |
129 | void VertexCompiler::compilePolygon (LDObject* drawobj, LDObject* trueobj, QList< VertexCompiler::CompiledTriangle >& data) | |
130 | { | |
131 | const QColor pickColor = getObjectColor (trueobj, PickColor); | |
132 | LDObject::Type type = drawobj->getType(); | |
133 | LDObjectList objs; | |
134 | ||
135 | assert (type != LDObject::ESubfile); | |
136 | ||
137 | if (type == LDObject::EQuad) | |
138 | { | |
139 | for (LDTriangle * t : static_cast<LDQuad*> (drawobj)->splitToTriangles()) | |
140 | objs << t; | |
141 | } | |
142 | else | |
143 | objs << drawobj; | |
144 | ||
145 | for (LDObject* obj : objs) | |
146 | { | |
147 | const LDObject::Type objtype = obj->getType(); | |
148 | const bool isline = (objtype == LDObject::ELine || objtype == LDObject::ECondLine); | |
149 | const int verts = isline ? 2 : obj->vertices(); | |
150 | QColor normalColor = getObjectColor (obj, Normal); | |
151 | ||
152 | assert (isline || objtype == LDObject::ETriangle); | |
153 | ||
154 | CompiledTriangle a; | |
155 | a.rgb = normalColor.rgb(); | |
156 | a.pickrgb = pickColor.rgb(); | |
157 | a.numVerts = verts; | |
158 | a.obj = trueobj; | |
159 | a.isCondLine = (objtype == LDObject::ECondLine); | |
160 | ||
161 | for (int i = 0; i < verts; ++i) | |
162 | { | |
163 | a.verts[i] = obj->getVertex (i); | |
164 | a.verts[i].y() = -a.verts[i].y(); | |
165 | a.verts[i].z() = -a.verts[i].z(); | |
166 | } | |
167 | ||
168 | data << a; | |
169 | } | |
170 | } | |
171 | ||
172 | // ============================================================================= | |
173 | // ----------------------------------------------------------------------------- | |
174 | void VertexCompiler::compileObject (LDObject* obj) | |
175 | { | |
176 | initObject (obj); | |
177 | QList<CompiledTriangle> data; | |
178 | QTime t0; | |
179 | ||
180 | for (int i = 0; i < GL::NumArrays; ++i) | |
181 | m_objArrays[obj][i].clear(); | |
182 | ||
183 | t0 = QTime::currentTime(); | |
184 | compileSubObject (obj, obj, data); | |
185 | DEBUG_PRINT ("COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime())); | |
186 | ||
187 | t0 = QTime::currentTime(); | |
188 | ||
189 | for (int i = 0; i < GL::NumArrays; ++i) | |
190 | { | |
191 | GL::VAOType type = (GL::VAOType) i; | |
192 | const bool islinearray = (type == GL::EdgeArray || type == GL::EdgePickArray); | |
193 | ||
194 | for (const CompiledTriangle & poly : data) | |
195 | { | |
196 | if (poly.isCondLine) | |
197 | { | |
198 | // Conditional lines go to the edge pick array and the array | |
199 | // specifically designated for conditional lines and nowhere else. | |
200 | if (type != GL::EdgePickArray && type != GL::CondEdgeArray) | |
201 | continue; | |
202 | } | |
203 | else | |
204 | { | |
205 | // Lines and only lines go to the line array and only to the line array. | |
206 | if ( (poly.numVerts == 2) ^ islinearray) | |
207 | continue; | |
208 | ||
209 | // Only conditional lines go into the conditional line array | |
210 | if (type == GL::CondEdgeArray) | |
211 | continue; | |
212 | } | |
213 | ||
214 | Array* verts = postprocess (poly, type); | |
215 | m_objArrays[obj][type].merge (verts); | |
216 | delete verts; | |
217 | } | |
218 | } | |
219 | ||
220 | DEBUG_PRINT ("POST-PROCESS: %1ms\n", t0.msecsTo (QTime::currentTime())); | |
221 | ||
222 | needMerge(); | |
223 | } | |
224 | ||
225 | // ============================================================================= | |
226 | // ----------------------------------------------------------------------------- | |
227 | void VertexCompiler::compileSubObject (LDObject* obj, LDObject* topobj, QList< VertexCompiler::CompiledTriangle >& data) | |
228 | { | |
229 | LDObjectList objs; | |
230 | ||
231 | switch (obj->getType()) | |
232 | { | |
233 | case LDObject::ETriangle: | |
234 | case LDObject::ELine: | |
235 | case LDObject::ECondLine: | |
236 | { | |
237 | compilePolygon (obj, topobj, data); | |
238 | } break; | |
239 | ||
240 | case LDObject::EQuad: | |
241 | { | |
242 | for (LDTriangle * triangle : static_cast<LDQuad*> (obj)->splitToTriangles()) | |
243 | compilePolygon (triangle, topobj, data); | |
244 | } break; | |
245 | ||
246 | case LDObject::ESubfile: | |
247 | { | |
248 | QTime t0 = QTime::currentTime(); | |
249 | objs = static_cast<LDSubfile*> (obj)->inlineContents (LDSubfile::RendererInline | LDSubfile::DeepCacheInline); | |
250 | DEBUG_PRINT ("\t- INLINE: %1ms\n", t0.msecsTo (QTime::currentTime())); | |
251 | DEBUG_PRINT ("\t- %1 objects\n", objs.size()); | |
252 | ||
253 | t0 = QTime::currentTime(); | |
254 | ||
255 | for (LDObject* obj : objs) | |
256 | { | |
257 | compileSubObject (obj, topobj, data); | |
258 | obj->deleteSelf(); | |
259 | } | |
260 | ||
261 | DEBUG_PRINT ("\t- SUB-COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime())); | |
262 | } break; | |
263 | ||
264 | default: | |
265 | {} break; | |
266 | } | |
267 | } | |
268 | ||
269 | // ============================================================================= | |
270 | // ----------------------------------------------------------------------------- | |
271 | void VertexCompiler::compileDocument() | |
272 | { | |
273 | for (LDObject * obj : m_file->getObjects()) | |
274 | compileObject (obj); | |
275 | } | |
276 | ||
277 | // ============================================================================= | |
278 | // ----------------------------------------------------------------------------- | |
279 | void VertexCompiler::forgetObject (LDObject* obj) | |
280 | { | |
281 | auto it = m_objArrays.find (obj); | |
282 | ||
283 | if (it != m_objArrays.end()) | |
284 | delete *it; | |
285 | ||
286 | m_objArrays.remove (obj); | |
287 | } | |
288 | ||
289 | // ============================================================================= | |
290 | // ----------------------------------------------------------------------------- | |
291 | void VertexCompiler::setFile (LDDocument* file) | |
292 | { | |
293 | m_file = file; | |
294 | } | |
295 | ||
296 | // ============================================================================= | |
297 | // ----------------------------------------------------------------------------- | |
298 | const VertexCompiler::Array* VertexCompiler::getMergedBuffer (GL::VAOType type) | |
299 | { | |
300 | // If there are objects staged for compilation, compile them now. | |
301 | if (m_staged.size() > 0) | |
302 | { | |
303 | for (LDObject * obj : m_staged) | |
304 | compileObject (obj); | |
305 | ||
306 | m_staged.clear(); | |
307 | } | |
308 | ||
309 | assert (type < GL::NumArrays); | |
310 | ||
311 | if (m_changed[type]) | |
312 | { | |
313 | m_changed[type] = false; | |
314 | m_mainArrays[type].clear(); | |
315 | ||
316 | for (LDObject* obj : m_file->getObjects()) | |
317 | { | |
318 | if (!obj->isScemantic()) | |
319 | continue; | |
320 | ||
321 | auto it = m_objArrays.find (obj); | |
322 | ||
323 | if (it != m_objArrays.end()) | |
324 | m_mainArrays[type].merge (& (*it) [type]); | |
325 | } | |
326 | ||
327 | DEBUG_PRINT ("merged array %1: %2 bytes\n", (int) type, m_mainArrays[type].writtenSize()); | |
328 | } | |
329 | ||
330 | return &m_mainArrays[type]; | |
331 | } | |
332 | ||
333 | // ============================================================================= | |
334 | // This turns a compiled triangle into usable VAO vertices | |
335 | // ----------------------------------------------------------------------------- | |
336 | VertexCompiler::Array* VertexCompiler::postprocess (const CompiledTriangle& triangle, GL::VAOType type) | |
337 | { | |
338 | Array* va = new Array; | |
339 | QList<Vertex> verts; | |
340 | ||
341 | for (int i = 0; i < triangle.numVerts; ++i) | |
342 | { | |
343 | alias v0 = triangle.verts[i]; | |
344 | Vertex v; | |
345 | v.x = v0.x(); | |
346 | v.y = v0.y(); | |
347 | v.z = v0.z(); | |
348 | ||
349 | switch (type) | |
350 | { | |
351 | case GL::MainArray: | |
352 | case GL::EdgeArray: | |
353 | case GL::CondEdgeArray: | |
354 | { | |
355 | v.color = triangle.rgb; | |
356 | } break; | |
357 | ||
358 | case GL::PickArray: | |
359 | case GL::EdgePickArray: | |
360 | { | |
361 | v.color = triangle.pickrgb; | |
362 | } break; | |
363 | ||
364 | case GL::BFCArray: | |
365 | case GL::NumArrays: | |
366 | break; // handled separately | |
367 | } | |
368 | ||
369 | verts << v; | |
370 | } | |
371 | ||
372 | if (type == GL::BFCArray) | |
373 | { | |
374 | int32 rgb = getObjectColor (triangle.obj, BFCFront).rgb(); | |
375 | ||
376 | for (Vertex v : verts) | |
377 | { | |
378 | v.color = rgb; | |
379 | va->write (v); | |
380 | } | |
381 | ||
382 | rgb = getObjectColor (triangle.obj, BFCBack).rgb(); | |
383 | ||
384 | for (int i = verts.size() - 1; i >= 0; --i) | |
385 | { | |
386 | Vertex v = verts[i]; | |
387 | v.color = rgb; | |
388 | va->write (v); | |
389 | } | |
390 | } | |
391 | else | |
392 | { | |
393 | for (Vertex v : verts) | |
394 | va->write (v); | |
395 | } | |
396 | ||
397 | return va; | |
398 | } | |
399 | ||
400 | // ============================================================================= | |
401 | // ----------------------------------------------------------------------------- | |
402 | uint32 VertexCompiler::getColorRGB (QColor& color) | |
403 | { | |
404 | return | |
405 | (color.red() & 0xFF) << 0x00 | | |
406 | (color.green() & 0xFF) << 0x08 | | |
407 | (color.blue() & 0xFF) << 0x10 | | |
408 | (color.alpha() & 0xFF) << 0x18; | |
409 | } | |
410 | ||
411 | // ============================================================================= | |
412 | // ----------------------------------------------------------------------------- | |
413 | QColor VertexCompiler::getObjectColor (LDObject* obj, ColorType colotype) const | |
414 | { | |
415 | QColor qcol; | |
416 | ||
417 | if (!obj->isColored()) | |
418 | return QColor(); | |
419 | ||
420 | if (colotype == PickColor) | |
421 | { | |
422 | // Make the color by the object's ID if we're picking, so we can make the | |
423 | // ID again from the color we get from the picking results. Be sure to use | |
424 | // the top level parent's index since we want a subfile's children point | |
425 | // to the subfile itself. | |
426 | long i = obj->topLevelParent()->getID(); | |
427 | ||
428 | // Calculate a color based from this index. This method caters for | |
429 | // 16777216 objects. I don't think that'll be exceeded anytime soon. :) | |
430 | // ATM biggest is 53588.dat with 12600 lines. | |
431 | int r = (i / (256 * 256)) % 256, | |
432 | g = (i / 256) % 256, | |
433 | b = i % 256; | |
434 | ||
435 | return QColor (r, g, b); | |
436 | } | |
437 | ||
438 | if ( (colotype == BFCFront || colotype == BFCBack) && | |
439 | obj->getType() != LDObject::ELine && | |
440 | obj->getType() != LDObject::ECondLine | |
441 | ) | |
442 | { | |
443 | if (colotype == BFCFront) | |
444 | qcol = QColor (40, 192, 0); | |
445 | else | |
446 | qcol = QColor (224, 0, 0); | |
447 | } | |
448 | else | |
449 | { | |
450 | if (obj->getColor() == maincolor) | |
451 | qcol = GL::getMainColor(); | |
452 | else | |
453 | { | |
454 | LDColor* col = getColor (obj->getColor()); | |
455 | ||
456 | if (col) | |
457 | qcol = col->faceColor; | |
458 | } | |
459 | ||
460 | if (obj->getColor() == edgecolor) | |
461 | { | |
462 | qcol = QColor (32, 32, 32); // luma (m_bgcolor) < 40 ? QColor (64, 64, 64) : Qt::black; | |
463 | LDColor* col; | |
464 | ||
465 | if (!gl_blackedges && obj->getParent() && (col = getColor (obj->getParent()->getColor()))) | |
466 | qcol = col->edgeColor; | |
467 | } | |
468 | ||
469 | if (qcol.isValid() == false) | |
470 | { | |
471 | // The color was unknown. Use main color to make the object at least | |
472 | // not appear pitch-black. | |
473 | if (obj->getColor() != edgecolor) | |
474 | qcol = GL::getMainColor(); | |
475 | else | |
476 | qcol = Qt::black; | |
477 | ||
478 | // Warn about the unknown color, but only once. | |
479 | for (short i : g_warnedColors) | |
480 | if (obj->getColor() == i) | |
481 | return qcol; | |
482 | ||
483 | log ("%1: Unknown color %2!\n", __func__, obj->getColor()); | |
484 | g_warnedColors << obj->getColor(); | |
485 | return qcol; | |
486 | } | |
487 | } | |
488 | ||
489 | if (obj->topLevelParent()->isSelected()) | |
490 | { | |
491 | // Brighten it up if selected. | |
492 | const int add = 51; | |
493 | ||
494 | qcol.setRed (min (qcol.red() + add, 255)); | |
495 | qcol.setGreen (min (qcol.green() + add, 255)); | |
496 | qcol.setBlue (min (qcol.blue() + add, 255)); | |
497 | } | |
498 | ||
499 | return qcol; | |
500 | } | |
501 | ||
502 | // ============================================================================= | |
503 | // ----------------------------------------------------------------------------- | |
504 | void VertexCompiler::needMerge() | |
505 | { | |
506 | // Set all of m_changed to true | |
507 | memset (m_changed, 0xFF, sizeof m_changed); | |
508 | } | |
509 | ||
510 | // ============================================================================= | |
511 | // ----------------------------------------------------------------------------- | |
512 | void VertexCompiler::initObject (LDObject* obj) | |
513 | { | |
514 | if (m_objArrays.find (obj) == m_objArrays.end()) | |
515 | m_objArrays[obj] = new Array[GL::NumArrays]; | |
516 | } | |
517 | ||
518 | // ============================================================================= | |
519 | // ----------------------------------------------------------------------------- | |
520 | void VertexCompiler::stageForCompilation (LDObject* obj) | |
521 | { | |
522 | m_staged << obj; | |
523 | removeDuplicates (m_staged); | |
524 | } | |
525 |