Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PreviewIdentifyTool.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
22 #include "panoinc_WX.h"
23 #include "panoinc.h"
24 
25 #include "PreviewIdentifyTool.h"
26 #include "hugin_config.h"
27 
28 #include "base_wx/platform.h"
29 #include "GLPreviewFrame.h"
30 #include "MainFrame.h"
31 
32 #include <wx/platform.h>
33 
34 //multitexture feature requires glew on some systems
35 #if defined HAVE_EPOXY && HAVE_EPOXY
36 #include <epoxy/gl.h>
37 #else
38 #include <GL/glew.h>
39 #endif
40 
41 #ifdef __WXMAC__
42 #include <OpenGL/gl.h>
43 #include <OpenGL/glu.h>
44 #else
45 #include <GL/gl.h>
46 #include <GL/glu.h>
47 #endif
48 
49 #include <algorithm>
50 #include <vector>
51 
52 // the size of the rectangular texture. Must be a power of two, and at least 8.
53 #define rect_ts 64
54 // the number of times larger the circular texture is, must be a power of 2, and
55 // at least 1. Making better improves the appearance of the circle.
56 #define circle_ts_multiple 4
57 #define circle_ts (rect_ts * circle_ts_multiple)
58 #define circle_middle ((float) (circle_ts - 1) / 2.0)
59 #define circle_border_outer (circle_middle - 0.5 * (float) circle_ts_multiple)
60 #define circle_border_inner (circle_middle - 2.5 * (float) circle_ts_multiple)
61 #define circle_border_peak (circle_middle - 1.5 * (float) circle_ts_multiple)
62 
68 std::vector<int> PreviewIdentifyTool::m_glyphWidth;
69 
70 #define FONT_TEXTURE_HEIGHT 75
71 wxBitmap GenerateFontTexture(const int textureHeight, int& textureWidth, std::vector<int>& glyphWidth)
72 {
73  wxBitmap bitmap(10 * textureHeight, textureHeight);
74  wxMemoryDC dc(bitmap);
75  dc.SetBackground(*wxBLACK_BRUSH);
76  dc.Clear();
77  wxFont font(wxSize(0, textureHeight), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
78  dc.SetFont(font);
79  dc.SetTextForeground(*wxWHITE);
80  dc.DrawText(wxT("0123456789"), 0, 0);
81  textureWidth = 0;
82  glyphWidth.resize(10, 0);
83  for (int i = 0; i < 10; ++i)
84  {
85  wxString number;
86  number << i;
87  wxSize textSize = dc.GetTextExtent(number);
88  textureWidth += textSize.GetWidth();
89  glyphWidth[i] = textSize.GetWidth();
90  };
91  dc.SelectObject(wxNullBitmap);
92  return bitmap;
93 }
94 
96  : Tool(helper)
97 {
98  m_holdControl = false;
99  m_constantOn = false;
100  m_holdLeft = false;
101  m_stopUpdating = true;
102  m_preview_frame = owner;
103  m_showNumbers = showNumbers;
104  if (!texture_created) {
105  // make the textures. We have a circle border and a square one.
106  // the textures are white with a the alpha chanel forming a border.
107  glGenTextures(1, (GLuint*) &rectangle_border_tex);
108  glGenTextures(1, (GLuint*) &circle_border_tex);
109  // we only want to specify alpha, but using just alpha in opengl attaches 0
110  // for the luminosity. I tried biasing the red green and blue values to get
111  // them to 1.0, but it didn't work under OS X for some reason. Instead we
112  // use a luminance alpha pair, and use 1.0 for luminance all the time.
113  {
114  // In the rectangle texture, the middle is 1/4 opaque, the outer pixels
115  // are completely transparent, and one pixel in from the edges is
116  // a completly opaque line.
117  GLubyte rect_tex_data[rect_ts][rect_ts][2];
118  // make everything white
119  for (unsigned int x = 0; x < rect_ts; x++)
120  {
121  for (unsigned int y = 0; y < rect_ts; y++)
122  {
123  rect_tex_data[x][y][0] = 255;
124  }
125  }
126  // now set the middle of the mask semi transparent
127  for (unsigned int x = 2; x < rect_ts - 2; x++)
128  {
129  for (unsigned int y = 2; y < rect_ts - 2; y++)
130  {
131  rect_tex_data[x][y][1] = 63;
132  }
133  }
134  // make an opaque border
135  for (unsigned int d = 1; d < rect_ts - 1; d++)
136  {
137  rect_tex_data[d][1][1] = 255;
138  rect_tex_data[d][rect_ts - 2][1] = 255;
139  rect_tex_data[1][d][1] = 255;
140  rect_tex_data[rect_ts - 2][d][1] = 255;
141  }
142  // make a transparent border around that
143  for (unsigned int d = 0; d < rect_ts; d++)
144  {
145  rect_tex_data[d][0][1] = 0;
146  rect_tex_data[d][rect_ts - 1][1] = 0;
147  rect_tex_data[0][d][1] = 0;
148  rect_tex_data[rect_ts - 1][d][1] = 0;
149  }
150  glBindTexture(GL_TEXTURE_2D, rectangle_border_tex);
151  gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, rect_ts, rect_ts,
152  GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, rect_tex_data);
153  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
154  GL_LINEAR_MIPMAP_LINEAR);
155  // clamp texture so it won't wrap over the border.
156  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
157  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
158  }
159  {
160  // the circular one should look similar to the rectangle one, but we
161  // enlarge it so that the circle apears less blocky. We don't want to
162  // make it equally sharper however, so we make it a bit fuzzier by
163  // blending.
164  GLubyte circle_tex_data[circle_ts][circle_ts][2];
165  for (unsigned int x = 0; x < circle_ts; x++)
166  {
167  for (unsigned int y = 0; y < circle_ts; y++)
168  {
169  float x_offs = (float) x - circle_middle,
170  y_offs = (float) y - circle_middle,
171  radius = sqrt(x_offs * x_offs + y_offs * y_offs),
172  intensity;
173  if (radius < circle_border_inner)
174  {
175  intensity = 63.0;
176  } else if (radius < circle_border_peak)
177  {
178  intensity = (radius - circle_border_inner) /
179  (float) circle_ts_multiple * 255.0 * 3.0 / 4.0 + 64.0;
180  } else if (radius < circle_border_outer)
181  {
182  intensity = (radius - circle_border_peak) /
183  (float) circle_ts_multiple * -255.0 + 256.0;
184  } else
185  {
186  intensity = 0.0;
187  }
188  circle_tex_data[x][y][0] = 255;
189  circle_tex_data[x][y][1] = (unsigned char) intensity;
190  }
191  }
192  glBindTexture(GL_TEXTURE_2D, circle_border_tex);
193  gluBuild2DMipmaps(GL_TEXTURE_2D,
194  GL_LUMINANCE_ALPHA, circle_ts, circle_ts,
195  GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, circle_tex_data);
196  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
197  GL_LINEAR_MIPMAP_LINEAR);
198  // clamp texture so it won't wrap over the border.
199  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
200  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
201  }
202  {
203  int textureWidth;
204  wxBitmap fontTexture(GenerateFontTexture(FONT_TEXTURE_HEIGHT, textureWidth, m_glyphWidth));
205  wxImage image = fontTexture.ConvertToImage();
206  glGenTextures(1, (GLuint*)&font_tex);
207  glBindTexture(GL_TEXTURE_2D, font_tex);
208  GLubyte* font_tex_data = new GLubyte[FONT_TEXTURE_HEIGHT * textureWidth * 2];
209  for (size_t x = 0; x < textureWidth; ++x)
210  {
211  for (size_t y = 0; y < FONT_TEXTURE_HEIGHT; ++y)
212  {
213  const unsigned char value = image.GetRed(x, y);
214  font_tex_data[2 * y * textureWidth + 2 * x] = value;
215  font_tex_data[2 * y * textureWidth + 2 * x + 1] = value;
216  };
217  };
218  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
219  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
220  gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, textureWidth, FONT_TEXTURE_HEIGHT,
221  GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, font_tex_data);
222  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
223  GL_LINEAR_MIPMAP_LINEAR);
224  delete[] font_tex_data;
225 
226  font_list = glGenLists(10);
227  float posX = 0;
228  for (int loop = 0; loop<10; loop++)
229  {
230  glNewList(font_list + loop, GL_COMPILE);
231  glBegin(GL_QUADS);
232  glTexCoord2f(posX, 0);
233  glVertex2i(0, 0);
234  glTexCoord2f(posX + m_glyphWidth[loop] / static_cast<float>(textureWidth), 0);
235  glVertex2i(m_glyphWidth[loop], 0);
236  glTexCoord2f(posX + m_glyphWidth[loop] / static_cast<float>(textureWidth), 1);
237  glVertex2i(m_glyphWidth[loop], FONT_TEXTURE_HEIGHT);
238  glTexCoord2f(posX, 1);
239  glVertex2i(0, FONT_TEXTURE_HEIGHT);
240  glEnd();
241  glTranslatef(m_glyphWidth[loop], 0, 0);
242  glEndList();
243  posX += m_glyphWidth[loop] / static_cast<float>(textureWidth);
244  }
245  }
246  texture_created = true;
247  }
248 }
250 {
251  if (texture_created)
252  {
253  // free the textures
254  glDeleteTextures(1, (GLuint*)&rectangle_border_tex);
255  glDeleteTextures(1, (GLuint*)&circle_border_tex);
256  glDeleteLists(font_list, 10);
257  glDeleteTextures(1, (GLuint*)&font_tex);
258  texture_created = false;
259  };
260 }
261 
263 {
264  // register notifications
269 
270  // clear up
271  // Assume that there are no images under the mouse when the tool is
272  // activated. This should be fine if the user clicks the button to activate
273  // the tool.
274  m_image_set.clear();
275  m_mouse_is_over_button = false;
276  /* TODO if it becomes possible to activate the tool by a keyboard shortcut
277  * or something, call ImagesUnderMouseChangedEvent() to make sure we display
278  * indicators for images currently under the cursor. */
280 }
281 
283  if (!m_image_set.empty())
284  {
285  for (auto& img : m_image_set)
286  {
287  DEBUG_ASSERT(img < helper->GetPanoramaPtr()->getNrOfImages());
288  // reset this button to its default system colour.
289  m_preview_frame->SetImageButtonColour(img, 0, 0, 0);
290  // remove the notification
292  }
293  }
294  m_image_set.clear();
296  m_stopUpdating = true;
297  ForceRedraw();
298 }
299 
301  m_stopUpdating = false;
303 }
304 
305 void PreviewIdentifyTool::MouseMoveEvent(double x, double y, wxMouseEvent & e)
306 {
307 
308  bool stop = false;
309  bool start = false;
310 
311  if (m_constantOn) {
312  if (e.Dragging() && !(m_holdLeft)) {
313  stop = true;
314  m_stopUpdating = true;
315  }
316 
317  if (m_stopUpdating && !e.LeftIsDown() && !e.MiddleIsDown() && !e.RightIsDown()) {
318  start = true;
319  }
320  }
321 
322  if (m_holdControl && !e.m_controlDown) {
323  m_holdControl = false;
324  if (!m_constantOn) {
325  stop = true;
326  }
327  }
328 
329  if (!m_holdControl && e.m_controlDown) {
330  m_holdControl = true;
331  stop = false;
332  if (m_stopUpdating) {
333  start = true;
334  }
335  }
336 
337  if (stop) {
338  this->StopUpdating();
339  } else if(start) {
340  this->ContinueUpdating();
341  }
342 
343 
344 }
345 
346 void PreviewIdentifyTool::KeypressEvent(int keycode, int modifierss, int pressed) {
347 
348  if (keycode == WXK_CONTROL) {
349  if (pressed) {
350  m_holdControl = true;
352  } else {
353  if(m_holdControl) {
354  StopUpdating();
355  }
356  m_holdControl = false;
357  }
358  }
359 }
360 
361 void PreviewIdentifyTool::setConstantOn(bool constant_on_in) {
362  m_constantOn = constant_on_in;
363  if (constant_on_in) {
364  m_stopUpdating = false;
365  helper->SetStatusMessage(_("Move the mouse over the images or image buttons to identify them."));
367  } else {
368  m_stopUpdating = true;
369  StopUpdating();
370  }
371 
372 }
373 
374 
376 {
377  if (m_stopUpdating) {
378  return;
379  }
380 
381  std::set<unsigned int> new_image_set = helper->GetImageNumbersUnderMouse();
382 
383  //UpdateIdentifyTools() will unrequest notification for the old indicators,
384  //reset the button colors, request notification for the new ones, swap in
385  //m_image_set with new_image_set, and force a redraw for all three
386  //PreviewIdentifyTool objects in GLPreviewFrame. This has the effect of
387  //displaying the indicators in both the preview and overview when you move
388  //your mouse over either when the Identify button is toggled on.
389  m_preview_frame->UpdateIdentifyTools(new_image_set);
390 
391  // if there is exactly two images, tell the user they can click to edit CPs.
392  if (m_image_set.size() == 2)
393  {
394  helper->SetStatusMessage(_("Click to create or edit control points here."));
395  } else {
396  helper->SetStatusMessage(_("Move the mouse over the images or image buttons to identify them."));
397  }
398 }
399 
401 {
402  // we draw the partly transparent identification boxes over the top of the
403  // entire stack of images in m_image_set so that the extents of images in the
404  // background are clearly marked.
405  const unsigned int num_images = m_image_set.size();
406  // draw the actual images
407  // the preview draws them in reverse order, so the lowest numbered appears
408  // on top. We will folow this convention to avoid confusion.
409  glMatrixMode(GL_MODELVIEW);
410  for (auto it = m_image_set.rbegin(); it != m_image_set.rend(); ++it)
411  {
412  DEBUG_ASSERT(*it < helper->GetPanoramaPtr()->getNrOfImages());
414  DrawImage(*it,
416  }
417  glMatrixMode(GL_TEXTURE);
418 
419  // now draw the identification boxes
420  glEnable(GL_BLEND);
421  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
422  unsigned int image_counter = 0;
423  const unsigned int canvasWidth = helper->GetViewStatePtr()->GetOptions()->getWidth();
424  const unsigned int canvasHeight = helper->GetViewStatePtr()->GetOptions()->getHeight();
425  for (auto it = m_image_set.rbegin(); it != m_image_set.rend(); ++it)
426  {
427  glMatrixMode(GL_TEXTURE);
428  // Use the mask to alter the shape of the identification boxes, but
429  // replace the normal image texture with the identification box itself.
431  {
433  glActiveTexture(GL_TEXTURE0);
434  }
435  // we want to shift the texture so it lines up with the cropped region.
436  glPushMatrix();
438  GetSrcImage(*it);
439  int width = src->getSize().width(), height = src->getSize().height();
440  vigra::Rect2D crop_region = src->getCropRect();
441  // pick a texture depending on crop mode and move it to the cropped area
442  switch (src->getCropMode())
443  {
445  glBindTexture(GL_TEXTURE_2D, circle_border_tex);
446  // change the crop region to a square around the circle.
447  if (crop_region.width() < crop_region.height())
448  {
449  // too tall, move top and bottom.
450  int diff = (crop_region.width() - crop_region.height()) / 2;
451  // diff is negative, so we will shrink the border in the y
452  // direction.
453  crop_region.addBorder(0, diff);
454  } else if (crop_region.width() > crop_region.height())
455  {
456  // too wide, move left and right
457  int diff = (crop_region.height() - crop_region.width()) / 2;
458  crop_region.addBorder(diff, 0);
459  }
460  {
461  float diameter = (float) crop_region.width();
462  glScalef((float) width / diameter,
463  (float) height / diameter, 1.0);
464  glTranslatef(-(float) crop_region.left() / (float) width,
465  -(float) crop_region.top() / (float) height,
466  0.0);
467  }
468  break;
470  // get the biggest rectangle contained by both the image
471  // and the cropped area.
472  crop_region &= vigra::Rect2D(src->getSize());
473  glBindTexture(GL_TEXTURE_2D, rectangle_border_tex);
474  glScalef((float) width / (float) crop_region.width(),
475  (float) height / (float) crop_region.height(),
476  1.0);
477  glTranslatef(-(float) crop_region.left() / (float) width,
478  -(float) crop_region.top() / (float) height,
479  0.0);
480  break;
482  glBindTexture(GL_TEXTURE_2D, rectangle_border_tex);
483  break;
484  }
485  // draw the image in this texture
486  glMatrixMode(GL_MODELVIEW);
487  unsigned char r,g,b;
488  HighlightColour(image_counter, num_images, r, g, b);
489  image_counter++;
490  glColor3ub(r,g,b);
492  glMatrixMode(GL_TEXTURE);
493  glPopMatrix();
494  // tell the preview frame to update the button to show the same colour.
495  m_preview_frame->SetImageButtonColour(*it, r, g, b);
496  // draw number
497  // this code works only for the preview window, not for the panosphere or mosaic plane
498  if (m_showNumbers)
499  {
503  transform.createInvTransform(*img, *opts);
504  hugin_utils::FDiff2D imageCenter(crop_region.upperLeft() + crop_region.size() / 2);
505  hugin_utils::FDiff2D imageCenterPano;
506  if (transform.transformImgCoord(imageCenterPano, imageCenter) && !wxGetKeyState(WXK_ALT))
507  {
508  glBindTexture(GL_TEXTURE_2D, font_tex);
510  {
511  glActiveTexture(GL_TEXTURE1);
512  glDisable(GL_TEXTURE_2D);
513  glActiveTexture(GL_TEXTURE0);
514  };
515  glMatrixMode(GL_MODELVIEW);
516  glPushMatrix();
517  wxString number;
518  number << *it;
519  int textWidth = 0;
520  unsigned char* listIndex = new unsigned char[number.Length()];
521  for (size_t i = 0; i < number.Length(); ++i)
522  {
523  textWidth += m_glyphWidth[number[i].GetValue() - 48];
524  listIndex[i] = number[i].GetValue() - 48;
525  }
526  float scaleFactor = std::min(canvasWidth, canvasHeight) / static_cast<float>(FONT_TEXTURE_HEIGHT) / 10;
527  imageCenterPano.x = std::min<double>(std::max<double>(imageCenterPano.x, textWidth*scaleFactor / 2.0), canvasWidth - textWidth * scaleFactor / 2.0);
528  imageCenterPano.y = std::min<double>(std::max<double>(imageCenterPano.y, FONT_TEXTURE_HEIGHT*scaleFactor / 2.0), canvasHeight - FONT_TEXTURE_HEIGHT * scaleFactor / 2.0);
529  glTranslatef(imageCenterPano.x, imageCenterPano.y, 0);
530  glScalef(scaleFactor, scaleFactor, 1.0);
531  glTranslatef(-textWidth / 2, -FONT_TEXTURE_HEIGHT / 2, 0);
532  glListBase(font_list);
533  glCallLists(number.Length(), GL_UNSIGNED_BYTE, listIndex);
534  glMatrixMode(GL_MODELVIEW);
535  glPopMatrix();
536  delete[] listIndex;
537  };
538  };
539  }
540  // set stuff back how we found it.
541  glMatrixMode(GL_MODELVIEW);
542  glDisable(GL_BLEND);
543  glColor3ub(255, 255, 255);
544 }
545 
547 {
548  // Delay drawing of images, so we can show them on top of the others.
549  DEBUG_ASSERT(image < helper->GetPanoramaPtr()->getNrOfImages());
550  if (m_image_set.count(image)) return false;
551  return true;
552 }
553 
554 void PreviewIdentifyTool::ShowImageNumber(unsigned int image)
555 {
556  DEBUG_ASSERT(image < helper->GetPanoramaPtr()->getNrOfImages());
557  // Add this image to the set of images drawn.
558  if (!m_image_set.count(image))
559  {
560  // it is not already in the set. Add it now
561  m_image_set.insert(image);
562  // we want notification of when it is drawn so we can delay drawing.
563  helper->NotifyMeBeforeDrawing(image, this);
564  // now we want a redraw.
565  ForceRedraw();
566  }
567  m_mouse_over_image = image;
568  m_mouse_is_over_button = true;
569 }
570 
572 {
574  {
575  // set the colour to the image the user just moused off to the default.
579  // now redraw without the indicator.
580  ForceRedraw();
581  m_mouse_is_over_button = false;
582  }
583 }
584 
585 // generate a colour given how many colours we need and an index.
586 void PreviewIdentifyTool::HighlightColour(unsigned int index,
587  unsigned int count,
588  unsigned char &red,
589  unsigned char &green,
590  unsigned char &blue)
591 {
592  DEBUG_ASSERT(index < count && index >= 0);
593  // the first one is red, the rest are evenly spaced throughout the spectrum
594  float hue = ((float) index / (float) count) * 6.0;
595  if (hue < 1.0)
596  {
597  // red to yellow
598  red = 255;
599  green = (unsigned char) (hue * 255.0);
600  blue = 0;
601  } else if (hue < 2.0) {
602  // yellow to green
603  red = (unsigned char) ((-hue + 2.0) * 255.0);
604  green = 255;
605  blue = 0;
606  } else if (hue < 3.0) {
607  // green to cyan
608  red = 0;
609  green = 255;
610  blue = (unsigned char) ((hue - 2.0) * 255.0);
611  } else if (hue < 4.0) {
612  // cyan to blue
613  red = 0;
614  green = (unsigned char) ((-hue + 4.0) * 255.0);
615  blue = 255;
616  } else if (hue < 5.0) {
617  // blue to magenta
618  red = (unsigned char) ((hue - 4.0) * 255.0);
619  green = 0;
620  blue = 255;
621  } else {
622  // magenta to red
623  red = 255;
624  green = 0;
625  blue = (unsigned char) ((-hue + 6.0) * 255.0);
626  }
627 }
628 
630 {
631 
632 
633  if ( e.LeftDown() && helper->IsMouseOverPano())
634  {
635  m_holdLeft = true;
636  }
637 
638  if (m_holdLeft && e.LeftUp() && (!m_image_set.empty()))
639  {
640  m_holdLeft = false;
641  if (m_constantOn || e.CmdDown())
642  {
643  // when there are at least two images with indicators shown, show the
644  // control point editor with the first two images when left clicked.
645  if(m_image_set.size()>1)
646  {
648  *(++m_image_set.begin()));
649  }
650  else
651  {
653  };
654  MainFrame::Get()->Raise();
655  }
656  }
657 
658  if (m_holdLeft && !(e.LeftIsDown())) {
659  m_holdLeft = false;
660  }
661 
662  if (m_constantOn) {
663  if (e.ButtonUp() && !e.MiddleIsDown() && !e.RightIsDown()) {
664  m_stopUpdating = false;
666  }
667  }
668 
669 }
670 
671 void PreviewIdentifyTool::UpdateWithNewImageSet(std::set<unsigned int> new_image_set)
672 {
673  // If we are currently showing indicators for some of the images, we want
674  // to work out which ones are not in the new set, so we can set their
675  // buttons back to the system colour.
676  if (!m_image_set.empty())
677  {
678  HuginBase::UIntSet difference;
679  std::set_difference (m_image_set.begin(), m_image_set.end(),
680  new_image_set.begin(), new_image_set.end(),
681  std::inserter(difference,difference.end()));
682  if (!difference.empty())
683  {
684  for (auto& img : difference)
685  {
686  DEBUG_ASSERT(img < helper->GetPanoramaPtr()->getNrOfImages());
687  // reset this button to its default system colour.
688  m_preview_frame->SetImageButtonColour(img, 0, 0, 0);
689  // remove the notification
691  }
692  }
693  }
694 
695  // now request to be notified when drawing the new ones.
696  if (!new_image_set.empty())
697  {
698  HuginBase::UIntSet difference;
699  std::set_difference(new_image_set.begin(), new_image_set.end(),
700  m_image_set.begin(), m_image_set.end(),
701  std::inserter(difference, difference.end()));
702  if (!difference.empty())
703  {
704  for (auto& img : difference)
705  {
706  DEBUG_ASSERT(img < helper->GetPanoramaPtr()->getNrOfImages());
707  // get notification of when this is about to be drawn.
708  helper->NotifyMeBeforeDrawing(img, this);
709  }
710  }
711  };
712  // remember the new set.
713  m_image_set.swap(new_image_set);
714 
715  // Redraw with new indicators. Since the indicators aren't part of the
716  // panorama and none of it is likely to change, we have to persuade the
717  // viewstate that a redraw is required.
718  ForceRedraw();
719 }
720 
722 {
725 }
void setConstantOn(bool constant_on_in)
PreviewIdentifyTool(ToolHelper *helper, GLPreviewFrame *owner, bool showNumbers)
constructor
unsigned int m_mouse_over_image
The image the user last placed their mouse over the button for.
implementation of huginApp Class
#define FONT_TEXTURE_HEIGHT
The OpenGL preview frame.
ViewState * GetViewStatePtr()
Definition: ToolHelper.cpp:305
wxBitmap GenerateFontTexture(const int textureHeight, int &textureWidth, std::vector< int > &glyphWidth)
#define circle_border_outer
void NotifyMeBeforeDrawing(unsigned int image_nr, Tool *tool)
Definition: ToolHelper.cpp:349
GLPreviewFrame * m_preview_frame
unsigned int getHeight() const
get panorama height
void StopShowingImages()
Notification for when moving the mouse off an image button.
void Activate()
Switch on a tool.
static unsigned int rectangle_border_tex
OpenGL texture name for the rectangular border texture.
#define DEBUG_ASSERT(cond)
Definition: utils.h:80
include file for the hugin project
void ForceRequireRedraw()
Definition: ViewState.cpp:439
void NotifyMe(Event event, Tool *tool)
Definition: ToolHelper.cpp:315
std::set< unsigned int > GetImageNumbersUnderMouse()
Definition: ToolHelper.cpp:281
static unsigned int font_list
OpenGL call list id for font.
void MouseButtonEvent(wxMouseEvent &e)
Show control point editor if mouse is over two images.
#define circle_ts
void AfterDrawImagesEvent()
Draw (using OpenGL) images above the others.
std::set< unsigned int > m_image_set
Set of image numbers of the images we are displaying highlighted.
VisualizationState * GetVisualizationStatePtr()
Definition: ToolHelper.cpp:300
void ShowImageNumber(unsigned int image)
Notification for when moving the mouse on an image button.
HuginBase::PanoramaOptions * GetOptions()
Definition: ViewState.cpp:273
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
#define circle_border_peak
void MouseMoveEvent(double x, double y, wxMouseEvent &e)
Notify when the mouse pointer has moved over the panorama preview.
ToolHelper * helper
The PreviewToolHelper that uses the same preview window and panorama as the tool should.
Definition: Tool.h:102
void HighlightColour(unsigned int index, unsigned int count, unsigned char &red, unsigned char &green, unsigned char &blue)
Generate a colour given how many colours we need and an index.
void DoNotNotifyMeBeforeDrawing(unsigned int image_nr, Tool *tool)
Definition: ToolHelper.cpp:397
#define circle_border_inner
Definition: Tool.h:42
static MainFrame * Get()
hack.. kind of a pseudo singleton...
Definition: MainFrame.cpp:2169
bool IsMouseOverPano()
Definition: ToolHelper.h:136
void createInvTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
create image-&gt;pano transformation
static unsigned int circle_border_tex
OpenGL texture name for the circular border texture.
TextureManager * GetTextureManager()
Definition: ViewState.h:104
void UpdateIdentifyTools(std::set< unsigned int > new_image_set)
#define circle_middle
void ShowMaskEditor(size_t imgNr, bool switchToCropMode=false)
opens the mask/crop editor with the given image selected
Definition: MainFrame.cpp:2040
void BindTexture(unsigned int image_number)
void UpdateWithNewImageSet(std::set< unsigned int > new_image_set)
unsigned int getWidth() const
include file for the hugin project
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
#define rect_ts
void KeypressEvent(int keycode, int modifiers, int pressed)
void ShowCtrlPointEditor(unsigned int img1, unsigned int img2)
opens the control points tab with the both images selected
Definition: MainFrame.cpp:2028
Holds transformations for Image -&gt; Pano and the other way.
void SetStatusMessage(wxString message)
Definition: ToolHelper.cpp:409
bool BeforeDrawImageEvent(unsigned int image)
Draw what the tool requires just before a given image is drawn.
void ImagesUnderMouseChangedEvent()
Notify when the images directly underneath the mouse pointer have changed.
HuginBase::SrcPanoImage * GetSrcImage(unsigned int image_nr)
Definition: ViewState.cpp:283
All variables of a source image.
Definition: SrcPanoImage.h:194
Panorama image options.
unsigned int GetMeshDisplayList(unsigned int image_nr)
Definition: ViewState.cpp:462
void SetImageButtonColour(unsigned int image_nr, unsigned char red, unsigned char green, unsigned char blue)
static T min(T x, T y)
Definition: svm.cpp:62
bool GetSupportMultiTexture() const
Definition: ViewState.h:106
#define circle_ts_multiple
static unsigned int font_tex
OpenGL texture name for the font texture.
static std::vector< int > m_glyphWidth
glyph width for font