Tue, 08 Apr 2014 11:07:47 +0300
Merge ../ldforge into gl
--- a/CMakeLists.txt Tue Apr 08 11:07:25 2014 +0300 +++ b/CMakeLists.txt Tue Apr 08 11:07:47 2014 +0300 @@ -33,6 +33,7 @@ src/editHistory.cc src/extPrograms.cc src/glRenderer.cc + src/glCompiler.cc src/ldConfig.cc src/ldDocument.cc src/ldObject.cc @@ -69,6 +70,7 @@ src/colorSelector.h src/configDialog.h src/glRenderer.h + src/glCompiler.h src/configuration.h src/mainWindow.h src/editHistory.h
--- a/src/actions.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/actions.cc Tue Apr 08 11:07:47 2014 +0300 @@ -35,6 +35,7 @@ #include "primitives.h" #include "radioGroup.h" #include "colors.h" +#include "glCompiler.h" #include "ui_newpart.h" extern_cfg (Bool, gl_wireframe); @@ -471,7 +472,6 @@ getCurrentDocument()->insertObj (idx, obj); obj->select(); - R()->compileObject (obj); idx++; } @@ -847,9 +847,7 @@ obj->destroy(); // Compile all objects in the new subfile - for (LDObject* obj : doc->objects()) - R()->compileObject (obj); - + R()->compiler()->compileDocument (doc); g_loadedFiles << doc; // Add a reference to the new subfile to where the selection was
--- a/src/actionsEdit.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/actionsEdit.cc Tue Apr 08 11:07:47 2014 +0300 @@ -94,7 +94,6 @@ LDObject* pasted = parseLine (line); getCurrentDocument()->insertObj (idx++, pasted); pasted->select(); - R()->compileObject (pasted); ++num; } @@ -123,18 +122,10 @@ // inlined contents. long idx = obj->lineNumber(); - if (idx == -1) + if (idx == -1 || obj->type() != LDObject::ESubfile) continue; - LDObjectList objs; - - if (obj->type() == LDObject::ESubfile) - { - LDSubfile::InlineFlags flags = deep ? LDSubfile::DeepCacheInline : LDSubfile::CacheInline; - objs = static_cast<LDSubfile*> (obj)->inlineContents (flags); - } - else - continue; + LDObjectList objs = static_cast<LDSubfile*> (obj)->inlineContents (deep, false); // Merge in the inlined objects for (LDObject* inlineobj : objs) @@ -144,7 +135,6 @@ LDObject* newobj = parseLine (line); getCurrentDocument()->insertObj (idx++, newobj); newobj->select(); - g_win->R()->compileObject (newobj); } // Delete the subfile now as it's been inlined. @@ -188,13 +178,7 @@ // after the first one. getCurrentDocument()->setObject (index, triangles[0]); getCurrentDocument()->insertObj (index + 1, triangles[1]); - - for (LDTriangle* t : triangles) - R()->compileObject (t); - - // Delete this quad now, it has been split. obj->destroy(); - num++; } @@ -224,17 +208,12 @@ ui.errorIcon->hide(); } - if (!dlg->exec()) + if (dlg->exec() == QDialog::Rejected) return; - LDObject* oldobj = obj; - // Reinterpret it from the text of the input field - obj = parseLine (ui.code->text()); - oldobj->replace (obj); - - // Refresh - R()->compileObject (obj); + LDObject* newobj = parseLine (ui.code->text()); + obj->replace (newobj); refresh(); } @@ -263,7 +242,6 @@ continue; obj->setColor (colnum); - R()->compileObject (obj); } refresh(); @@ -312,7 +290,6 @@ lines[i]->setColor (edgecolor); getCurrentDocument()->insertObj (idx, lines[i]); - R()->compileObject (lines[i]); } num += numLines; @@ -340,9 +317,7 @@ LDVertex* vert = new LDVertex; vert->pos = obj->vertex (i); vert->setColor (obj->color()); - getCurrentDocument()->insertObj (++ln, vert); - R()->compileObject (vert); ++num; } } @@ -394,10 +369,7 @@ vect[Z] *= *currentGrid().confs[Grid::Z]; for (LDObject* obj : selection()) - { obj->move (vect); - g_win->R()->compileObject (obj); - } g_win->refresh(); } @@ -441,10 +413,7 @@ LDObjectList sel = selection(); for (LDObject* obj : sel) - { obj->invert(); - R()->compileObject (obj); - } refresh(); } @@ -516,8 +485,6 @@ rotateVertex (v, rotpoint, transform); vert->pos = v; } - - g_win->R()->compileObject (obj); } g_win->refresh(); @@ -593,7 +560,6 @@ roundToDecimals (v[ax], 3); obj->setVertex (i, v); - R()->compileObject (obj); num += 3; } } @@ -621,7 +587,6 @@ col = edgecolor; obj->setColor (col); - R()->compileObject (obj); num++; } @@ -673,7 +638,6 @@ } obj->setVertex (i, v); - R()->compileObject (obj); } } @@ -708,7 +672,6 @@ v[ax] *= -1; obj->setVertex (i, v); - R()->compileObject (obj); } } @@ -727,8 +690,7 @@ if (obj->type() != LDObject::ECondLine) continue; - LDLine* repl = static_cast<LDCondLine*> (obj)->demote(); - R()->compileObject (repl); + static_cast<LDCondLine*> (obj)->demote(); ++num; } @@ -768,7 +730,6 @@ continue; obj->setColor (colnum); - R()->compileObject (obj); } print (tr ("Auto-colored: new color is [%1] %2"), colnum, getColor (colnum)->name);
--- a/src/basics.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/basics.cc Tue Apr 08 11:07:47 2014 +0300 @@ -316,7 +316,7 @@ case LDObject::ESubfile: { LDSubfile* ref = static_cast<LDSubfile*> (obj); - LDObjectList objs = ref->inlineContents (LDSubfile::DeepCacheInline); + LDObjectList objs = ref->inlineContents (true, false); for (LDObject * obj : objs) {
--- a/src/colors.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/colors.cc Tue Apr 08 11:07:47 2014 +0300 @@ -74,7 +74,7 @@ // ============================================================================= // ============================================================================= -int luma (QColor& col) +int luma (const QColor& col) { return (0.2126f * col.red()) + (0.7152f * col.green()) +
--- a/src/colors.h Tue Apr 08 11:07:25 2014 +0300 +++ b/src/colors.h Tue Apr 08 11:07:47 2014 +0300 @@ -31,7 +31,7 @@ }; void initColors(); -int luma (QColor& col); +int luma (const QColor& col); // Safely gets a color with the given number or null if no such color. LDColor* getColor (int colnum);
--- a/src/extPrograms.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/extPrograms.cc Tue Apr 08 11:07:47 2014 +0300 @@ -173,7 +173,7 @@ if (obj->type() == LDObject::ESubfile) { LDSubfile* ref = static_cast<LDSubfile*> (obj); - LDObjectList objs = ref->inlineContents (LDSubfile::DeepInline); + LDObjectList objs = ref->inlineContents (true, false); writeObjects (objs, f);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/glCompiler.cc Tue Apr 08 11:07:47 2014 +0300 @@ -0,0 +1,415 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define GL_GLEXT_PROTOTYPES +#include <GL/glu.h> +#include <GL/glext.h> +#include "glCompiler.h" +#include "ldObject.h" +#include "colors.h" +#include "ldDocument.h" +#include "miscallenous.h" +#include "glRenderer.h" +#include "dialogs.h" + +cfg (String, gl_selectcolor, "#0080FF") + +struct GLErrorInfo +{ + GLenum value; + QString text; +}; + +static const GLErrorInfo g_GLErrors[] = +{ + { GL_NO_ERROR, "No error" }, + { GL_INVALID_ENUM, "Unacceptable enumerator passed" }, + { GL_INVALID_VALUE, "Numeric argument out of range" }, + { GL_INVALID_OPERATION, "The operation is not allowed to be done in this state" }, + { GL_INVALID_FRAMEBUFFER_OPERATION, "Framebuffer object is not complete"}, + { GL_OUT_OF_MEMORY, "Out of memory" }, + { GL_STACK_UNDERFLOW, "The operation would have caused an underflow" }, + { GL_STACK_OVERFLOW, "The operation would have caused an overflow" }, +}; + +#include <QTime> + +#define CLOCK_INIT QTime t0; + +#define CLOCK_START \ +{ \ + t0 = QTime::currentTime(); \ +} + +#define CLOCK_TIME(A) \ +{ \ + fprint (stderr, A ": %1ms\n", t0.msecsTo (QTime::currentTime())); \ +} + +#define DEBUG_PRINT(...) fprint (stdout, __VA_ARGS__) + +extern_cfg (Bool, gl_blackedges); +extern_cfg (String, gl_bgcolor); +static QList<short> g_warnedColors; +static const QColor g_BFCFrontColor (40, 192, 40); +static const QColor g_BFCBackColor (224, 40, 40); +static QMap<LDObject*, QString> g_objectOrigins; + +// ============================================================================= +// +void checkGLError_private (const char* file, int line) +{ + QString errmsg; + GLenum errnum = glGetError(); + + if (errnum == GL_NO_ERROR) + return; + + for (const GLErrorInfo& err : g_GLErrors) + { + if (err.value == errnum) + { + errmsg = err.text; + break; + } + } + + print ("OpenGL ERROR: at %1:%2: %3", basename (QString (file)), line, errmsg); +} + +// ============================================================================= +// +GLCompiler::GLCompiler() +{ + needMerge(); + memset (m_vboSizes, 0, sizeof m_vboSizes); +} + +// ============================================================================= +// +void GLCompiler::initialize() +{ + glGenBuffers (g_numVBOs, &m_vbo[0]); + checkGLError(); +} + +// ============================================================================= +// +GLCompiler::~GLCompiler() +{ + glDeleteBuffers (g_numVBOs, &m_vbo[0]); + checkGLError(); +} + +// ============================================================================= +// +uint32 GLCompiler::colorToRGB (const QColor& color) +{ + return + (color.red() & 0xFF) << 0x00 | + (color.green() & 0xFF) << 0x08 | + (color.blue() & 0xFF) << 0x10 | + (color.alpha() & 0xFF) << 0x18; +} + +// ============================================================================= +// +QColor GLCompiler::indexColorForID (int id) const +{ + // Calculate a color based from this index. This method caters for + // 16777216 objects. I don't think that will be exceeded anytime soon. :) + int r = (id / 0x10000) % 0x100, + g = (id / 0x100) % 0x100, + b = id % 0x100; + + return QColor (r, g, b); +} + +// ============================================================================= +// +QColor GLCompiler::polygonColor (LDPolygon& poly, LDObject* topobj) const +{ + QColor qcol; + + if (poly.color == maincolor) + { + if (topobj->color() == maincolor) + qcol = GLRenderer::getMainColor(); + else + qcol = getColor (topobj->color())->faceColor; + } + elif (poly.color == edgecolor) + { + qcol = luma (QColor (gl_bgcolor)) > 40 ? Qt::black : Qt::white; + } + else + { + LDColor* col = getColor (poly.color); + + if (col) + qcol = col->faceColor; + } + + if (qcol.isValid() == false) + { + // The color was unknown. Use main color to make the poly.object at least + // not appear pitch-black. + if (poly.num != 2 && poly.num != 5) + qcol = GLRenderer::getMainColor(); + else + qcol = Qt::black; + + // Warn about the unknown color, but only once. + if (g_warnedColors.contains (poly.color) == false) + { + print ("Unknown color %1!\n", poly.color); + g_warnedColors << poly.color; + } + + return qcol; + } + + if (topobj->isSelected()) + { + // Brighten it up for the select list. + QColor selcolor (gl_selectcolor); + qcol.setRed ((qcol.red() + selcolor.red()) / 2); + qcol.setGreen ((qcol.green() + selcolor.green()) / 2); + qcol.setBlue ((qcol.blue() + selcolor.blue()) / 2); + } + + return qcol; +} + +// ============================================================================= +// +void GLCompiler::needMerge() +{ + for (int i = 0; i < countof (m_vboChanged); ++i) + m_vboChanged[i] = true; +} + +// ============================================================================= +// +void GLCompiler::stageForCompilation (LDObject* obj) +{ + m_staged << obj; +} + +// ============================================================================= +// +void GLCompiler::compileDocument (LDDocument* doc) +{ + if (doc == null) + return; + + for (LDObject* obj : doc->objects()) + compileObject (obj); +} + +// ============================================================================= +// +void GLCompiler::compileStaged() +{ + removeDuplicates (m_staged); + + for (LDObject* obj : m_staged) + compileObject (obj); + + m_staged.clear(); +} + +// ============================================================================= +// +void GLCompiler::prepareVBO (int vbonum) +{ + // Compile anything that still awaits it + compileStaged(); + + if (m_vboChanged[vbonum] == false) + return; + + QVector<GLfloat> vbodata; + + for (auto it = m_objectInfo.begin(); it != m_objectInfo.end(); ++it) + { + if (it.key()->document() == getCurrentDocument()) + { + print ("merge %1\n", it.key()->id()); + vbodata += it->data[vbonum]; + } + } + + glBindBuffer (GL_ARRAY_BUFFER, m_vbo[vbonum]); + glBufferData (GL_ARRAY_BUFFER, vbodata.size() * sizeof(GLfloat), vbodata.constData(), GL_STATIC_DRAW); + glBindBuffer (GL_ARRAY_BUFFER, 0); + checkGLError(); + m_vboChanged[vbonum] = false; + m_vboSizes[vbonum] = vbodata.size(); +} + +// ============================================================================= +// +void GLCompiler::dropObject (LDObject* obj) +{ + auto it = m_objectInfo.find (obj); + + if (it != m_objectInfo.end()) + { + m_objectInfo.erase (it); + needMerge(); + } +} + +// ============================================================================= +// +void GLCompiler::compileObject (LDObject* obj) +{ + if (obj->document()->isImplicit()) + return; + + g_objectOrigins[obj] = obj->document()->getDisplayName() + ":" + QString::number (obj->lineNumber()); + + if (obj->id() == 563) + print ("compile %1\n", g_objectOrigins[obj]); + + ObjectVBOInfo info; + dropObject (obj); + compileSubObject (obj, obj, &info); + m_objectInfo[obj] = info; + needMerge(); +} + +// ============================================================================= +// +void GLCompiler::compilePolygon (LDPolygon& poly, LDObject* topobj, ObjectVBOInfo* objinfo) +{ + EVBOSurface surface; + int numverts; + + switch (poly.num) + { + case 3: surface = VBOSF_Triangles; numverts = 3; break; + case 4: surface = VBOSF_Quads; numverts = 4; break; + case 2: surface = VBOSF_Lines; numverts = 2; break; + case 5: surface = VBOSF_CondLines; numverts = 2; break; + + default: + print ("OMGWTFBBQ weird polygon with number %1 (topobj: #%2, %3), origin: %4", + (int) poly.num, topobj->id(), topobj->typeName(), poly.origin); + assert (false); + } + + for (int complement = 0; complement < VBOCM_NumComplements; ++complement) + { + const int vbonum = vboNumber (surface, (EVBOComplement) complement); + QVector<GLfloat>& vbodata = objinfo->data[vbonum]; + const QColor normalColor = polygonColor (poly, topobj); + const QColor pickColor = indexColorForID (topobj->id()); + + for (int vert = 0; vert < numverts; ++vert) + { + switch ((EVBOComplement) complement) + { + case VBOCM_Surfaces: + { + // Write coordinates. Apparently Z must be flipped too? + vbodata << poly.vertices[vert].x() + << -poly.vertices[vert].y() + << -poly.vertices[vert].z(); + break; + } + + case VBOCM_NormalColors: + { + writeColor (vbodata, normalColor); + break; + } + + case VBOCM_PickColors: + { + writeColor (vbodata, pickColor); + break; + } + + case VBOCM_BFCFrontColors: + { + writeColor (vbodata, g_BFCFrontColor); + break; + } + + case VBOCM_BFCBackColors: + { + writeColor (vbodata, g_BFCBackColor); + break; + } + + case VBOCM_NumComplements: + break; + } + } + } +} + +// ============================================================================= +// +void GLCompiler::compileSubObject (LDObject* obj, LDObject* topobj, ObjectVBOInfo* objinfo) +{ + switch (obj->type()) + { + // Note: We cannot split quads into triangles here, it would mess up the + // wireframe view. Quads must go into separate vbos. + case LDObject::ETriangle: + case LDObject::EQuad: + case LDObject::ELine: + case LDObject::ECondLine: + { + LDPolygon* poly = obj->getPolygon(); + poly->id = topobj->id(); + compilePolygon (*poly, topobj, objinfo); + delete poly; + break; + } + + case LDObject::ESubfile: + { + LDSubfile* ref = static_cast<LDSubfile*> (obj); + auto data = ref->inlinePolygons(); + + for (LDPolygon& poly : data) + { + poly.id = topobj->id(); + compilePolygon (poly, topobj, objinfo); + } + break; + } + + default: + break; + } +} + +// ============================================================================= +// +void GLCompiler::writeColor (QVector<GLfloat>& array, const QColor& color) +{ + array << ((float) color.red()) / 255.0f + << ((float) color.green()) / 255.0f + << ((float) color.blue()) / 255.0f + << ((float) color.alpha()) / 255.0f; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/glCompiler.h Tue Apr 08 11:07:47 2014 +0300 @@ -0,0 +1,82 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LDFORGE_GLCOMPILER_H +#define LDFORGE_GLCOMPILER_H + +#include "main.h" +#include "glRenderer.h" +#include "glShared.h" +#include <QMap> + +// ============================================================================= +// +class GLCompiler +{ + public: + struct ObjectVBOInfo + { + QVector<GLfloat> data[g_numVBOs]; + }; + + GLCompiler(); + ~GLCompiler(); + void compileDocument (LDDocument* doc); + void dropObject (LDObject* obj); + void initialize(); + QColor polygonColor (LDPolygon& poly, LDObject* topobj) const; + QColor indexColorForID (int id) const; + void needMerge(); + void prepareVBO (int vbonum); + void stageForCompilation (LDObject* obj); + + static uint32 colorToRGB (const QColor& color); + + static inline int vboNumber (EVBOSurface surface, EVBOComplement complement) + { + return (surface * VBOCM_NumComplements) + complement; + } + + inline GLuint vbo (int vbonum) const + { + return m_vbo[vbonum]; + } + + inline int vboCount (int vbonum) const + { + return m_vboSizes[vbonum] / 3; + } + + private: + void compileStaged(); + void compileObject (LDObject* obj); + void compileSubObject (LDObject* obj, LDObject* topobj, GLCompiler::ObjectVBOInfo* objinfo); + void writeColor (QVector<float>& array, const QColor& color); + void compilePolygon (LDPolygon& poly, LDObject* topobj, GLCompiler::ObjectVBOInfo* objinfo); + + QMap<LDObject*, ObjectVBOInfo> m_objectInfo; + LDObjectList m_staged; // Objects that need to be compiled + GLuint m_vbo[g_numVBOs]; + bool m_vboChanged[g_numVBOs]; + int m_vboSizes[g_numVBOs]; +}; + +#define checkGLError() { checkGLError_private (__FILE__, __LINE__); } +void checkGLError_private (const char* file, int line); + +#endif // LDFORGE_GLCOMPILER_H
--- a/src/glRenderer.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/glRenderer.cc Tue Apr 08 11:07:47 2014 +0300 @@ -16,12 +16,16 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#define GL_GLEXT_PROTOTYPES +#include <GL/glu.h> +#include <GL/glext.h> #include <QGLWidget> #include <QWheelEvent> #include <QMouseEvent> #include <QContextMenuEvent> #include <QInputDialog> #include <QToolTip> +#include <qtextdocument.h> #include <QTimer> #include <GL/glu.h> @@ -38,6 +42,7 @@ #include "messageLog.h" #include "primitives.h" #include "misc/ringFinder.h" +#include "glCompiler.h" static const LDFixedCameraInfo g_FixedCameras[6] = { @@ -61,7 +66,6 @@ cfg (String, gl_bgcolor, "#FFFFFF") cfg (String, gl_maincolor, "#A0A0A0") cfg (Float, gl_maincolor_alpha, 1.0) -cfg (String, gl_selectcolor, "#0080FF") cfg (Int, gl_linethickness, 2) cfg (Bool, gl_colorbfc, false) cfg (Int, gl_camera, GLRenderer::EFreeCamera) @@ -96,37 +100,40 @@ GL::EFreeCamera }; -// Definitions for visual axes, drawn on the screen -const struct LDGLAxis +struct LDGLAxis { const QColor col; const Vertex vert; -} g_GLAxes[3] = +}; + +// Definitions for visual axes, drawn on the screen +static const LDGLAxis g_GLAxes[3] = { { QColor (255, 0, 0), Vertex (10000, 0, 0) }, // X { QColor (80, 192, 0), Vertex (0, 10000, 0) }, // Y { QColor (0, 160, 192), Vertex (0, 0, 10000) }, // Z }; -static bool g_glInvert = false; -static QList<int> g_warnedColors; +static GLuint g_GLAxes_VBO; +static GLuint g_GLAxes_ColorVBO; // ============================================================================= // GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) { m_isPicking = m_rangepick = false; - m_camera = (GL::EFixedCamera) gl_camera; + m_camera = (EFixedCamera) gl_camera; m_drawToolTip = false; m_editMode = ESelectMode; m_rectdraw = false; m_panning = false; + m_compiler = new GLCompiler; setDocument (null); setDrawOnly (false); setMessageLog (null); m_width = m_height = -1; m_hoverpos = g_origin; - + m_compiler = new GLCompiler; m_toolTipTimer = new QTimer (this); m_toolTipTimer->setSingleShot (true); connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (slot_toolTipTimer())); @@ -157,6 +164,8 @@ for (CameraIcon& info : m_cameraIcons) delete info.img; + + delete m_compiler; } // ============================================================================= @@ -242,13 +251,46 @@ void GLRenderer::initializeGL() { setBackground(); - glLineWidth (gl_linethickness); - + glLineStipple (1, 0x6666); setAutoFillBackground (false); setMouseTracking (true); setFocusPolicy (Qt::WheelFocus); - compileAllObjects(); + compiler()->initialize(); + initializeAxes(); +} + +// ============================================================================= +// +void GLRenderer::initializeAxes() +{ + float axesdata[18]; + float colordata[18]; + memset (axesdata, 0, sizeof axesdata); + + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + axesdata[(i * 6) + j] = g_GLAxes[i].vert.getCoordinate (j); + axesdata[(i * 6) + 3 + j] = -g_GLAxes[i].vert.getCoordinate (j); + } + + for (int j = 0; j < 2; ++j) + { + colordata[(i * 6) + (j * 3) + 0] = g_GLAxes[i].col.red(); + colordata[(i * 6) + (j * 3) + 1] = g_GLAxes[i].col.green(); + colordata[(i * 6) + (j * 3) + 2] = g_GLAxes[i].col.blue(); + } + } + + glGenBuffers (1, &g_GLAxes_VBO); + glBindBuffer (GL_ARRAY_BUFFER, g_GLAxes_VBO); + glBufferData (GL_ARRAY_BUFFER, sizeof axesdata, axesdata, GL_STATIC_DRAW); + glGenBuffers (1, &g_GLAxes_ColorVBO); + glBindBuffer (GL_ARRAY_BUFFER, g_GLAxes_ColorVBO); + glBufferData (GL_ARRAY_BUFFER, sizeof colordata, colordata, GL_STATIC_DRAW); + glBindBuffer (GL_ARRAY_BUFFER, 0); } // ============================================================================= @@ -282,104 +324,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 / 0x10000) % 0x100, - g = (i / 0x100) % 0x100, - b = i % 0x100; - - qglColor (QColor (r, g, b)); - return; - } - - if ((list == BFCFrontList || list == BFCBackList) && - obj->type() != LDObject::ELine && - obj->type() != LDObject::ECondLine) - { - 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) - { - LDColor* col; - - if (!gl_blackedges && obj->parent() && (col = ::getColor (obj->parent()->color()))) - qcol = col->edgeColor; - else - qcol = (m_darkbg == false) ? Qt::black : Qt::white; - } - - 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 (int i : g_warnedColors) - if (obj->color() == i) - return; - - print ("%1: Unknown color %2!\n", __func__, obj->color()); - g_warnedColors << obj->color(); - return; - } - } - - int r = qcol.red(), - g = qcol.green(), - b = qcol.blue(), - a = qcol.alpha(); - - if (obj->topLevelParent()->isSelected()) - { - // Brighten it up for the select list. - QColor selcolor (gl_selectcolor); - r = (r + selcolor.red()) / 2; - g = (g + selcolor.green()) / 2; - b = (b + selcolor.blue()) / 2; - } - - glColor4f ( - ((double) r) / 255.0f, - ((double) g) / 255.0f, - ((double) b) / 255.0f, - ((double) a) / 255.0f); -} - -// ============================================================================= -// void GLRenderer::refresh() { update(); @@ -390,10 +334,9 @@ // void GLRenderer::hardRefresh() { - compileAllObjects(); + compiler()->compileDocument (getCurrentDocument()); refresh(); - - glLineWidth (gl_linethickness); + glLineWidth (gl_linethickness); // TODO: ...? } // ============================================================================= @@ -425,7 +368,7 @@ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable (GL_DEPTH_TEST); - if (m_camera != EFreeCamera) + if (camera() != EFreeCamera) { glMatrixMode (GL_PROJECTION); glPushMatrix(); @@ -434,7 +377,7 @@ glOrtho (-m_virtWidth, m_virtWidth, -m_virtHeight, m_virtHeight, -100.0f, 100.0f); glTranslatef (pan (X), pan (Y), 0.0f); - if (m_camera != EFrontCamera && m_camera != EBackCamera) + if (camera() != EFrontCamera && camera() != EBackCamera) { glRotatef (90.0f, g_FixedCameras[camera()].glrotate[0], g_FixedCameras[camera()].glrotate[1], @@ -442,7 +385,7 @@ } // Back camera needs to be handled differently - if (m_camera == GLRenderer::EBackCamera) + if (camera() == EBackCamera) { glRotatef (180.0f, 1.0f, 0.0f, 0.0f); glRotatef (180.0f, 0.0f, 0.0f, 1.0f); @@ -461,47 +404,86 @@ glRotatef (rot (Z), 0.0f, 0.0f, 1.0f); } - const GL::ListType list = (!isDrawOnly() && isPicking()) ? PickList : NormalList; - - if (gl_colorbfc && !isPicking() && !isDrawOnly()) - { - glEnable (GL_CULL_FACE); + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_COLOR_ARRAY); - for (LDObject* obj : document()->objects()) - { - if (obj->isHidden()) - continue; - - glCullFace (GL_BACK); - glCallList (obj->glLists[BFCFrontList]); - - glCullFace (GL_FRONT); - glCallList (obj->glLists[BFCBackList]); - } - - glDisable (GL_CULL_FACE); + if (isPicking()) + { + drawVBOs (VBOSF_Triangles, VBOCM_PickColors, GL_TRIANGLES); + drawVBOs (VBOSF_Quads, VBOCM_PickColors, GL_QUADS); + drawVBOs (VBOSF_Lines, VBOCM_PickColors, GL_LINES); + drawVBOs (VBOSF_CondLines, VBOCM_PickColors, GL_LINES); } else { - for (LDObject* obj : document()->objects()) + if (gl_colorbfc) + { + glEnable (GL_CULL_FACE); + glCullFace (GL_BACK); + drawVBOs (VBOSF_Triangles, VBOCM_BFCFrontColors, GL_TRIANGLES); + drawVBOs (VBOSF_Quads, VBOCM_BFCFrontColors, GL_QUADS); + glCullFace (GL_FRONT); + drawVBOs (VBOSF_Triangles, VBOCM_BFCBackColors, GL_TRIANGLES); + drawVBOs (VBOSF_Quads, VBOCM_BFCBackColors, GL_QUADS); + glDisable (GL_CULL_FACE); + } + else { - if (obj->isHidden()) - continue; + drawVBOs (VBOSF_Triangles, VBOCM_NormalColors, GL_TRIANGLES); + drawVBOs (VBOSF_Quads, VBOCM_NormalColors, GL_QUADS); + } + + drawVBOs (VBOSF_Lines, VBOCM_NormalColors, GL_LINES); + drawVBOs (VBOSF_CondLines, VBOCM_NormalColors, GL_LINES); - glCallList (obj->glLists[list]); + if (gl_axes) + { + glBindBuffer (GL_ARRAY_BUFFER, g_GLAxes_VBO); + glVertexPointer (3, GL_FLOAT, 0, NULL); + glBindBuffer (GL_ARRAY_BUFFER, g_GLAxes_VBO); + glColorPointer (3, GL_FLOAT, 0, NULL); + glDrawArrays (GL_LINES, 0, 6); + checkGLError(); } } - if (gl_axes && !isPicking() && !isDrawOnly()) - glCallList (m_axeslist); - glPopMatrix(); + glBindBuffer (GL_ARRAY_BUFFER, 0); + glDisableClientState (GL_VERTEX_ARRAY); + glDisableClientState (GL_COLOR_ARRAY); + checkGLError(); + glDisable (GL_CULL_FACE); glMatrixMode (GL_MODELVIEW); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); } // ============================================================================= // +void GLRenderer::drawVBOs (EVBOSurface surface, EVBOComplement colors, GLenum type) +{ + int surfacenum = m_compiler->vboNumber (surface, VBOCM_Surfaces); + int colornum = m_compiler->vboNumber (surface, colors); + + m_compiler->prepareVBO (surfacenum); + m_compiler->prepareVBO (colornum); + GLuint surfacevbo = m_compiler->vbo (surfacenum); + GLuint colorvbo = m_compiler->vbo (colornum); + GLsizei count = m_compiler->vboCount (surfacevbo); + + if (count > 0) + { + glBindBuffer (GL_ARRAY_BUFFER, surfacevbo); + glVertexPointer (3, GL_FLOAT, 0, null); + checkGLError(); + glBindBuffer (GL_ARRAY_BUFFER, colorvbo); + glColorPointer (4, GL_FLOAT, 0, null); + checkGLError(); + glDrawArrays (type, 0, count); + checkGLError(); + } +} + +// ============================================================================= // 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. // @@ -510,7 +492,7 @@ assert (camera() != EFreeCamera); Vertex pos3d; - const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; + const LDFixedCameraInfo* cam = &g_FixedCameras[camera()]; const Axis axisX = cam->axisX; const Axis axisY = cam->axisY; const int negXFac = cam->negX ? -1 : 1, @@ -547,7 +529,7 @@ QPoint GLRenderer::coordconv3_2 (const Vertex& pos3d) const { GLfloat m[16]; - const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; + const LDFixedCameraInfo* cam = &g_FixedCameras[camera()]; const Axis axisX = cam->axisX; const Axis axisY = cam->axisY; const int negXFac = cam->negX ? -1 : 1, @@ -593,15 +575,27 @@ if (isDrawOnly()) return; - if (m_camera != EFreeCamera && !isPicking()) +#ifndef RELEASE + if (isPicking() == false) + { + QString text = format ("Rotation: (%1, %2, %3)\nPanning: (%4, %5), Zoom: %6", + rot(X), rot(Y), rot(Z), pan(X), pan(Y), zoom()); + QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text); + + paint.drawText ((width() - textSize.width()) / 2, height() - textSize.height(), textSize.width(), + textSize.height(), Qt::AlignCenter, text); + } +#endif + + if (camera() != EFreeCamera && !isPicking()) { // Paint the overlay image if we have one - const LDGLOverlay& overlay = currentDocumentData().overlays[m_camera]; + const LDGLOverlay& overlay = currentDocumentData().overlays[camera()]; if (overlay.img != null) { - QPoint v0 = coordconv3_2 (currentDocumentData().overlays[m_camera].v0), - v1 = coordconv3_2 (currentDocumentData().overlays[m_camera].v1); + QPoint v0 = coordconv3_2 (currentDocumentData().overlays[camera()].v0), + v1 = coordconv3_2 (currentDocumentData().overlays[camera()].v1); QRect targRect (v0.x(), v0.y(), abs (v1.x() - v0.x()), abs (v1.y() - v0.y())), srcRect (0, 0, overlay.img->width(), overlay.img->height()); @@ -894,133 +888,6 @@ // ============================================================================= // -void GLRenderer::compileAllObjects() -{ - if (!document()) - return; - - // Compiling all is a big job, use a busy cursor - setCursor (Qt::BusyCursor); - - m_knownVerts.clear(); - - for (LDObject* obj : document()->objects()) - compileObject (obj); - - // Compile axes - glDeleteLists (m_axeslist, 1); - m_axeslist = glGenLists (1); - glNewList (m_axeslist, GL_COMPILE); - glBegin (GL_LINES); - - for (const LDGLAxis& 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 int numverts = (obj->type() != LDObject::ECondLine) ? obj->vertices() : 2; - - if (g_glInvert == false) - for (int i = 0; i < numverts; ++i) - compileVertex (obj->vertex (i)); - else - for (int i = numverts - 1; i >= 0; --i) - compileVertex (obj->vertex (i)); - - glEnd(); -} - -// ============================================================================= -// -void GLRenderer::compileList (LDObject* obj, const GLRenderer::ListType list) -{ - setObjectColor (obj, list); - - switch (obj->type()) - { - case LDObject::ELine: - { - compileSubObject (obj, GL_LINES); - } break; - - case LDObject::ECondLine: - { - // 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::ETriangle: - { - compileSubObject (obj, GL_TRIANGLES); - } break; - - case LDObject::EQuad: - { - compileSubObject (obj, GL_QUADS); - } break; - - case LDObject::ESubfile: - { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - LDObjectList objs; - - objs = ref->inlineContents (LDSubfile::DeepCacheInline | LDSubfile::RendererInline); - bool oldinvert = g_glInvert; - - if (ref->transform().getDeterminant() < 0) - g_glInvert = !g_glInvert; - - LDObject* prev = ref->previous(); - - if (prev && prev->type() == LDObject::EBFC && static_cast<LDBFC*> (prev)->statement() == LDBFC::InvertNext) - g_glInvert = !g_glInvert; - - for (LDObject* obj : objs) - { - compileList (obj, list); - obj->destroy(); - } - - g_glInvert = oldinvert; - } break; - - default: - break; - } -} - -// ============================================================================= -// -void GLRenderer::compileVertex (const Vertex& vrt) -{ - glVertex3d (vrt[X], -vrt[Y], -vrt[Z]); -} - -// ============================================================================= -// void GLRenderer::clampAngle (double& angle) const { while (angle < 0) @@ -1375,13 +1242,14 @@ { qint32 idx = (*(pixelptr + 0) * 0x10000) + - (*(pixelptr + 1) * 0x00100) + - (*(pixelptr + 2) * 0x00001); + (*(pixelptr + 1) * 0x100) + + *(pixelptr + 2); pixelptr += 4; if (idx == 0xFFFFFF) continue; // White is background; skip + dprint ("id: %1\n", idx); LDObject* obj = LDObject::fromID (idx); assert (obj != null); @@ -1441,7 +1309,7 @@ case ECircleMode: { // Cannot draw into the free camera - use top instead. - if (m_camera == EFreeCamera) + if (camera() == EFreeCamera) setCamera (ETopCamera); // Disable the context menu - we need the right mouse button @@ -1711,7 +1579,7 @@ // void GLRenderer::getRelativeAxes (Axis& relX, Axis& relY) const { - const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; + const LDFixedCameraInfo* cam = &g_FixedCameras[camera()]; relX = cam->axisX; relY = cam->axisY; } @@ -1726,10 +1594,11 @@ { for (int i = 0; i < obj->vertices(); ++i) verts << obj->vertex (i); - } elif (obj->type() == LDObject::ESubfile) + } + elif (obj->type() == LDObject::ESubfile) { LDSubfile* ref = static_cast<LDSubfile*> (obj); - LDObjectList objs = ref->inlineContents (LDSubfile::DeepCacheInline); + LDObjectList objs = ref->inlineContents (true, false); for (LDObject* obj : objs) { @@ -1745,32 +1614,27 @@ // void GLRenderer::compileObject (LDObject* obj) { - deleteLists (obj); - - for (const GL::ListType listType : g_glListTypes) - { - if (isDrawOnly() && listType != GL::NormalList) - continue; - - GLuint list = glGenLists (1); - glNewList (list, GL_COMPILE); - - obj->glLists[listType] = list; - compileList (obj, listType); - - glEndList(); - } + compiler()->stageForCompilation (obj); // Mark in known vertices of this object + /* QList<Vertex> verts = getVertices (obj); m_knownVerts << verts; removeDuplicates (m_knownVerts); + */ obj->setGLInit (true); } // ============================================================================= // +void GLRenderer::forgetObject (LDObject* obj) +{ + compiler()->dropObject (obj); +} + +// ============================================================================= +// uchar* GLRenderer::getScreencap (int& w, int& h) { w = m_width; @@ -1794,7 +1658,7 @@ // We come here if the cursor has stayed in one place for longer than a // a second. Check if we're holding it over a camera icon - if so, draw // a tooltip. -for (CameraIcon & icon : m_cameraIcons) + for (CameraIcon & icon : m_cameraIcons) { if (icon.destRect.contains (m_pos)) { @@ -1808,24 +1672,10 @@ // ============================================================================= // -void GLRenderer::deleteLists (LDObject* obj) -{ - // Delete the lists but only if they have been initialized - if (!obj->isGLInit()) - return; - - for (const GL::ListType listType : g_glListTypes) - glDeleteLists (obj->glLists[listType], 1); - - obj->setGLInit (false); -} - -// ============================================================================= -// Axis GLRenderer::getCameraAxis (bool y, GLRenderer::EFixedCamera camid) { if (camid == (GL::EFixedCamera) - 1) - camid = m_camera; + camid = camera(); const LDFixedCameraInfo* cam = &g_FixedCameras[camid]; return (y) ? cam->axisY : cam->axisX; @@ -1841,6 +1691,7 @@ if (img->isNull()) { critical (tr ("Failed to load overlay image!")); + currentDocumentData().overlays[cam].invalid = true; delete img; return false; } @@ -1853,6 +1704,7 @@ info.ox = x; info.oy = y; info.img = img; + info.invalid = false; if (info.lw == 0) info.lw = (info.lh * img->width()) / img->height(); @@ -1872,11 +1724,11 @@ // Set alpha of all pixels to 0.5 for (long i = 0; i < img->width(); ++i) - for (long j = 0; j < img->height(); ++j) - { - uint32 pixel = img->pixel (i, j); - img->setPixel (i, j, 0x80000000 | (pixel & 0x00FFFFFF)); - } + for (long j = 0; j < img->height(); ++j) + { + uint32 pixel = img->pixel (i, j); + img->setPixel (i, j, 0x80000000 | (pixel & 0x00FFFFFF)); + } updateOverlayObjects(); return true; @@ -1940,9 +1792,12 @@ // void GLRenderer::zoomToFit() { + print ("zooming %1 to fit..\n", camera()); + zoom() = 30.0f; + if (document() == null || m_width == -1 || m_height == -1) { - zoom() = 30.0f; + print ("document is invalid!\n"); return; } @@ -1984,22 +1839,23 @@ if (imgdata[i] != white || imgdata[((h - 1) * w) + i] != white) { filled = true; - goto endOfLoop; + break; } } // Left and right edges - for (int i = 0; i < h; ++i) + if (filled == false) { - if (imgdata[i * w] != white || imgdata[(i * w) + w - 1] != white) + for (int i = 0; i < h; ++i) { - filled = true; - goto endOfLoop; + if (imgdata[i * w] != white || imgdata[(i * w) + w - 1] != white) + { + filled = true; + break; + } } } -endOfLoop: - delete[] cap; if (firstrun) @@ -2033,6 +1889,7 @@ setBackground(); setPicking (false); + print ("zoom to fit done.\n"); } // ============================================================================= @@ -2140,7 +1997,7 @@ delete meta.img; meta.img = null; } - elif (ovlobj && (!meta.img || meta.fname != ovlobj->fileName())) + elif (ovlobj && (meta.img == null || meta.fname != ovlobj->fileName()) && meta.invalid == false) setupOverlay (cam, ovlobj->fileName(), ovlobj->x(), ovlobj->y(), ovlobj->width(), ovlobj->height()); } @@ -2158,7 +2015,7 @@ LDGLOverlay& meta = currentDocumentData().overlays[cam]; LDOverlay* ovlobj = findOverlayObject (cam); - if (!meta.img && ovlobj) + if (meta.img == null && ovlobj != null) { // If this is the last overlay image, we need to remove the empty space after it as well. LDObject* nextobj = ovlobj->next(); @@ -2169,7 +2026,8 @@ // If the overlay object was there and the overlay itself is // not, remove the object. ovlobj->destroy(); - } elif (meta.img && !ovlobj) + } + elif (meta.img != null && ovlobj == null) { // Inverse case: image is there but the overlay object is // not, thus create the object.
--- a/src/glRenderer.h Tue Apr 08 11:07:25 2014 +0300 +++ b/src/glRenderer.h Tue Apr 08 11:07:47 2014 +0300 @@ -22,7 +22,9 @@ #include "macros.h" #include "ldObject.h" #include "ldDocument.h" +#include "glShared.h" +class GLCompiler; class MessageManager; class QDialogButtonBox; class RadioGroup; @@ -49,6 +51,7 @@ lh; QString fname; QImage* img; + bool invalid; }; struct LDFixedCameraInfo @@ -77,12 +80,23 @@ LDGLData() { - for (int i = 0; i < 6; ++i) + for (int i = 0; i < 7; ++i) { - overlays[i].img = null; - depthValues[i] = 0.0f; + if (i < 6) + { + overlays[i].img = null; + overlays[i].invalid = false; + depthValues[i] = 0.0f; + } + + zoom[i] = 30.0; + panX[i] = 0.0; + panY[i] = 0.0; } + rotX = 0; + rotY = 0; + rotZ = 0; init = false; } }; @@ -119,10 +133,10 @@ // and Qt doesn't like that. struct CameraIcon { - QPixmap* img; - QRect srcRect, - destRect, - selRect; + QPixmap* img; + QRect srcRect, + destRect, + selRect; EFixedCamera cam; }; @@ -132,6 +146,7 @@ PROPERTY (private, bool, isPicking, setPicking, STOCK_WRITE) PROPERTY (public, LDDocument*, document, setDocument, CUSTOM_WRITE) PROPERTY (public, EditMode, editMode, setEditMode, CUSTOM_WRITE) + PROPERTY (private, GLCompiler*, compiler, setCompiler, STOCK_WRITE) public: GLRenderer (QWidget* parent = null); @@ -144,13 +159,12 @@ void clearOverlay(); void compileObject (LDObject* obj); - void compileAllObjects(); void drawGLScene(); void endDraw (bool accept); + void forgetObject (LDObject* obj); Axis getCameraAxis (bool y, EFixedCamera camid = (EFixedCamera) - 1); const char* getCameraName() const; double getDepthValue() const; - QColor getMainColor(); LDGLOverlay& getOverlay (int newcam); uchar* getScreencap (int& w, int& h); void hardRefresh(); @@ -169,6 +183,7 @@ void zoomAllToFit(); static void deleteLists (LDObject* obj); + static QColor getMainColor(); protected: void contextMenuEvent (QContextMenuEvent* ev); @@ -243,6 +258,12 @@ // Convert a 2D point to a 3D point Vertex coordconv2_3 (const QPoint& pos2d, bool snap) const; + // Draw a VBO array + void drawVBOs (EVBOSurface surface, EVBOComplement colors, GLenum type); + + // Determine which color to draw text with + QColor getTextPen() const; + // Convert a 3D point to a 2D point QPoint coordconv3_2 (const Vertex& pos3d) const; @@ -294,6 +315,7 @@ private slots: void slot_toolTipTimer(); + void initializeAxes(); }; // Alias for short namespaces
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/glShared.h Tue Apr 08 11:07:47 2014 +0300 @@ -0,0 +1,73 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013, 2014 Santeri Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LDFORGE_GLSHARED_H +#define LDFORGE_GLSHARED_H +#include <QString> + +class LDObject; + +struct LDPolygon +{ + char num; + Vertex vertices[4]; + int id; + int color; + QString origin; + + inline int numVertices() const + { + return (num == 5) ? 4 : num; + } +}; + +enum EVBOSurface +{ + VBOSF_Lines, + VBOSF_Triangles, + VBOSF_Quads, + VBOSF_CondLines, + VBOSF_NumSurfaces +}; + +enum EVBOComplement +{ + VBOCM_Surfaces, + VBOCM_NormalColors, + VBOCM_PickColors, + VBOCM_BFCFrontColors, + VBOCM_BFCBackColors, + VBOCM_NumComplements +}; + +// KDevelop doesn't seem to understand some VBO stuff +#ifdef IN_IDE_PARSER +using GLint = int; +using GLsizei = int; +using GLenum = unsigned int; +using GLuint = unsigned int; +void glBindBuffer (GLenum, GLuint); +void glGenBuffers (GLuint, GLuint*); +void glDeleteBuffers (GLuint, GLuint*); +void glBufferData (GLuint, GLuint, void*, GLuint); +void glBufferSubData (GLenum, GLint, GLsizei, void*); +#endif + +static const int g_numVBOs = VBOSF_NumSurfaces * VBOCM_NumComplements; + +#endif // LDFORGE_GLSHARED_H \ No newline at end of file
--- a/src/ldDocument.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/ldDocument.cc Tue Apr 08 11:07:47 2014 +0300 @@ -19,7 +19,9 @@ #include <QMessageBox> #include <QFileDialog> #include <QDir> +#include <QTime> #include <QApplication> + #include "main.h" #include "configuration.h" #include "ldDocument.h" @@ -29,6 +31,7 @@ #include "dialogs.h" #include "glRenderer.h" #include "misc/invokeLater.h" +#include "glCompiler.h" cfg (String, io_ldpath, ""); cfg (List, io_recentfiles, {}); @@ -128,6 +131,7 @@ setTabIndex (-1); setHistory (new History); history()->setDocument (this); + m_needsGLReInit = true; } // ============================================================================= @@ -144,11 +148,7 @@ for (LDObject* obj : objects()) obj->destroy(); - // Clear the cache as well - for (LDObject* obj : cache()) - obj->destroy(); - - delete m_history; + delete history(); delete m_gldata; // If we just closed the current file, we need to set the current @@ -1073,6 +1073,7 @@ #endif obj->setDocument (this); + g_win->R()->compileObject (obj); return getObjectCount() - 1; } @@ -1092,6 +1093,7 @@ history()->add (new AddHistory (pos, obj)); m_objects.insert (pos, obj); obj->setDocument (this); + g_win->R()->compileObject (obj); #ifdef DEBUG if (!isImplicit()) @@ -1142,6 +1144,7 @@ m_objects[idx]->unselect(); m_objects[idx]->setDocument (null); obj->setDocument (this); + g_win->R()->compileObject (obj); m_objects[idx] = obj; } @@ -1199,81 +1202,76 @@ // ============================================================================= // -LDObjectList LDDocument::inlineContents (LDSubfile::InlineFlags flags) +void LDDocument::initializeGLData() +{ + print (getDisplayName() + ": Initializing GL data"); + LDObjectList objs = inlineContents (true, true); + + for (LDObject* obj : objs) + { + assert (obj->type() != LDObject::ESubfile); + LDPolygon* data = obj->getPolygon(); + + if (data != null) + { + m_polygonData << *data; + delete data; + } + + obj->destroy(); + } + + m_needsGLReInit = false; +} + +// ============================================================================= +// +QList<LDPolygon> LDDocument::inlinePolygons() +{ + if (m_needsGLReInit == true) + initializeGLData(); + + return polygonData(); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +LDObjectList LDDocument::inlineContents (bool deep, bool renderinline) { // Possibly substitute with logoed studs: // stud.dat -> stud-logo.dat // stud2.dat -> stud-logo2.dat - if (gl_logostuds && (flags & LDSubfile::RendererInline)) + if (gl_logostuds && renderinline) { // Ensure logoed studs are loaded first loadLogoedStuds(); - if (name() == "stud.dat" && g_logoedStud) - return g_logoedStud->inlineContents (flags); - elif (name() == "stud2.dat" && g_logoedStud2) - return g_logoedStud2->inlineContents (flags); + if (name() == "stud.dat" && g_logoedStud != null) + return g_logoedStud->inlineContents (deep, renderinline); + elif (name() == "stud2.dat" && g_logoedStud2 != null) + return g_logoedStud2->inlineContents (deep, renderinline); } LDObjectList objs, objcache; - bool deep = flags & LDSubfile::DeepInline, - doCache = flags & LDSubfile::CacheInline; - - if (m_needsCache) - { - m_cache.clear(); - doCache = true; - } - - // If we have this cached, just create a copy of that - if (deep && cache().isEmpty() == false) + for (LDObject* obj : objects()) { - for (LDObject* obj : cache()) - objs << obj->createCopy(); - } - else - { - if (!deep) - doCache = false; - - for (LDObject* obj : objects()) - { - // Skip those without scemantic meaning - if (!obj->isScemantic()) - continue; + // Skip those without scemantic meaning + if (!obj->isScemantic()) + continue; - // Got another sub-file reference, inline it if we're deep-inlining. If not, - // just add it into the objects normally. Also, we only cache immediate - // subfiles and this is not one. Yay, recursion! - if (deep && obj->type() == LDObject::ESubfile) - { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - - // We only want to cache immediate subfiles, so shed the caching - // flag when recursing deeper in hierarchy. - LDObjectList otherobjs = ref->inlineContents (flags & ~ (LDSubfile::CacheInline)); + // Got another sub-file reference, inline it if we're deep-inlining. If not, + // just add it into the objects normally. Yay, recursion! + if (deep == true && obj->type() == LDObject::ESubfile) + { + LDSubfile* ref = static_cast<LDSubfile*> (obj); + LDObjectList otherobjs = ref->inlineContents (deep, renderinline); - for (LDObject* otherobj : otherobjs) - { - // Cache this object, if desired - if (doCache) - objcache << otherobj->createCopy(); - - objs << otherobj; - } - } - else - { - if (doCache) - objcache << obj->createCopy(); - - objs << obj->createCopy(); - } + for (LDObject* otherobj : otherobjs) + objs << otherobj; } - - if (doCache) - setCache (objcache); + else + objs << obj->createCopy(); } return objs; @@ -1309,6 +1307,7 @@ g_win->updateTitle(); g_win->R()->setDocument (f); g_win->R()->repaint(); + g_win->R()->compiler()->needMerge(); print ("Changed file to %1", f->getDisplayName()); } }
--- a/src/ldDocument.h Tue Apr 08 11:07:25 2014 +0300 +++ b/src/ldDocument.h Tue Apr 08 11:07:47 2014 +0300 @@ -21,11 +21,13 @@ #include "main.h" #include "ldObject.h" #include "editHistory.h" +#include "glShared.h" class History; class OpenProgressDialog; class LDDocumentPointer; struct LDGLData; +class GLCompiler; namespace LDPaths { @@ -66,6 +68,7 @@ PROPERTY (public, bool, isImplicit, setImplicit, STOCK_WRITE) PROPERTY (public, long, savePosition, setSavePosition, STOCK_WRITE) PROPERTY (public, int, tabIndex, setTabIndex, STOCK_WRITE) + PROPERTY (public, QList<LDPolygon>, polygonData, setPolygonData, STOCK_WRITE) public: LDDocument(); @@ -78,7 +81,8 @@ QString getDisplayName(); const LDObjectList& getSelection() const; bool hasUnsavedChanges() const; // Does this document have unsaved changes? - LDObjectList inlineContents (LDSubfile::InlineFlags flags); + void initializeGLData(); + LDObjectList inlineContents (bool deep, bool renderinline); void insertObj (int pos, LDObject* obj); int getObjectCount() const; LDObject* getObject (int pos) const; @@ -88,6 +92,7 @@ void setObject (int idx, LDObject* obj); void addReference (LDDocumentPointer* ptr); void removeReference (LDDocumentPointer* ptr); + QList<LDPolygon> inlinePolygons(); inline LDDocument& operator<< (LDObject* obj) { @@ -145,9 +150,9 @@ LDObjectList m_sel; LDGLData* m_gldata; - // If set to true, next inline of this document discards the cache and - // re-builds it. - bool m_needsCache; + // If set to true, next polygon inline of this document discards the + // stored polygon data and re-builds it. + bool m_needsGLReInit; static LDDocument* m_curdoc; };
--- a/src/ldObject.cc Tue Apr 08 11:07:25 2014 +0300 +++ b/src/ldObject.cc Tue Apr 08 11:07:47 2014 +0300 @@ -16,6 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + #include "main.h" #include "ldObject.h" #include "ldDocument.h" @@ -24,6 +25,7 @@ #include "editHistory.h" #include "glRenderer.h" #include "colors.h" +#include "glCompiler.h" cfg (String, ld_defaultname, ""); cfg (String, ld_defaultuser, ""); @@ -269,7 +271,7 @@ document()->forgetObject (this); // Delete the GL lists - GL::deleteLists (this); + g_win->R()->forgetObject (this); // Remove this object from the list of LDObjects g_LDObjects.removeOne (this); @@ -318,10 +320,10 @@ } // ============================================================================= -// -LDObjectList LDSubfile::inlineContents (InlineFlags flags) +// ----------------------------------------------------------------------------- +LDObjectList LDSubfile::inlineContents (bool deep, bool render) { - LDObjectList objs = fileInfo()->inlineContents (flags); + LDObjectList objs = fileInfo()->inlineContents (deep, render); // Transform the objects for (LDObject* obj : objs) @@ -336,6 +338,45 @@ // ============================================================================= // +LDPolygon* LDObject::getPolygon() +{ + Type ot = type(); + int num = + (ot == LDObject::ELine) ? 2 : + (ot == LDObject::ETriangle) ? 3 : + (ot == LDObject::EQuad) ? 4 : + (ot == LDObject::ECondLine) ? 5 : + 0; + if (num == 0) + return null; + + LDPolygon* data = new LDPolygon; + data->id = id(); + data->num = num; + data->color = color(); + data->origin = origin(); + + for (int i = 0; i < data->numVertices(); ++i) + data->vertices[i] = vertex (i); + + return data; +} + +// ============================================================================= +// +QList<LDPolygon> LDSubfile::inlinePolygons() +{ + QList<LDPolygon> data = fileInfo()->inlinePolygons(); + + for (LDPolygon& entry : data) + for (int i = 0; i < entry.numVertices(); ++i) + entry.vertices[i].transform (transform(), position()); + + return data; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- long LDObject::lineNumber() const { assert (document() != null); @@ -646,6 +687,7 @@ void LDOverlay::invert() {} // ============================================================================= +// // Hook the set accessors of certain properties to this changeProperty function. // It takes care of history management so we can capture low-level changes, this // makes history stuff work out of the box. @@ -657,14 +699,17 @@ if (*ptr == val) return; - if (obj->document() && (idx = obj->lineNumber()) != -1) + if (obj->document() != null && (idx = obj->lineNumber()) != -1) { QString before = obj->asText(); *ptr = val; QString after = obj->asText(); if (before != after) + { obj->document()->addToHistory (new EditHistory (idx, before, after)); + g_win->R()->compileObject (obj); + } } else *ptr = val; @@ -821,5 +866,28 @@ */ LDObject* copy = parseLine (asText()); + + if (origin().isEmpty() == false) + copy->setOrigin (origin()); + elif (document() != null) + copy->setOrigin (document()->getDisplayName() + ":" + QString::number (lineNumber())); + return copy; -} \ No newline at end of file +} + +// ============================================================================= +// +void LDSubfile::setFileInfo (const LDDocumentPointer& a) +{ + m_fileInfo = a; + + // If it's an immediate subfile reference (i.e. this subfile belongs in an + // explicit file), we need to pre-compile the GL polygons for the document + // if they don't exist already. + if (a != null && + a->isImplicit() == false && + a->polygonData().isEmpty()) + { + a->initializeGLData(); + } +};
--- a/src/ldObject.h Tue Apr 08 11:07:25 2014 +0300 +++ b/src/ldObject.h Tue Apr 08 11:07:47 2014 +0300 @@ -20,6 +20,7 @@ #include "main.h" #include "basics.h" #include "misc/documentPointer.h" +#include "glShared.h" #define LDOBJ(T) \ protected: \ @@ -72,6 +73,7 @@ PROPERTY (private, int, id, setID, STOCK_WRITE) PROPERTY (public, int, color, setColor, CUSTOM_WRITE) PROPERTY (public, bool, isGLInit, setGLInit, STOCK_WRITE) + PROPERTY (public, QString, origin, setOrigin, STOCK_WRITE) public: // Object type codes. @@ -172,6 +174,7 @@ // Get a description of a list of LDObjects static QString describeObjects (const LDObjectList& objs); static LDObject* fromID (int id); + LDPolygon* getPolygon(); // TODO: make these private! // OpenGL list for this object @@ -381,7 +384,7 @@ LDOBJ_COLORED LDOBJ_SCEMANTIC LDOBJ_HAS_MATRIX - PROPERTY (public, LDDocumentPointer, fileInfo, setFileInfo, STOCK_WRITE) + PROPERTY (public, LDDocumentPointer, fileInfo, setFileInfo, CUSTOM_WRITE) public: enum InlineFlag @@ -401,7 +404,8 @@ // Inlines this subfile. Note that return type is an array of heap-allocated // LDObject copies, they must be deleted manually. - LDObjectList inlineContents (InlineFlags flags); + LDObjectList inlineContents (bool deep, bool render); + QList<LDPolygon> inlinePolygons(); protected: ~LDSubfile();
--- a/src/macros.h Tue Apr 08 11:07:25 2014 +0300 +++ b/src/macros.h Tue Apr 08 11:07:47 2014 +0300 @@ -17,6 +17,7 @@ */ #pragma once +#include <type_traits> #ifndef __GNUC__ # define __attribute__(X) @@ -24,6 +25,20 @@ // ============================================================================= // +#define countof(A) (safeCountOf<std::is_array<decltype(A)>::value, (sizeof A / sizeof *A)>()) + +template<bool isArray, size_t elems> +inline constexpr int safeCountOf() __attribute__ ((always_inline)); + +template<bool isArray, size_t elems> +inline constexpr int safeCountOf() +{ + static_assert (isArray, "parameter to countof must be an array"); + return elems; +} + +// ============================================================================= +// #define PROPERTY(ACCESS, TYPE, READ, WRITE, WRITETYPE) \ private: \ TYPE m_##READ; \