Visual Servoing Platform version 3.5.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
50vpGDIRenderer::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
107vpGDIRenderer::~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
123bool 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
141void vpGDIRenderer::setImg(const vpImage<vpRGBa> &I)
142{
143 // converts the image into a HBITMAP
144 convert(I, m_bmp);
145}
146
153void 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
164void vpGDIRenderer::setImg(const vpImage<unsigned char> &I)
165{
166 // converts the image into a HBITMAP
167 convert(I, m_bmp);
168}
169
176void 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
186bool 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
216void 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
256void 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
315void 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
355void 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
414bool 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
451bool 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
481void 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
513void 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
656void 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
717void 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
733void 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
802void 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
851void 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
910void 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
999void 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
1025void dummy_vpGDIRenderer(){};
1026#endif
Class to define RGB colors available for display functionnalities.
Definition: vpColor.h:158
static const vpColor white
Definition: vpColor.h:212
vpColorIdentifier id
Definition: vpColor.h:206
static const vpColor red
Definition: vpColor.h:217
static const vpColor darkGray
Definition: vpColor.h:215
static const vpColor black
Definition: vpColor.h:211
static const vpColor cyan
Definition: vpColor.h:226
static const vpColor orange
Definition: vpColor.h:227
static const vpColor darkRed
Definition: vpColor.h:218
static const vpColor blue
Definition: vpColor.h:223
static const vpColor lightGray
Definition: vpColor.h:213
static const vpColor lightBlue
Definition: vpColor.h:222
static const vpColor darkGreen
Definition: vpColor.h:221
static const vpColor darkBlue
Definition: vpColor.h:224
static const vpColor purple
Definition: vpColor.h:228
static const vpColor lightGreen
Definition: vpColor.h:219
static const vpColor yellow
Definition: vpColor.h:225
@ id_lightBlue
Definition: vpColor.h:184
@ id_yellow
Definition: vpColor.h:190
@ id_darkGray
Definition: vpColor.h:170
@ id_green
Definition: vpColor.h:180
@ id_darkRed
Definition: vpColor.h:176
@ id_lightGray
Definition: vpColor.h:166
@ id_red
Definition: vpColor.h:174
@ id_lightRed
Definition: vpColor.h:172
@ id_white
Definition: vpColor.h:164
@ id_black
Definition: vpColor.h:162
@ id_blue
Definition: vpColor.h:186
@ id_darkGreen
Definition: vpColor.h:182
@ id_gray
Definition: vpColor.h:168
@ id_lightGreen
Definition: vpColor.h:178
@ id_purple
Definition: vpColor.h:196
@ id_orange
Definition: vpColor.h:194
@ id_cyan
Definition: vpColor.h:192
@ id_darkBlue
Definition: vpColor.h:188
@ id_unknown
Definition: vpColor.h:199
static const vpColor lightRed
Definition: vpColor.h:216
static const vpColor green
Definition: vpColor.h:220
static const vpColor gray
Definition: vpColor.h:214
Error that can be emited by the vpDisplay class and its derivates.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
void set_j(double jj)
Definition: vpImagePoint.h:177
double get_j() const
Definition: vpImagePoint.h:214
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_i(double ii)
Definition: vpImagePoint.h:166
double get_u() const
Definition: vpImagePoint.h:262
double get_i() const
Definition: vpImagePoint.h:203
double get_v() const
Definition: vpImagePoint.h:273
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
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
static double sqr(double x)
Definition: vpMath.h:116
static int round(double x)
Definition: vpMath.h:247
Definition: vpRGBa.h:67
unsigned char B
Blue component.
Definition: vpRGBa.h:150
unsigned char R
Red component.
Definition: vpRGBa.h:148
unsigned char G
Green component.
Definition: vpRGBa.h:149
@ alpha_default
Definition: vpRGBa.h:69
unsigned char A
Additionnal component.
Definition: vpRGBa.h:151
VISP_EXPORT double measureTimeMs()