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