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 } |
|