src/glRenderer.cpp

changeset 931
85080f7a1c20
parent 927
409b82a4765e
child 941
f895379d7fab
equal deleted inserted replaced
929:66e8453e1768 931:85080f7a1c20
1 /*
2 * LDForge: LDraw parts authoring CAD
3 * Copyright (C) 2013 - 2015 Teemu Piippo
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #define GL_GLEXT_PROTOTYPES
20 #include <GL/glu.h>
21 #include <GL/glext.h>
22 #include <QGLWidget>
23 #include <QWheelEvent>
24 #include <QMouseEvent>
25 #include <QContextMenuEvent>
26 #include <QInputDialog>
27 #include <QToolTip>
28 #include <QTextDocument>
29 #include <QTimer>
30 #include <GL/glu.h>
31 #include "main.h"
32 #include "configuration.h"
33 #include "ldDocument.h"
34 #include "glRenderer.h"
35 #include "colors.h"
36 #include "mainWindow.h"
37 #include "miscallenous.h"
38 #include "editHistory.h"
39 #include "dialogs.h"
40 #include "addObjectDialog.h"
41 #include "messageLog.h"
42 #include "glCompiler.h"
43 #include "primitives.h"
44
45 const LDFixedCamera g_FixedCameras[6] =
46 {
47 {{ 1, 0, 0 }, X, Z, false, false, false }, // top
48 {{ 0, 0, 0 }, X, Y, false, true, false }, // front
49 {{ 0, 1, 0 }, Z, Y, true, true, false }, // left
50 {{ -1, 0, 0 }, X, Z, false, true, true }, // bottom
51 {{ 0, 0, 0 }, X, Y, true, true, true }, // back
52 {{ 0, -1, 0 }, Z, Y, false, true, true }, // right
53 };
54
55 CFGENTRY (String, BackgroundColor, "#FFFFFF")
56 CFGENTRY (String, MainColor, "#A0A0A0")
57 CFGENTRY (Float, MainColorAlpha, 1.0)
58 CFGENTRY (Int, LineThickness, 2)
59 CFGENTRY (Bool, BFCRedGreenView, false)
60 CFGENTRY (Int, Camera, EFreeCamera)
61 CFGENTRY (Bool, BlackEdges, false)
62 CFGENTRY (Bool, DrawAxes, false)
63 CFGENTRY (Bool, DrawWireframe, false)
64 CFGENTRY (Bool, UseLogoStuds, false)
65 CFGENTRY (Bool, AntiAliasedLines, true)
66 CFGENTRY (Bool, RandomColors, false)
67 CFGENTRY (Bool, HighlightObjectBelowCursor, true)
68 CFGENTRY (Bool, DrawSurfaces, true)
69 CFGENTRY (Bool, DrawEdgeLines, true)
70 CFGENTRY (Bool, DrawConditionalLines, true)
71
72 // argh
73 const char* g_CameraNames[7] =
74 {
75 QT_TRANSLATE_NOOP ("GLRenderer", "Top"),
76 QT_TRANSLATE_NOOP ("GLRenderer", "Front"),
77 QT_TRANSLATE_NOOP ("GLRenderer", "Left"),
78 QT_TRANSLATE_NOOP ("GLRenderer", "Bottom"),
79 QT_TRANSLATE_NOOP ("GLRenderer", "Back"),
80 QT_TRANSLATE_NOOP ("GLRenderer", "Right"),
81 QT_TRANSLATE_NOOP ("GLRenderer", "Free")
82 };
83
84 struct LDGLAxis
85 {
86 const QColor col;
87 const Vertex vert;
88 };
89
90 // Definitions for visual axes, drawn on the screen
91 static const LDGLAxis g_GLAxes[3] =
92 {
93 { QColor (192, 96, 96), Vertex (10000, 0, 0) }, // X
94 { QColor (48, 192, 48), Vertex (0, 10000, 0) }, // Y
95 { QColor (48, 112, 192), Vertex (0, 0, 10000) }, // Z
96 };
97
98 static bool RendererInitialized (false);
99
100 // =============================================================================
101 //
102 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent)
103 {
104 m_isPicking = false;
105 m_camera = (ECamera) cfg::Camera;
106 m_drawToolTip = false;
107 m_editmode = AbstractEditMode::createByType (this, EditModeType::Select);
108 m_panning = false;
109 m_compiler = new GLCompiler (this);
110 setDrawOnly (false);
111 setMessageLog (null);
112 m_width = m_height = -1;
113 m_position3D = Origin;
114 m_toolTipTimer = new QTimer (this);
115 m_toolTipTimer->setSingleShot (true);
116 m_isCameraMoving = false;
117 m_thinBorderPen = QPen (QColor (0, 0, 0, 208), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
118 m_thinBorderPen.setWidth (1);
119 setAcceptDrops (true);
120 connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (slot_toolTipTimer()));
121
122 // Init camera icons
123 for (ECamera cam = EFirstCamera; cam < ENumCameras; ++cam)
124 {
125 QString iconname = format ("camera-%1", tr (g_CameraNames[cam]).toLower());
126 CameraIcon* info = &m_cameraIcons[cam];
127 info->img = new QPixmap (GetIcon (iconname));
128 info->cam = cam;
129 }
130
131 calcCameraIcons();
132 }
133
134 // =============================================================================
135 //
136 GLRenderer::~GLRenderer()
137 {
138 for (int i = 0; i < 6; ++i)
139 delete currentDocumentData().overlays[i].img;
140
141 for (CameraIcon& info : m_cameraIcons)
142 delete info.img;
143
144 if (messageLog())
145 messageLog()->setRenderer (null);
146
147 m_compiler->setRenderer (null);
148 delete m_compiler;
149 delete m_editmode;
150
151 glDeleteBuffers (1, &m_axesVBO);
152 glDeleteBuffers (1, &m_axesColorVBO);
153 }
154
155 // =============================================================================
156 // Calculates the "hitboxes" of the camera icons so that we can tell when the
157 // cursor is pointing at the camera icon.
158 //
159 void GLRenderer::calcCameraIcons()
160 {
161 int i = 0;
162
163 for (CameraIcon& info : m_cameraIcons)
164 {
165 // MATH
166 const long x1 = (m_width - (info.cam != EFreeCamera ? 48 : 16)) + ((i % 3) * 16) - 1,
167 y1 = ((i / 3) * 16) + 1;
168
169 info.srcRect = QRect (0, 0, 16, 16);
170 info.destRect = QRect (x1, y1, 16, 16);
171 info.selRect = QRect (
172 info.destRect.x(),
173 info.destRect.y(),
174 info.destRect.width() + 1,
175 info.destRect.height() + 1
176 );
177
178 ++i;
179 }
180 }
181
182 // =============================================================================
183 //
184 void GLRenderer::initGLData()
185 {
186 glEnable (GL_BLEND);
187 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
188 glEnable (GL_POLYGON_OFFSET_FILL);
189 glPolygonOffset (1.0f, 1.0f);
190
191 glEnable (GL_DEPTH_TEST);
192 glShadeModel (GL_SMOOTH);
193 glEnable (GL_MULTISAMPLE);
194
195 if (cfg::AntiAliasedLines)
196 {
197 glEnable (GL_LINE_SMOOTH);
198 glEnable (GL_POLYGON_SMOOTH);
199 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
200 glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST);
201 } else
202 {
203 glDisable (GL_LINE_SMOOTH);
204 glDisable (GL_POLYGON_SMOOTH);
205 }
206 }
207
208 // =============================================================================
209 //
210 void GLRenderer::needZoomToFit()
211 {
212 if (document() != null)
213 currentDocumentData().needZoomToFit = true;
214 }
215
216 // =============================================================================
217 //
218 void GLRenderer::resetAngles()
219 {
220 rot (X) = 30.0f;
221 rot (Y) = 325.f;
222 pan (X) = pan (Y) = rot (Z) = 0.0f;
223 needZoomToFit();
224 }
225
226 // =============================================================================
227 //
228 void GLRenderer::resetAllAngles()
229 {
230 ECamera oldcam = camera();
231
232 for (int i = 0; i < 7; ++i)
233 {
234 setCamera ((ECamera) i);
235 resetAngles();
236 }
237
238 setCamera (oldcam);
239 }
240
241 // =============================================================================
242 //
243 void GLRenderer::initializeGL()
244 {
245 #ifdef USE_QT5
246 initializeOpenGLFunctions();
247 #endif
248 setBackground();
249 glLineWidth (cfg::LineThickness);
250 glLineStipple (1, 0x6666);
251 setAutoFillBackground (false);
252 setMouseTracking (true);
253 setFocusPolicy (Qt::WheelFocus);
254 compiler()->initialize();
255 initializeAxes();
256 RendererInitialized = true;
257 }
258
259 // =============================================================================
260 //
261 void GLRenderer::initializeAxes()
262 {
263 float axesdata[18];
264 float colordata[18];
265 memset (axesdata, 0, sizeof axesdata);
266
267 for (int i = 0; i < 3; ++i)
268 {
269 for_axes (ax)
270 {
271 axesdata[(i * 6) + ax] = g_GLAxes[i].vert[ax];
272 axesdata[(i * 6) + 3 + ax] = -g_GLAxes[i].vert[ax];
273 }
274
275 for (int j = 0; j < 2; ++j)
276 {
277 colordata[(i * 6) + (j * 3) + 0] = g_GLAxes[i].col.red();
278 colordata[(i * 6) + (j * 3) + 1] = g_GLAxes[i].col.green();
279 colordata[(i * 6) + (j * 3) + 2] = g_GLAxes[i].col.blue();
280 }
281 }
282
283 glGenBuffers (1, &m_axesVBO);
284 glBindBuffer (GL_ARRAY_BUFFER, m_axesVBO);
285 glBufferData (GL_ARRAY_BUFFER, sizeof axesdata, axesdata, GL_STATIC_DRAW);
286 glGenBuffers (1, &m_axesColorVBO);
287 glBindBuffer (GL_ARRAY_BUFFER, m_axesColorVBO);
288 glBufferData (GL_ARRAY_BUFFER, sizeof colordata, colordata, GL_STATIC_DRAW);
289 glBindBuffer (GL_ARRAY_BUFFER, 0);
290 }
291
292 // =============================================================================
293 //
294 QColor GLRenderer::getMainColor()
295 {
296 QColor col (cfg::MainColor);
297
298 if (not col.isValid())
299 return QColor (0, 0, 0);
300
301 col.setAlpha (cfg::MainColorAlpha * 255.f);
302 return col;
303 }
304
305 // =============================================================================
306 //
307 void GLRenderer::setBackground()
308 {
309 if (isPicking())
310 {
311 glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
312 return;
313 }
314
315 QColor col (cfg::BackgroundColor);
316
317 if (not col.isValid())
318 return;
319
320 col.setAlpha (255);
321
322 m_darkbg = Luma (col) < 80;
323 m_bgcolor = col;
324 qglClearColor (col);
325 }
326
327 // =============================================================================
328 //
329 void GLRenderer::refresh()
330 {
331 update();
332
333 if (isVisible())
334 swapBuffers();
335 }
336
337 // =============================================================================
338 //
339 void GLRenderer::hardRefresh()
340 {
341 if (not RendererInitialized)
342 return;
343
344 compiler()->compileDocument (CurrentDocument());
345 refresh();
346 }
347
348 // =============================================================================
349 //
350 void GLRenderer::resizeGL (int w, int h)
351 {
352 m_width = w;
353 m_height = h;
354
355 calcCameraIcons();
356
357 glViewport (0, 0, w, h);
358 glMatrixMode (GL_PROJECTION);
359 glLoadIdentity();
360 gluPerspective (45.0f, (double) w / (double) h, 1.0f, 10000.0f);
361 glMatrixMode (GL_MODELVIEW);
362 }
363
364 // =============================================================================
365 //
366 void GLRenderer::drawGLScene()
367 {
368 if (document() == null)
369 return;
370
371 if (currentDocumentData().needZoomToFit)
372 {
373 currentDocumentData().needZoomToFit = false;
374 zoomAllToFit();
375 }
376
377 if (cfg::DrawWireframe and not isPicking())
378 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
379
380 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
381 glEnable (GL_DEPTH_TEST);
382
383 if (camera() != EFreeCamera)
384 {
385 glMatrixMode (GL_PROJECTION);
386 glPushMatrix();
387
388 glLoadIdentity();
389 glOrtho (-m_virtWidth, m_virtWidth, -m_virtHeight, m_virtHeight, -100.0f, 100.0f);
390 glTranslatef (pan (X), pan (Y), 0.0f);
391
392 if (camera() != EFrontCamera and camera() != EBackCamera)
393 {
394 glRotatef (90.0f, g_FixedCameras[camera()].glrotate[0],
395 g_FixedCameras[camera()].glrotate[1],
396 g_FixedCameras[camera()].glrotate[2]);
397 }
398
399 // Back camera needs to be handled differently
400 if (camera() == EBackCamera)
401 {
402 glRotatef (180.0f, 1.0f, 0.0f, 0.0f);
403 glRotatef (180.0f, 0.0f, 0.0f, 1.0f);
404 }
405 }
406 else
407 {
408 glMatrixMode (GL_MODELVIEW);
409 glPushMatrix();
410 glLoadIdentity();
411
412 glTranslatef (0.0f, 0.0f, -2.0f);
413 glTranslatef (pan (X), pan (Y), -zoom());
414 glRotatef (rot (X), 1.0f, 0.0f, 0.0f);
415 glRotatef (rot (Y), 0.0f, 1.0f, 0.0f);
416 glRotatef (rot (Z), 0.0f, 0.0f, 1.0f);
417 }
418
419 glEnableClientState (GL_VERTEX_ARRAY);
420 glEnableClientState (GL_COLOR_ARRAY);
421
422 if (isPicking())
423 {
424 drawVBOs (VBOSF_Triangles, VBOCM_PickColors, GL_TRIANGLES);
425 drawVBOs (VBOSF_Quads, VBOCM_PickColors, GL_QUADS);
426 drawVBOs (VBOSF_Lines, VBOCM_PickColors, GL_LINES);
427 drawVBOs (VBOSF_CondLines, VBOCM_PickColors, GL_LINES);
428 }
429 else
430 {
431 if (cfg::BFCRedGreenView)
432 {
433 glEnable (GL_CULL_FACE);
434 glCullFace (GL_BACK);
435 drawVBOs (VBOSF_Triangles, VBOCM_BFCFrontColors, GL_TRIANGLES);
436 drawVBOs (VBOSF_Quads, VBOCM_BFCFrontColors, GL_QUADS);
437 glCullFace (GL_FRONT);
438 drawVBOs (VBOSF_Triangles, VBOCM_BFCBackColors, GL_TRIANGLES);
439 drawVBOs (VBOSF_Quads, VBOCM_BFCBackColors, GL_QUADS);
440 glDisable (GL_CULL_FACE);
441 }
442 else
443 {
444 if (cfg::RandomColors)
445 {
446 drawVBOs (VBOSF_Triangles, VBOCM_RandomColors, GL_TRIANGLES);
447 drawVBOs (VBOSF_Quads, VBOCM_RandomColors, GL_QUADS);
448 }
449 else
450 {
451 drawVBOs (VBOSF_Triangles, VBOCM_NormalColors, GL_TRIANGLES);
452 drawVBOs (VBOSF_Quads, VBOCM_NormalColors, GL_QUADS);
453 }
454 }
455
456 drawVBOs (VBOSF_Lines, VBOCM_NormalColors, GL_LINES);
457 glEnable (GL_LINE_STIPPLE);
458 drawVBOs (VBOSF_CondLines, VBOCM_NormalColors, GL_LINES);
459 glDisable (GL_LINE_STIPPLE);
460
461 if (cfg::DrawAxes)
462 {
463 glBindBuffer (GL_ARRAY_BUFFER, m_axesVBO);
464 glVertexPointer (3, GL_FLOAT, 0, NULL);
465 glBindBuffer (GL_ARRAY_BUFFER, m_axesVBO);
466 glColorPointer (3, GL_FLOAT, 0, NULL);
467 glDrawArrays (GL_LINES, 0, 6);
468 CHECK_GL_ERROR();
469 }
470 }
471
472 glPopMatrix();
473 glBindBuffer (GL_ARRAY_BUFFER, 0);
474 glDisableClientState (GL_VERTEX_ARRAY);
475 glDisableClientState (GL_COLOR_ARRAY);
476 CHECK_GL_ERROR();
477 glDisable (GL_CULL_FACE);
478 glMatrixMode (GL_MODELVIEW);
479 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
480 }
481
482 // =============================================================================
483 //
484 void GLRenderer::drawVBOs (EVBOSurface surface, EVBOComplement colors, GLenum type)
485 {
486 // Filter this through some configuration options
487 if ((Eq (surface, VBOSF_Quads, VBOSF_Triangles) and cfg::DrawSurfaces == false) or
488 (surface == VBOSF_Lines and cfg::DrawEdgeLines == false) or
489 (surface == VBOSF_CondLines and cfg::DrawConditionalLines == false))
490 {
491 return;
492 }
493
494 int surfacenum = m_compiler->vboNumber (surface, VBOCM_Surfaces);
495 int colornum = m_compiler->vboNumber (surface, colors);
496 m_compiler->prepareVBO (surfacenum);
497 m_compiler->prepareVBO (colornum);
498 GLuint surfacevbo = m_compiler->vbo (surfacenum);
499 GLuint colorvbo = m_compiler->vbo (colornum);
500 GLsizei count = m_compiler->vboSize (surfacenum) / 3;
501
502 if (count > 0)
503 {
504 glBindBuffer (GL_ARRAY_BUFFER, surfacevbo);
505 glVertexPointer (3, GL_FLOAT, 0, null);
506 CHECK_GL_ERROR();
507 glBindBuffer (GL_ARRAY_BUFFER, colorvbo);
508 glColorPointer (4, GL_FLOAT, 0, null);
509 CHECK_GL_ERROR();
510 glDrawArrays (type, 0, count);
511 CHECK_GL_ERROR();
512 }
513 }
514
515 // =============================================================================
516 // This converts a 2D point on the screen to a 3D point in the model. If 'snap'
517 // is true, the 3D point will snap to the current grid.
518 //
519 Vertex GLRenderer::coordconv2_3 (const QPoint& pos2d, bool snap) const
520 {
521 assert (camera() != EFreeCamera);
522
523 Vertex pos3d;
524 const LDFixedCamera* cam = &g_FixedCameras[camera()];
525 const Axis axisX = cam->axisX;
526 const Axis axisY = cam->axisY;
527 const int negXFac = cam->negX ? -1 : 1,
528 negYFac = cam->negY ? -1 : 1;
529
530 // Calculate cx and cy - these are the LDraw unit coords the cursor is at.
531 double cx = (-m_virtWidth + ((2 * pos2d.x() * m_virtWidth) / m_width) - pan (X));
532 double cy = (m_virtHeight - ((2 * pos2d.y() * m_virtHeight) / m_height) - pan (Y));
533
534 if (snap)
535 {
536 cx = Grid::Snap (cx, Grid::Coordinate);
537 cy = Grid::Snap (cy, Grid::Coordinate);
538 }
539
540 cx *= negXFac;
541 cy *= negYFac;
542
543 RoundToDecimals (cx, 4);
544 RoundToDecimals (cy, 4);
545
546 // Create the vertex from the coordinates
547 pos3d.setCoordinate (axisX, cx);
548 pos3d.setCoordinate (axisY, cy);
549 pos3d.setCoordinate ((Axis) (3 - axisX - axisY), getDepthValue());
550 return pos3d;
551 }
552
553 // =============================================================================
554 //
555 // Inverse operation for the above - convert a 3D position to a 2D screen
556 // position. Don't ask me how this code manages to work, I don't even know.
557 //
558 QPoint GLRenderer::coordconv3_2 (const Vertex& pos3d)
559 {
560 GLfloat m[16];
561 const LDFixedCamera* cam = &g_FixedCameras[camera()];
562 const Axis axisX = cam->axisX;
563 const Axis axisY = cam->axisY;
564 const int negXFac = cam->negX ? -1 : 1,
565 negYFac = cam->negY ? -1 : 1;
566
567 glGetFloatv (GL_MODELVIEW_MATRIX, m);
568
569 const double x = pos3d.x();
570 const double y = pos3d.y();
571 const double z = pos3d.z();
572
573 Vertex transformed;
574 transformed.setX ((m[0] * x) + (m[1] * y) + (m[2] * z) + m[3]);
575 transformed.setY ((m[4] * x) + (m[5] * y) + (m[6] * z) + m[7]);
576 transformed.setZ ((m[8] * x) + (m[9] * y) + (m[10] * z) + m[11]);
577
578 double rx = (((transformed[axisX] * negXFac) + m_virtWidth + pan (X)) * m_width) / (2 * m_virtWidth);
579 double ry = (((transformed[axisY] * negYFac) - m_virtHeight + pan (Y)) * m_height) / (2 * m_virtHeight);
580
581 return QPoint (rx, -ry);
582 }
583
584 QPen GLRenderer::textPen() const
585 {
586 return QPen (m_darkbg ? Qt::white : Qt::black);
587 }
588
589 QPen GLRenderer::linePen() const
590 {
591 QPen linepen (m_thinBorderPen);
592 linepen.setWidth (2);
593 linepen.setColor (Luma (m_bgcolor) < 40 ? Qt::white : Qt::black);
594 return linepen;
595 }
596
597 // =============================================================================
598 //
599 void GLRenderer::paintEvent (QPaintEvent*)
600 {
601 doMakeCurrent();
602 m_virtWidth = zoom();
603 m_virtHeight = (m_height * m_virtWidth) / m_width;
604 initGLData();
605 drawGLScene();
606
607 QPainter paint (this);
608 QFontMetrics metrics = QFontMetrics (QFont());
609 paint.setRenderHint (QPainter::HighQualityAntialiasing);
610
611 // If we wish to only draw the brick, stop here
612 if (isDrawOnly())
613 return;
614
615 #ifndef RELEASE
616 if (not isPicking())
617 {
618 QString text = format ("Rotation: (%1, %2, %3)\nPanning: (%4, %5), Zoom: %6",
619 rot(X), rot(Y), rot(Z), pan(X), pan(Y), zoom());
620 QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text);
621 paint.setPen (textPen());
622 paint.drawText ((width() - textSize.width()) / 2, height() - textSize.height(), textSize.width(),
623 textSize.height(), Qt::AlignCenter, text);
624 }
625 #endif
626
627 if (camera() != EFreeCamera and not isPicking())
628 {
629 // Paint the overlay image if we have one
630 const LDGLOverlay& overlay = currentDocumentData().overlays[camera()];
631
632 if (overlay.img != null)
633 {
634 QPoint v0 = coordconv3_2 (currentDocumentData().overlays[camera()].v0),
635 v1 = coordconv3_2 (currentDocumentData().overlays[camera()].v1);
636
637 QRect targRect (v0.x(), v0.y(), Abs (v1.x() - v0.x()), Abs (v1.y() - v0.y())),
638 srcRect (0, 0, overlay.img->width(), overlay.img->height());
639 paint.drawImage (targRect, *overlay.img, srcRect);
640 }
641
642 // Paint the coordinates onto the screen.
643 QString text = format (tr ("X: %1, Y: %2, Z: %3"), m_position3D[X], m_position3D[Y], m_position3D[Z]);
644 QFontMetrics metrics = QFontMetrics (font());
645 QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text);
646 paint.setPen (textPen());
647 paint.drawText (m_width - textSize.width(), m_height - 16, textSize.width(),
648 textSize.height(), Qt::AlignCenter, text);
649 }
650
651 if (not isPicking())
652 {
653 // Draw edit mode HUD
654 m_editmode->render (paint);
655
656 // Draw a background for the selected camera
657 paint.setPen (m_thinBorderPen);
658 paint.setBrush (QBrush (QColor (0, 128, 160, 128)));
659 paint.drawRect (m_cameraIcons[camera()].selRect);
660
661 // Draw the camera icons
662 for (CameraIcon& info : m_cameraIcons)
663 {
664 // Don't draw the free camera icon when in draw mode
665 if (&info == &m_cameraIcons[EFreeCamera] and not m_editmode->allowFreeCamera())
666 continue;
667
668 paint.drawPixmap (info.destRect, *info.img, info.srcRect);
669 }
670
671 QString formatstr = tr ("%1 Camera");
672
673 // Draw a label for the current camera in the bottom left corner
674 {
675 const int margin = 4;
676
677 QString label;
678 label = format (formatstr, tr (g_CameraNames[camera()]));
679 paint.setPen (textPen());
680 paint.drawText (QPoint (margin, height() - (margin + metrics.descent())), label);
681 }
682
683 // Tool tips
684 if (m_drawToolTip)
685 {
686 if (not m_cameraIcons[m_toolTipCamera].destRect.contains (m_mousePosition))
687 m_drawToolTip = false;
688 else
689 {
690 QString label = format (formatstr, tr (g_CameraNames[m_toolTipCamera]));
691 QToolTip::showText (m_globalpos, label);
692 }
693 }
694 }
695
696 // Message log
697 if (messageLog())
698 {
699 int y = 0;
700 const int margin = 2;
701 QColor penColor = textPen().color();
702
703 for (const MessageManager::Line& line : messageLog()->getLines())
704 {
705 penColor.setAlphaF (line.alpha);
706 paint.setPen (penColor);
707 paint.drawText (QPoint (margin, y + margin + metrics.ascent()), line.text);
708 y += metrics.height();
709 }
710 }
711 }
712
713 // =============================================================================
714 //
715 void GLRenderer::drawBlip (QPainter& paint, QPointF pos) const
716 {
717 QPen pen = m_thinBorderPen;
718 const int blipsize = 8;
719 pen.setWidth (1);
720 paint.setPen (pen);
721 paint.setBrush (QColor (64, 192, 0));
722 paint.drawEllipse (pos.x() - blipsize / 2, pos.y() - blipsize / 2, blipsize, blipsize);
723 }
724
725 // =============================================================================
726 //
727 void GLRenderer::clampAngle (double& angle) const
728 {
729 while (angle < 0)
730 angle += 360.0;
731
732 while (angle > 360.0)
733 angle -= 360.0;
734 }
735
736 // =============================================================================
737 //
738 void GLRenderer::mouseReleaseEvent (QMouseEvent* ev)
739 {
740 const bool wasLeft = (m_lastButtons & Qt::LeftButton) and not (ev->buttons() & Qt::LeftButton);
741
742 Qt::MouseButtons releasedbuttons = m_lastButtons & ~ev->buttons();
743
744 if (m_panning)
745 m_panning = false;
746
747 if (wasLeft)
748 {
749 // Check if we selected a camera icon
750 if (not mouseHasMoved())
751 {
752 for (CameraIcon & info : m_cameraIcons)
753 {
754 if (info.destRect.contains (ev->pos()))
755 {
756 setCamera (info.cam);
757 goto end;
758 }
759 }
760 }
761 }
762
763 if (not isDrawOnly())
764 {
765 AbstractEditMode::MouseEventData data;
766 data.ev = ev;
767 data.mouseMoved = mouseHasMoved();
768 data.keymods = m_keymods;
769 data.releasedButtons = releasedbuttons;
770
771 if (m_editmode->mouseReleased (data))
772 goto end;
773 }
774
775 end:
776 update();
777 m_totalmove = 0;
778 }
779
780 // =============================================================================
781 //
782 void GLRenderer::mousePressEvent (QMouseEvent* ev)
783 {
784 m_totalmove = 0;
785 m_lastButtons = ev->buttons();
786
787 if (m_editmode->mousePressed (ev))
788 ev->accept();
789 }
790
791 // =============================================================================
792 //
793 void GLRenderer::mouseMoveEvent (QMouseEvent* ev)
794 {
795 int dx = ev->x() - m_mousePosition.x();
796 int dy = ev->y() - m_mousePosition.y();
797 m_totalmove += Abs (dx) + Abs (dy);
798 setCameraMoving (false);
799
800 if (not m_editmode->mouseMoved (ev))
801 {
802 const bool left = ev->buttons() & Qt::LeftButton,
803 mid = ev->buttons() & Qt::MidButton,
804 shift = ev->modifiers() & Qt::ShiftModifier;
805
806 if (mid or (left and shift))
807 {
808 pan (X) += 0.03f * dx * (zoom() / 7.5f);
809 pan (Y) -= 0.03f * dy * (zoom() / 7.5f);
810 m_panning = true;
811 setCameraMoving (true);
812 }
813 elif (left and camera() == EFreeCamera)
814 {
815 rot (X) = rot (X) + dy;
816 rot (Y) = rot (Y) + dx;
817
818 clampAngle (rot (X));
819 clampAngle (rot (Y));
820 setCameraMoving (true);
821 }
822 }
823
824 // Start the tool tip timer
825 if (not m_drawToolTip)
826 m_toolTipTimer->start (500);
827
828 // Update 2d position
829 m_mousePosition = ev->pos();
830 m_globalpos = ev->globalPos();
831
832 #ifndef USE_QT5
833 m_mousePositionF = ev->posF();
834 #else
835 m_mousePositionF = ev->localPos();
836 #endif
837
838 // Calculate 3d position of the cursor
839 m_position3D = (camera() != EFreeCamera) ? coordconv2_3 (m_mousePosition, true) : Origin;
840
841 highlightCursorObject();
842 update();
843 ev->accept();
844 }
845
846 // =============================================================================
847 //
848 void GLRenderer::keyPressEvent (QKeyEvent* ev)
849 {
850 m_keymods = ev->modifiers();
851 }
852
853 // =============================================================================
854 //
855 void GLRenderer::keyReleaseEvent (QKeyEvent* ev)
856 {
857 m_keymods = ev->modifiers();
858 m_editmode->keyReleased (ev);
859 update();
860 }
861
862 // =============================================================================
863 //
864 void GLRenderer::wheelEvent (QWheelEvent* ev)
865 {
866 doMakeCurrent();
867
868 zoomNotch (ev->delta() > 0);
869 zoom() = Clamp (zoom(), 0.01, 10000.0);
870 setCameraMoving (true);
871 update();
872 ev->accept();
873 }
874
875 // =============================================================================
876 //
877 void GLRenderer::leaveEvent (QEvent* ev)
878 {
879 (void) ev;
880 m_drawToolTip = false;
881 m_toolTipTimer->stop();
882 update();
883 }
884
885 // =============================================================================
886 //
887 void GLRenderer::contextMenuEvent (QContextMenuEvent* ev)
888 {
889 g_win->spawnContextMenu (ev->globalPos());
890 }
891
892 // =============================================================================
893 //
894 void GLRenderer::setCamera (const ECamera cam)
895 {
896 // The edit mode may forbid the free camera.
897 if (cam == EFreeCamera and not m_editmode->allowFreeCamera())
898 return;
899
900 m_camera = cam;
901 cfg::Camera = (int) cam;
902 g_win->updateEditModeActions();
903 }
904
905 // =============================================================================
906 //
907 void GLRenderer::pick (int mouseX, int mouseY, bool additive)
908 {
909 pick (QRect (mouseX, mouseY, mouseX + 1, mouseY + 1), additive);
910 }
911
912 // =============================================================================
913 //
914 void GLRenderer::pick (QRect const& range, bool additive)
915 {
916 doMakeCurrent();
917
918 // Clear the selection if we do not wish to add to it.
919 if (not additive)
920 {
921 LDObjectList oldsel = Selection();
922 CurrentDocument()->clearSelection();
923
924 for (LDObjectPtr obj : oldsel)
925 compileObject (obj);
926 }
927
928 // Paint the picking scene
929 setPicking (true);
930 drawGLScene();
931
932 int x0 = range.left();
933 int y0 = range.top();
934 int x1 = x0 + range.width();
935 int y1 = y0 + range.height();
936
937 // Clamp the values to ensure they're within bounds
938 x0 = Max (0, x0);
939 y0 = Max (0, y0);
940 x1 = Min (x1, m_width);
941 y1 = Min (y1, m_height);
942 const int areawidth = (x1 - x0);
943 const int areaheight = (y1 - y0);
944 const qint32 numpixels = areawidth * areaheight;
945
946 // Allocate space for the pixel data.
947 uchar* const pixeldata = new uchar[4 * numpixels];
948 uchar* pixelptr = &pixeldata[0];
949
950 // Read pixels from the color buffer.
951 glReadPixels (x0, m_height - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata);
952
953 LDObjectPtr removedObj;
954 QList<qint32> indices;
955
956 // Go through each pixel read and add them to the selection.
957 // Note: black is background, those indices are skipped.
958 for (qint32 i = 0; i < numpixels; ++i)
959 {
960 qint32 idx =
961 (*(pixelptr + 0) * 0x10000) +
962 (*(pixelptr + 1) * 0x100) +
963 *(pixelptr + 2);
964 pixelptr += 4;
965
966 if (idx != 0)
967 indices << idx;
968 }
969
970 RemoveDuplicates (indices);
971
972 for (qint32 idx : indices)
973 {
974 LDObjectPtr obj = LDObject::fromID (idx);
975 assert (obj != null);
976
977 // If this is an additive single pick and the object is currently selected,
978 // we remove it from selection instead.
979 if (additive)
980 {
981 if (obj->isSelected())
982 {
983 obj->deselect();
984 removedObj = obj;
985 break;
986 }
987 }
988
989 obj->select();
990 }
991
992 delete[] pixeldata;
993
994 // Update everything now.
995 g_win->updateSelection();
996
997 // Recompile the objects now to update their color
998 for (LDObjectPtr obj : Selection())
999 compileObject (obj);
1000
1001 if (removedObj)
1002 compileObject (removedObj);
1003
1004 setPicking (false);
1005 repaint();
1006 }
1007
1008 //
1009 // Simpler version of GLRenderer::pick which simply picks whatever object on the screen
1010 //
1011 LDObjectPtr GLRenderer::pickOneObject (int mouseX, int mouseY)
1012 {
1013 uchar pixel[4];
1014 doMakeCurrent();
1015 setPicking (true);
1016 drawGLScene();
1017 glReadPixels (mouseX, m_height - mouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
1018 LDObjectPtr obj = LDObject::fromID ((pixel[0] * 0x10000) + (pixel[1] * 0x100) + pixel[2]);
1019 setPicking (false);
1020 repaint();
1021 return obj;
1022 }
1023
1024 // =============================================================================
1025 //
1026 void GLRenderer::setEditMode (EditModeType a)
1027 {
1028 if (m_editmode != null and m_editmode->type() == a)
1029 return;
1030
1031 delete m_editmode;
1032 m_editmode = AbstractEditMode::createByType (this, a);
1033
1034 // If we cannot use the free camera, use the top one instead.
1035 if (camera() == EFreeCamera and not m_editmode->allowFreeCamera())
1036 setCamera (ETopCamera);
1037
1038 g_win->updateEditModeActions();
1039 update();
1040 }
1041
1042 // =============================================================================
1043 //
1044 EditModeType GLRenderer::currentEditModeType() const
1045 {
1046 return m_editmode->type();
1047 }
1048
1049 // =============================================================================
1050 //
1051 void GLRenderer::setDocument (LDDocumentPtr const& a)
1052 {
1053 m_document = a;
1054
1055 if (a != null)
1056 {
1057 initOverlaysFromObjects();
1058
1059 if (not currentDocumentData().init)
1060 {
1061 resetAllAngles();
1062 currentDocumentData().init = true;
1063 }
1064
1065 currentDocumentData().needZoomToFit = true;
1066 }
1067 }
1068
1069 // =============================================================================
1070 //
1071 void GLRenderer::setPicking (const bool& a)
1072 {
1073 m_isPicking = a;
1074 setBackground();
1075
1076 if (isPicking())
1077 {
1078 glDisable (GL_DITHER);
1079
1080 // Use particularly thick lines while picking ease up selecting lines.
1081 glLineWidth (Max<double> (cfg::LineThickness, 6.5));
1082 }
1083 else
1084 {
1085 glEnable (GL_DITHER);
1086
1087 // Restore line thickness
1088 glLineWidth (cfg::LineThickness);
1089 }
1090 }
1091
1092 // =============================================================================
1093 //
1094 void GLRenderer::getRelativeAxes (Axis& relX, Axis& relY) const
1095 {
1096 const LDFixedCamera* cam = &g_FixedCameras[camera()];
1097 relX = cam->axisX;
1098 relY = cam->axisY;
1099 }
1100
1101 // =============================================================================
1102 //
1103 Axis GLRenderer::getRelativeZ() const
1104 {
1105 const LDFixedCamera* cam = &g_FixedCameras[camera()];
1106 return (Axis) (3 - cam->axisX - cam->axisY);
1107 }
1108
1109 // =============================================================================
1110 //
1111 static QList<Vertex> GetVerticesOf (LDObjectPtr obj)
1112 {
1113 QList<Vertex> verts;
1114
1115 if (obj->numVertices() >= 2)
1116 {
1117 for (int i = 0; i < obj->numVertices(); ++i)
1118 verts << obj->vertex (i);
1119 }
1120 elif (obj->type() == OBJ_Subfile)
1121 {
1122 LDSubfilePtr ref = obj.staticCast<LDSubfile>();
1123 LDObjectList objs = ref->inlineContents (true, false);
1124
1125 for (LDObjectPtr obj : objs)
1126 {
1127 verts << GetVerticesOf (obj);
1128 obj->destroy();
1129 }
1130 }
1131
1132 return verts;
1133 }
1134
1135 // =============================================================================
1136 //
1137 void GLRenderer::compileObject (LDObjectPtr obj)
1138 {
1139 compiler()->stageForCompilation (obj);
1140 }
1141
1142 // =============================================================================
1143 //
1144 void GLRenderer::forgetObject (LDObjectPtr obj)
1145 {
1146 if (compiler() != null)
1147 compiler()->dropObject (obj);
1148 }
1149
1150 // =============================================================================
1151 //
1152 uchar* GLRenderer::getScreencap (int& w, int& h)
1153 {
1154 w = m_width;
1155 h = m_height;
1156 uchar* cap = new uchar[4 * w * h];
1157
1158 m_screencap = true;
1159 update();
1160 m_screencap = false;
1161
1162 // Capture the pixels
1163 glReadPixels (0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, cap);
1164
1165 return cap;
1166 }
1167
1168 // =============================================================================
1169 //
1170 void GLRenderer::slot_toolTipTimer()
1171 {
1172 // We come here if the cursor has stayed in one place for longer than a
1173 // a second. Check if we're holding it over a camera icon - if so, draw
1174 // a tooltip.
1175 for (CameraIcon & icon : m_cameraIcons)
1176 {
1177 if (icon.destRect.contains (m_mousePosition))
1178 {
1179 m_toolTipCamera = icon.cam;
1180 m_drawToolTip = true;
1181 update();
1182 break;
1183 }
1184 }
1185 }
1186
1187 // =============================================================================
1188 //
1189 Axis GLRenderer::getCameraAxis (bool y, ECamera camid)
1190 {
1191 if (camid == (ECamera) -1)
1192 camid = camera();
1193
1194 const LDFixedCamera* cam = &g_FixedCameras[camid];
1195 return (y) ? cam->axisY : cam->axisX;
1196 }
1197
1198 // =============================================================================
1199 //
1200 bool GLRenderer::setupOverlay (ECamera cam, QString file, int x, int y, int w, int h)
1201 {
1202 QImage* img = new QImage (QImage (file).convertToFormat (QImage::Format_ARGB32));
1203 LDGLOverlay& info = getOverlay (cam);
1204
1205 if (img->isNull())
1206 {
1207 Critical (tr ("Failed to load overlay image!"));
1208 currentDocumentData().overlays[cam].invalid = true;
1209 delete img;
1210 return false;
1211 }
1212
1213 delete info.img; // delete the old image
1214
1215 info.fname = file;
1216 info.lw = w;
1217 info.lh = h;
1218 info.ox = x;
1219 info.oy = y;
1220 info.img = img;
1221 info.invalid = false;
1222
1223 if (info.lw == 0)
1224 info.lw = (info.lh * img->width()) / img->height();
1225 elif (info.lh == 0)
1226 info.lh = (info.lw * img->height()) / img->width();
1227
1228 const Axis x2d = getCameraAxis (false, cam),
1229 y2d = getCameraAxis (true, cam);
1230 const double negXFac = g_FixedCameras[cam].negX ? -1 : 1,
1231 negYFac = g_FixedCameras[cam].negY ? -1 : 1;
1232
1233 info.v0 = info.v1 = Origin;
1234 info.v0.setCoordinate (x2d, -(info.ox * info.lw * negXFac) / img->width());
1235 info.v0.setCoordinate (y2d, (info.oy * info.lh * negYFac) / img->height());
1236 info.v1.setCoordinate (x2d, info.v0[x2d] + info.lw);
1237 info.v1.setCoordinate (y2d, info.v0[y2d] + info.lh);
1238
1239 // Set alpha of all pixels to 0.5
1240 for (long i = 0; i < img->width(); ++i)
1241 for (long j = 0; j < img->height(); ++j)
1242 {
1243 uint32 pixel = img->pixel (i, j);
1244 img->setPixel (i, j, 0x80000000 | (pixel & 0x00FFFFFF));
1245 }
1246
1247 updateOverlayObjects();
1248 return true;
1249 }
1250
1251 // =============================================================================
1252 //
1253 void GLRenderer::clearOverlay()
1254 {
1255 if (camera() == EFreeCamera)
1256 return;
1257
1258 LDGLOverlay& info = currentDocumentData().overlays[camera()];
1259 delete info.img;
1260 info.img = null;
1261
1262 updateOverlayObjects();
1263 }
1264
1265 // =============================================================================
1266 //
1267 void GLRenderer::setDepthValue (double depth)
1268 {
1269 assert (camera() < EFreeCamera);
1270 currentDocumentData().depthValues[camera()] = depth;
1271 }
1272
1273 // =============================================================================
1274 //
1275 double GLRenderer::getDepthValue() const
1276 {
1277 assert (camera() < EFreeCamera);
1278 return currentDocumentData().depthValues[camera()];
1279 }
1280
1281 // =============================================================================
1282 //
1283 const char* GLRenderer::getCameraName() const
1284 {
1285 return g_CameraNames[camera()];
1286 }
1287
1288 // =============================================================================
1289 //
1290 LDGLOverlay& GLRenderer::getOverlay (int newcam)
1291 {
1292 return currentDocumentData().overlays[newcam];
1293 }
1294
1295 // =============================================================================
1296 //
1297 void GLRenderer::zoomNotch (bool inward)
1298 {
1299 zoom() *= inward ? 0.833f : 1.2f;
1300 }
1301
1302 // =============================================================================
1303 //
1304 void GLRenderer::zoomToFit()
1305 {
1306 zoom() = 30.0f;
1307
1308 if (document() == null or m_width == -1 or m_height == -1)
1309 return;
1310
1311 bool lastfilled = false;
1312 bool firstrun = true;
1313 enum { black = 0xFF000000 };
1314 bool inward = true;
1315 int runaway = 50;
1316
1317 // Use the pick list while drawing the scene, this way we can tell whether borders
1318 // are background or not.
1319 setPicking (true);
1320
1321 while (--runaway)
1322 {
1323 if (zoom() > 10000.0 or zoom() < 0.0)
1324 {
1325 // Nothing to draw if we get here.
1326 zoom() = 30.0;
1327 break;
1328 }
1329
1330 zoomNotch (inward);
1331 QVector<unsigned char> capture (4 * m_width * m_height);
1332 drawGLScene();
1333 glReadPixels (0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, capture.data());
1334 QImage image (capture.constData(), m_width, m_height, QImage::Format_ARGB32);
1335 bool filled = false;
1336
1337 // Check the top and bottom rows
1338 for (int i = 0; i < image.width(); ++i)
1339 {
1340 if (image.pixel (i, 0) != black or image.pixel (i, m_height - 1) != black)
1341 {
1342 filled = true;
1343 break;
1344 }
1345 }
1346
1347 // Left and right edges
1348 if (filled == false)
1349 {
1350 for (int i = 0; i < image.height(); ++i)
1351 {
1352 if (image.pixel (0, i) != black or image.pixel (m_width - 1, i) != black)
1353 {
1354 filled = true;
1355 break;
1356 }
1357 }
1358 }
1359
1360 if (firstrun)
1361 {
1362 // If this is the first run, we don't know enough to determine
1363 // whether the zoom was to fit, so we mark in our knowledge so
1364 // far and start over.
1365 inward = not filled;
1366 firstrun = false;
1367 }
1368 else
1369 {
1370 // If this run filled the screen and the last one did not, the
1371 // last run had ideal zoom - zoom a bit back and we should reach it.
1372 if (filled and not lastfilled)
1373 {
1374 zoomNotch (false);
1375 break;
1376 }
1377
1378 // If this run did not fill the screen and the last one did, we've
1379 // now reached ideal zoom so we're done here.
1380 if (not filled and lastfilled)
1381 break;
1382
1383 inward = not filled;
1384 }
1385
1386 lastfilled = filled;
1387 }
1388
1389 setPicking (false);
1390 }
1391
1392 // =============================================================================
1393 //
1394 void GLRenderer::zoomAllToFit()
1395 {
1396 zoomToFit();
1397 }
1398
1399 // =============================================================================
1400 //
1401 void GLRenderer::mouseDoubleClickEvent (QMouseEvent* ev)
1402 {
1403 if (m_editmode->mouseDoubleClicked (ev))
1404 ev->accept();
1405 }
1406
1407 // =============================================================================
1408 //
1409 LDOverlayPtr GLRenderer::findOverlayObject (ECamera cam)
1410 {
1411 for (LDObjectPtr obj : document()->objects())
1412 {
1413 LDOverlayPtr ovlobj = obj.dynamicCast<LDOverlay>();
1414
1415 if (ovlobj != null and obj.staticCast<LDOverlay>()->camera() == cam)
1416 return ovlobj;
1417 }
1418
1419 return LDOverlayPtr();
1420 }
1421
1422 // =============================================================================
1423 //
1424 // Read in overlays from the current file and update overlay info accordingly.
1425 //
1426 void GLRenderer::initOverlaysFromObjects()
1427 {
1428 for (ECamera cam = EFirstCamera; cam < ENumCameras; ++cam)
1429 {
1430 if (cam == EFreeCamera)
1431 continue;
1432
1433 LDGLOverlay& meta = currentDocumentData().overlays[cam];
1434 LDOverlayPtr ovlobj = findOverlayObject (cam);
1435
1436 if (ovlobj == null and meta.img != null)
1437 {
1438 delete meta.img;
1439 meta.img = null;
1440 }
1441 elif (ovlobj != null and
1442 (meta.img == null or meta.fname != ovlobj->fileName()) and
1443 not meta.invalid)
1444 {
1445 setupOverlay (cam, ovlobj->fileName(), ovlobj->x(),
1446 ovlobj->y(), ovlobj->width(), ovlobj->height());
1447 }
1448 }
1449 }
1450
1451 // =============================================================================
1452 //
1453 void GLRenderer::updateOverlayObjects()
1454 {
1455 for (ECamera cam = EFirstCamera; cam < ENumCameras; ++cam)
1456 {
1457 if (cam == EFreeCamera)
1458 continue;
1459
1460 LDGLOverlay& meta = currentDocumentData().overlays[cam];
1461 LDOverlayPtr ovlobj = findOverlayObject (cam);
1462
1463 if (meta.img == null and ovlobj != null)
1464 {
1465 // If this is the last overlay image, we need to remove the empty space after it as well.
1466 LDObjectPtr nextobj = ovlobj->next();
1467
1468 if (nextobj and nextobj->type() == OBJ_Empty)
1469 nextobj->destroy();
1470
1471 // If the overlay object was there and the overlay itself is
1472 // not, remove the object.
1473 ovlobj->destroy();
1474 }
1475 elif (meta.img != null and ovlobj == null)
1476 {
1477 // Inverse case: image is there but the overlay object is
1478 // not, thus create the object.
1479 ovlobj = LDSpawn<LDOverlay>();
1480
1481 // Find a suitable position to place this object. We want to place
1482 // this into the header, which is everything up to the first scemantic
1483 // object. If we find another overlay object, place this object after
1484 // the last one found. Otherwise, place it before the first schemantic
1485 // object and put an empty object after it (though don't do this if
1486 // there was no schemantic elements at all)
1487 int i, lastOverlay = -1;
1488 bool found = false;
1489
1490 for (i = 0; i < document()->getObjectCount(); ++i)
1491 {
1492 LDObjectPtr obj = document()->getObject (i);
1493
1494 if (obj->isScemantic())
1495 {
1496 found = true;
1497 break;
1498 }
1499
1500 if (obj->type() == OBJ_Overlay)
1501 lastOverlay = i;
1502 }
1503
1504 if (lastOverlay != -1)
1505 document()->insertObj (lastOverlay + 1, ovlobj);
1506 else
1507 {
1508 document()->insertObj (i, ovlobj);
1509
1510 if (found)
1511 document()->insertObj (i + 1, LDSpawn<LDEmpty>());
1512 }
1513 }
1514
1515 if (meta.img != null and ovlobj != null)
1516 {
1517 ovlobj->setCamera (cam);
1518 ovlobj->setFileName (meta.fname);
1519 ovlobj->setX (meta.ox);
1520 ovlobj->setY (meta.oy);
1521 ovlobj->setWidth (meta.lw);
1522 ovlobj->setHeight (meta.lh);
1523 }
1524 }
1525
1526 if (g_win->R() == this)
1527 g_win->refresh();
1528 }
1529
1530 // =============================================================================
1531 //
1532 void GLRenderer::highlightCursorObject()
1533 {
1534 if (not cfg::HighlightObjectBelowCursor and objectAtCursor() == null)
1535 return;
1536
1537 LDObjectWeakPtr newObject;
1538 LDObjectWeakPtr oldObject = objectAtCursor();
1539 qint32 newIndex;
1540
1541 if (isCameraMoving() or not cfg::HighlightObjectBelowCursor)
1542 {
1543 newIndex = 0;
1544 }
1545 else
1546 {
1547 setPicking (true);
1548 drawGLScene();
1549 setPicking (false);
1550
1551 unsigned char pixel[4];
1552 glReadPixels (m_mousePosition.x(), m_height - m_mousePosition.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel[0]);
1553 newIndex = pixel[0] * 0x10000 | pixel[1] * 0x100 | pixel[2];
1554 }
1555
1556 if (newIndex != (oldObject != null ? oldObject.toStrongRef()->id() : 0))
1557 {
1558 if (newIndex != 0)
1559 newObject = LDObject::fromID (newIndex);
1560
1561 setObjectAtCursor (newObject);
1562
1563 if (oldObject != null)
1564 compileObject (oldObject);
1565
1566 if (newObject != null)
1567 compileObject (newObject);
1568 }
1569
1570 update();
1571 }
1572
1573 void GLRenderer::dragEnterEvent (QDragEnterEvent* ev)
1574 {
1575 if (g_win != null and ev->source() == g_win->getPrimitivesTree() and g_win->getPrimitivesTree()->currentItem() != null)
1576 ev->acceptProposedAction();
1577 }
1578
1579 void GLRenderer::dropEvent (QDropEvent* ev)
1580 {
1581 if (g_win != null and ev->source() == g_win->getPrimitivesTree())
1582 {
1583 QString primName = static_cast<SubfileListItem*> (g_win->getPrimitivesTree()->currentItem())->primitive()->name;
1584 LDSubfilePtr ref = LDSpawn<LDSubfile>();
1585 ref->setColor (MainColor());
1586 ref->setFileInfo (GetDocument (primName));
1587 ref->setPosition (Origin);
1588 ref->setTransform (IdentityMatrix);
1589 LDDocument::current()->insertObj (g_win->getInsertionPoint(), ref);
1590 ref->select();
1591 g_win->buildObjList();
1592 g_win->R()->refresh();
1593 ev->acceptProposedAction();
1594 }
1595 }
1596
1597 Vertex const& GLRenderer::position3D() const
1598 {
1599 return m_position3D;
1600 }
1601
1602 LDFixedCamera const& GLRenderer::getFixedCamera (ECamera cam) const
1603 {
1604 return g_FixedCameras[cam];
1605 }
1606
1607 bool GLRenderer::mouseHasMoved() const
1608 {
1609 return m_totalmove >= 10;
1610 }
1611
1612 QPoint const& GLRenderer::mousePosition() const
1613 {
1614 return m_mousePosition;
1615 }
1616
1617 QPointF const& GLRenderer::mousePositionF() const
1618 {
1619 return m_mousePositionF;
1620 }
1621
1622 void GLRenderer::doMakeCurrent()
1623 {
1624 makeCurrent();
1625 initializeOpenGLFunctions();
1626 }
1627
1628 int GLRenderer::depthNegateFactor() const
1629 {
1630 return g_FixedCameras[camera()].negatedDepth ? -1 : 1;
1631 }
1632
1633 Qt::KeyboardModifiers GLRenderer::keyboardModifiers() const
1634 {
1635 return m_keymods;
1636 }
1637
1638 LDFixedCamera const& GetFixedCamera (ECamera cam)
1639 {
1640 assert (cam != EFreeCamera);
1641 return g_FixedCameras[cam];
1642 }

mercurial