Visual Servoing Platform  version 3.6.1 under development (2023-11-30)
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 
68 
79 void vpDisplayWin32::init(vpImage<unsigned char> &I, int x, int y, const std::string &title)
80 {
81  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
82  vpERROR_TRACE("Image not initialized ");
83  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
84  }
85 
87  init(I.getWidth(), I.getHeight(), x, y, title);
88  window.renderer->setWidth(I.getWidth() / m_scale);
89  window.renderer->setHeight(I.getHeight() / m_scale);
90  window.renderer->setImg(I);
91 
92  I.display = this;
93 }
94 
103 void vpDisplayWin32::init(vpImage<vpRGBa> &I, int x, int y, const std::string &title)
104 {
105  if ((I.getHeight() == 0) || (I.getWidth() == 0)) {
106  vpERROR_TRACE("Image not initialized ");
107  throw(vpDisplayException(vpDisplayException::notInitializedError, "Image not initialized"));
108  }
109 
111  init(I.getWidth(), I.getHeight(), x, y, title);
112  window.renderer->setWidth(I.getWidth() / m_scale);
113  window.renderer->setHeight(I.getHeight() / m_scale);
114  window.renderer->setImg(I);
115 
116  I.display = this;
117 }
118 
127 void vpDisplayWin32::init(unsigned int width, unsigned int height, int x, int y, const std::string &title)
128 {
129  if (!title.empty())
130  m_title = title;
131  else
132  m_title = std::string(" ");
133 
134  if (x != -1)
135  m_windowXPosition = x;
136  if (y != -1)
137  m_windowYPosition = y;
138 
139  // we prepare the window's thread creation
140  setScale(m_scaleType, width, height);
141  threadParam *param = new threadParam;
142  param->x = m_windowXPosition;
143  param->y = m_windowYPosition;
144  param->w = width / m_scale;
145  param->h = height / m_scale;
146  param->vpDisp = this;
147  param->title = this->m_title;
148 
149  // creates the window in a separate thread
150  hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)vpCreateWindow, param, 0, &threadId);
151 
152  // the initialization worked
153  iStatus = (hThread != (HANDLE)nullptr);
154 
156 }
157 
163 {
164  // if the window is not initialized yet
165  if (!window.isInitialized()) {
166  // wait
167  if (WAIT_OBJECT_0 != WaitForSingleObject(window.semaInit, MAX_INIT_DELAY))
168  throw(vpDisplayException(vpDisplayException::notInitializedError, "Window not initialized"));
169  // problem : the window is not initialized
170  }
171 }
172 
185 {
186  // waits if the window is not initialized
187  waitForInit();
188 
189  // sets the image to render
190  window.renderer->setImg(I);
191  // sends a message to the window
192  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
193 }
194 
212 void vpDisplayWin32::displayImageROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int width,
213  unsigned int height)
214 {
215  // waits if the window is not initialized
216  waitForInit();
217 
218  // sets the image to render
219  window.renderer->setImgROI(I, iP, width, height);
220  // sends a message to the window
221  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
222 }
223 
236 {
237  // wait if the window is not initialized
238  waitForInit();
239 
240  // sets the image to render
241  window.renderer->setImg(I);
242  // sends a message to the window
243  // PostMessage(window.getHWnd(), vpWM_DISPLAY, 0,0);
244 }
245 
263 void vpDisplayWin32::displayImageROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
264  unsigned int height)
265 {
266  // waits if the window is not initialized
267  waitForInit();
268 
269  // sets the image to render
270  window.renderer->setImgROI(I, iP, width, height);
271  // sends a message to the window
272  // PostMessage(window.getHWnd(),vpWM_DISPLAY,0,0);
273 }
274 
290 bool vpDisplayWin32::getClick(bool blocking)
291 {
292  // wait if the window is not initialized
293  waitForInit();
294  bool ret = false;
295  // sends a message to the window
296  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
297 
298  // waits for a button to be pressed
299  if (blocking) {
300  WaitForSingleObject(window.semaClick, 0);
301  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
302  WaitForSingleObject(window.semaClick, INFINITE);
303  ret = true;
304  }
305  else {
306  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
307  }
308 
309  return ret;
310 }
311 
328 bool vpDisplayWin32::getClick(vpImagePoint &ip, bool blocking)
329 {
330  // wait if the window is not initialized
331  waitForInit();
332 
333  bool ret = false;
334  double u, v;
335  // tells the window there has been a getclick demand
336  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
337  // waits for a click
338  if (blocking) {
339  WaitForSingleObject(window.semaClick, 0);
340  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
341  WaitForSingleObject(window.semaClick, INFINITE);
342  ret = true;
343  }
344  else {
345  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
346  }
347 
348  u = window.clickX;
349  v = window.clickY;
350  ip.set_u(u * m_scale);
351  ip.set_v(v * m_scale);
352 
353  return ret;
354 }
355 
375 {
376  // wait if the window is not initialized
377  waitForInit();
378  bool ret = false;
379  double u, v;
380  // tells the window there has been a getclickup demand
381  // PostMessage(window.getHWnd(), vpWM_GETCLICK, 0,0);
382  // waits for a click
383  if (blocking) {
384  WaitForSingleObject(window.semaClick, 0);
385  WaitForSingleObject(window.semaClickUp, 0); // to erase previous events
386  WaitForSingleObject(window.semaClick, INFINITE);
387  ret = true;
388  }
389  else
390  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClick, 0));
391 
392  u = window.clickX;
393  v = window.clickY;
394  ip.set_u(u * m_scale);
395  ip.set_v(v * m_scale);
396  button = window.clickButton;
397 
398  return ret;
399 }
400 
424 {
425  // wait if the window is not initialized
426  waitForInit();
427  bool ret = false;
428  double u, v;
429  // tells the window there has been a getclickup demand
430  // PostMessage(window.getHWnd(), vpWM_GETCLICKUP, 0,0);
431 
432  // waits for a click release
433  if (blocking) {
434  WaitForSingleObject(window.semaClickUp, 0);
435  WaitForSingleObject(window.semaClick, 0); // to erase previous events
436  WaitForSingleObject(window.semaClickUp, INFINITE);
437  ret = true;
438  }
439  else
440  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaClickUp, 0));
441 
442  u = window.clickXUp;
443  v = window.clickYUp;
444  ip.set_u(u * m_scale);
445  ip.set_v(v * m_scale);
446  button = window.clickButtonUp;
447 
448  return ret;
449 }
450 
467 {
468  // wait if the window is not initialized
469  waitForInit();
470 
471  bool ret = false;
472  // waits for a keyboard event
473  if (blocking) {
474  WaitForSingleObject(window.semaKey, 0); // key down
475  WaitForSingleObject(window.semaKey, 0); // key up
476  WaitForSingleObject(window.semaKey, INFINITE);
477  ret = true;
478  }
479  else
480  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaKey, 0));
481 
482  return ret;
483 }
503 bool vpDisplayWin32::getKeyboardEvent(std::string &key, bool blocking)
504 {
505  // wait if the window is not initialized
506  waitForInit();
507 
508  bool ret = false;
509  // waits for a keyboard event
510  if (blocking) {
511  WaitForSingleObject(window.semaKey, 0); // key down
512  WaitForSingleObject(window.semaKey, 0); // key up
513  WaitForSingleObject(window.semaKey, INFINITE);
514  ret = true;
515  }
516  else {
517  ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaKey, 0));
518  }
519  // printf("key: %ud\n", window.key);
520  std::stringstream ss;
521  ss << window.lpString;
522  key = ss.str();
523 
524  return ret;
525 }
537 {
538  // wait if the window is not initialized
539  waitForInit();
540 
541  bool ret = (WAIT_OBJECT_0 == WaitForSingleObject(window.semaMove, 0));
542  if (ret) {
543  double u, v;
544  // tells the window there has been a getclick demand
545  // PostMessage(window.getHWnd(), vpWM_GETPOINTERMOTIONEVENT, 0,0);
546 
547  u = window.coordX;
548  v = window.coordY;
549  ip.set_u(u * m_scale);
550  ip.set_v(v * m_scale);
551  }
552 
553  return ret;
554 }
555 
567 {
568  // wait if the window is not initialized
569  waitForInit();
570 
571  bool ret = true;
572  double u, v;
573  // tells the window there has been a getclick demand
574  // PostMessage(window.getHWnd(), vpWM_GETPOINTERMOTIONEVENT, 0,0);
575 
576  u = window.coordX;
577  v = window.coordY;
578  ip.set_u(u * m_scale);
579  ip.set_v(v * m_scale);
580 
581  return ret;
582 }
583 
591 void vpDisplayWin32::setWindowPosition(int winx, int winy)
592 {
593  // wait if the window is not initialized
594  waitForInit();
595 
596  // cahange the window position only
597  SetWindowPos(window.hWnd, HWND_TOP, winx, winy, 0, 0,
598  SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
599 }
600 
606 void vpDisplayWin32::setTitle(const std::string &windowtitle)
607 {
608  // wait if the window is not initialized
609  waitForInit();
610  SetWindowText(window.hWnd, windowtitle.c_str());
611 }
612 
618 void vpDisplayWin32::setFont(const std::string & /* fontname */) { vpERROR_TRACE("Not yet implemented"); }
619 
626 {
627  // waits if the window is not initialized
628  waitForInit();
629 
630  // sends a message to the window
631  PostMessage(window.getHWnd(), vpWM_DISPLAY, 0, 0);
632 }
633 
639 void vpDisplayWin32::flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height)
640 {
641  // waits if the window is not initialized
642  waitForInit();
643  /*
644  Under windows, flushing an ROI takes more time than
645  flushing the whole image.
646  Therefore, we update the maximum area even when asked to update a region.
647  */
648  WORD left = (WORD)iP.get_u();
649  WORD right = (WORD)(iP.get_u() + width - 1);
650 
651  WORD top = (WORD)iP.get_v();
652  WORD bottom = (WORD)(iP.get_v() + height - 1);
653 
654  // sends a message to the window
655  WPARAM wp = MAKEWPARAM(left, right);
656  LPARAM lp = MAKELPARAM(top, bottom);
657 
658  PostMessage(window.getHWnd(), vpWM_DISPLAY_ROI, wp, lp);
659 }
660 
667 void vpDisplayWin32::displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness)
668 {
669  // wait if the window is not initialized
670  waitForInit();
671  if (thickness == 1) {
672  window.renderer->setPixel(ip, color);
673  }
674  else {
675  window.renderer->drawRect(ip, thickness * m_scale, thickness * m_scale, color, true, 1);
676  }
677 }
678 
685 void vpDisplayWin32::displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
686  unsigned int thickness)
687 {
688  // wait if the window is not initialized
689  waitForInit();
690  window.renderer->drawLine(ip1, ip2, color, thickness);
691 }
692 
702 void vpDisplayWin32::displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
703  unsigned int thickness)
704 {
705  // wait if the window is not initialized
706  waitForInit();
707  window.renderer->drawLine(ip1, ip2, color, thickness, PS_DASHDOT);
708 }
709 
723 void vpDisplayWin32::displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height,
724  const vpColor &color, bool fill, unsigned int thickness)
725 {
726  // wait if the window is not initialized
727  waitForInit();
728  window.renderer->drawRect(topLeft, width, height, color, fill, thickness);
729 }
730 
743 void vpDisplayWin32::displayRectangle(const vpImagePoint &topLeft, const vpImagePoint &bottomRight,
744  const vpColor &color, bool fill, unsigned int thickness)
745 {
746  // wait if the window is not initialized
747  waitForInit();
748  unsigned int width = static_cast<unsigned int>(bottomRight.get_j() - topLeft.get_j());
749  unsigned int height = static_cast<unsigned int>(bottomRight.get_i() - topLeft.get_i());
750  window.renderer->drawRect(topLeft, width, height, color, fill, thickness);
751 }
752 
764 void vpDisplayWin32::displayRectangle(const vpRect &rectangle, const vpColor &color, bool fill, unsigned int thickness)
765 {
766  // wait if the window is not initialized
767  waitForInit();
768  vpImagePoint topLeft;
769  topLeft.set_i(rectangle.getTop());
770  topLeft.set_j(rectangle.getLeft());
771  window.renderer->drawRect(topLeft, static_cast<unsigned int>(rectangle.getWidth()),
772  static_cast<unsigned int>(rectangle.getHeight()), color, fill, thickness);
773 }
774 
784 void vpDisplayWin32::displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
785  unsigned int thickness)
786 {
787  // wait if the window is not initialized
788  waitForInit();
789  window.renderer->drawCircle(center, radius, color, fill, thickness);
790 }
791 
798 void vpDisplayWin32::displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color)
799 {
800  // wait if the window is not initialized
801  waitForInit();
802  window.renderer->drawText(ip, text.c_str(), color);
803 }
804 
812 void vpDisplayWin32::displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color,
813  unsigned int thickness)
814 {
815  // wait if the window is not initialized
816  waitForInit();
817  window.renderer->drawCross(ip, size, color, thickness);
818 }
819 
827 void vpDisplayWin32::displayArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
828  unsigned int w, unsigned int h, unsigned int thickness)
829 
830 {
831  // wait if the window is not initialized
832  waitForInit();
833  window.renderer->drawArrow(ip1, ip2, color, w, h, thickness);
834 }
835 
841 {
842  // wait if the window is not initialized
843  waitForInit();
844  window.renderer->clear(color);
845 }
846 
852 {
854  waitForInit();
855  PostMessage(window.getHWnd(), vpWM_CLOSEDISPLAY, 0, 0);
856  // if the destructor is called for a reason different than a
857  // problem in the thread creation
858  if (iStatus) {
859  // waits for the thread to end
860  WaitForSingleObject(hThread, INFINITE);
861  CloseHandle(hThread);
862  }
864  window.initialized = false;
865  }
866 }
867 
873 {
874  // wait if the window is not initialized
875  waitForInit();
876  window.renderer->getImage(I);
877 }
878 
883 void vpDisplayWin32::getScreenSize(unsigned int &w, unsigned int &h)
884 {
885  w = GetSystemMetrics(SM_CXSCREEN);
886  h = GetSystemMetrics(SM_CYSCREEN);
887 }
888 
893 {
894  unsigned int width, height;
895  getScreenSize(width, height);
896  return width;
897 }
898 
903 {
904  unsigned int width, height;
905  getScreenSize(width, height);
906  return height;
907 }
908 #elif !defined(VISP_BUILD_SHARED_LIBS)
909 // Work around to avoid warning: libvisp_core.a(vpDisplayWin32.cpp.o) has no
910 // symbols
911 void dummy_vpDisplayWin32() { };
912 #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 getClickUp(vpImagePoint &ip, vpMouseButton::vpMouseButtonType &button, bool blocking=true) override
void displayText(const vpImagePoint &ip, const std::string &text, const vpColor &color=vpColor::green) override
void closeDisplay() override
void displayLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) override
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="") override
void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1) override
unsigned int getScreenWidth() override
unsigned int getScreenHeight() override
void displayDotLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1) override
DWORD threadId
Id of the window's thread.
vpWin32Window window
The window.
void flushDisplay() 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) override
void clearDisplay(const vpColor &color=vpColor::white) override
void flushDisplayROI(const vpImagePoint &iP, unsigned int width, unsigned int height) override
flush the Win32 buffer It's necessary to use this function to see the results of any drawing
void displayCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill=false, unsigned int thickness=1) override
vpDisplayWin32(vpWin32Renderer *rend=nullptr)
bool getPointerPosition(vpImagePoint &ip) override
HANDLE hThread
Handle of the window's thread.
friend void vpCreateWindow(threadParam *param)
Function used to launch the window in a thread.
void displayPoint(const vpImagePoint &ip, const vpColor &color, unsigned int thickness=1) override
bool iStatus
Initialization status.
void displayImageROI(const vpImage< unsigned char > &I, const vpImagePoint &iP, unsigned int width, unsigned int height) override
static const int MAX_INIT_DELAY
Maximum delay for window initialization.
virtual ~vpDisplayWin32() 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) override
void setFont(const std::string &fontname) override
Set the font used to display text.
bool getKeyboardEvent(bool blocking=true) override
void displayImage(const vpImage< vpRGBa > &I) override
bool getPointerMotionEvent(vpImagePoint &ip) override
void setWindowPosition(int winx, int winy) override
void getScreenSize(unsigned int &width, unsigned int &height) override
bool getClick(bool blocking=true) override
void setTitle(const std::string &windowtitle) override
void getImage(vpImage< vpRGBa > &I) 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:255
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:294
double get_j() const
Definition: vpImagePoint.h:125
void set_i(double ii)
Definition: vpImagePoint.h:283
double get_u() const
Definition: vpImagePoint.h:136
void set_u(double u)
Definition: vpImagePoint.h:320
void set_v(double v)
Definition: vpImagePoint.h:331
double get_i() const
Definition: vpImagePoint.h:114
double get_v() const
Definition: vpImagePoint.h:147
unsigned int getWidth() const
Definition: vpImage.h:240
unsigned int getHeight() const
Definition: vpImage.h:182
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:388