Visual Servoing Platform  version 3.4.0
vpGDIRenderer.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * GDI renderer for windows 32 display
33  *
34  * Authors:
35  * Bruno Renier
36  *
37  *****************************************************************************/
38 
39 #include <visp3/core/vpConfig.h>
40 #define GDI_ROBUST
41 #if (defined(VISP_HAVE_GDI))
42 
43 #ifndef DOXYGEN_SHOULD_SKIP_THIS
44 
45 #include <visp3/gui/vpGDIRenderer.h>
46 
50 vpGDIRenderer::vpGDIRenderer() : m_bmp(NULL), m_bmp_width(0), m_bmp_height(0), timelost(0)
51 {
52  // if the screen depth is not 32bpp, throw an exception
53  int bpp = GetDeviceCaps(GetDC(NULL), BITSPIXEL);
54  if (bpp != 32)
56  "vpGDIRenderer supports only 32bits depth: screen is %dbits depth!", bpp);
57 
58  InitializeCriticalSection(&m_criticalSection);
59 
60  // initialize GDI the palette
61  vpColor pcolor; // Predefined colors
62 
63  pcolor = vpColor::black;
64  m_colors[vpColor::id_black] = RGB(pcolor.R, pcolor.G, pcolor.B);
65  pcolor = vpColor::lightBlue;
66  m_colors[vpColor::id_lightBlue] = RGB(pcolor.R, pcolor.G, pcolor.B);
67  pcolor = vpColor::blue;
68  m_colors[vpColor::id_blue] = RGB(pcolor.R, pcolor.G, pcolor.B);
69  pcolor = vpColor::darkBlue;
70  m_colors[vpColor::id_darkBlue] = RGB(pcolor.R, pcolor.G, pcolor.B);
71  pcolor = vpColor::cyan;
72  m_colors[vpColor::id_cyan] = RGB(pcolor.R, pcolor.G, pcolor.B);
73  pcolor = vpColor::lightGreen;
74  m_colors[vpColor::id_lightGreen] = RGB(pcolor.R, pcolor.G, pcolor.B);
75  pcolor = vpColor::green;
76  m_colors[vpColor::id_green] = RGB(pcolor.R, pcolor.G, pcolor.B);
77  pcolor = vpColor::darkGreen;
78  m_colors[vpColor::id_darkGreen] = RGB(pcolor.R, pcolor.G, pcolor.B);
79  pcolor = vpColor::lightRed;
80  m_colors[vpColor::id_lightRed] = RGB(pcolor.R, pcolor.G, pcolor.B);
81  pcolor = vpColor::red;
82  m_colors[vpColor::id_red] = RGB(pcolor.R, pcolor.G, pcolor.B);
83  pcolor = vpColor::darkRed;
84  m_colors[vpColor::id_darkRed] = RGB(pcolor.R, pcolor.G, pcolor.B);
85  pcolor = vpColor::white;
86  m_colors[vpColor::id_white] = RGB(pcolor.R, pcolor.G, pcolor.B);
87  pcolor = vpColor::lightGray;
88  m_colors[vpColor::id_lightGray] = RGB(pcolor.R, pcolor.G, pcolor.B);
89  pcolor = vpColor::gray;
90  m_colors[vpColor::id_gray] = RGB(pcolor.R, pcolor.G, pcolor.B);
91  pcolor = vpColor::darkGray;
92  m_colors[vpColor::id_darkGray] = RGB(pcolor.R, pcolor.G, pcolor.B);
93  pcolor = vpColor::yellow;
94  m_colors[vpColor::id_yellow] = RGB(pcolor.R, pcolor.G, pcolor.B);
95  pcolor = vpColor::orange;
96  m_colors[vpColor::id_orange] = RGB(pcolor.R, pcolor.G, pcolor.B);
97  pcolor = vpColor::purple;
98  m_colors[vpColor::id_purple] = RGB(pcolor.R, pcolor.G, pcolor.B);
99 
100  m_rwidth = 0;
101  m_rheight = 0;
102 }
103 
107 vpGDIRenderer::~vpGDIRenderer()
108 {
109  // Deletes the critical section object
110  DeleteCriticalSection(&m_criticalSection);
111  // Deletes the bitmap
112  DeleteObject(m_bmp);
113  // Deletes the font object
114  DeleteObject(m_hFont);
115 }
116 
123 bool vpGDIRenderer::init(HWND hWindow, unsigned int width, unsigned int height)
124 {
125  timelost = 0.;
126  m_hWnd = hWindow;
127 
128  m_rwidth = width;
129  m_rheight = height;
130 
131  // creates the font
132  m_hFont = CreateFont(18, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
133  CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, NULL);
134  return true;
135 }
136 
141 void vpGDIRenderer::setImg(const vpImage<vpRGBa> &I)
142 {
143  // converts the image into a HBITMAP
144  convert(I, m_bmp);
145 }
146 
153 void vpGDIRenderer::setImgROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int width,
154  unsigned int height)
155 {
156  // converts the image into a HBITMAP
157  convertROI(I, iP, width, height);
158 }
159 
164 void vpGDIRenderer::setImg(const vpImage<unsigned char> &I)
165 {
166  // converts the image into a HBITMAP
167  convert(I, m_bmp);
168 }
169 
176 void vpGDIRenderer::setImgROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
177  unsigned int height)
178 {
179  // converts the image into a HBITMAP
180  convertROI(I, iP, width, height);
181 }
182 
186 bool vpGDIRenderer::render()
187 {
188  // gets the window's DC
189  PAINTSTRUCT ps;
190  HDC hDCScreen = BeginPaint(m_hWnd, &ps);
191 
192  // create a memory DC
193  HDC hDCMem = CreateCompatibleDC(hDCScreen);
194 
195  // selects this bmp in memory
196  EnterCriticalSection(&m_criticalSection);
197  SelectObject(hDCMem, m_bmp);
198 
199  // blits it on the window's DC
200  BitBlt(hDCScreen, 0, 0, static_cast<int>(m_rwidth), static_cast<int>(m_rheight), hDCMem, 0, 0, SRCCOPY);
201 
202  LeaveCriticalSection(&m_criticalSection);
203  // DeleteDC(hDCMem);
204  DeleteObject(hDCMem);
205 
206  EndPaint(m_hWnd, &ps);
207 
208  return true;
209 }
210 
216 void vpGDIRenderer::convert(const vpImage<vpRGBa> &I, HBITMAP &hBmp)
217 {
218  // allocate the buffer
219  unsigned char *imBuffer = new unsigned char[m_rwidth * m_rheight * 4];
220 
221  if (m_rscale == 1) {
222  for (unsigned int i = 0, k = 0; i < m_rwidth * m_rheight * 4; i += 4, k++) {
223  imBuffer[i + 0] = I.bitmap[k].B;
224  imBuffer[i + 1] = I.bitmap[k].G;
225  imBuffer[i + 2] = I.bitmap[k].R;
226  imBuffer[i + 3] = I.bitmap[k].A;
227  }
228  } else {
229  for (unsigned int i = 0; i < m_rheight; i++) {
230  unsigned int i_ = i * m_rscale;
231  unsigned int ii_ = i * m_rwidth;
232  for (unsigned int j = 0; j < m_rwidth; j++) {
233  vpRGBa val = I[i_][j * m_rscale];
234  unsigned int index_ = (ii_ + j) * 4;
235  imBuffer[index_] = val.B;
236  imBuffer[++index_] = val.G;
237  imBuffer[++index_] = val.R;
238  imBuffer[++index_] = val.A;
239  }
240  }
241  }
242 
243  // updates the bitmap's pixel data
244  updateBitmap(hBmp, imBuffer, m_rwidth, m_rheight);
245 
246  // we don't need this buffer anymore
247  delete[] imBuffer;
248 }
249 
256 void vpGDIRenderer::convertROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int width,
257  unsigned int height)
258 {
259  int i_min = (std::max)((int)ceil(iP.get_i() / m_rscale), 0);
260  int j_min = (std::max)((int)ceil(iP.get_j() / m_rscale), 0);
261  int i_max = (std::min)((int)ceil((iP.get_i() + height) / m_rscale), (int)m_rheight);
262  int j_max = (std::min)((int)ceil((iP.get_j() + width) / m_rscale), (int)m_rwidth);
263 
264  int h = i_max - i_min;
265  int w = j_max - j_min;
266 
267  // allocate the buffer
268  unsigned char *imBuffer = new unsigned char[w * h * 4];
269 
270  if (m_rscale == 1) {
271  vpRGBa *bitmap = I.bitmap;
272  unsigned int iwidth = I.getWidth();
273  bitmap = bitmap + (int)(i_min * iwidth + j_min);
274 
275  int k = 0;
276  for (int i = 0; i < w * h * 4; i += 4) {
277  imBuffer[i + 0] = (bitmap + k)->B;
278  imBuffer[i + 1] = (bitmap + k)->G;
279  imBuffer[i + 2] = (bitmap + k)->R;
280  imBuffer[i + 3] = (bitmap + k)->A;
281  // bitmap++;
282  k++;
283  if (k == w) {
284  bitmap = bitmap + iwidth;
285  k = 0;
286  }
287  }
288  } else {
289  for (int i = 0; i < h; i++) {
290  unsigned int i_ = (i_min + i) * m_rscale;
291  unsigned int ii_ = i * w;
292  for (int j = 0; j < w; j++) {
293  vpRGBa val = I[i_][(j_min + j) * m_rscale];
294  unsigned int index_ = (ii_ + j) * 4;
295  imBuffer[index_] = val.B;
296  imBuffer[++index_] = val.G;
297  imBuffer[++index_] = val.R;
298  imBuffer[++index_] = val.A;
299  }
300  }
301  }
302 
303  // updates the bitmap's pixel data
304  updateBitmapROI(imBuffer, i_min, j_min, w, h);
305 
306  // we don't need this buffer anymore
307  delete[] imBuffer;
308 }
309 
315 void vpGDIRenderer::convert(const vpImage<unsigned char> &I, HBITMAP &hBmp)
316 {
317  // allocate the buffer
318  unsigned char *imBuffer = new unsigned char[m_rwidth * m_rheight * 4];
319 
320  if (m_rscale == 1) {
321  for (unsigned int i = 0, k = 0; i < m_rwidth * m_rheight * 4; i += 4, k++) {
322  imBuffer[i + 0] = I.bitmap[k];
323  imBuffer[i + 1] = I.bitmap[k];
324  imBuffer[i + 2] = I.bitmap[k];
325  imBuffer[i + 3] = vpRGBa::alpha_default;
326  }
327  } else {
328  for (unsigned int i = 0; i < m_rheight; i++) {
329  unsigned int i_ = i * m_rscale;
330  unsigned int ii_ = i * m_rwidth;
331  for (unsigned int j = 0; j < m_rwidth; j++) {
332  unsigned char val = I[i_][j * m_rscale];
333  unsigned int index_ = (ii_ + j) * 4;
334  imBuffer[index_] = val;
335  imBuffer[++index_] = val;
336  imBuffer[++index_] = val;
337  imBuffer[++index_] = vpRGBa::alpha_default;
338  }
339  }
340  }
341 
342  // updates the bitmap's pixel data
343  updateBitmap(hBmp, imBuffer, m_rwidth, m_rheight);
344 
345  // we don't need this buffer anymore
346  delete[] imBuffer;
347 }
348 
355 void vpGDIRenderer::convertROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
356  unsigned int height)
357 {
358  int i_min = (std::max)((int)ceil(iP.get_i() / m_rscale), 0);
359  int j_min = (std::max)((int)ceil(iP.get_j() / m_rscale), 0);
360  int i_max = (std::min)((int)ceil((iP.get_i() + height) / m_rscale), (int)m_rheight);
361  int j_max = (std::min)((int)ceil((iP.get_j() + width) / m_rscale), (int)m_rwidth);
362 
363  int h = i_max - i_min;
364  int w = j_max - j_min;
365 
366  // allocate the buffer
367  unsigned char *imBuffer = new unsigned char[w * h * 4];
368 
369  if (m_rscale == 1) {
370  for (int i = 0; i < h; i++) {
371  unsigned int i_ = i_min + i;
372  unsigned int ii_ = i * w;
373  for (int j = 0; j < w; j++) {
374  unsigned char val = I[i_][j_min + j];
375  unsigned int index_ = (ii_ + j) * 4;
376  imBuffer[index_] = val;
377  imBuffer[++index_] = val;
378  imBuffer[++index_] = val;
379  imBuffer[++index_] = vpRGBa::alpha_default;
380  }
381  }
382  } else {
383  for (int i = 0; i < h; i++) {
384  unsigned int i_ = (i_min + i) * m_rscale;
385  unsigned int ii_ = i * w;
386  for (int j = 0; j < w; j++) {
387  unsigned char val = I[i_][(j_min + j) * m_rscale];
388  unsigned int index_ = (ii_ + j) * 4;
389  imBuffer[index_] = val;
390  imBuffer[++index_] = val;
391  imBuffer[++index_] = val;
392  imBuffer[++index_] = vpRGBa::alpha_default;
393  }
394  }
395  }
396 
397  // updates the bitmap's pixel data
398  updateBitmapROI(imBuffer, i_min, j_min, w, h);
399 
400  // we don't need this buffer anymore
401  delete[] imBuffer;
402 }
403 
414 bool vpGDIRenderer::updateBitmap(HBITMAP &hBmp, unsigned char *imBuffer, unsigned int w, unsigned int h)
415 {
416  // the bitmap may only be accessed by one thread at the same time
417  // that's why we enter critical section
418  EnterCriticalSection(&m_criticalSection);
419 
420  // if the existing bitmap object is of the right size
421  if ((m_bmp_width == w) && (m_bmp_height == h) && w != 0 && h != 0) {
422  // just replace the content
423  SetBitmapBits(hBmp, w * h * 4, imBuffer);
424  } else {
425  if (hBmp != NULL) {
426  // delete the old BITMAP
427  DeleteObject(hBmp);
428  }
429  // create a new BITMAP from this buffer
430  if ((hBmp = CreateBitmap(static_cast<int>(w), static_cast<int>(h), 1, 32, (void *)imBuffer)) == NULL)
431  return false;
432 
433  m_bmp_width = w;
434  m_bmp_height = h;
435  }
436 
437  LeaveCriticalSection(&m_criticalSection);
438  return true;
439 }
440 
451 bool vpGDIRenderer::updateBitmapROI(unsigned char *imBuffer, int i_min, int j_min, int w, int h)
452 {
453  HBITMAP htmp = CreateBitmap(w, h, 1, 32, (void *)imBuffer);
454 
455  // get the window's DC
456  HDC hDCScreen = GetDC(m_hWnd);
457  HDC hDCMem = CreateCompatibleDC(hDCScreen);
458  HDC hDCMem2 = CreateCompatibleDC(hDCScreen);
459 
460  // select this bmp in memory
461  EnterCriticalSection(&m_criticalSection);
462  SelectObject(hDCMem, m_bmp);
463  SelectObject(hDCMem2, htmp);
464 
465  BitBlt(hDCMem, j_min, i_min, w, h, hDCMem2, 0, 0, SRCCOPY);
466  LeaveCriticalSection(&m_criticalSection);
467 
468  DeleteDC(hDCMem);
469  ReleaseDC(m_hWnd, hDCScreen);
470  DeleteObject(htmp);
471 
472  return true;
473 }
474 
481 void vpGDIRenderer::setPixel(const vpImagePoint &iP, const vpColor &color)
482 {
483  // get the window's DC
484  HDC hDCScreen = GetDC(m_hWnd);
485  HDC hDCMem = CreateCompatibleDC(hDCScreen);
486 
487  // select this bmp in memory
488  EnterCriticalSection(&m_criticalSection);
489  SelectObject(hDCMem, m_bmp);
490 
491  if (color.id < vpColor::id_unknown)
492  SetPixel(hDCMem, vpMath::round(iP.get_u() / m_rscale), vpMath::round(iP.get_v() / m_rscale), m_colors[color.id]);
493  else {
494  COLORREF gdicolor = RGB(color.R, color.G, color.B);
495  SetPixel(hDCMem, vpMath::round(iP.get_u() / m_rscale), vpMath::round(iP.get_v() / m_rscale), gdicolor);
496  }
497  // display the result (flush)
498  // BitBlt(hDCScreen, x, y, 1, 1, hDCMem, x, y, SRCCOPY);
499 
500  LeaveCriticalSection(&m_criticalSection);
501 
502  DeleteDC(hDCMem);
503  ReleaseDC(m_hWnd, hDCScreen);
504 }
505 
513 void vpGDIRenderer::drawLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
514  unsigned int thickness, int style)
515 {
516  HDC hDCScreen = NULL, hDCMem = NULL;
517  HPEN hPen = NULL;
518 #ifdef GDI_ROBUST
519  double start = vpTime::measureTimeMs();
520  while (vpTime::measureTimeMs() - start < 1000) {
521  hDCScreen = GetDC(m_hWnd);
522  if (!hDCScreen)
523  continue;
524  hDCMem = CreateCompatibleDC(hDCScreen);
525  if (!hDCMem) {
526  ReleaseDC(m_hWnd, hDCScreen);
527  continue;
528  }
529 
530  // create the pen
531  if (color.id < vpColor::id_unknown)
532  hPen = CreatePen(style, static_cast<int>(thickness), m_colors[color.id]);
533  else {
534  COLORREF gdicolor = RGB(color.R, color.G, color.B);
535  hPen = CreatePen(style, static_cast<int>(thickness), gdicolor);
536  }
537  if (!hPen) {
538  DeleteDC(hDCMem);
539  ReleaseDC(m_hWnd, hDCScreen);
540  continue;
541  }
542  if (!SetBkMode(hDCMem, TRANSPARENT)) {
543  DeleteObject(hPen);
544  DeleteDC(hDCMem);
545  ReleaseDC(m_hWnd, hDCScreen);
546  continue;
547  }
548 
549  // select this bmp in memory
550  EnterCriticalSection(&m_criticalSection);
551 
552  if (!SelectObject(hDCMem, m_bmp)) {
553  LeaveCriticalSection(&m_criticalSection);
554  DeleteObject(hPen);
555  DeleteDC(hDCMem);
556  ReleaseDC(m_hWnd, hDCScreen);
557  continue;
558  }
559 
560  // select the pen
561  if (!SelectObject(hDCMem, hPen)) {
562  LeaveCriticalSection(&m_criticalSection);
563  DeleteObject(hPen);
564  DeleteDC(hDCMem);
565  ReleaseDC(m_hWnd, hDCScreen);
566  continue;
567  }
568  break;
569  }
570  timelost += (vpTime::measureTimeMs() - start);
571 #else
572  // get the window's DC
573  hDCScreen = GetDC(m_hWnd);
574  hDCMem = CreateCompatibleDC(hDCScreen);
575  // create the pen
576  if (color.id < vpColor::id_unknown)
577  hPen = CreatePen(style, static_cast<int>(thickness), m_colors[color.id]);
578  else {
579  COLORREF gdicolor = RGB(color.R, color.G, color.B);
580  hPen = CreatePen(style, static_cast<int>(thickness), gdicolor);
581  }
582  SetBkMode(hDCMem, TRANSPARENT);
583 
584  // select this bmp in memory
585  EnterCriticalSection(&m_criticalSection);
586  SelectObject(hDCMem, m_bmp);
587 
588  // select the pen
589  SelectObject(hDCMem, hPen);
590 #endif
591  // Warning: When thickness > 1 and pen style is PS_DASHDOT, the drawing
592  // displays a solid line That's why in that case we implement the dashdot
593  // line manually drawing multiple small lines
594  if (thickness != 1 && style != PS_SOLID) {
595  vpImagePoint ip1_ = ip1;
596  vpImagePoint ip2_ = ip2;
597 
598  double size = 10. * m_rscale;
599  double length = sqrt(vpMath::sqr(ip2_.get_i() - ip1_.get_i()) + vpMath::sqr(ip2_.get_j() - ip1_.get_j()));
600  bool vertical_line = (int)ip2_.get_j() == (int)ip1_.get_j();
601  if (vertical_line) {
602  if (ip2_.get_i() < ip1_.get_i()) {
603  std::swap(ip1_, ip2_);
604  }
605  } else if (ip2_.get_j() < ip1_.get_j()) {
606  std::swap(ip1_, ip2_);
607  }
608 
609  double diff_j = vertical_line ? 1 : ip2_.get_j() - ip1_.get_j();
610  double deltaj = size / length * diff_j;
611  double deltai = size / length * (ip2_.get_i() - ip1_.get_i());
612  double slope = (ip2_.get_i() - ip1_.get_i()) / diff_j;
613  double orig = ip1_.get_i() - slope * ip1_.get_j();
614 
615  if (vertical_line) {
616  for (unsigned int i = (unsigned int)ip1_.get_i(); i < ip2_.get_i(); i += (unsigned int)(2 * deltai)) {
617  double j = ip1_.get_j();
618 
619  // Move to the starting point
620  MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), NULL);
621  // Draw the line
622  LineTo(hDCMem, vpMath::round(j / m_rscale), vpMath::round((i + deltai) / m_rscale));
623  }
624  } else {
625  for (unsigned int j = (unsigned int)ip1_.get_j(); j < ip2_.get_j(); j += (unsigned int)(2 * deltaj)) {
626  double i = slope * j + orig;
627  // Move to the starting point
628  MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), NULL);
629  // Draw the line
630  LineTo(hDCMem, vpMath::round((j + deltaj) / m_rscale), vpMath::round((i + deltai) / m_rscale));
631  }
632  }
633  } else {
634  // move to the starting point
635  MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), NULL);
636  // Draw the line
637  LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
638  }
639 
640  LeaveCriticalSection(&m_criticalSection);
641 
642  DeleteObject(hPen);
643  DeleteDC(hDCMem);
644  ReleaseDC(m_hWnd, hDCScreen);
645 }
646 
656 void vpGDIRenderer::drawRect(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color,
657  bool fill, unsigned int thickness)
658 {
659  if (thickness == 0)
660  thickness = 1;
661  // get the window's DC
662  HDC hDCScreen = GetDC(m_hWnd);
663  HDC hDCMem = CreateCompatibleDC(hDCScreen);
664 
665  // create the pen
666  HPEN hPen;
667  COLORREF gdicolor = RGB(0, 0, 0);
668 
669  if (color.id < vpColor::id_unknown)
670  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
671  else {
672  gdicolor = RGB(color.R, color.G, color.B);
673  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
674  }
675 
676  // create an hollow or solid brush (depends on boolean fill)
677  LOGBRUSH lBrush;
678  if (fill) {
679  lBrush.lbStyle = BS_SOLID;
680  if (color.id < vpColor::id_unknown)
681  lBrush.lbColor = m_colors[color.id];
682  else {
683  lBrush.lbColor = gdicolor;
684  }
685  } else
686  lBrush.lbStyle = BS_HOLLOW;
687  HBRUSH hbrush = CreateBrushIndirect(&lBrush);
688 
689  // select this bmp in memory
690  EnterCriticalSection(&m_criticalSection);
691  SelectObject(hDCMem, m_bmp);
692 
693  // select the brush
694  SelectObject(hDCMem, hbrush);
695  // select the pen
696  SelectObject(hDCMem, hPen);
697 
698  // draw the rectangle
699  Rectangle(hDCMem, vpMath::round(topLeft.get_u() / m_rscale), vpMath::round(topLeft.get_v() / m_rscale),
700  vpMath::round((topLeft.get_u() + width) / m_rscale), vpMath::round((topLeft.get_v() + height) / m_rscale));
701 
702  // display the result (flush)
703  // BitBlt(hDCScreen, j, i, width, height, hDCMem, j, i, SRCCOPY);
704 
705  LeaveCriticalSection(&m_criticalSection);
706 
707  DeleteObject(hbrush);
708  DeleteObject(hPen);
709  DeleteDC(hDCMem);
710  ReleaseDC(m_hWnd, hDCScreen);
711 }
712 
717 void vpGDIRenderer::clear(const vpColor &color)
718 {
719  vpImagePoint ip;
720  ip.set_i(0);
721  ip.set_j(0);
722  drawRect(ip, m_rwidth, m_rheight, color, true, 0);
723 }
724 
733 void vpGDIRenderer::drawCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
734  unsigned int thickness)
735 {
736 
737  // get the window's DC
738  HDC hDCScreen = GetDC(m_hWnd);
739  HDC hDCMem = CreateCompatibleDC(hDCScreen);
740 
741  // create the pen
742  HPEN hPen;
743  if (color.id < vpColor::id_unknown)
744  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
745  else {
746  COLORREF gdicolor = RGB(color.R, color.G, color.B);
747  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
748  }
749 
750  // create an hollow brush
751  LOGBRUSH lBrush;
752  lBrush.lbStyle = BS_HOLLOW;
753  HBRUSH hbrush = CreateBrushIndirect(&lBrush);
754 
755  // computes bounding rectangle
756  int radius_ = static_cast<int>(radius);
757  int x1 = vpMath::round(center.get_u() / m_rscale) - radius_ / m_rscale;
758  int y1 = vpMath::round(center.get_v() / m_rscale) - radius_ / m_rscale;
759  int x2 = vpMath::round(center.get_u() / m_rscale) + radius_ / m_rscale;
760  int y2 = vpMath::round(center.get_v() / m_rscale) + radius_ / m_rscale;
761 
762  // select this bmp in memory
763  EnterCriticalSection(&m_criticalSection);
764  SelectObject(hDCMem, m_bmp);
765 
766  // select the brush
767  SelectObject(hDCMem, hbrush);
768  // select the pen
769  SelectObject(hDCMem, hPen);
770 
771  // draw the circle
772  if (fill == false)
773  Ellipse(hDCMem, x1, y1, x2, y2);
774 
775  else {
776  while (x2 - x1 > 0) {
777  x1++;
778  x2--;
779  y1++;
780  y2--;
781  Ellipse(hDCMem, x1, y1, x2, y2);
782  }
783  }
784 
785  // display the result (flush)
786  // BitBlt(hDCScreen, x1, y1, x2-x1, y2-y1, hDCMem, x1, y1, SRCCOPY);
787 
788  LeaveCriticalSection(&m_criticalSection);
789 
790  DeleteObject(hbrush);
791  DeleteObject(hPen);
792  DeleteDC(hDCMem);
793  ReleaseDC(m_hWnd, hDCScreen);
794 }
795 
802 void vpGDIRenderer::drawText(const vpImagePoint &ip, const char *text, const vpColor &color)
803 {
804  // get the window's DC
805  HDC hDCScreen = GetDC(m_hWnd);
806  HDC hDCMem = CreateCompatibleDC(hDCScreen);
807 
808  // select this bmp in memory
809  EnterCriticalSection(&m_criticalSection);
810  SelectObject(hDCMem, m_bmp);
811 
812  // Select the font
813  SelectObject(hDCMem, m_hFont);
814 
815  // set the text color
816  if (color.id < vpColor::id_unknown)
817  SetTextColor(hDCMem, m_colors[color.id]);
818  else {
819  COLORREF gdicolor = RGB(color.R, color.G, color.B);
820  SetTextColor(hDCMem, gdicolor);
821  }
822 
823  // we don't use the bkColor
824  SetBkMode(hDCMem, TRANSPARENT);
825 
826  SIZE size;
827  int length = (int)strlen(text);
828 
829  // get the displayed string dimensions
830  GetTextExtentPoint32(hDCMem, text, length, &size);
831 
832  // displays the string
833  TextOut(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale), text, length);
834 
835  // display the result (flush)
836  // BitBlt(hDCScreen, j, i, size.cx, size.cy, hDCMem, j, i, SRCCOPY);
837 
838  LeaveCriticalSection(&m_criticalSection);
839 
840  DeleteDC(hDCMem);
841  ReleaseDC(m_hWnd, hDCScreen);
842 }
843 
851 void vpGDIRenderer::drawCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness)
852 {
853  /* unsigned */ int half_size = static_cast<int>(size / 2 / m_rscale);
854 
855  // if half_size is equal to zero, nothing is displayed with the code
856  // just below. So, if half_size is equal to zero we just draw the
857  // pixel.
858  if (half_size) {
859  // get the window's DC
860  HDC hDCScreen = GetDC(m_hWnd);
861  HDC hDCMem = CreateCompatibleDC(hDCScreen);
862 
863  // create the pen
864  HPEN hPen;
865  if (color.id < vpColor::id_unknown)
866  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
867  else {
868  COLORREF gdicolor = RGB(color.R, color.G, color.B);
869  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
870  }
871 
872  // select this bmp in memory
873  EnterCriticalSection(&m_criticalSection);
874  SelectObject(hDCMem, m_bmp);
875 
876  // select the pen
877  SelectObject(hDCMem, hPen);
878 
879  // move to the starting point
880  MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale) - half_size, vpMath::round(ip.get_v() / m_rscale), NULL);
881  // Draw the first line (horizontal)
882  LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale) + half_size, vpMath::round(ip.get_v() / m_rscale));
883 
884  // move to the starting point
885  MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) - half_size, NULL);
886  // Draw the second line (vertical)
887  LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) + half_size);
888 
889  // display the result (flush)
890  // BitBlt(hDCScreen, j-(size/2), i-(size/2), size, size,
891  // hDCMem, j-(size/2), i-(size/2), SRCCOPY);
892 
893  LeaveCriticalSection(&m_criticalSection);
894 
895  DeleteObject(hPen);
896  DeleteDC(hDCMem);
897  ReleaseDC(m_hWnd, hDCScreen);
898  } else {
899  setPixel(ip, color);
900  }
901 }
902 
910 void vpGDIRenderer::drawArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
911  unsigned int h, unsigned int thickness)
912 {
913  double a = ip2.get_i() / m_rscale - ip1.get_i() / m_rscale;
914  double b = ip2.get_j() / m_rscale - ip1.get_j() / m_rscale;
915  double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
916 
917  // computes the coordinates of the rectangle to blit later
918  // unsigned int x = (j2 >= j1) ? j1 : j2;
919  // unsigned int y = (i2 >= i1) ? i1 : i2;
920  // unsigned int w = (j2 >= j1) ? j2-j1 : j1-j2;
921  // unsigned int h = (i2 >= i1) ? i2-i1 : i1-i2;
922 
923  // get the window's DC
924  HDC hDCScreen = GetDC(m_hWnd);
925  HDC hDCMem = CreateCompatibleDC(hDCScreen);
926 
927  // create the pen
928  HPEN hPen;
929  if (color.id < vpColor::id_unknown)
930  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
931  else {
932  COLORREF gdicolor = RGB(color.R, color.G, color.B);
933  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
934  }
935 
936  // select this bmp in memory
937  EnterCriticalSection(&m_criticalSection);
938  SelectObject(hDCMem, m_bmp);
939 
940  // select the pen
941  SelectObject(hDCMem, hPen);
942 
943  if ((a == 0) && (b == 0)) {
944  // DisplayCrossLarge(i1,j1,3,col) ;
945  } else {
946  a /= lg;
947  b /= lg;
948 
949  vpImagePoint ip3;
950  ip3.set_i(ip2.get_i() / m_rscale - w * a);
951  ip3.set_j(ip2.get_j() / m_rscale - w * b);
952 
953  vpImagePoint ip4;
954 
955  // double t = 0 ;
956  // while (t<=_l)
957  {
958  ip4.set_i(ip3.get_i() - b * h);
959  ip4.set_j(ip3.get_j() + a * h);
960 
961  if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
962  MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), NULL);
963  LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
964  }
965  // t+=0.1 ;
966  }
967 
968  // t = 0 ;
969  // while (t>= -_l)
970  {
971  ip4.set_i(ip3.get_i() + b * h);
972  ip4.set_j(ip3.get_j() - a * h);
973 
974  if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
975  MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), NULL);
976  LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
977  }
978 
979  // t-=0.1 ;
980  }
981  MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), NULL);
982  LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
983  }
984 
985  // display the result (flush)
986  // BitBlt(hDCScreen, x, y, w, h, hDCMem, x, y, SRCCOPY);
987 
988  LeaveCriticalSection(&m_criticalSection);
989 
990  DeleteObject(hPen);
991  DeleteDC(hDCMem);
992  ReleaseDC(m_hWnd, hDCScreen);
993 }
994 
999 void vpGDIRenderer::getImage(vpImage<vpRGBa> &I)
1000 {
1001  // size of image buffer : m_rwidth*m_rheight*4
1002  unsigned int size = m_rwidth * m_rheight * 4;
1003  unsigned char *imBuffer = new unsigned char[size];
1004 
1005  // gets the hbitmap's bitmap
1006  GetBitmapBits(m_bmp, static_cast<LONG>(size), (void *)imBuffer);
1007 
1008  // resize the destination image as needed
1009  I.resize(m_rheight, m_rwidth);
1010 
1011  // copy the content
1012  for (unsigned int i = 0; i < size; i += 4) {
1013  I.bitmap[i >> 2].R = imBuffer[i + 2];
1014  I.bitmap[i >> 2].G = imBuffer[i + 1];
1015  I.bitmap[i >> 2].B = imBuffer[i + 0];
1016  I.bitmap[i >> 2].A = vpRGBa::alpha_default; // default opacity
1017  }
1018 
1019  delete[] imBuffer;
1020 }
1021 #endif
1022 #elif !defined(VISP_BUILD_SHARED_LIBS)
1023 // Work arround to avoid warning: libvisp_core.a(vpGDIRenderer.cpp.o) has no
1024 // symbols
1025 void dummy_vpGDIRenderer(){};
1026 #endif
double get_v() const
Definition: vpImagePoint.h:273
double get_i() const
Definition: vpImagePoint.h:203
unsigned int getWidth() const
Definition: vpImage.h:246
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
unsigned char B
Blue component.
Definition: vpRGBa.h:150
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
static const vpColor black
Definition: vpColor.h:211
static const vpColor darkRed
Definition: vpColor.h:218
Class to define RGB colors available for display functionnalities.
Definition: vpColor.h:157
double get_u() const
Definition: vpImagePoint.h:262
static const vpColor lightGray
Definition: vpColor.h:213
static const vpColor darkBlue
Definition: vpColor.h:224
unsigned char G
Green component.
Definition: vpRGBa.h:149
static const vpColor green
Definition: vpColor.h:220
double get_j() const
Definition: vpImagePoint.h:214
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:126
static const vpColor lightRed
Definition: vpColor.h:216
Definition: vpRGBa.h:66
static const vpColor red
Definition: vpColor.h:217
static const vpColor orange
Definition: vpColor.h:227
vpColorIdentifier id
Definition: vpColor.h:206
static const vpColor cyan
Definition: vpColor.h:226
static const vpColor lightGreen
Definition: vpColor.h:219
void set_i(double ii)
Definition: vpImagePoint.h:166
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
static double sqr(double x)
Definition: vpMath.h:116
unsigned char A
Additionnal component.
Definition: vpRGBa.h:151
static const vpColor gray
Definition: vpColor.h:214
static const vpColor darkGray
Definition: vpColor.h:215
static int round(double x)
Definition: vpMath.h:245
void set_j(double jj)
Definition: vpImagePoint.h:177
Error that can be emited by the vpDisplay class and its derivates.
unsigned char R
Red component.
Definition: vpRGBa.h:148
static const vpColor darkGreen
Definition: vpColor.h:221
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:87
static const vpColor yellow
Definition: vpColor.h:225
static const vpColor lightBlue
Definition: vpColor.h:222
static const vpColor purple
Definition: vpColor.h:228
static const vpColor white
Definition: vpColor.h:212
static const vpColor blue
Definition: vpColor.h:223