src/gldata.cc

changeset 668
6a05c4969074
child 671
14a6da9c0bfe
equal deleted inserted replaced
667:31540c1f22ea 668:6a05c4969074
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

mercurial