Wed, 25 Sep 2013 11:02:44 +0300
Merge branch 'master' into gl
--- a/src/file.cpp Sun Sep 22 23:27:07 2013 +0300 +++ b/src/file.cpp Wed Sep 25 11:02:44 2013 +0300 @@ -33,6 +33,7 @@ #include "history.h" #include "dialogs.h" #include "gldraw.h" +#include "gldata.h" cfg (String, io_ldpath, ""); cfg (List, io_recentfiles, {}); @@ -282,7 +283,7 @@ // Trim the trailing newline qchar c; - while ((c = line[line.length() - 1]) == '\n' || c == '\r') + while (line.length() > 0 && ((c = line[line.length() - 1]) == '\n' || c == '\r')) line.chop (1); LDObject* obj = parseLine (line); @@ -1085,6 +1086,7 @@ g_win->updateFileListItem (f); g_win->buildObjList(); g_win->updateTitle(); + g_vertexCompiler.needMerge(); g_win->R()->setFile (f); g_win->R()->resetAngles(); g_win->R()->repaint();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gldata.cpp Wed Sep 25 11:02:44 2013 +0300 @@ -0,0 +1,461 @@ +#include "gldata.h" +#include "ldtypes.h" +#include "colors.h" +#include "file.h" +#include "misc.h" +#include "gldraw.h" +#include <QDate> + +cfg (Bool, gl_blackedges, false); +static List<short> g_warnedColors; +VertexCompiler g_vertexCompiler; + +// ============================================================================= +// ----------------------------------------------------------------------------- +VertexCompiler::Array::Array() : + m_data (null) +{ + clear(); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +VertexCompiler::Array::~Array() { + delete[] m_data; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::Array::clear() { + delete[] m_data; + + m_data = new Vertex[64]; + m_size = 64; + m_ptr = &m_data[0]; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::Array::resizeToFit (Size newSize) { + if (allocatedSize() >= newSize) + return; + + int32 cachedWriteSize = writtenSize(); + + // Add some lee-way space to reduce the amount of resizing. + newSize += 256; + + const Size oldSize = allocatedSize(); + + // We need to back up the data first + Vertex* copy = new Vertex[oldSize]; + memcpy (copy, m_data, oldSize); + + // Re-create the buffer + delete[] m_data; + m_data = new Vertex[newSize]; + m_size = newSize; + m_ptr = &m_data[cachedWriteSize / sizeof (Vertex)]; + + // Copy the data back + memcpy (m_data, copy, oldSize); + delete[] copy; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +const VertexCompiler::Vertex* VertexCompiler::Array::data() const { + return m_data; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +const VertexCompiler::Array::Size& VertexCompiler::Array::allocatedSize() const { + return m_size; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +VertexCompiler::Array::Size VertexCompiler::Array::writtenSize() const { + return (m_ptr - m_data) * sizeof (Vertex); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::Array::write (const Vertex& f) { + // Ensure there's enoughspace for the new vertex + resizeToFit (writtenSize() + sizeof f); + + // Write the float in + *m_ptr++ = f; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::Array::merge (Array* other) { + // Ensure there's room for both buffers + resizeToFit (writtenSize() + other->writtenSize()); + + memcpy (m_ptr, other->data(), other->writtenSize()); + m_ptr += other->writtenSize() / sizeof (Vertex); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +VertexCompiler::VertexCompiler() : + m_file (null) +{ + needMerge(); +} + +VertexCompiler::~VertexCompiler() {} + +// ============================================================================= +// Note: we use the top level object's color but the draw object's vertices. +// This is so that the index color is generated correctly - it has to reference +// the top level object's ID. This is crucial for picking to work. +// ----------------------------------------------------------------------------- +void VertexCompiler::compilePolygon (LDObject* drawobj, LDObject* trueobj, List<CompiledTriangle>& data) { + const QColor pickColor = getObjectColor (trueobj, PickColor); + LDObject::Type type = drawobj->getType(); + List<LDObject*> objs; + + assert (type != LDObject::Subfile); + + if (type == LDObject::Quad) { + for (LDTriangle* t : static_cast<LDQuad*> (drawobj)->splitToTriangles()) + objs << t; + } else + objs << drawobj; + + for (LDObject* obj : objs) { + const LDObject::Type objtype = obj->getType(); + const bool isline = (objtype == LDObject::Line || objtype == LDObject::CndLine); + const int verts = isline ? 2 : obj->vertices(); + QColor normalColor = getObjectColor (obj, Normal); + + assert (isline || objtype == LDObject::Triangle); + + CompiledTriangle a; + a.rgb = normalColor.rgb(); + a.pickrgb = pickColor.rgb(); + a.numVerts = verts; + a.obj = trueobj; + a.isCondLine = (objtype == LDObject::CndLine); + + for (int i = 0; i < verts; ++i) { + a.verts[i] = obj->getVertex (i); + a.verts[i].y() = -a.verts[i].y(); + a.verts[i].z() = -a.verts[i].z(); + } + + data << a; + } +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::compileObject (LDObject* obj) { + initObject (obj); + List<CompiledTriangle> data; + QTime t0; + + for (int i = 0; i < GL::NumArrays; ++i) + m_objArrays[obj][i].clear(); + + t0 = QTime::currentTime(); + compileSubObject (obj, obj, data); + print ("COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime())); + + t0 = QTime::currentTime(); + for (int i = 0; i < GL::NumArrays; ++i) { + GL::VAOType type = (GL::VAOType) i; + const bool islinearray = (type == GL::EdgeArray || type == GL::EdgePickArray); + + for (const CompiledTriangle& poly : data) { + if (poly.isCondLine) { + // Conditional lines go to the edge pick array and the array + // specifically designated for conditional lines and nowhere else. + if (type != GL::EdgePickArray && type != GL::CondEdgeArray) + continue; + } else { + // Lines and only lines go to the line array and only to the line array. + if ((poly.numVerts == 2) ^ islinearray) + continue; + + // Only conditional lines go into the conditional line array + if (type == GL::CondEdgeArray) + continue; + } + + Array* verts = postprocess (poly, type); + m_objArrays[obj][type].merge (verts); + delete verts; + } + } + print ("POST-PROCESS: %1ms\n", t0.msecsTo (QTime::currentTime())); + + needMerge(); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::compileSubObject (LDObject* obj, LDObject* topobj, List<CompiledTriangle>& data) { + List<LDObject*> objs; + + switch (obj->getType()) { + case LDObject::Triangle: + case LDObject::Line: + case LDObject::CndLine: + compilePolygon (obj, topobj, data); + break; + + case LDObject::Quad: + for (LDTriangle* triangle : static_cast<LDQuad*> (obj)->splitToTriangles()) + compilePolygon (triangle, topobj, data); + break; + + case LDObject::Subfile: + { + QTime t0 = QTime::currentTime(); + objs = static_cast<LDSubfile*> (obj)->inlineContents (LDSubfile::RendererInline | LDSubfile::DeepCacheInline); + print ("\t- INLINE: %1ms\n", t0.msecsTo (QTime::currentTime())); + print ("\t- %1 objects\n", objs.size()); + + t0 = QTime::currentTime(); + for (LDObject* obj : objs) { + compileSubObject (obj, topobj, data); + delete obj; + } + print ("\t- SUB-COMPILATION: %1ms\n", t0.msecsTo (QTime::currentTime())); + } + break; + + default: + break; + } +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::compileFile() { + for (LDObject* obj : m_file->objects()) + compileObject (obj); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::forgetObject (LDObject* obj) { + auto it = m_objArrays.find (obj); + if (it != m_objArrays.end()) + delete *it; + + m_objArrays.remove (obj); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::setFile (LDFile* file) { + m_file = file; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +const VertexCompiler::Array* VertexCompiler::getMergedBuffer (GL::VAOType type) { + // If there are objects staged for compilation, compile them now. + if (m_staged.size() > 0) { + for (LDObject* obj : m_staged) + compileObject (obj); + + m_staged.clear(); + } + + assert (type < GL::NumArrays); + + if (m_changed[type]) { + m_changed[type] = false; + m_mainArrays[type].clear(); + + for (LDObject* obj : m_file->objects()) { + if (!obj->isScemantic()) + continue; + + auto it = m_objArrays.find (obj); + + if (it != m_objArrays.end()) + m_mainArrays[type].merge (&(*it)[type]); + } + + print ("merged array %1: %2 bytes\n", (int) type, m_mainArrays[type].writtenSize()); + } + + return &m_mainArrays[type]; +} + +// ============================================================================= +// This turns a compiled triangle into usable VAO vertices +// ----------------------------------------------------------------------------- +VertexCompiler::Array* VertexCompiler::postprocess (const CompiledTriangle& triangle, GL::VAOType type) { + Array* va = new Array; + List<Vertex> verts; + + for (int i = 0; i < triangle.numVerts; ++i) { + alias v0 = triangle.verts[i]; + Vertex v; + v.x = v0.x(); + v.y = v0.y(); + v.z = v0.z(); + + switch (type) { + case GL::MainArray: + case GL::EdgeArray: + case GL::CondEdgeArray: + v.color = triangle.rgb; + break; + + case GL::PickArray: + case GL::EdgePickArray: + v.color = triangle.pickrgb; + + case GL::BFCArray: + break; // handled separately + + case GL::NumArrays: + assert (false); + } + + verts << v; + } + + if (type == GL::BFCArray) { + int32 rgb = getObjectColor (triangle.obj, BFCFront).rgb(); + for (Vertex v : verts) { + v.color = rgb; + va->write (v); + } + + rgb = getObjectColor (triangle.obj, BFCBack).rgb(); + for (Vertex v : c_rev<Vertex> (verts)) { + v.color = rgb; + va->write (v); + } + } else { + for (Vertex v : verts) + va->write (v); + } + + return va; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +uint32 VertexCompiler::getColorRGB (QColor& color) { + return + (color.red() & 0xFF) << 0x00 | + (color.green() & 0xFF) << 0x08 | + (color.blue() & 0xFF) << 0x10 | + (color.alpha() & 0xFF) << 0x18; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +QColor VertexCompiler::getObjectColor (LDObject* obj, ColorType colotype) const { + QColor qcol; + + if (!obj->isColored()) + return QColor(); + + if (colotype == PickColor) { + // Make the color by the object's ID if we're picking, so we can make the + // ID again from the color we get from the picking results. Be sure to use + // the top level parent's index since we want a subfile's children point + // to the subfile itself. + long i = obj->topLevelParent()->id(); + + // Calculate a color based from this index. This method caters for + // 16777216 objects. I don't think that'll be exceeded anytime soon. :) + // ATM biggest is 53588.dat with 12600 lines. + int r = (i / (256 * 256)) % 256, + g = (i / 256) % 256, + b = i % 256; + + return QColor (r, g, b); + } + + if ((colotype == BFCFront || colotype == BFCBack) && + obj->getType() != LDObject::Line && + obj->getType() != LDObject::CndLine) { + + if (colotype == BFCFront) + qcol = QColor (40, 192, 0); + else + qcol = QColor (224, 0, 0); + } else { + if (obj->color() == maincolor) + qcol = GL::getMainColor(); + else { + LDColor* col = getColor (obj->color()); + + if (col) + qcol = col->faceColor; + } + + if (obj->color() == edgecolor) { + qcol = QColor (32, 32, 32); // luma (m_bgcolor) < 40 ? QColor (64, 64, 64) : Qt::black; + LDColor* col; + + if (!gl_blackedges && obj->parent() && (col = getColor (obj->parent()->color()))) + qcol = col->edgeColor; + } + + if (qcol.isValid() == false) { + // The color was unknown. Use main color to make the object at least + // not appear pitch-black. + if (obj->color() != edgecolor) + qcol = GL::getMainColor(); + else + qcol = Qt::black; + + // Warn about the unknown color, but only once. + for (short i : g_warnedColors) + if (obj->color() == i) + return qcol; + + log ("%1: Unknown color %2!\n", __func__, obj->color()); + g_warnedColors << obj->color(); + return qcol; + } + } + + if (obj->topLevelParent()->selected()) { + // Brighten it up if selected. + const int add = 51; + + qcol.setRed (min (qcol.red() + add, 255)); + qcol.setGreen (min (qcol.green() + add, 255)); + qcol.setBlue (min (qcol.blue() + add, 255)); + } + + return qcol; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::needMerge() { + // Set all of m_changed to true + memset (m_changed, 0xFF, sizeof m_changed); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::initObject (LDObject* obj) { + if (m_objArrays.find (obj) == m_objArrays.end()) + m_objArrays[obj] = new Array[GL::NumArrays]; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void VertexCompiler::stageForCompilation (LDObject* obj) { + m_staged << obj; + m_staged.makeUnique(); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gldata.h Wed Sep 25 11:02:44 2013 +0300 @@ -0,0 +1,116 @@ +#ifndef LDFORGE_GLDATA_H +#define LDFORGE_GLDATA_H + +#include "types.h" +#include "gldraw.h" +#include <QMap> +#include <QRgb> + +class QColor; +class LDTriangle; +class LDFile; + +/* ============================================================================= + * ----------------------------------------------------------------------------- + * VertexCompiler + * + * This class manages vertex arrays for the GL renderer, compiling vertices into + * VAO-readable triangles which can be requested with getMergedBuffer. + * + * There are 5 main array types: + * - the normal polygon array, for triangles + * - edge line array, for lines + * - BFC array, this is the same as the normal polygon array except that the + * - polygons are listed twice, once normally and green and once reversed + * - and red, this allows BFC red/green view. + * - Picking array, this is the samea s the normal polygon array except the + * - polygons are compiled with their index color, this way the picking + * - method is capable of determining which object was selected by pixel + * - color. + * - Edge line picking array, the pick array version of the edge line array. + * + * There are also these same 5 arrays for every LDObject compiled. The main + * arrays are generated on demand from the ones in the current file's + * LDObjects and stored in cache for faster rendering. + * + * The nested Array class contains a vector-like buffer of the Vertex structs, + * these structs are the VAOs that get passed to the renderer. + */ + +class VertexCompiler { +public: + enum ColorType { + Normal, + BFCFront, + BFCBack, + PickColor, + }; + + struct CompiledTriangle { + vertex verts[3]; + uint8 numVerts; // 2 if a line + QRgb rgb; // Color of this poly normally + QRgb pickrgb; // Color of this poly while picking + bool isCondLine; // Is this a conditional line? + LDObject* obj; // Pointer to the object this poly represents + }; + + struct Vertex { + float x, y, z; + uint32 color; + float pad[4]; + }; + + class Array { + public: + typedef int32 Size; + + Array(); + Array (const Array& other) = delete; + ~Array(); + + void clear(); + void merge (Array* other); + void resizeToFit (Size newSize); + const Size& allocatedSize() const; + Size writtenSize() const; + const Vertex* data() const; + void write (const VertexCompiler::Vertex& f); + Array& operator= (const Array& other) = delete; + + private: + Vertex* m_data; + Vertex* m_ptr; + Size m_size; + }; + + VertexCompiler(); + ~VertexCompiler(); + void setFile (LDFile* file); + void compileFile(); + void forgetObject (LDObject* obj); + void initObject (LDObject* obj); + const Array* getMergedBuffer (GL::VAOType type); + QColor getObjectColor (LDObject* obj, ColorType list) const; + void needMerge(); + void stageForCompilation (LDObject* obj); + + static uint32 getColorRGB (QColor& color); + +private: + void compilePolygon (LDObject* drawobj, LDObject* trueobj, List<CompiledTriangle>& data); + void compileObject (LDObject* obj); + void compileSubObject (LDObject* obj, LDObject* topobj, List<CompiledTriangle>& data); + Array* postprocess (const CompiledTriangle& i, GL::VAOType type); + + QMap<LDObject*, Array*> m_objArrays; + QMap<LDFile*, Array*> m_fileCache; + Array m_mainArrays[GL::NumArrays]; + LDFile* m_file; + bool m_changed[GL::NumArrays]; + List<LDObject*> m_staged; +}; + +extern VertexCompiler g_vertexCompiler; + +#endif // LDFORGE_GLDATA_H \ No newline at end of file
--- a/src/gldraw.cpp Sun Sep 22 23:27:07 2013 +0300 +++ b/src/gldraw.cpp Wed Sep 25 11:02:44 2013 +0300 @@ -24,7 +24,6 @@ #include <QToolTip> #include <QTimer> #include <GL/glu.h> - #include "common.h" #include "config.h" #include "file.h" @@ -36,9 +35,11 @@ #include "dialogs.h" #include "addObjectDialog.h" #include "messagelog.h" +#include "gldata.h" +#include "build/moc_gldraw.cpp" static const struct staticCameraMeta { - const char glrotate[3]; + const int8 glrotate[3]; const Axis axisX, axisY; const bool negX, negY; } g_staticCameras[6] = { @@ -56,20 +57,19 @@ cfg (Int, gl_linethickness, 2); cfg (Bool, gl_colorbfc, false); cfg (Int, gl_camera, GLRenderer::Free); -cfg (Bool, gl_blackedges, false); cfg (Bool, gl_axes, false); cfg (Bool, gl_wireframe, false); cfg (Bool, gl_logostuds, false); // argh const char* g_CameraNames[7] = { - QT_TRANSLATE_NOOP ("GLRenderer", "Top"), - QT_TRANSLATE_NOOP ("GLRenderer", "Front"), - QT_TRANSLATE_NOOP ("GLRenderer", "Left"), - QT_TRANSLATE_NOOP ("GLRenderer", "Bottom"), - QT_TRANSLATE_NOOP ("GLRenderer", "Back"), - QT_TRANSLATE_NOOP ("GLRenderer", "Right"), - QT_TRANSLATE_NOOP ("GLRenderer", "Free") + QT_TRANSLATE_NOOP ("GLRenderer", "Top"), + QT_TRANSLATE_NOOP ("GLRenderer", "Front"), + QT_TRANSLATE_NOOP ("GLRenderer", "Left"), + QT_TRANSLATE_NOOP ("GLRenderer", "Bottom"), + QT_TRANSLATE_NOOP ("GLRenderer", "Back"), + QT_TRANSLATE_NOOP ("GLRenderer", "Right"), + QT_TRANSLATE_NOOP ("GLRenderer", "Free") }; const GL::Camera g_Cameras[7] = { @@ -87,13 +87,10 @@ const vertex vert; } g_GLAxes[3] = { { QColor (255, 0, 0), vertex (10000, 0, 0) }, - { QColor (80, 192, 0), vertex (0, 10000, 0) }, + { QColor (80, 192, 0), vertex (0, 10000, 0) }, { QColor (0, 160, 192), vertex (0, 0, 10000) }, }; -static bool g_glInvert = false; -static List<short> g_warnedColors; - // ============================================================================= // ----------------------------------------------------------------------------- GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) { @@ -191,11 +188,13 @@ setBackground(); glLineWidth (gl_linethickness); + glLineStipple (1, 0x6666); setAutoFillBackground (false); setMouseTracking (true); setFocusPolicy (Qt::WheelFocus); - compileAllObjects(); + + g_vertexCompiler.compileFile(); } // ============================================================================= @@ -227,96 +226,6 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::setObjectColor (LDObject* obj, const ListType list) { - QColor qcol; - - if (!obj->isColored()) - return; - - if (list == GL::PickList) { - // Make the color by the object's ID if we're picking, so we can make the - // ID again from the color we get from the picking results. Be sure to use - // the top level parent's index since we want a subfile's children point - // to the subfile itself. - long i = obj->topLevelParent()->id(); - - // Calculate a color based from this index. This method caters for - // 16777216 objects. I don't think that'll be exceeded anytime soon. :) - // ATM biggest is 53588.dat with 12600 lines. - double r = (i / (256 * 256)) % 256, - g = (i / 256) % 256, - b = i % 256; - - qglColor (QColor (r, g, b)); - return; - } - - if ((list == BFCFrontList || list == BFCBackList) && - obj->getType() != LDObject::Line && - obj->getType() != LDObject::CndLine) { - - if (list == GL::BFCFrontList) - qcol = QColor (40, 192, 0); - else - qcol = QColor (224, 0, 0); - } else { - if (obj->color() == maincolor) - qcol = getMainColor(); - else { - LDColor* col = getColor (obj->color()); - - if (col) - qcol = col->faceColor; - } - - if (obj->color() == edgecolor) { - qcol = luma (m_bgcolor) < 40 ? QColor (64, 64, 64) : Qt::black; - LDColor* col; - - if (!gl_blackedges && obj->parent() && (col = getColor (obj->parent()->color()))) - qcol = col->edgeColor; - } - - if (qcol.isValid() == false) { - // The color was unknown. Use main color to make the object at least - // not appear pitch-black. - if (obj->color() != edgecolor) - qcol = getMainColor(); - - // Warn about the unknown colors, but only once. - for (short i : g_warnedColors) - if (obj->color() == i) - return; - - printf ("%s: Unknown color %d!\n", __func__, obj->color()); - g_warnedColors << obj->color(); - return; - } - } - - long r = qcol.red(), - g = qcol.green(), - b = qcol.blue(), - a = qcol.alpha(); - - if (obj->topLevelParent()->selected()) { - // Brighten it up for the select list. - const uchar add = 51; - - r = min (r + add, 255l); - g = min (g + add, 255l); - b = min (b + add, 255l); - } - - glColor4f ( - ((double) r) / 255.0f, - ((double) g) / 255.0f, - ((double) b) / 255.0f, - ((double) a) / 255.0f); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- void GLRenderer::refresh() { update(); swapBuffers(); @@ -325,7 +234,7 @@ // ============================================================================= // ----------------------------------------------------------------------------- void GLRenderer::hardRefresh() { - compileAllObjects(); + g_vertexCompiler.compileFile(); refresh(); glLineWidth (gl_linethickness); @@ -373,7 +282,7 @@ } // Back camera needs to be handled differently - if (m_camera == GLRenderer::Back) { + if (m_camera == GL::Back) { glRotatef (180.0f, 1.0f, 0.0f, 0.0f); glRotatef (180.0f, 0.0f, 0.0f, 1.0f); } @@ -389,35 +298,29 @@ glRotatef (m_rotZ, 0.0f, 0.0f, 1.0f); } - const GL::ListType list = (!drawOnly() && m_picking) ? PickList : NormalList; + // Draw the VAOs now + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_COLOR_ARRAY); + glDisableClientState (GL_NORMAL_ARRAY); - if (gl_colorbfc && !m_picking && !drawOnly()) { + if (gl_colorbfc) { glEnable (GL_CULL_FACE); - - for (LDObject* obj : file()->objects()) { - if (obj->hidden()) - continue; - - glCullFace (GL_BACK); - glCallList (obj->glLists[BFCFrontList]); - - glCullFace (GL_FRONT); - glCallList (obj->glLists[BFCBackList]); - } - + glCullFace (GL_CCW); + } else glDisable (GL_CULL_FACE); - } else { - for (LDObject* obj : file()->objects()) { - if (obj->hidden()) - continue; - - glCallList (obj->glLists[list]); - } + + drawVAOs ((m_picking ? PickArray : gl_colorbfc ? BFCArray : MainArray), GL_TRIANGLES); + drawVAOs ((m_picking ? EdgePickArray : EdgeArray), GL_LINES); + + // Draw conditional lines. Note that conditional lines are drawn into + // EdgePickArray in the picking scene, so when picking, don't do anything + // here. + if (!m_picking) { + glEnable (GL_LINE_STIPPLE); + drawVAOs (CondEdgeArray, GL_LINES); + glDisable (GL_LINE_STIPPLE); } - if (gl_axes && !m_picking && !drawOnly()) - glCallList (m_axeslist); - glPopMatrix(); glMatrixMode (GL_MODELVIEW); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); @@ -425,6 +328,14 @@ // ============================================================================= // ----------------------------------------------------------------------------- +void GLRenderer::drawVAOs (VAOType arrayType, GLenum type) { + const VertexCompiler::Array* array = g_vertexCompiler.getMergedBuffer (arrayType); + glVertexPointer (3, GL_FLOAT, sizeof (VertexCompiler::Vertex), &array->data()[0].x); + glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (VertexCompiler::Vertex), &array->data()[0].color); + glDrawArrays (type, 0, array->writtenSize() / sizeof (VertexCompiler::Vertex)); +} + +// ============================================================================= // This converts a 2D point on the screen to a 3D point in the model. If 'snap' // is true, the 3D point will snap to the current grid. // ----------------------------------------------------------------------------- @@ -675,118 +586,7 @@ // ============================================================================= // ----------------------------------------------------------------------------- void GLRenderer::compileAllObjects() { - if (!file()) - return; - - // Compiling all is a big job, use a busy cursor - setCursor (Qt::BusyCursor); - - m_knownVerts.clear(); - - for (LDObject* obj : file()->objects()) - compileObject (obj); - - // Compile axes - glDeleteLists (m_axeslist, 1); - m_axeslist = glGenLists (1); - glNewList (m_axeslist, GL_COMPILE); - glBegin (GL_LINES); - - for (const GLAxis& ax : g_GLAxes) { - qglColor (ax.col); - compileVertex (ax.vert); - compileVertex (-ax.vert); - } - - glEnd(); - glEndList(); - - setCursor (Qt::ArrowCursor); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -void GLRenderer::compileSubObject (LDObject* obj, const GLenum gltype) { - glBegin (gltype); - - const short numverts = (obj->getType() != LDObject::CndLine) ? obj->vertices() : 2; - - if (g_glInvert == false) - for (short i = 0; i < numverts; ++i) - compileVertex (obj->m_coords[i]); - else - for (short i = numverts - 1; i >= 0; --i) - compileVertex (obj->m_coords[i]); - - glEnd(); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -void GLRenderer::compileList (LDObject* obj, const GLRenderer::ListType list) { - setObjectColor (obj, list); - - switch (obj->getType()) { - case LDObject::Line: - compileSubObject (obj, GL_LINES); - break; - - case LDObject::CndLine: - // Draw conditional lines with a dash pattern - however, use a full - // line when drawing a pick list to make selecting them easier. - if (list != GL::PickList) { - glLineStipple (1, 0x6666); - glEnable (GL_LINE_STIPPLE); - } - - compileSubObject (obj, GL_LINES); - - glDisable (GL_LINE_STIPPLE); - break; - - case LDObject::Triangle: - compileSubObject (obj, GL_TRIANGLES); - break; - - case LDObject::Quad: - compileSubObject (obj, GL_QUADS); - break; - - case LDObject::Subfile: { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - List<LDObject*> objs; - - objs = ref->inlineContents ( - LDSubfile::DeepInline | - LDSubfile::CacheInline | - LDSubfile::RendererInline); - bool oldinvert = g_glInvert; - - if (ref->transform().determinant() < 0) - g_glInvert = !g_glInvert; - - LDObject* prev = ref->prev(); - if (prev && prev->getType() == LDObject::BFC && static_cast<LDBFC*> (prev)->type == LDBFC::InvertNext) - g_glInvert = !g_glInvert; - - for (LDObject* obj : objs) { - compileList (obj, list); - delete obj; - } - - g_glInvert = oldinvert; - } - break; - - default: - break; - } -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -void GLRenderer::compileVertex (const vertex& vrt) { - glVertex3d (vrt[X], -vrt[Y], -vrt[Z]); + g_vertexCompiler.compileFile(); } // ============================================================================= @@ -1055,9 +855,9 @@ glGetIntegerv (GL_VIEWPORT, viewport); - short x0 = mouseX, - y0 = mouseY; - short x1, y1; + int x0 = mouseX, + y0 = mouseY, + x1, y1; // Determine how big an area to read - with range picking, we pick by // the area given, with single pixel picking, we use an 1 x 1 area. @@ -1077,14 +877,14 @@ dataswap (y0, y1); // Clamp the values to ensure they're within bounds - x0 = max<short> (0, x0); - y0 = max<short> (0, y0); - x1 = min<short> (x1, m_width); - y1 = min<short> (y1, m_height); + x0 = max (0, x0); + y0 = max (0, y0); + x1 = min (x1, m_width); + y1 = min (y1, m_height); - const short areawidth = (x1 - x0); - const short areaheight = (y1 - y0); - const long numpixels = areawidth * areaheight; + const int areawidth = (x1 - x0); + const int areaheight = (y1 - y0); + const int64 numpixels = areawidth * areaheight; // Allocate space for the pixel data. uchar* const pixeldata = new uchar[4 * numpixels]; @@ -1098,17 +898,24 @@ LDObject* removedObj = null; // Go through each pixel read and add them to the selection. - for (long i = 0; i < numpixels; ++i) { - long idx = - (*(pixelptr + 0) * 0x10000) + + for (int64 i = 0; i < numpixels; ++i) { + printf ("Color: #%X%X%X\n", pixelptr[0], pixelptr[1], pixelptr[2]); + + int32 idx = + (*(pixelptr + 0) * 0x00001) + (*(pixelptr + 1) * 0x00100) + - (*(pixelptr + 2) * 0x00001); + (*(pixelptr + 2) * 0x10000); + pixelptr += 4; if (idx == 0xFFFFFF) continue; // White is background; skip LDObject* obj = LDObject::fromID (idx); + if (!obj) { + log ("WARNING: Object #%1 doesn't exist!", idx); + continue; + } // If this is an additive single pick and the object is currently selected, // we remove it from selection instead. @@ -1209,6 +1016,7 @@ // ----------------------------------------------------------------------------- SET_ACCESSOR (LDFile*, GLRenderer::setFile) { m_file = val; + g_vertexCompiler.setFile (val); if (val != null) overlaysFromObjects(); @@ -1298,26 +1106,7 @@ // ============================================================================= // ----------------------------------------------------------------------------- void GLRenderer::compileObject (LDObject* obj) { - deleteLists (obj); - - for (const GL::ListType listType : g_glListTypes) { - if (drawOnly() && listType != GL::NormalList) - continue; - - GLuint list = glGenLists (1); - glNewList (list, GL_COMPILE); - - obj->glLists[listType] = list; - compileList (obj, listType); - - glEndList(); - } - - // Mark in known vertices of this object - List<vertex> verts = getVertices (obj); - m_knownVerts << verts; - m_knownVerts.makeUnique(); - + g_vertexCompiler.stageForCompilation (obj); obj->m_glinit = true; }
--- a/src/gldraw.h Sun Sep 22 23:27:07 2013 +0300 +++ b/src/gldraw.h Wed Sep 25 11:02:44 2013 +0300 @@ -67,6 +67,16 @@ enum Camera { Top, Front, Left, Bottom, Back, Right, Free }; enum ListType { NormalList, PickList, BFCFrontList, BFCBackList }; + enum VAOType { + MainArray, + EdgeArray, + CondEdgeArray, + BFCArray, + PickArray, + EdgePickArray, + NumArrays + }; + GLRenderer (QWidget* parent = null); ~GLRenderer(); @@ -79,7 +89,7 @@ double depthValue() const; void drawGLScene(); void endDraw (bool accept); - QColor getMainColor(); + static QColor getMainColor(); overlayMeta& getOverlay (int newcam); void hardRefresh(); void initGLData(); @@ -131,8 +141,8 @@ QPoint m_pos, m_globalpos, m_rangeStart; QPen m_thickBorderPen, m_thinBorderPen; Camera m_camera, m_toolTipCamera; - uint m_axeslist; - ushort m_width, m_height; + GLuint m_axeslist; + int m_width, m_height; List<vertex> m_drawedVerts; bool m_rectdraw; vertex m_rectverts[4]; @@ -145,15 +155,12 @@ void addDrawnVertex (vertex m_hoverpos); void calcCameraIcons(); // Compute geometry for camera icons void clampAngle (double& angle) const; // Clamps an angle to [0, 360] - void compileList (LDObject* obj, const ListType list); // Compile one of the lists of an object - void compileSubObject (LDObject* obj, const GLenum gltype); // Sub-routine for object compiling - void compileVertex (const vertex& vrt); // Compile a single vertex to a list vertex coordconv2_3 (const QPoint& pos2d, bool snap) const; // Convert a 2D point to a 3D point QPoint coordconv3_2 (const vertex& pos3d) const; // Convert a 3D point to a 2D point - LDOverlay* findOverlayObject (Camera cam); + void drawVAOs (VAOType arrayType, GLenum type); // Draw a VAO array + LDOverlay* findOverlayObject (Camera cam); void updateRectVerts(); void pick (uint mouseX, uint mouseY); // Perform object selection - void setObjectColor (LDObject* obj, const ListType list); // Set the color to an object list QColor getTextPen() const; // Determine which color to draw text with private slots:
--- a/src/gui.cpp Sun Sep 22 23:27:07 2013 +0300 +++ b/src/gui.cpp Wed Sep 25 11:02:44 2013 +0300 @@ -501,10 +501,14 @@ void ForgeWindow::updateSelection() { g_bSelectionLocked = true; + print ("1\n"); for (LDObject* obj : LDFile::current()->objects()) obj->setSelected (false); + print ("2\n"); ui->objectList->clearSelection(); + + print ("3\n"); for (LDObject* obj : m_sel) { if (obj->qObjListEntry == null) continue; @@ -513,6 +517,7 @@ obj->setSelected (true); } + print ("4\n"); g_bSelectionLocked = false; slot_selectionChanged(); }
--- a/src/ldtypes.cpp Sun Sep 22 23:27:07 2013 +0300 +++ b/src/ldtypes.cpp Wed Sep 25 11:02:44 2013 +0300 @@ -24,6 +24,7 @@ #include "history.h" #include "gldraw.h" #include "colors.h" +#include "gldata.h" cfg (String, ld_defaultname, ""); cfg (String, ld_defaultuser, ""); @@ -265,6 +266,8 @@ if (pos < g_LDObjects.size()) g_LDObjects.erase (pos); + + g_vertexCompiler.forgetObject (this); } // =============================================================================
--- a/src/src.pro Sun Sep 22 23:27:07 2013 +0300 +++ b/src/src.pro Wed Sep 25 11:02:44 2013 +0300 @@ -10,6 +10,7 @@ SOURCES = *.cpp HEADERS = *.h FORMS = ui/*.ui +CONFIG += qt debug QT += opengl network QMAKE_CXXFLAGS += -std=c++0x
--- a/src/types.h Sun Sep 22 23:27:07 2013 +0300 +++ b/src/types.h Wed Sep 25 11:02:44 2013 +0300 @@ -279,6 +279,11 @@ std::deque<T> m_vect; }; +template<class T> static inline T& operator>> (const T& a, List<T>& b) { + b.insert (0, a); + return b; +} + // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // =============================================================================