Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
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, const unsigned int width,
154  const 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, const unsigned int width,
177  const 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, const unsigned int width,
257  const 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, const unsigned int width,
356  const 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  double size = 10. * m_rscale;
596  double length = sqrt(vpMath::sqr(ip2.get_i() - ip1.get_i()) + vpMath::sqr(ip2.get_j() - ip1.get_j()));
597  double deltaj = size / length * (ip2.get_j() - ip1.get_j());
598  double deltai = size / length * (ip2.get_i() - ip1.get_i());
599  double slope = (ip2.get_i() - ip1.get_i()) / (ip2.get_j() - ip1.get_j());
600  double orig = ip1.get_i() - slope * ip1.get_j();
601  for (unsigned int j = (unsigned int)ip1.get_j(); j < ip2.get_j(); j += (unsigned int)(2 * deltaj)) {
602  double i = slope * j + orig;
603  // move to the starting point
604  MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), NULL);
605  // Draw the line
606  LineTo(hDCMem, vpMath::round((j + deltaj) / m_rscale), vpMath::round((i + deltai) / m_rscale));
607  }
608  } else {
609  // move to the starting point
610  MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), NULL);
611  // Draw the line
612  LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
613  }
614 
615  LeaveCriticalSection(&m_criticalSection);
616 
617  DeleteObject(hPen);
618  DeleteDC(hDCMem);
619  ReleaseDC(m_hWnd, hDCScreen);
620 }
621 
631 void vpGDIRenderer::drawRect(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color,
632  bool fill, unsigned int thickness)
633 {
634  if (thickness == 0)
635  thickness = 1;
636  // get the window's DC
637  HDC hDCScreen = GetDC(m_hWnd);
638  HDC hDCMem = CreateCompatibleDC(hDCScreen);
639 
640  // create the pen
641  HPEN hPen;
642  COLORREF gdicolor = RGB(0, 0, 0);
643 
644  if (color.id < vpColor::id_unknown)
645  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
646  else {
647  gdicolor = RGB(color.R, color.G, color.B);
648  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
649  }
650 
651  // create an hollow or solid brush (depends on boolean fill)
652  LOGBRUSH lBrush;
653  if (fill) {
654  lBrush.lbStyle = BS_SOLID;
655  if (color.id < vpColor::id_unknown)
656  lBrush.lbColor = m_colors[color.id];
657  else {
658  lBrush.lbColor = gdicolor;
659  }
660  } else
661  lBrush.lbStyle = BS_HOLLOW;
662  HBRUSH hbrush = CreateBrushIndirect(&lBrush);
663 
664  // select this bmp in memory
665  EnterCriticalSection(&m_criticalSection);
666  SelectObject(hDCMem, m_bmp);
667 
668  // select the brush
669  SelectObject(hDCMem, hbrush);
670  // select the pen
671  SelectObject(hDCMem, hPen);
672 
673  // draw the rectangle
674  Rectangle(hDCMem, vpMath::round(topLeft.get_u() / m_rscale), vpMath::round(topLeft.get_v() / m_rscale),
675  vpMath::round((topLeft.get_u() + width) / m_rscale), vpMath::round((topLeft.get_v() + height) / m_rscale));
676 
677  // display the result (flush)
678  // BitBlt(hDCScreen, j, i, width, height, hDCMem, j, i, SRCCOPY);
679 
680  LeaveCriticalSection(&m_criticalSection);
681 
682  DeleteObject(hbrush);
683  DeleteObject(hPen);
684  DeleteDC(hDCMem);
685  ReleaseDC(m_hWnd, hDCScreen);
686 }
687 
692 void vpGDIRenderer::clear(const vpColor &color)
693 {
694  vpImagePoint ip;
695  ip.set_i(0);
696  ip.set_j(0);
697  drawRect(ip, m_rwidth, m_rheight, color, true, 0);
698 }
699 
708 void vpGDIRenderer::drawCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
709  unsigned int thickness)
710 {
711 
712  // get the window's DC
713  HDC hDCScreen = GetDC(m_hWnd);
714  HDC hDCMem = CreateCompatibleDC(hDCScreen);
715 
716  // create the pen
717  HPEN hPen;
718  if (color.id < vpColor::id_unknown)
719  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
720  else {
721  COLORREF gdicolor = RGB(color.R, color.G, color.B);
722  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
723  }
724 
725  // create an hollow brush
726  LOGBRUSH lBrush;
727  lBrush.lbStyle = BS_HOLLOW;
728  HBRUSH hbrush = CreateBrushIndirect(&lBrush);
729 
730  // computes bounding rectangle
731  int radius_ = static_cast<int>(radius);
732  int x1 = vpMath::round(center.get_u() / m_rscale) - radius_ / m_rscale;
733  int y1 = vpMath::round(center.get_v() / m_rscale) - radius_ / m_rscale;
734  int x2 = vpMath::round(center.get_u() / m_rscale) + radius_ / m_rscale;
735  int y2 = vpMath::round(center.get_v() / m_rscale) + radius_ / m_rscale;
736 
737  // select this bmp in memory
738  EnterCriticalSection(&m_criticalSection);
739  SelectObject(hDCMem, m_bmp);
740 
741  // select the brush
742  SelectObject(hDCMem, hbrush);
743  // select the pen
744  SelectObject(hDCMem, hPen);
745 
746  // draw the circle
747  if (fill == false)
748  Ellipse(hDCMem, x1, y1, x2, y2);
749 
750  else {
751  while (x2 - x1 > 0) {
752  x1++;
753  x2--;
754  y1++;
755  y2--;
756  Ellipse(hDCMem, x1, y1, x2, y2);
757  }
758  }
759 
760  // display the result (flush)
761  // BitBlt(hDCScreen, x1, y1, x2-x1, y2-y1, hDCMem, x1, y1, SRCCOPY);
762 
763  LeaveCriticalSection(&m_criticalSection);
764 
765  DeleteObject(hbrush);
766  DeleteObject(hPen);
767  DeleteDC(hDCMem);
768  ReleaseDC(m_hWnd, hDCScreen);
769 }
770 
777 void vpGDIRenderer::drawText(const vpImagePoint &ip, const char *text, const vpColor &color)
778 {
779  // get the window's DC
780  HDC hDCScreen = GetDC(m_hWnd);
781  HDC hDCMem = CreateCompatibleDC(hDCScreen);
782 
783  // select this bmp in memory
784  EnterCriticalSection(&m_criticalSection);
785  SelectObject(hDCMem, m_bmp);
786 
787  // Select the font
788  SelectObject(hDCMem, m_hFont);
789 
790  // set the text color
791  if (color.id < vpColor::id_unknown)
792  SetTextColor(hDCMem, m_colors[color.id]);
793  else {
794  COLORREF gdicolor = RGB(color.R, color.G, color.B);
795  SetTextColor(hDCMem, gdicolor);
796  }
797 
798  // we don't use the bkColor
799  SetBkMode(hDCMem, TRANSPARENT);
800 
801  SIZE size;
802  int length = (int)strlen(text);
803 
804  // get the displayed string dimensions
805  GetTextExtentPoint32(hDCMem, text, length, &size);
806 
807  // displays the string
808  TextOut(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale), text, length);
809 
810  // display the result (flush)
811  // BitBlt(hDCScreen, j, i, size.cx, size.cy, hDCMem, j, i, SRCCOPY);
812 
813  LeaveCriticalSection(&m_criticalSection);
814 
815  DeleteDC(hDCMem);
816  ReleaseDC(m_hWnd, hDCScreen);
817 }
818 
826 void vpGDIRenderer::drawCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness)
827 {
828  /* unsigned */ int half_size = static_cast<int>(size / 2 / m_rscale);
829 
830  // if half_size is equal to zero, nothing is displayed with the code
831  // just below. So, if half_size is equal to zero we just draw the
832  // pixel.
833  if (half_size) {
834  // get the window's DC
835  HDC hDCScreen = GetDC(m_hWnd);
836  HDC hDCMem = CreateCompatibleDC(hDCScreen);
837 
838  // create the pen
839  HPEN hPen;
840  if (color.id < vpColor::id_unknown)
841  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
842  else {
843  COLORREF gdicolor = RGB(color.R, color.G, color.B);
844  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
845  }
846 
847  // select this bmp in memory
848  EnterCriticalSection(&m_criticalSection);
849  SelectObject(hDCMem, m_bmp);
850 
851  // select the pen
852  SelectObject(hDCMem, hPen);
853 
854  // move to the starting point
855  MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale) - half_size, vpMath::round(ip.get_v() / m_rscale), NULL);
856  // Draw the first line (horizontal)
857  LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale) + half_size, vpMath::round(ip.get_v() / m_rscale));
858 
859  // move to the starting point
860  MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) - half_size, NULL);
861  // Draw the second line (vertical)
862  LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) + half_size);
863 
864  // display the result (flush)
865  // BitBlt(hDCScreen, j-(size/2), i-(size/2), size, size,
866  // hDCMem, j-(size/2), i-(size/2), SRCCOPY);
867 
868  LeaveCriticalSection(&m_criticalSection);
869 
870  DeleteObject(hPen);
871  DeleteDC(hDCMem);
872  ReleaseDC(m_hWnd, hDCScreen);
873  } else {
874  setPixel(ip, color);
875  }
876 }
877 
885 void vpGDIRenderer::drawArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
886  unsigned int h, unsigned int thickness)
887 {
888  double a = ip2.get_i() / m_rscale - ip1.get_i() / m_rscale;
889  double b = ip2.get_j() / m_rscale - ip1.get_j() / m_rscale;
890  double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
891 
892  // computes the coordinates of the rectangle to blit later
893  // unsigned int x = (j2 >= j1) ? j1 : j2;
894  // unsigned int y = (i2 >= i1) ? i1 : i2;
895  // unsigned int w = (j2 >= j1) ? j2-j1 : j1-j2;
896  // unsigned int h = (i2 >= i1) ? i2-i1 : i1-i2;
897 
898  // get the window's DC
899  HDC hDCScreen = GetDC(m_hWnd);
900  HDC hDCMem = CreateCompatibleDC(hDCScreen);
901 
902  // create the pen
903  HPEN hPen;
904  if (color.id < vpColor::id_unknown)
905  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
906  else {
907  COLORREF gdicolor = RGB(color.R, color.G, color.B);
908  hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
909  }
910 
911  // select this bmp in memory
912  EnterCriticalSection(&m_criticalSection);
913  SelectObject(hDCMem, m_bmp);
914 
915  // select the pen
916  SelectObject(hDCMem, hPen);
917 
918  if ((a == 0) && (b == 0)) {
919  // DisplayCrossLarge(i1,j1,3,col) ;
920  } else {
921  a /= lg;
922  b /= lg;
923 
924  vpImagePoint ip3;
925  ip3.set_i(ip2.get_i() / m_rscale - w * a);
926  ip3.set_j(ip2.get_j() / m_rscale - w * b);
927 
928  vpImagePoint ip4;
929 
930  // double t = 0 ;
931  // while (t<=_l)
932  {
933  ip4.set_i(ip3.get_i() - b * h);
934  ip4.set_j(ip3.get_j() + a * h);
935 
936  if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
937  MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), NULL);
938  LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
939  }
940  // t+=0.1 ;
941  }
942 
943  // t = 0 ;
944  // while (t>= -_l)
945  {
946  ip4.set_i(ip3.get_i() + b * h);
947  ip4.set_j(ip3.get_j() - a * h);
948 
949  if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
950  MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), NULL);
951  LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
952  }
953 
954  // t-=0.1 ;
955  }
956  MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), NULL);
957  LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
958  }
959 
960  // display the result (flush)
961  // BitBlt(hDCScreen, x, y, w, h, hDCMem, x, y, SRCCOPY);
962 
963  LeaveCriticalSection(&m_criticalSection);
964 
965  DeleteObject(hPen);
966  DeleteDC(hDCMem);
967  ReleaseDC(m_hWnd, hDCScreen);
968 }
969 
974 void vpGDIRenderer::getImage(vpImage<vpRGBa> &I)
975 {
976  // size of image buffer : m_rwidth*m_rheight*4
977  unsigned int size = m_rwidth * m_rheight * 4;
978  unsigned char *imBuffer = new unsigned char[size];
979 
980  // gets the hbitmap's bitmap
981  GetBitmapBits(m_bmp, static_cast<LONG>(size), (void *)imBuffer);
982 
983  // resize the destination image as needed
984  I.resize(m_rheight, m_rwidth);
985 
986  // copy the content
987  for (unsigned int i = 0; i < size; i += 4) {
988  I.bitmap[i >> 2].R = imBuffer[i + 2];
989  I.bitmap[i >> 2].G = imBuffer[i + 1];
990  I.bitmap[i >> 2].B = imBuffer[i + 0];
991  I.bitmap[i >> 2].A = vpRGBa::alpha_default; // default opacity
992  }
993 
994  delete[] imBuffer;
995 }
996 #endif
997 #elif !defined(VISP_BUILD_SHARED_LIBS)
998 // Work arround to avoid warning: libvisp_core.a(vpGDIRenderer.cpp.o) has no
999 // symbols
1000 void dummy_vpGDIRenderer(){};
1001 #endif
double get_v() const
Definition: vpImagePoint.h:274
double get_i() const
Definition: vpImagePoint.h:204
unsigned int getWidth() const
Definition: vpImage.h:239
unsigned char B
Blue component.
Definition: vpRGBa.h:150
Type * bitmap
points toward the bitmap
Definition: vpImage.h:133
static const vpColor black
Definition: vpColor.h:174
static const vpColor darkRed
Definition: vpColor.h:181
Class to define colors available for display functionnalities.
Definition: vpColor.h:120
double get_u() const
Definition: vpImagePoint.h:263
static const vpColor lightGray
Definition: vpColor.h:176
static const vpColor darkBlue
Definition: vpColor.h:187
unsigned char G
Green component.
Definition: vpRGBa.h:149
static const vpColor green
Definition: vpColor.h:183
static int round(const double x)
Definition: vpMath.h:235
double get_j() const
Definition: vpImagePoint.h:215
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:88
static const vpColor lightRed
Definition: vpColor.h:179
Definition: vpRGBa.h:66
static const vpColor red
Definition: vpColor.h:180
static const vpColor orange
Definition: vpColor.h:190
vpColorIdentifier id
Definition: vpColor.h:169
void set_i(const double ii)
Definition: vpImagePoint.h:167
static const vpColor cyan
Definition: vpColor.h:189
static const vpColor lightGreen
Definition: vpColor.h:182
static double sqr(double x)
Definition: vpMath.h:108
unsigned char A
Additionnal component.
Definition: vpRGBa.h:151
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:866
static const vpColor gray
Definition: vpColor.h:177
static const vpColor darkGray
Definition: vpColor.h:178
void set_j(const double jj)
Definition: vpImagePoint.h:178
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:184
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
static const vpColor yellow
Definition: vpColor.h:188
static const vpColor lightBlue
Definition: vpColor.h:185
static const vpColor purple
Definition: vpColor.h:191
static const vpColor white
Definition: vpColor.h:175
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
Definition: vpImagePoint.h:285
static const vpColor blue
Definition: vpColor.h:186