Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
vpDisplayWin32.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software 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 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Windows 32 display base class
32  */
33 
34 #include <visp3/core/vpConfig.h>
35 #if (defined(VISP_HAVE_GDI) || defined(VISP_HAVE_D3D9))
36 
37 #include <string>
38 #include <visp3/core/vpDisplayException.h>
39 #include <visp3/gui/vpDisplayWin32.h>
40 
42 
43 const int vpDisplayWin32::MAX_INIT_DELAY = 5000;
44 
49 void vpCreateWindow(threadParam *param)
50 {
51  // char* title = param->title;
52  (param->vpDisp)->window.initWindow(param->title.c_str(), param->x, param->y, param->w, param->h);
53  delete param;
54 }
55 
59 vpDisplayWin32::vpDisplayWin32(vpWin32Renderer *rend) : iStatus(false), window(rend) { }
60 
61 vpDisplayWin32::vpDisplayWin32(vpImage<vpRGBa> &I, int winx, int winy, const std::string &title)
62  : iStatus(false), window(nullptr)
63 {
64  init(I, winx, winy, title);
65 }
66 
67 vpDisplayWin32::vpDisplayWin32(vpImage<unsigned char> &I, int winx, int winy, const std::string &title)
68  : iStatus(false), window(nullptr)
69 {
70  init(I, winx, winy, title);
71 }
72 
73 
74 
79 
90 void vpDisplayWin32::init(vpImage<unsigned char> &I, int x, int y, const std::string &title)
91 {
92  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
93  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
94  }
95 
97  init(I.getWidth(), I.getHeight(), x, y, title);
98  window.renderer->setWidth(I.getWidth() / m_scale);
99  window.renderer->setHeight(I.getHeight() / m_scale);
100  window.renderer->setImg(I);
101 
102  I.display = this;
103 }
104 
113 void vpDisplayWin32::init(vpImage<vpRGBa> &I, int x, int y, const std::string &title)
114 {
115  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
116  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
117  }
118 
120  init(I.getWidth(), I.getHeight(), x, y, title);
121  window.renderer->setWidth(I.getWidth() / m_scale);
122  window.renderer->setHeight(I.getHeight() / m_scale);
123  window.renderer->setImg(I);
124 
125  I.display = this;
126 }
127 
136 void vpDisplayWin32::init(unsigned int width, unsigned int height, int x, int y, const std::string &title)
137 {
138  if (!title.empty())
139  m_title = title;
140  else
141  m_title = std::string(" ");
142 
143  if (x != -1)
144  m_windowXPosition = x;
145  if (y != -1)
146  m_windowYPosition = y;
147 
148  // we prepare the window's thread creation
149  setScale(m_scaleType, width, height);
150  threadParam *param = new threadParam;
151  param->x = m_windowXPosition;
152  param->y = m_windowYPosition;
153  param->w = width / m_scale;
154  param->h = height / m_scale;
155  param->vpDisp = this;
156  param->title = this->m_title;
157 
158  // creates the window in a separate thread
159  hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)vpCreateWindow, param, 0, &threadId);
160 
161  // the initialization worked
162  iStatus = (hThread != (HANDLE)nullptr);
163 
165 }
166 
172 {
173  // if the window is not initialized yet
174  if (!window.isInitialized()) {
175  // wait
176  if (WAIT_OBJECT_0 != WaitForSingleObject(window.semaInit, MAX_INIT_DELAY))
177  throw(vpDisplayException(vpDisplayException::notInitializedError, "Window not initialized"));
178  // problem : the window is not initialized
179  }
180 }
181 
194 {
195  // waits if the window is not initialized
196  waitForInit();
197 
198  // sets the image to render
199  window.renderer->setImg(I);
200  // sends a message to the window
201  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
202 }
203 
221 void vpDisplayWin32::displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int width,
222  unsigned int height)
223 {
224  // waits if the window is not initialized
225  waitForInit();
226 
227  // sets the image to render
228  window.renderer->setImgROI(I, iP, width, height);
229  // sends a message to the window
230  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
231 }
232 
245 {
246  // wait if the window is not initialized
247  waitForInit();
248 
249  // sets the image to render
250  window.renderer->setImg(I);
251  // sends a message to the window
252  // PostMessage(window.getHWnd(), vpWM_DISPLAY, 0,0);
253 }
254 
272 void vpDisplayWin32::displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
273  unsigned int height)
274 {
275  // waits if the window is not initialized
276  waitForInit();
277 
278  // sets the image to render
279  window.renderer->setImgROI(I, iP, width, height);
280  // sends a message to the window
281  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
282 }
283 
299 bool vpDisplayWin32::getClick(bool blocking)
300 {
301  // wait if the window is not initialized
302  waitForInit();
303  bool ret = false;
304  // sends a message to the window
305  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
306 
307  // waits for a button to be pressed
308  if (blocking) {
309  WaitForSingleObject(window.semaClick, 0);
310  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
311  WaitForSingleObject(window.semaClick, INFINITE);
312  ret = true;
313  }
314  else {
315  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
316  }
317 
318  return ret;
319 }
320 
337 bool vpDisplayWin32::getClick(vpImagePoint &ip, bool blocking)
338 {
339  // wait if the window is not initialized
340  waitForInit();
341 
342  bool ret = false;
343  double u, v;
344  // tells the window there has been a getclick demand
345  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
346  // waits for a click
347  if (blocking) {
348  WaitForSingleObject(window.semaClick, 0);
349  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
350  WaitForSingleObject(window.semaClick, INFINITE);
351  ret = true;
352  }
353  else {
354  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
355  }
356 
357  u = window.clickX;
358  v = window.clickY;
359  ip.set_u(u * m_scale);
360  ip.set_v(v * m_scale);
361 
362  return ret;
363 }
364 
384 {
385  // wait if the window is not initialized
386  waitForInit();
387  bool ret = false;
388  double u, v;
389  // tells the window there has been a getclickup demand
390  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
391  // waits for a click
392  if (blocking) {
393  WaitForSingleObject(window.semaClick, 0);
394  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
395  WaitForSingleObject(window.semaClick, INFINITE);
396  ret = true;
397  }
398  else
399  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
400 
401  u = window.clickX;
402  v = window.clickY;
403  ip.set_u(u * m_scale);
404  ip.set_v(v * m_scale);
405  button = window.clickButton;
406 
407  return ret;
408 }
409 
433 {
434  // wait if the window is not initialized
435  waitForInit();
436  bool ret = false;
437  double u, v;
438  // tells the window there has been a getclickup demand
439  // PostMessage(window.getHWnd(), vpWM_GETCLICKUP, 0,0);
440 
441  // waits for a click release
442  if (blocking) {
443  WaitForSingleObject(window.semaClickUp, 0);
444  WaitForSingleObject(window.semaClick, 0); // to erase previous events
445  WaitForSingleObject(window.semaClickUp, INFINITE);
446  ret = true;
447  }
448  else
449  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClickUp, 0));
450 
451  u = window.clickXUp;
452  v = window.clickYUp;
453  ip.set_u(u * m_scale);
454  ip.set_v(v * m_scale);
455  button = window.clickButtonUp;
456 
457  return ret;
458 }
459 
476 {
477  // wait if the window is not initialized
478  waitForInit();
479 
480  bool ret = false;
481  // waits for a keyboard event
482  if (blocking) {
483  WaitForSingleObject(window.semaKey, 0); // key down
484  WaitForSingleObject(window.semaKey, 0); // key up
485  WaitForSingleObject(window.semaKey, INFINITE);
486  ret = true;
487  }
488  else
489  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaKey, 0));
490 
491  return ret;
492 }
512 bool vpDisplayWin32::getKeyboardEvent(std::string &key, bool blocking)
513 {
514  // wait if the window is not initialized
515  waitForInit();
516 
517  bool ret = false;
518  // waits for a keyboard event
519  if (blocking) {
520  WaitForSingleObject(window.semaKey, 0); // key down
521  WaitForSingleObject(window.semaKey, 0); // key up
522  WaitForSingleObject(window.semaKey, INFINITE);
523  ret = true;
524  }
525  else {
526  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaKey, 0));
527  }
528  // printf("key: %ud\n", window.key);
529  std::stringstream ss;
530  ss << window.lpString;
531  key = ss.str();
532 
533  return ret;
534 }
546 {
547  // wait if the window is not initialized
548  waitForInit();
549 
550  bool ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaMove, 0));
551  if (ret) {
552  double u, v;
553  // tells the window there has been a getclick demand
554  // PostMessage(window.getHWnd(), vpWM_GETPOINTERMOTIONEVENT, 0,0);
555 
556  u = window.coordX;
557  v = window.coordY;
558  ip.set_u(u * m_scale);
559  ip.set_v(v * m_scale);
560  }
561 
562  return ret;
563 }
564 
576 {
577  // wait if the window is not initialized
578  waitForInit();
579 
580  bool ret = true;
581  double u, v;
582  // tells the window there has been a getclick demand
583  // PostMessage(window.getHWnd(), vpWM_GETPOINTERMOTIONEVENT, 0,0);
584 
585  u = window.coordX;
586  v = window.coordY;
587  ip.set_u(u * m_scale);
588  ip.set_v(v * m_scale);
589 
590  return ret;
591 }
592 
600 void vpDisplayWin32::setWindowPosition(int winx, int winy)
601 {
602  // wait if the window is not initialized
603  waitForInit();
604 
605  // cahange the window position only
606  SetWindowPos(window.hWnd, HWND_TOP, winx, winy, 0, 0,
607  SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
608 }
609 
615 void vpDisplayWin32::setTitle(const std::string &windowtitle)
616 {
617  // wait if the window is not initialized
618  waitForInit();
619  SetWindowText(window.hWnd, windowtitle.c_str());
620 }
621 
627 void vpDisplayWin32::setFont(const std::string & /* fontname */)
628 {
629  // Not yet implemented
630 }
631 
638 {
639  // waits if the window is not initialized
640  waitForInit();
641 
642  // sends a message to the window
643  PostMessage(window.getHWnd(), vpWM_DISPLAY, 0, 0);
644 }
645 
651 void vpDisplayWin32::flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height)
652 {
653  // waits if the window is not initialized
654  waitForInit();
655  /*
656  Under windows, flushing an ROI takes more time than
657  flushing the whole image.
658  Therefore, we update the maximum area even when asked to update a region.
659  */
660  WORD left = (WORD)iP.get_u();
661  WORD right = (WORD)(iP.get_u() + width - 1);
662 
663  WORD top = (WORD)iP.get_v();
664  WORD bottom = (WORD)(iP.get_v() + height - 1);
665 
666  // sends a message to the window
667  WPARAM wp = MAKEWPARAM(left, right);
668  LPARAM lp = MAKELPARAM(top, bottom);
669 
670  PostMessage(window.getHWnd(), vpWM_DISPLAY_ROI, wp, lp);
671 }
672 
679 void vpDisplayWin32::displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness)
680 {
681  // wait if the window is not initialized
682  waitForInit();
683  if (thickness == 1) {
684  window.renderer->setPixel(ip, color);
685  }
686  else {
687  window.renderer->drawRect(ip, thickness * m_scale, thickness * m_scale, color, true, 1);
688  }
689 }
690 
697 void vpDisplayWin32::displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
698  unsigned int thickness)
699 {
700  // wait if the window is not initialized
701  waitForInit();
702  window.renderer->drawLine(ip1, ip2, color, thickness);
703 }
704 
714 void vpDisplayWin32::displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
715  unsigned int thickness)
716 {
717  // wait if the window is not initialized
718  waitForInit();
719  window.renderer->drawLine(ip1, ip2, color, thickness, PS_DASHDOT);
720 }
721 
735 void vpDisplayWin32::displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height,
736  const vpColor &color, bool fill, unsigned int thickness)
737 {
738  // wait if the window is not initialized
739  waitForInit();
740  window.renderer->drawRect(topLeft, width, height, color, fill, thickness);
741 }
742 
755 void vpDisplayWin32::displayRectangle(const vpImagePoint &topLeft, const vpImagePoint &bottomRight,
756  const vpColor &color, bool fill, unsigned int thickness)
757 {
758  // wait if the window is not initialized
759  waitForInit();
760  unsigned int width = static_cast<unsigned int>(bottomRight.get_j() - topLeft.get_j());
761  unsigned int height = static_cast<unsigned int>(bottomRight.get_i() - topLeft.get_i());
762  window.renderer->drawRect(topLeft, width, height, color, fill, thickness);
763 }
764 
776 void vpDisplayWin32::displayRectangle(const vpRect &rectangle, const vpColor &color, bool fill, unsigned int thickness)
777 {
778  // wait if the window is not initialized
779  waitForInit();
780  vpImagePoint topLeft;
781  topLeft.set_i(rectangle.getTop());
782  topLeft.set_j(rectangle.getLeft());
783  window.renderer->drawRect(topLeft, static_cast<unsigned int>(rectangle.getWidth()),
784  static_cast<unsigned int>(rectangle.getHeight()), color, fill, thickness);
785 }
786 
796 void vpDisplayWin32::displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
797  unsigned int thickness)
798 {
799  // wait if the window is not initialized
800  waitForInit();
801  window.renderer->drawCircle(center, radius, color, fill, thickness);
802 }
803 
810 void vpDisplayWin32::displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color)
811 {
812  // wait if the window is not initialized
813  waitForInit();
814  window.renderer->drawText(ip, text.c_str(), color);
815 }
816 
824 void vpDisplayWin32::displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color,
825  unsigned int thickness)
826 {
827  // wait if the window is not initialized
828  waitForInit();
829  window.renderer->drawCross(ip, size, color, thickness);
830 }
831 
839 void vpDisplayWin32::displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
840  unsigned int w, unsigned int h, unsigned int thickness)
841 
842 {
843  // wait if the window is not initialized
844  waitForInit();
845  window.renderer->drawArrow(ip1, ip2, color, w, h, thickness);
846 }
847 
853 {
854  // wait if the window is not initialized
855  waitForInit();
856  window.renderer->clear(color);
857 }
858 
864 {
866  waitForInit();
867  PostMessage(window.getHWnd(), vpWM_CLOSEDISPLAY, 0, 0);
868  // if the destructor is called for a reason different than a
869  // problem in the thread creation
870  if (iStatus) {
871  // waits for the thread to end
872  WaitForSingleObject(hThread, INFINITE);
873  CloseHandle(hThread);
874  }
876  window.initialized = false;
877  }
878 }
879 
885 {
886  // wait if the window is not initialized
887  waitForInit();
888  window.renderer->getImage(I);
889 }
890 
895 void vpDisplayWin32::getScreenSize(unsigned int &w, unsigned int &h)
896 {
897  w = GetSystemMetrics(SM_CXSCREEN);
898  h = GetSystemMetrics(SM_CYSCREEN);
899 }
900 
905 {
906  unsigned int width, height;
907  getScreenSize(width, height);
908  return width;
909 }
910 
915 {
916  unsigned int width, height;
917  getScreenSize(width, height);
918  return height;
919 }
920 
921 END_VISP_NAMESPACE
922 
923 #elif !defined(VISP_BUILD_SHARED_LIBS)
924 // Work around to avoid warning: libvisp_gui.a(vpDisplayWin32.cpp.o) has no symbols
925 void dummy_vpDisplayWin32() { };
926 #endif
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:157
Error that can be emitted by the vpDisplay class and its derivatives.
@ notInitializedError
Display not initialized.
void displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color=vpColor::green) VP_OVERRIDE
virtual ~vpDisplayWin32() VP_OVERRIDE
void displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1) VP_OVERRIDE
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="") VP_OVERRIDE
void displayImageROI(const vpImage< unsigned char > &I, const vpImagePoint &iP, unsigned int width, unsigned int height) VP_OVERRIDE
bool getClickUp(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking=true) VP_OVERRIDE
bool getClick(bool blocking=true) VP_OVERRIDE
DWORD threadId
Id of the window's thread.
vpWin32Window window
The window.
unsigned int getScreenWidth() VP_OVERRIDE
void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1) VP_OVERRIDE
void displayImage(const vpImage< vpRGBa > &I) VP_OVERRIDE
void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) VP_OVERRIDE
bool getPointerPosition(vpImagePoint &ip) VP_OVERRIDE
void closeDisplay() VP_OVERRIDE
VP_EXPLICIT vpDisplayWin32(vpWin32Renderer *rend=nullptr)
void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) VP_OVERRIDE
unsigned int getScreenHeight() VP_OVERRIDE
void setTitle(const std::string &windowtitle) VP_OVERRIDE
HANDLE hThread
Handle of the window's thread.
friend void vpCreateWindow(threadParam *param)
Function used to launch the window in a thread.
void flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height) VP_OVERRIDE
flush the Win32 buffer It's necessary to use this function to see the results of any drawing
bool iStatus
Initialization status.
void setWindowPosition(int winx, int winy) VP_OVERRIDE
void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1) VP_OVERRIDE
bool getPointerMotionEvent(vpImagePoint &ip) VP_OVERRIDE
void getScreenSize(unsigned int &width, unsigned int &height) VP_OVERRIDE
void getImage(vpImage< vpRGBa > &I) VP_OVERRIDE
void flushDisplay() VP_OVERRIDE
flush the Win32 buffer It's necessary to use this function to see the results of any drawing
void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1) VP_OVERRIDE
void setFont(const std::string &fontname) VP_OVERRIDE
Set the font used to display text.
void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1) VP_OVERRIDE
void clearDisplay(const vpColor &color=vpColor::white) VP_OVERRIDE
static const int MAX_INIT_DELAY
Maximum delay for window initialization.
bool getKeyboardEvent(bool blocking=true) VP_OVERRIDE
vpScaleType m_scaleType
Definition: vpDisplay.h:933
int m_windowXPosition
display position
Definition: vpDisplay.h:926
std::string m_title
Definition: vpDisplay.h:931
int m_windowYPosition
display position
Definition: vpDisplay.h:928
unsigned int m_scale
Definition: vpDisplay.h:932
bool m_displayHasBeenInitialized
display has been initialized
Definition: vpDisplay.h:924
void setScale(vpScaleType scaleType, unsigned int width, unsigned int height)
Definition: vpDisplay.cpp:262
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
void set_j(double jj)
Definition: vpImagePoint.h:309
double get_j() const
Definition: vpImagePoint.h:125
void set_i(double ii)
Definition: vpImagePoint.h:298
double get_u() const
Definition: vpImagePoint.h:136
void set_u(double u)
Definition: vpImagePoint.h:335
void set_v(double v)
Definition: vpImagePoint.h:346
double get_i() const
Definition: vpImagePoint.h:114
double get_v() const
Definition: vpImagePoint.h:147
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getHeight() const
Definition: vpImage.h:181
vpDisplay * display
Definition: vpImage.h:136
Defines a rectangle in the plane.
Definition: vpRect.h:79
double getWidth() const
Definition: vpRect.h:227
double getLeft() const
Definition: vpRect.h:173
double getHeight() const
Definition: vpRect.h:166
double getTop() const
Definition: vpRect.h:192