gldraw.cpp

changeset 133
5a8073d713a3
parent 132
577e8e89d8de
child 134
7fd0784471df
equal deleted inserted replaced
132:577e8e89d8de 133:5a8073d713a3
24 #include "file.h" 24 #include "file.h"
25 #include "gldraw.h" 25 #include "gldraw.h"
26 #include "bbox.h" 26 #include "bbox.h"
27 #include "colors.h" 27 #include "colors.h"
28 #include "gui.h" 28 #include "gui.h"
29 #include "misc.h"
29 30
30 static double g_faObjectOffset[3]; 31 static double g_faObjectOffset[3];
31 static double g_StoredBBoxSize; 32 static double g_StoredBBoxSize;
32 33
33 static short g_dPulseTick = 0; 34 static short g_dPulseTick = 0;
44 // ============================================================================= 45 // =============================================================================
45 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
46 // ============================================================================= 47 // =============================================================================
47 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) { 48 GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) {
48 resetAngles (); 49 resetAngles ();
49 picking = false; 50 picking = rangepick = false;
50 51
51 qPulseTimer = new QTimer (this); 52 qPulseTimer = new QTimer (this);
52 connect (qPulseTimer, SIGNAL (timeout ()), this, SLOT (slot_timerUpdate ())); 53 connect (qPulseTimer, SIGNAL (timeout ()), this, SLOT (slot_timerUpdate ()));
53 } 54 }
54 55
137 assert (i != -1); 138 assert (i != -1);
138 139
139 // Calculate a color based from this index. This method caters for 140 // Calculate a color based from this index. This method caters for
140 // 16777216 objects. I don't think that'll be exceeded anytime soon. :) 141 // 16777216 objects. I don't think that'll be exceeded anytime soon. :)
141 // ATM biggest is 53588.dat with 12600 lines. 142 // ATM biggest is 53588.dat with 12600 lines.
142 double r = i % 256; 143 double r = (i / (256 * 256)) % 256,
143 double g = (i / 256) % 256; 144 g = (i / 256) % 256,
144 double b = (i / (256 * 256)) % 256; 145 b = i % 256;
145 146
146 glColor3f (r / 255.f, g / 255.f, b / 255.f); 147 glColor3f (r / 255.f, g / 255.f, b / 255.f);
147 return; 148 return;
148 } 149 }
149 150
236 237
237 // ============================================================================= 238 // =============================================================================
238 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 239 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
239 // ============================================================================= 240 // =============================================================================
240 void GLRenderer::resizeGL (int w, int h) { 241 void GLRenderer::resizeGL (int w, int h) {
242 width = w;
243 height = h;
244
241 glViewport (0, 0, w, h); 245 glViewport (0, 0, w, h);
242 glLoadIdentity (); 246 glLoadIdentity ();
243 glMatrixMode (GL_PROJECTION); 247 glMatrixMode (GL_PROJECTION);
244 gluPerspective (45.0f, (double)w / (double)h, 0.1f, 100.0f); 248 gluPerspective (45.0f, (double)w / (double)h, 0.1f, 100.0f);
245 } 249 }
246 250
251 template<class T> using initlist = std::initializer_list<T>;
252
247 // ============================================================================= 253 // =============================================================================
248 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 254 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
249 // ============================================================================= 255 // =============================================================================
250 void GLRenderer::paintGL () { 256 void GLRenderer::paintGL () {
251 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 257 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
265 glRotatef (rotZ, 0.0f, 0.0f, 1.0f); 271 glRotatef (rotZ, 0.0f, 0.0f, 1.0f);
266 272
267 for (LDObject* obj : g_CurrentFile->objects) 273 for (LDObject* obj : g_CurrentFile->objects)
268 glCallList ((picking == false) ? obj->uGLList : obj->uGLPickList); 274 glCallList ((picking == false) ? obj->uGLList : obj->uGLPickList);
269 glPopMatrix (); 275 glPopMatrix ();
276
277 // If we're range-picking, draw a rectangle encompassing the selection area.
278 if (rangepick && !picking) {
279 const short x0 = rangeStart.x (),
280 y0 = rangeStart.y (),
281 x1 = pos.x (),
282 y1 = pos.y ();
283
284 glMatrixMode (GL_PROJECTION);
285
286 glPushMatrix ();
287 glLoadIdentity ();
288 glOrtho (.0, width, height, .0, -1.0, 1.0);
289
290 for (int x : vector<int> ({GL_QUADS, GL_LINE_LOOP})) {
291 if (x == GL_QUADS)
292 glColor4f (.0, .8, 1.0, .6);
293 else
294 glColor4f (1.0, 1.0, 1.0, 1.0);
295
296 glBegin (x);
297 glVertex2i (x0, y0);
298 glVertex2i (x1, y0);
299 glVertex2i (x1, y1);
300 glVertex2i (x0, y1);
301 glEnd ();
302 }
303 glPopMatrix ();
304
305 glMatrixMode (GL_MODELVIEW);
306 }
270 } 307 }
271 308
272 // ============================================================================= 309 // =============================================================================
273 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 310 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
274 // ============================================================================= 311 // =============================================================================
435 472
436 // ============================================================================= 473 // =============================================================================
437 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 474 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
438 // ============================================================================= 475 // =============================================================================
439 void GLRenderer::mouseReleaseEvent (QMouseEvent* ev) { 476 void GLRenderer::mouseReleaseEvent (QMouseEvent* ev) {
440 if ((qMouseButtons & Qt::LeftButton) && !(ev->buttons() & Qt::LeftButton)) { 477 if ((lastButtons & Qt::LeftButton) && !(ev->buttons() & Qt::LeftButton)) {
441 if (ulTotalMouseMove < 10) 478 if (ulTotalMouseMove < 10 || rangepick)
442 pick (ev->x(), ev->y(), (qKeyMods & Qt::ControlModifier)); 479 pick (ev->x (), ev->y (), (qKeyMods & Qt::ControlModifier));
443 480
481 rangepick = false;
444 ulTotalMouseMove = 0; 482 ulTotalMouseMove = 0;
445 } 483 }
446 } 484 }
447 485
448 // ============================================================================= 486 // =============================================================================
449 void GLRenderer::mousePressEvent (QMouseEvent* ev) { 487 void GLRenderer::mousePressEvent (QMouseEvent* ev) {
450 qMouseButtons = ev->buttons(); 488 if (ev->buttons () & Qt::LeftButton)
451 if (ev->buttons() & Qt::LeftButton)
452 ulTotalMouseMove = 0; 489 ulTotalMouseMove = 0;
490
491 if (ev->modifiers () & Qt::ShiftModifier) {
492 rangepick = true;
493 rangeStart.setX (ev->x ());
494 rangeStart.setY (ev->y ());
495 }
496
497 lastButtons = ev->buttons ();
453 } 498 }
454 499
455 // ============================================================================= 500 // =============================================================================
456 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 501 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
457 // ============================================================================= 502 // =============================================================================
458 void GLRenderer::mouseMoveEvent (QMouseEvent* ev) { 503 void GLRenderer::mouseMoveEvent (QMouseEvent* ev) {
459 int dx = ev->x () - lastPos.x (); 504 int dx = ev->x () - pos.x ();
460 int dy = ev->y () - lastPos.y (); 505 int dy = ev->y () - pos.y ();
461 ulTotalMouseMove += abs (dx) + abs (dy); 506 ulTotalMouseMove += abs (dx) + abs (dy);
462 507
463 if (ev->buttons () & Qt::LeftButton) { 508 if (ev->buttons () & Qt::LeftButton && !rangepick) {
464 rotX = rotX + (dy); 509 rotX = rotX + (dy);
465 rotY = rotY + (dx); 510 rotY = rotY + (dx);
511
466 clampAngle (rotX); 512 clampAngle (rotX);
467 clampAngle (rotY); 513 clampAngle (rotY);
468 }
469
470 if (ev->buttons () & Qt::RightButton) {
471 rotX = rotX + (dy);
472 rotZ = rotZ + (dx);
473 clampAngle (rotX);
474 clampAngle (rotZ);
475 } 514 }
476 515
477 if (ev->buttons () & Qt::MidButton) { 516 if (ev->buttons () & Qt::MidButton) {
478 panX += 0.03f * dx; 517 panX += 0.03f * dx;
479 panY -= 0.03f * dy; 518 panY -= 0.03f * dy;
480 } 519 }
481 520
482 lastPos = ev->pos (); 521 pos = ev->pos ();
483 updateGL (); 522 updateGL ();
484 } 523 }
485 524
486 // ============================================================================= 525 // =============================================================================
487 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 526 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
514 } 553 }
515 554
516 // ========================================================================= // 555 // ========================================================================= //
517 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 556 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
518 // ========================================================================= // 557 // ========================================================================= //
519 void GLRenderer::pick (uint uMouseX, uint uMouseY, bool bAdd) { 558 void GLRenderer::pick (uint mx, uint my, bool add) {
520 if (bAdd == false) { 559 GLint viewport[4];
560
561 if (add == false) {
521 // Clear the selection if we don't wish to add to it. 562 // Clear the selection if we don't wish to add to it.
522 std::vector<LDObject*> paOldSelection = g_ForgeWindow->paSelection; 563 std::vector<LDObject*> paOldSelection = g_ForgeWindow->paSelection;
523 g_ForgeWindow->paSelection.clear (); 564 g_ForgeWindow->paSelection.clear ();
524 565
525 // Recompile the prior selection to remove the highlight color 566 // Recompile the prior selection to remove the highlight color
526 for (LDObject* obj : paOldSelection) 567 for (LDObject* obj : paOldSelection)
527 recompileObject (obj); 568 recompileObject (obj);
528 } 569 }
529 570
571 picking = true;
572
573 // Paint the picking scene
530 glDisable (GL_DITHER); 574 glDisable (GL_DITHER);
531 glClearColor (1.0f, 1.0f, 1.0f, 1.0f); 575 glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
532
533 picking = true;
534
535 paintGL (); 576 paintGL ();
536 577
537 GLubyte ucaPixel[3]; 578 glGetIntegerv (GL_VIEWPORT, viewport);
538 GLint daViewport[4]; 579
539 glGetIntegerv (GL_VIEWPORT, daViewport); 580 short x0 = mx,
540 glReadPixels (uMouseX, daViewport[3] - uMouseY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, 581 y0 = my;
541 reinterpret_cast<GLvoid*> (ucaPixel)); 582 short x1, y1;
542 583
543 // If we hit a white pixel, we selected the background. This no object is selected. 584 if (rangepick) {
544 const bool bHasSelection = (ucaPixel[0] != 255 || ucaPixel[1] != 255 || ucaPixel[2] != 255); 585 x1 = rangeStart.x ();
545 586 y1 = rangeStart.y ();
546 if (bHasSelection) { 587 } else {
547 ulong idx = ucaPixel[0] + (ucaPixel[1] * 256) + (ucaPixel[2] * 256 * 256); 588 x1 = x0 + 1;
589 y1 = y0 + 1;
590 }
591
592 if (x0 > x1)
593 dataswap (x0, x1);
594
595 if (y0 > y1)
596 dataswap (y0, y1);
597
598 // Clamp the values to ensure they're within bounds
599 x0 = max<short> (0, x0);
600 y0 = max<short> (0, y0);
601 x1 = min<short> (x1, width);
602 y1 = min<short> (y1, height);
603
604 short areawidth = (x1 - x0);
605 short areaheight = (y1 - y0);
606
607 const long numpixels = areawidth * areaheight;
608 uchar* const pixeldata = new uchar[4 * numpixels];
609 uchar* pixelptr = &pixeldata[0];
610
611 assert (viewport[3] == height);
612
613 glReadPixels (x0, viewport[3] - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata);
614
615 for (long i = 0; i < numpixels; ++i) {
616 uint32 idx =
617 (*(pixelptr) * 0x10000) +
618 (*(pixelptr + 1) * 0x00100) +
619 (*(pixelptr + 2) * 0x00001);
620 pixelptr += 4;
621
622 if (idx == 0xFFFFFF)
623 continue; // White is background; skip
548 624
549 LDObject* obj = g_CurrentFile->object (idx); 625 LDObject* obj = g_CurrentFile->object (idx);
550 g_ForgeWindow->paSelection.push_back (obj); 626 g_ForgeWindow->paSelection.push_back (obj);
551 } 627 }
552 628
629 delete[] pixeldata;
630
631 std::vector<LDObject*>& sel = g_ForgeWindow->paSelection;
632 std::sort (sel.begin(), sel.end ());
633 std::vector<LDObject*>::iterator pos = std::unique (sel.begin (), sel.end ());
634 sel.resize (std::distance (sel.begin (), pos));
635
553 g_ForgeWindow->buildObjList (); 636 g_ForgeWindow->buildObjList ();
554 637
555 picking = false; 638 picking = false;
639 rangepick = false;
556 glEnable (GL_DITHER); 640 glEnable (GL_DITHER);
557 641
558 setBackground (); 642 setBackground ();
559 updateSelFlash (); 643 updateSelFlash ();
560 644

mercurial