Visual Servoing Platform  version 3.6.1 under development (2024-04-20)
vpDisplayWin32.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Windows 32 display base class
33  *
34  * Authors:
35  * Bruno Renier
36  *
37 *****************************************************************************/
38 
39 #include <visp3/core/vpConfig.h>
40 #if (defined(VISP_HAVE_GDI) || defined(VISP_HAVE_D3D9))
41 
42 #include <string>
43 #include <visp3/core/vpDisplayException.h>
44 #include <visp3/gui/vpDisplayWin32.h>
45 
46 const int vpDisplayWin32::MAX_INIT_DELAY = 5000;
47 
52 void vpCreateWindow(threadParam *param)
53 {
54  // char* title = param->title;
55  (param->vpDisp)->window.initWindow(param->title.c_str(), param->x, param->y, param->w, param->h);
56  delete param;
57 }
58 
62 vpDisplayWin32::vpDisplayWin32(vpWin32Renderer *rend) : iStatus(false), window(rend) { }
63 
64 vpDisplayWin32::vpDisplayWin32(vpImage<vpRGBa> &I, int winx, int winy, const std::string &title)
65  : iStatus(false), window(nullptr)
66 {
67  init(I, winx, winy, title);
68 }
69 
70 vpDisplayWin32::vpDisplayWin32(vpImage<unsigned char> &I, int winx, int winy, const std::string &title)
71  : iStatus(false), window(nullptr)
72 {
73  init(I, winx, winy, title);
74 }
75 
76 
77 
82 
93 void vpDisplayWin32::init(vpImage<unsigned char> &I, int x, int y, const std::string &title)
94 {
95  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
96  vpERROR_TRACE("Image not initialized ");
97  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
98  }
99 
101  init(I.getWidth(), I.getHeight(), x, y, title);
102  window.renderer->setWidth(I.getWidth() / m_scale);
103  window.renderer->setHeight(I.getHeight() / m_scale);
104  window.renderer->setImg(I);
105 
106  I.display = this;
107 }
108 
117 void vpDisplayWin32::init(vpImage<vpRGBa> &I, int x, int y, const std::string &title)
118 {
119  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
120  vpERROR_TRACE("Image not initialized ");
121  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
122  }
123 
125  init(I.getWidth(), I.getHeight(), x, y, title);
126  window.renderer->setWidth(I.getWidth() / m_scale);
127  window.renderer->setHeight(I.getHeight() / m_scale);
128  window.renderer->setImg(I);
129 
130  I.display = this;
131 }
132 
141 void vpDisplayWin32::init(unsigned int width, unsigned int height, int x, int y, const std::string &title)
142 {
143  if (!title.empty())
144  m_title = title;
145  else
146  m_title = std::string(" ");
147 
148  if (x != -1)
149  m_windowXPosition = x;
150  if (y != -1)
151  m_windowYPosition = y;
152 
153  // we prepare the window's thread creation
154  setScale(m_scaleType, width, height);
155  threadParam *param = new threadParam;
156  param->x = m_windowXPosition;
157  param->y = m_windowYPosition;
158  param->w = width / m_scale;
159  param->h = height / m_scale;
160  param->vpDisp = this;
161  param->title = this->m_title;
162 
163  // creates the window in a separate thread
164  hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)vpCreateWindow, param, 0, &threadId);
165 
166  // the initialization worked
167  iStatus = (hThread != (HANDLE)nullptr);
168 
170 }
171 
177 {
178  // if the window is not initialized yet
179  if (!window.isInitialized()) {
180  // wait
181  if (WAIT_OBJECT_0 != WaitForSingleObject(window.semaInit, MAX_INIT_DELAY))
182  throw(vpDisplayException(vpDisplayException::notInitializedError, "Window not initialized"));
183  // problem : the window is not initialized
184  }
185 }
186 
199 {
200  // waits if the window is not initialized
201  waitForInit();
202 
203  // sets the image to render
204  window.renderer->setImg(I);
205  // sends a message to the window
206  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
207 }
208 
226 void vpDisplayWin32::displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int width,
227  unsigned int height)
228 {
229  // waits if the window is not initialized
230  waitForInit();
231 
232  // sets the image to render
233  window.renderer->setImgROI(I, iP, width, height);
234  // sends a message to the window
235  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
236 }
237 
250 {
251  // wait if the window is not initialized
252  waitForInit();
253 
254  // sets the image to render
255  window.renderer->setImg(I);
256  // sends a message to the window
257  // PostMessage(window.getHWnd(), vpWM_DISPLAY, 0,0);
258 }
259 
277 void vpDisplayWin32::displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
278  unsigned int height)
279 {
280  // waits if the window is not initialized
281  waitForInit();
282 
283  // sets the image to render
284  window.renderer->setImgROI(I, iP, width, height);
285  // sends a message to the window
286  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
287 }
288 
304 bool vpDisplayWin32::getClick(bool blocking)
305 {
306  // wait if the window is not initialized
307  waitForInit();
308  bool ret = false;
309  // sends a message to the window
310  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
311 
312  // waits for a button to be pressed
313  if (blocking) {
314  WaitForSingleObject(window.semaClick, 0);
315  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
316  WaitForSingleObject(window.semaClick, INFINITE);
317  ret = true;
318  }
319  else {
320  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
321  }
322 
323  return ret;
324 }
325 
342 bool vpDisplayWin32::getClick(vpImagePoint &ip, bool blocking)
343 {
344  // wait if the window is not initialized
345  waitForInit();
346 
347  bool ret = false;
348  double u, v;
349  // tells the window there has been a getclick demand
350  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
351  // waits for a click
352  if (blocking) {
353  WaitForSingleObject(window.semaClick, 0);
354  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
355  WaitForSingleObject(window.semaClick, INFINITE);
356  ret = true;
357  }
358  else {
359  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
360  }
361 
362  u = window.clickX;
363  v = window.clickY;
364  ip.set_u(u * m_scale);
365  ip.set_v(v * m_scale);
366 
367  return ret;
368 }
369 
389 {
390  // wait if the window is not initialized
391  waitForInit();
392  bool ret = false;
393  double u, v;
394  // tells the window there has been a getclickup demand
395  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
396  // waits for a click
397  if (blocking) {
398  WaitForSingleObject(window.semaClick, 0);
399  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
400  WaitForSingleObject(window.semaClick, INFINITE);
401  ret = true;
402  }
403  else
404  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
405 
406  u = window.clickX;
407  v = window.clickY;
408  ip.set_u(u * m_scale);
409  ip.set_v(v * m_scale);
410  button = window.clickButton;
411 
412  return ret;
413 }
414 
438 {
439  // wait if the window is not initialized
440  waitForInit();
441  bool ret = false;
442  double u, v;
443  // tells the window there has been a getclickup demand
444  // PostMessage(window.getHWnd(), vpWM_GETCLICKUP, 0,0);
445 
446  // waits for a click release
447  if (blocking) {
448  WaitForSingleObject(window.semaClickUp, 0);
449  WaitForSingleObject(window.semaClick, 0); // to erase previous events
450  WaitForSingleObject(window.semaClickUp, INFINITE);
451  ret = true;
452  }
453  else
454  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClickUp, 0));
455 
456  u = window.clickXUp;
457  v = window.clickYUp;
458  ip.set_u(u * m_scale);
459  ip.set_v(v * m_scale);
460  button = window.clickButtonUp;
461 
462  return ret;
463 }
464 
481 {
482  // wait if the window is not initialized
483  waitForInit();
484 
485  bool ret = false;
486  // waits for a keyboard event
487  if (blocking) {
488  WaitForSingleObject(window.semaKey, 0); // key down
489  WaitForSingleObject(window.semaKey, 0); // key up
490  WaitForSingleObject(window.semaKey, INFINITE);
491  ret = true;
492  }
493  else
494  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaKey, 0));
495 
496  return ret;
497 }
517 bool vpDisplayWin32::getKeyboardEvent(std::string &key, bool blocking)
518 {
519  // wait if the window is not initialized
520  waitForInit();
521 
522  bool ret = false;
523  // waits for a keyboard event
524  if (blocking) {
525  WaitForSingleObject(window.semaKey, 0); // key down
526  WaitForSingleObject(window.semaKey, 0); // key up
527  WaitForSingleObject(window.semaKey, INFINITE);
528  ret = true;
529  }
530  else {
531  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaKey, 0));
532  }
533  // printf("key: %ud\n", window.key);
534  std::stringstream ss;
535  ss << window.lpString;
536  key = ss.str();
537 
538  return ret;
539 }
551 {
552  // wait if the window is not initialized
553  waitForInit();
554 
555  bool ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaMove, 0));
556  if (ret) {
557  double u, v;
558  // tells the window there has been a getclick demand
559  // PostMessage(window.getHWnd(), vpWM_GETPOINTERMOTIONEVENT, 0,0);
560 
561  u = window.coordX;
562  v = window.coordY;
563  ip.set_u(u * m_scale);
564  ip.set_v(v * m_scale);
565  }
566 
567  return ret;
568 }
569 
581 {
582  // wait if the window is not initialized
583  waitForInit();
584 
585  bool ret = true;
586  double u, v;
587  // tells the window there has been a getclick demand
588  // PostMessage(window.getHWnd(), vpWM_GETPOINTERMOTIONEVENT, 0,0);
589 
590  u = window.coordX;
591  v = window.coordY;
592  ip.set_u(u * m_scale);
593  ip.set_v(v * m_scale);
594 
595  return ret;
596 }
597 
605 void vpDisplayWin32::setWindowPosition(int winx, int winy)
606 {
607  // wait if the window is not initialized
608  waitForInit();
609 
610  // cahange the window position only
611  SetWindowPos(window.hWnd, HWND_TOP, winx, winy, 0, 0,
612  SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
613 }
614 
620 void vpDisplayWin32::setTitle(const std::string &windowtitle)
621 {
622  // wait if the window is not initialized
623  waitForInit();
624  SetWindowText(window.hWnd, windowtitle.c_str());
625 }
626 
632 void vpDisplayWin32::setFont(const std::string & /* fontname */) { vpERROR_TRACE("Not yet implemented"); }
633 
640 {
641  // waits if the window is not initialized
642  waitForInit();
643 
644  // sends a message to the window
645  PostMessage(window.getHWnd(), vpWM_DISPLAY, 0, 0);
646 }
647 
653 void vpDisplayWin32::flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height)
654 {
655  // waits if the window is not initialized
656  waitForInit();
657  /*
658  Under windows, flushing an ROI takes more time than
659  flushing the whole image.
660  Therefore, we update the maximum area even when asked to update a region.
661  */
662  WORD left = (WORD)iP.get_u();
663  WORD right = (WORD)(iP.get_u() + width - 1);
664 
665  WORD top = (WORD)iP.get_v();
666  WORD bottom = (WORD)(iP.get_v() + height - 1);
667 
668  // sends a message to the window
669  WPARAM wp = MAKEWPARAM(left, right);
670  LPARAM lp = MAKELPARAM(top, bottom);
671 
672  PostMessage(window.getHWnd(), vpWM_DISPLAY_ROI, wp, lp);
673 }
674 
681 void vpDisplayWin32::displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness)
682 {
683  // wait if the window is not initialized
684  waitForInit();
685  if (thickness == 1) {
686  window.renderer->setPixel(ip, color);
687  }
688  else {
689  window.renderer->drawRect(ip, thickness * m_scale, thickness * m_scale, color, true, 1);
690  }
691 }
692 
699 void vpDisplayWin32::displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
700  unsigned int thickness)
701 {
702  // wait if the window is not initialized
703  waitForInit();
704  window.renderer->drawLine(ip1, ip2, color, thickness);
705 }
706 
716 void vpDisplayWin32::displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
717  unsigned int thickness)
718 {
719  // wait if the window is not initialized
720  waitForInit();
721  window.renderer->drawLine(ip1, ip2, color, thickness, PS_DASHDOT);
722 }
723 
737 void vpDisplayWin32::displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height,
738  const vpColor &color, bool fill, unsigned int thickness)
739 {
740  // wait if the window is not initialized
741  waitForInit();
742  window.renderer->drawRect(topLeft, width, height, color, fill, thickness);
743 }
744 
757 void vpDisplayWin32::displayRectangle(const vpImagePoint &topLeft, const vpImagePoint &bottomRight,
758  const vpColor &color, bool fill, unsigned int thickness)
759 {
760  // wait if the window is not initialized
761  waitForInit();
762  unsigned int width = static_cast<unsigned int>(bottomRight.get_j() - topLeft.get_j());
763  unsigned int height = static_cast<unsigned int>(bottomRight.get_i() - topLeft.get_i());
764  window.renderer->drawRect(topLeft, width, height, color, fill, thickness);
765 }
766 
778 void vpDisplayWin32::displayRectangle(const vpRect &rectangle, const vpColor &color, bool fill, unsigned int thickness)
779 {
780  // wait if the window is not initialized
781  waitForInit();
782  vpImagePoint topLeft;
783  topLeft.set_i(rectangle.getTop());
784  topLeft.set_j(rectangle.getLeft());
785  window.renderer->drawRect(topLeft, static_cast<unsigned int>(rectangle.getWidth()),
786  static_cast<unsigned int>(rectangle.getHeight()), color, fill, thickness);
787 }
788 
798 void vpDisplayWin32::displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
799  unsigned int thickness)
800 {
801  // wait if the window is not initialized
802  waitForInit();
803  window.renderer->drawCircle(center, radius, color, fill, thickness);
804 }
805 
812 void vpDisplayWin32::displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color)
813 {
814  // wait if the window is not initialized
815  waitForInit();
816  window.renderer->drawText(ip, text.c_str(), color);
817 }
818 
826 void vpDisplayWin32::displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color,
827  unsigned int thickness)
828 {
829  // wait if the window is not initialized
830  waitForInit();
831  window.renderer->drawCross(ip, size, color, thickness);
832 }
833 
841 void vpDisplayWin32::displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
842  unsigned int w, unsigned int h, unsigned int thickness)
843 
844 {
845  // wait if the window is not initialized
846  waitForInit();
847  window.renderer->drawArrow(ip1, ip2, color, w, h, thickness);
848 }
849 
855 {
856  // wait if the window is not initialized
857  waitForInit();
858  window.renderer->clear(color);
859 }
860 
866 {
868  waitForInit();
869  PostMessage(window.getHWnd(), vpWM_CLOSEDISPLAY, 0, 0);
870  // if the destructor is called for a reason different than a
871  // problem in the thread creation
872  if (iStatus) {
873  // waits for the thread to end
874  WaitForSingleObject(hThread, INFINITE);
875  CloseHandle(hThread);
876  }
878  window.initialized = false;
879  }
880 }
881 
887 {
888  // wait if the window is not initialized
889  waitForInit();
890  window.renderer->getImage(I);
891 }
892 
897 void vpDisplayWin32::getScreenSize(unsigned int &w, unsigned int &h)
898 {
899  w = GetSystemMetrics(SM_CXSCREEN);
900  h = GetSystemMetrics(SM_CYSCREEN);
901 }
902 
907 {
908  unsigned int width, height;
909  getScreenSize(width, height);
910  return width;
911 }
912 
917 {
918  unsigned int width, height;
919  getScreenSize(width, height);
920  return height;
921 }
922 #elif !defined(VISP_BUILD_SHARED_LIBS)
923 // Work around to avoid warning: libvisp_core.a(vpDisplayWin32.cpp.o) has no symbols
924 void dummy_vpDisplayWin32() { };
925 #endif
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:152
Error that can be emitted by the vpDisplay class and its derivatives.
@ notInitializedError
Display not initialized.
bool getClick(bool blocking=true) vp_override
void getImage(vpImage< vpRGBa > &I) vp_override
void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1) vp_override
bool getPointerMotionEvent(vpImagePoint &ip) vp_override
void getScreenSize(unsigned int &width, unsigned int &height) vp_override
void displayImageROI(const vpImage< unsigned char > &I, const vpImagePoint &iP, unsigned int width, unsigned int height) vp_override
virtual ~vpDisplayWin32() vp_override
void displayImage(const vpImage< vpRGBa > &I) vp_override
void clearDisplay(const vpColor &color=vpColor::white) vp_override
DWORD threadId
Id of the window's thread.
vpWin32Window window
The window.
void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) vp_override
void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1) vp_override
bool getClickUp(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking=true) vp_override
void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) vp_override
void setWindowPosition(int winx, int winy) vp_override
void flushDisplay() vp_override
flush the Win32 buffer It's necessary to use this function to see the results of any drawing
unsigned int getScreenHeight() vp_override
bool getKeyboardEvent(bool blocking=true) vp_override
void setFont(const std::string &fontname) vp_override
Set the font used to display text.
void setTitle(const std::string &windowtitle) vp_override
vpDisplayWin32(vpWin32Renderer *rend=nullptr)
void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1) vp_override
HANDLE hThread
Handle of the window's thread.
bool getPointerPosition(vpImagePoint &ip) vp_override
friend void vpCreateWindow(threadParam *param)
Function used to launch the window in a thread.
bool iStatus
Initialization status.
void closeDisplay() vp_override
unsigned int getScreenWidth() vp_override
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="") vp_override
static const int MAX_INIT_DELAY
Maximum delay for window initialization.
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 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
void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1) vp_override
void displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color=vpColor::green) vp_override
vpScaleType m_scaleType
Definition: vpDisplay.h:215
int m_windowXPosition
display position
Definition: vpDisplay.h:208
std::string m_title
Definition: vpDisplay.h:213
int m_windowYPosition
display position
Definition: vpDisplay.h:210
unsigned int m_scale
Definition: vpDisplay.h:214
bool m_displayHasBeenInitialized
display has been initialized
Definition: vpDisplay.h:206
void setScale(vpScaleType scaleType, unsigned int width, unsigned int height)
Definition: vpDisplay.cpp:256
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:304
double get_j() const
Definition: vpImagePoint.h:125
void set_i(double ii)
Definition: vpImagePoint.h:293
double get_u() const
Definition: vpImagePoint.h:136
void set_u(double u)
Definition: vpImagePoint.h:330
void set_v(double v)
Definition: vpImagePoint.h:341
double get_i() const
Definition: vpImagePoint.h:114
double get_v() const
Definition: vpImagePoint.h:147
unsigned int getWidth() const
Definition: vpImage.h:245
unsigned int getHeight() const
Definition: vpImage.h:184
vpDisplay * display
Definition: vpImage.h:140
Defines a rectangle in the plane.
Definition: vpRect.h:76
double getWidth() const
Definition: vpRect.h:224
double getLeft() const
Definition: vpRect.h:170
double getHeight() const
Definition: vpRect.h:163
double getTop() const
Definition: vpRect.h:189
#define vpERROR_TRACE
Definition: vpDebug.h:382