src/gldata.cpp

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

mercurial