diff -r 9374fea8f77f -r f1b8cb53d2a2 gldraw.cpp
--- a/gldraw.cpp Wed May 08 14:57:48 2013 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1214 +0,0 @@
-/*
- * LDForge: LDraw parts authoring CAD
- * Copyright (C) 2013 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 .
- */
-
-#include
-#include
-#include
-#include "common.h"
-#include "config.h"
-#include "file.h"
-#include "gldraw.h"
-#include "bbox.h"
-#include "colors.h"
-#include "gui.h"
-#include "misc.h"
-#include "history.h"
-
-static double g_objOffset[3];
-
-static short g_pulseTick = 0;
-static const short g_numPulseTicks = 8;
-static const short g_pulseInterval = 65;
-
-static const struct staticCameraMeta {
- const char glrotate[3];
- const Axis axisX, axisY;
- const bool negX, negY;
-} g_staticCameras[6] = {
- { { 1, 0, 0 }, X, Z, false, false },
- { { 0, 0, 0 }, X, Y, false, true },
- { { 0, 1, 0 }, Z, Y, true, true },
- { { -1, 0, 0 }, X, Z, false, true },
- { { 0, 0, 0 }, X, Y, true, true },
- { { 0, -1, 0 }, Z, Y, false, true },
-};
-
-cfg (str, gl_bgcolor, "#CCCCD9");
-cfg (str, gl_maincolor, "#707078");
-cfg (float, gl_maincolor_alpha, 1.0);
-cfg (int, gl_linethickness, 2);
-cfg (bool, gl_colorbfc, true);
-cfg (bool, gl_selflash, false);
-cfg (int, gl_camera, GLRenderer::Free);
-cfg (bool, gl_blackedges, true);
-cfg (bool, gl_axes, false);
-
-// CameraIcon::img is a heap-allocated QPixmap because otherwise it gets
-// initialized before program gets to main() and constructs a QApplication
-// and Qt doesn't like that.
-struct CameraIcon {
- QPixmap* img;
- QRect srcRect, destRect, selRect;
- GLRenderer::Camera cam;
-} g_CameraIcons[7];
-
-const char* g_CameraNames[7] = { "Top", "Front", "Left", "Bottom", "Back", "Right", "Free" };
-
-const GLRenderer::Camera g_Cameras[7] = {
- GLRenderer::Top,
- GLRenderer::Front,
- GLRenderer::Left,
- GLRenderer::Bottom,
- GLRenderer::Back,
- GLRenderer::Right,
- GLRenderer::Free
-};
-
-const struct GLAxis {
- const QColor col;
- const vertex vert;
-} g_GLAxes[3] = {
- { QColor (255, 0, 0), vertex (10000, 0, 0) },
- { QColor (128, 192, 0), vertex (0, 10000, 0) },
- { QColor (0, 160, 192), vertex (0, 0, 10000) },
-};
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) {
- resetAngles ();
- m_picking = m_rangepick = false;
- m_camera = (GLRenderer::Camera) gl_camera.value;
- m_drawToolTip = false;
- m_planeDraw = false;
-
- m_pulseTimer = new QTimer (this);
- connect (m_pulseTimer, SIGNAL (timeout ()), this, SLOT (slot_timerUpdate ()));
-
- m_toolTipTimer = new QTimer (this);
- m_toolTipTimer->setSingleShot (true);
- connect (m_toolTipTimer, SIGNAL (timeout ()), this, SLOT (slot_toolTipTimer ()));
-
- m_thickBorderPen = QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
- m_thinBorderPen = m_thickBorderPen;
- m_thinBorderPen.setWidth (1);
-
- // Init camera icons
- for (const GLRenderer::Camera cam : g_Cameras) {
- str iconname;
- iconname.format ("camera-%s", str (g_CameraNames[cam]).tolower ().chars ());
-
- CameraIcon* info = &g_CameraIcons[cam];
- info->img = new QPixmap (getIcon (iconname));
- info->cam = cam;
- }
-
- calcCameraIconRects ();
-}
-
-// =============================================================================
-GLRenderer::~GLRenderer() {
- for (CameraIcon& info : g_CameraIcons)
- delete info.img;
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::calcCameraIconRects () {
- ushort i = 0;
-
- for (CameraIcon& info : g_CameraIcons) {
- const long x1 = (m_width - (info.cam != Free ? 48 : 16)) + ((i % 3) * 16) - 1,
- y1 = ((i / 3) * 16) + 1;
-
- info.srcRect = QRect (0, 0, 16, 16);
- info.destRect = QRect (x1, y1, 16, 16);
- info.selRect = QRect (info.destRect.x (), info.destRect.y (),
- info.destRect.width () + 1, info.destRect.height () + 1);
- ++i;
- }
-}
-
-// =============================================================================
-void GLRenderer::resetAngles () {
- m_rotX = 30.0f;
- m_rotY = 325.f;
- m_panX = m_panY = m_rotZ = 0.0f;
-
- // Set the default zoom based on the bounding box
- m_zoom = g_BBox.size () * 6;
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::initializeGL () {
- setBackground ();
-
- glEnable (GL_POLYGON_OFFSET_FILL);
- glPolygonOffset (1.0f, 1.0f);
-
- glEnable (GL_DEPTH_TEST);
- glShadeModel (GL_SMOOTH);
- glEnable (GL_MULTISAMPLE);
-
- glEnable (GL_BLEND);
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- glEnable (GL_LINE_SMOOTH);
- glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
-
- glLineWidth (gl_linethickness);
-
- setAutoFillBackground (false);
- setMouseTracking (true);
- setFocusPolicy (Qt::WheelFocus);
- compileObjects ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-QColor GLRenderer::getMainColor () {
- QColor col (gl_maincolor.value.chars());
-
- if (!col.isValid ())
- return QColor (0, 0, 0);
-
- col.setAlpha (gl_maincolor_alpha * 255.f);
- return col;
-}
-
-// -----------------------------------------------------------------------------
-void GLRenderer::setBackground () {
- QColor col (gl_bgcolor.value.chars());
-
- if (!col.isValid ())
- return;
-
- m_darkbg = luma (col) < 80;
-
- col.setAlpha (255);
- qglClearColor (col);
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-static vector g_daWarnedColors;
-void GLRenderer::setObjectColor (LDObject* obj) {
- QColor qcol;
-
- if (!obj->isColored())
- return;
-
- if (m_picking) {
- // Make the color by the object's index color if we're picking, so we can
- // make the index from the color we get from the picking results.
- long i = obj->getIndex (g_curfile);
-
- // If we couldn't find the index, this object must not be from this file,
- // therefore it must be an object inlined from a subfile reference or
- // decomposed from a radial. Find the top level parent object and use
- // its index.
- if (i == -1)
- i = obj->topLevelParent ()->getIndex (g_curfile);
-
- // We should have the index now.
- assert (i != -1);
-
- // 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, 255));
- return;
- }
-
-#if 0
- if (gl_colorbfc &&
- obj->getType () != LDObject::Line &&
- obj->getType () != LDObject::CondLine)
- {
- if (bBackSide)
- glColor4f (0.9f, 0.0f, 0.0f, 1.0f);
- else
- glColor4f (0.0f, 0.8f, 0.0f, 1.0f);
- return;
- }
-#endif
-
- if (obj->dColor == maincolor)
- qcol = getMainColor ();
- else {
- color* col = getColor (obj->dColor);
- qcol = col->qColor;
- }
-
- if (obj->dColor == edgecolor) {
- qcol = Qt::black;
- color* col;
-
- if (!gl_blackedges && obj->parent != null && (col = getColor (obj->parent->dColor)) != null)
- qcol = col->qEdge;
- }
-
- if (qcol.isValid () == false) {
- // The color was unknown. Use main color to make the object at least
- // not appear pitch-black.
- if (obj->dColor != edgecolor)
- qcol = getMainColor ();
-
- // Warn about the unknown colors, but only once.
- for (short i : g_daWarnedColors)
- if (obj->dColor == i)
- return;
-
- printf ("%s: Unknown color %d!\n", __func__, obj->dColor);
- g_daWarnedColors.push_back (obj->dColor);
- return;
- }
-
- long r = qcol.red (),
- g = qcol.green (),
- b = qcol.blue (),
- a = qcol.alpha ();
-
- // If it's selected, brighten it up, also pulse flash it if desired.
- if (g_win->isSelected (obj)) {
- short tick, numTicks;
-
- if (gl_selflash) {
- tick = (g_pulseTick < (g_numPulseTicks / 2)) ? g_pulseTick : (g_numPulseTicks - g_pulseTick);
- numTicks = g_numPulseTicks;
- } else {
- tick = 2;
- numTicks = 5;
- }
-
- const long add = ((tick * 128) / numTicks);
- r = min (r + add, 255l);
- g = min (g + add, 255l);
- b = min (b + add, 255l);
-
- // a = 255;
- }
-
- glColor4f (
- ((double) r) / 255.0f,
- ((double) g) / 255.0f,
- ((double) b) / 255.0f,
- ((double) a) / 255.0f);
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::refresh () {
- update ();
- swapBuffers ();
-}
-
-// =============================================================================
-void GLRenderer::hardRefresh () {
- compileObjects ();
- refresh ();
-
- glLineWidth (gl_linethickness);
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::resizeGL (int w, int h) {
- m_width = w;
- m_height = h;
-
- calcCameraIconRects ();
-
- glViewport (0, 0, w, h);
- glMatrixMode (GL_PROJECTION);
- glLoadIdentity ();
- gluPerspective (45.0f, (double)w / (double)h, 1.0f, 10000.0f);
- glMatrixMode (GL_MODELVIEW);
-}
-
-void GLRenderer::drawGLScene () const {
- if (g_curfile == null)
- return;
-
- glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glEnable (GL_DEPTH_TEST);
-
- if (m_camera != GLRenderer::Free) {
- glMatrixMode (GL_PROJECTION);
- glPushMatrix ();
-
- glLoadIdentity ();
- glOrtho (-m_virtWidth, m_virtWidth, -m_virtHeight, m_virtHeight, -100.0f, 100.0f);
- glTranslatef (m_panX, m_panY, 0.0f);
- glRotatef (90.0f, g_staticCameras[m_camera].glrotate[0],
- g_staticCameras[m_camera].glrotate[1],
- g_staticCameras[m_camera].glrotate[2]);
-
- // Back camera needs to be handled differently
- if (m_camera == GLRenderer::Back) {
- glRotatef (180.0f, 1.0f, 0.0f, 0.0f);
- glRotatef (180.0f, 0.0f, 0.0f, 1.0f);
- }
- } else {
- glMatrixMode (GL_MODELVIEW);
- glPushMatrix ();
- glLoadIdentity ();
-
- glTranslatef (0.0f, 0.0f, -2.0f);
- glTranslatef (m_panX, m_panY, -m_zoom);
- glRotatef (m_rotX, 1.0f, 0.0f, 0.0f);
- glRotatef (m_rotY, 0.0f, 1.0f, 0.0f);
- glRotatef (m_rotZ, 0.0f, 0.0f, 1.0f);
- }
-
- for (LDObject* obj : g_curfile->m_objs) {
- if (obj->hidden ())
- continue; // Don't draw hidden objects
-
- glCallList (m_picking == false ? obj->uGLList : obj->uGLPickList);
- }
-
- if (gl_axes && !m_picking)
- glCallList (m_axeslist);
-
- glPopMatrix ();
- glMatrixMode (GL_MODELVIEW);
-}
-
-// =============================================================================
-vertex GLRenderer::coord_2to3 (const QPoint& pos2d, const bool snap) const {
- vertex pos3d;
- const staticCameraMeta* cam = &g_staticCameras[m_camera];
- const Axis axisX = cam->axisX;
- const Axis axisY = cam->axisY;
- const short negXFac = cam->negX ? -1 : 1,
- negYFac = cam->negY ? -1 : 1;
-
- // Calculate cx and cy - these are the LDraw unit coords the cursor is at.
- double cx = (-m_virtWidth + ((2 * pos2d.x () * m_virtWidth) / m_width) - m_panX) - (negXFac * g_objOffset[axisX]);
- double cy = (m_virtHeight - ((2 * pos2d.y () * m_virtHeight) / m_height) - m_panY) - (negYFac * g_objOffset[axisY]);
-
- if (snap) {
- cx = Grid::snap (cx, (Grid::Config) axisX);
- cy = Grid::snap (cy, (Grid::Config) axisY);
- }
-
- cx *= negXFac;
- cy *= negYFac;
-
- pos3d = g_origin;
- pos3d[axisX] = cx;
- pos3d[axisY] = cy;
- return pos3d;
-}
-
-// =============================================================================
-QPoint GLRenderer::coord_3to2 (const vertex& pos3d) const {
- /*
- cx = (-m_virtWidth + ((2 * pos2d.x () * m_virtWidth) / m_width) - m_panX) - (negXFac * g_objOffset[axisX]);
-
- cx = (-vw + ((2 * x * vw) / w) - panx) - (neg * ofs)
- cx + (neg * ofs) = (-vw + ((2 * x * vw) / w) - panx)
- cx + (neg * ofs) = ((2 * x * vw) / w) - vw - panx
- (cx + (neg * ofs)) + vw + panx = (2 * x * vw) / w
- ((cx + (neg * ofs)) + vw + panx) * w = 2 * vw * x
-
- x = (((cx + (neg * ofs)) + vw + panx) * w) / (2 * vw)
- */
-
- QPoint pos2d;
- const staticCameraMeta* cam = &g_staticCameras[m_camera];
- const Axis axisX = cam->axisX;
- const Axis axisY = cam->axisY;
- const short negXFac = cam->negX ? -1 : 1,
- negYFac = cam->negY ? -1 : 1;
-
- short x1 = (((pos3d[axisX] + (negXFac * g_objOffset[axisX])) +
- m_virtWidth + m_panX) * m_width) / (2 * m_virtWidth);
- short y1 = -(((pos3d[axisY] + (negYFac * g_objOffset[axisY])) -
- m_virtHeight + m_panY) * m_height) / (2 * m_virtHeight);
-
- x1 *= negXFac;
- y1 *= negYFac;
-
- pos2d = QPoint (x1, y1);
- return pos2d;
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::paintEvent (QPaintEvent* ev) {
- Q_UNUSED (ev)
- m_virtWidth = m_zoom;
- m_virtHeight = (m_height * m_virtWidth) / m_width;
- drawGLScene ();
-
- QPainter paint (this);
- QFontMetrics metrics = QFontMetrics (QFont ());
- paint.setRenderHint (QPainter::Antialiasing);
-
- m_hoverpos = g_origin;
-
- if (m_camera != Free) {
- // Calculate 3d position of the cursor
- m_hoverpos = coord_2to3 (m_pos, true);
-
- // Paint the coordinates onto the screen.
- str text;
- text.format ("X: %s, Y: %s, Z: %s", ftoa (m_hoverpos[X]).chars (),
- ftoa (m_hoverpos[Y]).chars (), ftoa (m_hoverpos[Z]).chars ());
-
- QFontMetrics metrics = QFontMetrics (font ());
- QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text);
-
- paint.drawText (m_width - textSize.width (), m_height - 16, textSize.width (),
- textSize.height (), Qt::AlignCenter, text);
-
- // If we're plane drawing, draw the vertices onto the screen.
- if (m_planeDraw) {
- ushort numverts = m_planeDrawVerts.size () + 1;
- const short blipsize = 8;
-
- if (numverts > 0) {
- QPoint* poly = new QPoint[numverts];
-
- uchar i = 0;
- for (vertex& vert : m_planeDrawVerts) {
- poly[i] = coord_3to2 (vert);
- ++i;
- }
-
- // Draw the cursor vertex as the last one in the list.
- if (numverts < 5)
- poly[i] = coord_3to2 (m_hoverpos);
- else
- numverts = 4;
-
- paint.setPen (m_thinBorderPen);
- paint.setBrush (QColor (128, 192, 0));
-
- // Draw vertex blips
- for (ushort i = 0; i < numverts; ++i) {
- QPoint& blip = poly[i];
- paint.drawEllipse (blip.x () - blipsize / 2, blip.y () - blipsize / 2,
- blipsize, blipsize);
- }
-
- paint.setPen (m_thickBorderPen);
- paint.setBrush (QColor (128, 192, 0, 128));
- paint.drawPolygon (poly, numverts);
-
- delete[] poly;
- }
- }
- }
-
- // Camera icons
- if (!m_picking && m_planeDraw == false) {
- // Draw a background for the selected camera
- paint.setPen (m_thinBorderPen);
- paint.setBrush (QBrush (QColor (0, 128, 160, 128)));
- paint.drawRect (g_CameraIcons[camera ()].selRect);
-
- // Draw the actual icons
- for (CameraIcon& info : g_CameraIcons)
- paint.drawPixmap (info.destRect, *info.img, info.srcRect);
-
- // Draw a label for the current camera in the top left corner
- {
- const ushort margin = 4;
-
- str label;
- label.format ("%s Camera", g_CameraNames[camera ()]);
- paint.setBrush (Qt::black);
- paint.drawText (QPoint (margin, margin + metrics.ascent ()), label);
- }
-
- // Tool tips
- if (m_drawToolTip) {
- if (g_CameraIcons[m_toolTipCamera].destRect.contains (m_pos) == false)
- m_drawToolTip = false;
- else {
- QPen bord = m_thinBorderPen;
- bord.setBrush (Qt::black);
-
- const ushort margin = 2;
- ushort x0 = m_pos.x (),
- y0 = m_pos.y ();
-
- str label;
- label.format ("%s Camera", g_CameraNames[m_toolTipCamera]);
-
- const ushort textWidth = metrics.width (label),
- textHeight = metrics.height (),
- fullWidth = textWidth + (2 * margin),
- fullHeight = textHeight + (2 * margin);
-
- QRect area (m_pos.x (), m_pos.y (), fullWidth, fullHeight);
-
- if (x0 + fullWidth > m_width)
- x0 -= fullWidth;
-
- if (y0 + fullHeight > m_height)
- y0 -= fullHeight;
-
- paint.setBrush (QColor (0, 128, 255, 208));
- paint.setPen (bord);
- paint.drawRect (x0, y0, fullWidth, fullHeight);
-
- paint.setBrush (Qt::black);
- paint.drawText (QPoint (x0 + margin, y0 + margin + metrics.ascent ()), label);
- }
- }
- }
-
- // If we're range-picking, draw a rectangle encompassing the selection area.
- if (m_rangepick && !m_picking) {
- const short x0 = m_rangeStart.x (),
- y0 = m_rangeStart.y (),
- x1 = m_pos.x (),
- y1 = m_pos.y ();
-
- QRect rect (x0, y0, x1 - x0, y1 - y0);
- QColor fillColor = (m_addpick ? "#80FF00" : "#00CCFF");
- fillColor.setAlphaF (0.2f);
-
- paint.setPen (m_thickBorderPen);
- paint.setBrush (QBrush (fillColor));
- paint.drawRect (rect);
- }
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::compileObjects () {
- if (g_BBox.empty () == false) {
- g_objOffset[X] = -(g_BBox.v0 ()[X] + g_BBox.v1 ()[X]) / 2;
- g_objOffset[Y] = -(g_BBox.v0 ()[Y] + g_BBox.v1 ()[Y]) / 2;
- g_objOffset[Z] = -(g_BBox.v0 ()[Z] + g_BBox.v1 ()[Z]) / 2;
- } else {
- // use a default bbox if we need
- g_objOffset[X] = g_objOffset[Y] = g_objOffset[Z] = 0;
- }
-
- if (!g_curfile) {
- printf ("renderer: no files loaded, cannot compile anything\n");
- return;
- }
-
- for (LDObject* obj : g_curfile->m_objs) {
- GLuint* upaLists[2] = {
- &obj->uGLList,
- &obj->uGLPickList
- };
-
- for (GLuint* upMemberList : upaLists) {
- GLuint uList = glGenLists (1);
- glNewList (uList, GL_COMPILE);
-
- m_picking = (upMemberList == &obj->uGLPickList);
- compileOneObject (obj);
- m_picking = false;
-
- glEndList ();
- *upMemberList = uList;
- }
- }
-
- // Compile axes
- 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 ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::compileSubObject (LDObject* obj, const GLenum gltype) {
- glBegin (gltype);
-
- const short numverts = (obj->getType () != LDObject::CondLine) ? obj->vertices () : 2;
-
- for (short i = 0; i < numverts; ++i)
- compileVertex (obj->vaCoords[i]);
-
- glEnd ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::compileOneObject (LDObject* obj) {
- setObjectColor (obj);
-
- switch (obj->getType ()) {
- case LDObject::Line:
- compileSubObject (obj, GL_LINES);
- break;
-
- case LDObject::CondLine:
- 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 (obj);
- vector objs = ref->inlineContents (true, true);
-
- for (LDObject* obj : objs) {
- compileOneObject (obj);
- delete obj;
- }
- }
- break;
-
- case LDObject::Radial:
- {
- LDRadial* pRadial = static_cast (obj);
- std::vector objs = pRadial->decompose (true);
-
- for (LDObject* obj : objs) {
- compileOneObject (obj);
- delete obj;
- }
- }
- break;
-
-#if 0
- TODO: find a proper way to draw vertices without having them be affected by zoom.
- case LDObject::Vertex:
- {
- LDVertex* pVert = static_cast (obj);
- LDTriangle* pPoly;
- vertex* vPos = &(pVert->vPosition);
- const double fPolyScale = max (fZoom, 1.0);
-
-#define BIPYRAMID_COORD(N) ((((i + N) % 4) >= 2 ? 1 : -1) * 0.3f * fPolyScale)
-
- for (int i = 0; i < 8; ++i) {
- pPoly = new LDTriangle;
- pPoly->vaCoords[0] = {vPos->x, vPos->y + ((i >= 4 ? 1 : -1) * 0.4f * fPolyScale), vPos->z};
- pPoly->vaCoords[1] = {
- vPos->x + BIPYRAMID_COORD (0),
- vPos->y,
- vPos->z + BIPYRAMID_COORD (1)
- };
-
- pPoly->vaCoords[2] = {
- vPos->x + BIPYRAMID_COORD (1),
- vPos->y,
- vPos->z + BIPYRAMID_COORD (2)
- };
-
- pPoly->dColor = pVert->dColor;
- compileOneObject (pPoly);
- delete pPoly;
- }
- }
- break;
-#endif // 0
-
- default:
- break;
- }
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::compileVertex (const vertex& vrt) {
- glVertex3d (
- (vrt[X] + g_objOffset[0]),
- -(vrt[Y] + g_objOffset[1]),
- -(vrt[Z] + g_objOffset[2]));
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::clampAngle (double& angle) {
- while (angle < 0)
- angle += 360.0;
- while (angle > 360.0)
- angle -= 360.0;
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::mouseReleaseEvent (QMouseEvent* ev) {
- const bool wasLeft = (m_lastButtons & Qt::LeftButton) && !(ev->buttons() & Qt::LeftButton);
- const bool wasRight = (m_lastButtons & Qt::RightButton) && !(ev->buttons() & Qt::RightButton);
-
- if (wasLeft) {
- if (m_planeDraw) {
- // If we picked an already-existing vertex, stop drawing
- for (vertex& vert : m_planeDrawVerts) {
- if (vert == m_hoverpos) {
- endPlaneDraw (true);
- return;
- }
- }
-
- // Also, if have 4 verts, also stop drawing.
- if (m_planeDrawVerts.size () >= 4)
- endPlaneDraw (true);
-
- m_planeDrawVerts.push_back (m_hoverpos);
-
- update ();
- return;
- } else {
- if (!m_rangepick)
- m_addpick = (m_keymods & Qt::ControlModifier);
-
- if (m_totalmove < 10 || m_rangepick)
- pick (ev->x (), ev->y ());
- }
-
- m_rangepick = false;
- m_totalmove = 0;
- return;
- }
-
- if (wasRight && m_planeDraw) {
- if (m_planeDrawVerts.size () > 0) {
- // Remove the last vertex
- m_planeDrawVerts.erase (m_planeDrawVerts.end () - 1);
- } else {
- endPlaneDraw (false);
- return;
- }
-
- update ();
- }
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::mousePressEvent (QMouseEvent* ev) {
- if (ev->buttons () & Qt::LeftButton)
- m_totalmove = 0;
-
- if (ev->modifiers () & Qt::ShiftModifier) {
- m_rangepick = true;
- m_rangeStart.setX (ev->x ());
- m_rangeStart.setY (ev->y ());
-
- m_addpick = (m_keymods & Qt::ControlModifier);
- }
-
- m_lastButtons = ev->buttons ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::mouseMoveEvent (QMouseEvent* ev) {
- int dx = ev->x () - m_pos.x ();
- int dy = ev->y () - m_pos.y ();
- m_totalmove += abs (dx) + abs (dy);
-
- if (ev->buttons () & Qt::LeftButton && !m_rangepick) {
- m_rotX = m_rotX + (dy);
- m_rotY = m_rotY + (dx);
-
- clampAngle (m_rotX);
- clampAngle (m_rotY);
- }
-
- if (ev->buttons () & Qt::MidButton) {
- m_panX += 0.03f * dx * (m_zoom / 7.5f);
- m_panY -= 0.03f * dy * (m_zoom / 7.5f);
- }
-
- // Start the tool tip timer
- if (!m_drawToolTip)
- m_toolTipTimer->start (1000);
-
- m_pos = ev->pos ();
- update ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::keyPressEvent (QKeyEvent* ev) {
- m_keymods = ev->modifiers ();
-}
-
-void GLRenderer::keyReleaseEvent (QKeyEvent* ev) {
- m_keymods = ev->modifiers ();
-}
-
-// =============================================================================
-void GLRenderer::wheelEvent (QWheelEvent* ev) {
- m_zoom *= (ev->delta () < 0) ? 1.2f : (1.0f / 1.2f);
- m_zoom = clamp (m_zoom, 0.01, 10000.0);
-
- update ();
- ev->accept ();
-}
-
-// =============================================================================
-void GLRenderer::leaveEvent (QEvent* ev) {
- Q_UNUSED (ev);
- m_drawToolTip = false;
- m_toolTipTimer->stop ();
- update ();
-}
-
-// =============================================================================
-void GLRenderer::contextMenuEvent (QContextMenuEvent* ev) {
- g_win->spawnContextMenu (ev->globalPos ());
-}
-
-// =============================================================================
-void GLRenderer::setCamera (const GLRenderer::Camera cam) {
- m_camera = cam;
- gl_camera = (int) cam;
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::updateSelFlash () {
- if (gl_selflash && g_win->sel ().size() > 0) {
- m_pulseTimer->start (g_pulseInterval);
- g_pulseTick = 0;
- } else
- m_pulseTimer->stop ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::pick (uint mouseX, uint mouseY) {
- // Check if we selected a camera icon
- if (!m_rangepick) {
- QPoint pos (mouseX, mouseY);
-
- for (CameraIcon& info : g_CameraIcons) {
- if (info.destRect.contains (pos)) {
- setCamera (info.cam);
- update ();
- return;
- }
- }
- }
-
- GLint viewport[4];
- LDObject* removedObject = null;
-
- // Clear the selection if we do not wish to add to it.
- if (!m_addpick) {
- std::vector oldsel = g_win->sel ();
- g_win->sel ().clear ();
-
- // Recompile the prior selection to remove the highlight color
- for (LDObject* obj : oldsel)
- recompileObject (obj);
- }
-
- m_picking = true;
-
- // Paint the picking scene
- glDisable (GL_DITHER);
- glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
- drawGLScene ();
-
- glGetIntegerv (GL_VIEWPORT, viewport);
-
- short x0 = mouseX,
- y0 = mouseY;
- short 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.
- if (m_rangepick) {
- x1 = m_rangeStart.x ();
- y1 = m_rangeStart.y ();
- } else {
- x1 = x0 + 1;
- y1 = y0 + 1;
- }
-
- // x0 and y0 must be less than x1 and y1, respectively.
- if (x0 > x1)
- dataswap (x0, x1);
-
- if (y0 > y1)
- dataswap (y0, y1);
-
- // Clamp the values to ensure they're within bounds
- 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;
-
- // Allocate space for the pixel data.
- uchar* const pixeldata = new uchar[4 * numpixels];
- uchar* pixelptr = &pixeldata[0];
-
- assert (viewport[3] == m_height);
-
- // Read pixels from the color buffer.
- glReadPixels (x0, viewport[3] - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata);
-
- // Go through each pixel read and add them to the selection.
- for (long i = 0; i < numpixels; ++i) {
- uint32 idx =
- (*(pixelptr) * 0x10000) +
- (*(pixelptr + 1) * 0x00100) +
- (*(pixelptr + 2) * 0x00001);
- pixelptr += 4;
-
- if (idx == 0xFFFFFF)
- continue; // White is background; skip
-
- LDObject* obj = g_curfile->object (idx);
-
- // If this is an additive single pick and the object is currently selected,
- // we remove it from selection instead.
- if (!m_rangepick && m_addpick) {
- bool removed = false;
-
- for (ulong i = 0; i < g_win->sel ().size(); ++i) {
- if (g_win->sel ()[i] == obj) {
- g_win->sel ().erase (g_win->sel ().begin () + i);
- removedObject = obj;
- removed = true;
- }
- }
-
- if (removed)
- break;
- }
-
- g_win->sel ().push_back (obj);
- }
-
- delete[] pixeldata;
-
- // Remove duplicate entries. For this to be effective, the vector must be
- // sorted first.
- std::vector& sel = g_win->sel ();
- std::sort (sel.begin(), sel.end ());
- std::vector::iterator pos = std::unique (sel.begin (), sel.end ());
- sel.resize (std::distance (sel.begin (), pos));
-
- // Update everything now.
- g_win->buildObjList ();
-
- m_picking = false;
- m_rangepick = false;
- glEnable (GL_DITHER);
-
- setBackground ();
- updateSelFlash ();
-
- for (LDObject* obj : g_win->sel ())
- recompileObject (obj);
-
- if (removedObject != null)
- recompileObject (removedObject);
-
- drawGLScene ();
- swapBuffers ();
- update ();
-}
-
-// =============================================================================
-void GLRenderer::beginPlaneDraw () {
- if (m_camera == Free)
- return; // Cannot draw with the free camera
-
- m_planeDraw = true;
-
- // Disable the context menu - we need the right mouse button
- // for removing vertices.
- setContextMenuPolicy (Qt::NoContextMenu);
-
- // Use the crosshair cursor when plane drawing.
- setCursor (Qt::CrossCursor);
-
- // Clear the selection when beginning to draw onto a plane.
- // FIXME: make the selection clearing stuff in ::pick a method and use it
- // here! This code doesn't update the GL lists.
- g_win->sel ().clear ();
- g_win->updateSelection ();
- update ();
-}
-
-// =============================================================================
-void GLRenderer::endPlaneDraw (bool accept) {
- // If we accepted, clean the selection and create the object
- if (accept) {
- vector& verts = m_planeDrawVerts;
- LDObject* obj = null;
-
- switch (verts.size ()) {
- case 1:
- {
- // 1 vertex - add a vertex object
- obj = new LDVertex;
- static_cast (obj)->vPosition = verts[0];
- obj->dColor = maincolor;
- }
- break;
-
- case 2:
- {
- // 2 verts - make a line
- obj = new LDLine;
- obj->dColor = edgecolor;
- for (ushort i = 0; i < 2; ++i)
- obj->vaCoords[i] = verts[i];
- }
- break;
-
- case 3:
- case 4:
- {
- obj = (verts.size () == 3) ?
- static_cast (new LDTriangle) :
- static_cast (new LDQuad);
-
- obj->dColor = maincolor;
- for (ushort i = 0; i < obj->vertices (); ++i)
- obj->vaCoords[i] = verts[i];
- }
- break;
- }
-
- if (obj) {
- g_curfile->addObject (obj);
- recompileObject (obj);
- g_win->refresh ();
-
- History::addEntry (new AddHistory ({(ulong) obj->getIndex (g_curfile)}, {obj->clone ()}));
- }
- }
-
- m_planeDraw = false;
- m_planeDrawVerts.clear ();
-
- unsetCursor ();
-
- // Restore the context menu
- setContextMenuPolicy (Qt::DefaultContextMenu);
-
- update ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void GLRenderer::recompileObject (LDObject* obj) {
- // Replace the old list with the new one.
- GLuint uList = glGenLists (1);
- glNewList (uList, GL_COMPILE);
-
- compileOneObject (obj);
-
- glEndList ();
- obj->uGLList = uList;
-}
-
-// =============================================================================
-uchar* GLRenderer::screencap (ushort& w, ushort& h) {
- w = m_width;
- h = m_height;
- uchar* cap = new uchar[4 * w * h];
-
- m_screencap = true;
- update ();
- m_screencap = false;
-
- // Capture the pixels
- glReadPixels (0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, cap);
-
- // Restore the background
- setBackground ();
-
- return cap;
-}
-
-// =============================================================================
-void GLRenderer::slot_timerUpdate () {
- ++g_pulseTick %= g_numPulseTicks;
-
- for (LDObject* obj : g_win->sel ())
- recompileObject (obj);
-
- update ();
-}
-
-// =============================================================================
-void GLRenderer::slot_toolTipTimer () {
- // 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 : g_CameraIcons) {
- if (icon.destRect.contains (m_pos)) {
- m_toolTipCamera = icon.cam;
- m_drawToolTip = true;
- update ();
- break;
- }
- }
-}
\ No newline at end of file