Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
vpGDIRenderer.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See https://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * 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, unsigned int height)
154{
155 // converts the image into a HBITMAP
156 convertROI(I, iP, width, height);
157}
158
163void vpGDIRenderer::setImg(const vpImage<unsigned char> &I)
164{
165 // converts the image into a HBITMAP
166 convert(I, m_bmp);
167}
168
175void vpGDIRenderer::setImgROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
176 unsigned int height)
177{
178 // converts the image into a HBITMAP
179 convertROI(I, iP, width, height);
180}
181
185bool vpGDIRenderer::render()
186{
187 // gets the window's DC
188 PAINTSTRUCT ps;
189 HDC hDCScreen = BeginPaint(m_hWnd, &ps);
190
191 // create a memory DC
192 HDC hDCMem = CreateCompatibleDC(hDCScreen);
193
194 // selects this bmp in memory
195 EnterCriticalSection(&m_criticalSection);
196 SelectObject(hDCMem, m_bmp);
197
198 // blits it on the window's DC
199 BitBlt(hDCScreen, 0, 0, static_cast<int>(m_rwidth), static_cast<int>(m_rheight), hDCMem, 0, 0, SRCCOPY);
200
201 LeaveCriticalSection(&m_criticalSection);
202 // DeleteDC(hDCMem);
203 DeleteObject(hDCMem);
204
205 EndPaint(m_hWnd, &ps);
206
207 return true;
208}
209
215void vpGDIRenderer::convert(const vpImage<vpRGBa> &I, HBITMAP &hBmp)
216{
217 // allocate the buffer
218 unsigned char *imBuffer = new unsigned char[m_rwidth * m_rheight * 4];
219
220 if (m_rscale == 1) {
221 for (unsigned int i = 0, k = 0; i < m_rwidth * m_rheight * 4; i += 4, k++) {
222 imBuffer[i + 0] = I.bitmap[k].B;
223 imBuffer[i + 1] = I.bitmap[k].G;
224 imBuffer[i + 2] = I.bitmap[k].R;
225 imBuffer[i + 3] = I.bitmap[k].A;
226 }
227 } else {
228 for (unsigned int i = 0; i < m_rheight; i++) {
229 unsigned int i_ = i * m_rscale;
230 unsigned int ii_ = i * m_rwidth;
231 for (unsigned int j = 0; j < m_rwidth; j++) {
232 vpRGBa val = I[i_][j * m_rscale];
233 unsigned int index_ = (ii_ + j) * 4;
234 imBuffer[index_] = val.B;
235 imBuffer[++index_] = val.G;
236 imBuffer[++index_] = val.R;
237 imBuffer[++index_] = val.A;
238 }
239 }
240 }
241
242 // updates the bitmap's pixel data
243 updateBitmap(hBmp, imBuffer, m_rwidth, m_rheight);
244
245 // we don't need this buffer anymore
246 delete[] imBuffer;
247}
248
255void vpGDIRenderer::convertROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int width,
256 unsigned int height)
257{
258 int i_min = (std::max)((int)ceil(iP.get_i() / m_rscale), 0);
259 int j_min = (std::max)((int)ceil(iP.get_j() / m_rscale), 0);
260 int i_max = (std::min)((int)ceil((iP.get_i() + height) / m_rscale), (int)m_rheight);
261 int j_max = (std::min)((int)ceil((iP.get_j() + width) / m_rscale), (int)m_rwidth);
262
263 int h = i_max - i_min;
264 int w = j_max - j_min;
265
266 // allocate the buffer
267 unsigned char *imBuffer = new unsigned char[w * h * 4];
268
269 if (m_rscale == 1) {
270 vpRGBa *bitmap = I.bitmap;
271 unsigned int iwidth = I.getWidth();
272 bitmap = bitmap + (int)(i_min * iwidth + j_min);
273
274 int k = 0;
275 for (int i = 0; i < w * h * 4; i += 4) {
276 imBuffer[i + 0] = (bitmap + k)->B;
277 imBuffer[i + 1] = (bitmap + k)->G;
278 imBuffer[i + 2] = (bitmap + k)->R;
279 imBuffer[i + 3] = (bitmap + k)->A;
280 // bitmap++;
281 k++;
282 if (k == w) {
283 bitmap = bitmap + iwidth;
284 k = 0;
285 }
286 }
287 } else {
288 for (int i = 0; i < h; i++) {
289 unsigned int i_ = (i_min + i) * m_rscale;
290 unsigned int ii_ = i * w;
291 for (int j = 0; j < w; j++) {
292 vpRGBa val = I[i_][(j_min + j) * m_rscale];
293 unsigned int index_ = (ii_ + j) * 4;
294 imBuffer[index_] = val.B;
295 imBuffer[++index_] = val.G;
296 imBuffer[++index_] = val.R;
297 imBuffer[++index_] = val.A;
298 }
299 }
300 }
301
302 // updates the bitmap's pixel data
303 updateBitmapROI(imBuffer, i_min, j_min, w, h);
304
305 // we don't need this buffer anymore
306 delete[] imBuffer;
307}
308
314void vpGDIRenderer::convert(const vpImage<unsigned char> &I, HBITMAP &hBmp)
315{
316 // allocate the buffer
317 unsigned char *imBuffer = new unsigned char[m_rwidth * m_rheight * 4];
318
319 if (m_rscale == 1) {
320 for (unsigned int i = 0, k = 0; i < m_rwidth * m_rheight * 4; i += 4, k++) {
321 imBuffer[i + 0] = I.bitmap[k];
322 imBuffer[i + 1] = I.bitmap[k];
323 imBuffer[i + 2] = I.bitmap[k];
324 imBuffer[i + 3] = vpRGBa::alpha_default;
325 }
326 } else {
327 for (unsigned int i = 0; i < m_rheight; i++) {
328 unsigned int i_ = i * m_rscale;
329 unsigned int ii_ = i * m_rwidth;
330 for (unsigned int j = 0; j < m_rwidth; j++) {
331 unsigned char val = I[i_][j * m_rscale];
332 unsigned int index_ = (ii_ + j) * 4;
333 imBuffer[index_] = val;
334 imBuffer[++index_] = val;
335 imBuffer[++index_] = val;
336 imBuffer[++index_] = vpRGBa::alpha_default;
337 }
338 }
339 }
340
341 // updates the bitmap's pixel data
342 updateBitmap(hBmp, imBuffer, m_rwidth, m_rheight);
343
344 // we don't need this buffer anymore
345 delete[] imBuffer;
346}
347
354void vpGDIRenderer::convertROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
355 unsigned int height)
356{
357 int i_min = (std::max)((int)ceil(iP.get_i() / m_rscale), 0);
358 int j_min = (std::max)((int)ceil(iP.get_j() / m_rscale), 0);
359 int i_max = (std::min)((int)ceil((iP.get_i() + height) / m_rscale), (int)m_rheight);
360 int j_max = (std::min)((int)ceil((iP.get_j() + width) / m_rscale), (int)m_rwidth);
361
362 int h = i_max - i_min;
363 int w = j_max - j_min;
364
365 // allocate the buffer
366 unsigned char *imBuffer = new unsigned char[w * h * 4];
367
368 if (m_rscale == 1) {
369 for (int i = 0; i < h; i++) {
370 unsigned int i_ = i_min + i;
371 unsigned int ii_ = i * w;
372 for (int j = 0; j < w; j++) {
373 unsigned char val = I[i_][j_min + j];
374 unsigned int index_ = (ii_ + j) * 4;
375 imBuffer[index_] = val;
376 imBuffer[++index_] = val;
377 imBuffer[++index_] = val;
378 imBuffer[++index_] = vpRGBa::alpha_default;
379 }
380 }
381 } else {
382 for (int i = 0; i < h; i++) {
383 unsigned int i_ = (i_min + i) * m_rscale;
384 unsigned int ii_ = i * w;
385 for (int j = 0; j < w; j++) {
386 unsigned char val = I[i_][(j_min + j) * m_rscale];
387 unsigned int index_ = (ii_ + j) * 4;
388 imBuffer[index_] = val;
389 imBuffer[++index_] = val;
390 imBuffer[++index_] = val;
391 imBuffer[++index_] = vpRGBa::alpha_default;
392 }
393 }
394 }
395
396 // updates the bitmap's pixel data
397 updateBitmapROI(imBuffer, i_min, j_min, w, h);
398
399 // we don't need this buffer anymore
400 delete[] imBuffer;
401}
402
413bool vpGDIRenderer::updateBitmap(HBITMAP &hBmp, unsigned char *imBuffer, unsigned int w, unsigned int h)
414{
415 // the bitmap may only be accessed by one thread at the same time
416 // that's why we enter critical section
417 EnterCriticalSection(&m_criticalSection);
418
419 // if the existing bitmap object is of the right size
420 if ((m_bmp_width == w) && (m_bmp_height == h) && w != 0 && h != 0) {
421 // just replace the content
422 SetBitmapBits(hBmp, w * h * 4, imBuffer);
423 } else {
424 if (hBmp != NULL) {
425 // delete the old BITMAP
426 DeleteObject(hBmp);
427 }
428 // create a new BITMAP from this buffer
429 if ((hBmp = CreateBitmap(static_cast<int>(w), static_cast<int>(h), 1, 32, (void *)imBuffer)) == NULL)
430 return false;
431
432 m_bmp_width = w;
433 m_bmp_height = h;
434 }
435
436 LeaveCriticalSection(&m_criticalSection);
437 return true;
438}
439
450bool vpGDIRenderer::updateBitmapROI(unsigned char *imBuffer, int i_min, int j_min, int w, int h)
451{
452 HBITMAP htmp = CreateBitmap(w, h, 1, 32, (void *)imBuffer);
453
454 // get the window's DC
455 HDC hDCScreen = GetDC(m_hWnd);
456 HDC hDCMem = CreateCompatibleDC(hDCScreen);
457 HDC hDCMem2 = CreateCompatibleDC(hDCScreen);
458
459 // select this bmp in memory
460 EnterCriticalSection(&m_criticalSection);
461 SelectObject(hDCMem, m_bmp);
462 SelectObject(hDCMem2, htmp);
463
464 BitBlt(hDCMem, j_min, i_min, w, h, hDCMem2, 0, 0, SRCCOPY);
465 LeaveCriticalSection(&m_criticalSection);
466
467 DeleteDC(hDCMem);
468 ReleaseDC(m_hWnd, hDCScreen);
469 DeleteObject(htmp);
470
471 return true;
472}
473
480void vpGDIRenderer::setPixel(const vpImagePoint &iP, const vpColor &color)
481{
482 // get the window's DC
483 HDC hDCScreen = GetDC(m_hWnd);
484 HDC hDCMem = CreateCompatibleDC(hDCScreen);
485
486 // select this bmp in memory
487 EnterCriticalSection(&m_criticalSection);
488 SelectObject(hDCMem, m_bmp);
489
490 if (color.id < vpColor::id_unknown)
491 SetPixel(hDCMem, vpMath::round(iP.get_u() / m_rscale), vpMath::round(iP.get_v() / m_rscale), m_colors[color.id]);
492 else {
493 COLORREF gdicolor = RGB(color.R, color.G, color.B);
494 SetPixel(hDCMem, vpMath::round(iP.get_u() / m_rscale), vpMath::round(iP.get_v() / m_rscale), gdicolor);
495 }
496 // display the result (flush)
497 // BitBlt(hDCScreen, x, y, 1, 1, hDCMem, x, y, SRCCOPY);
498
499 LeaveCriticalSection(&m_criticalSection);
500
501 DeleteDC(hDCMem);
502 ReleaseDC(m_hWnd, hDCScreen);
503}
504
512void vpGDIRenderer::drawLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
513 unsigned int thickness, int style)
514{
515 HDC hDCScreen = NULL, hDCMem = NULL;
516 HPEN hPen = NULL;
517#ifdef GDI_ROBUST
518 double start = vpTime::measureTimeMs();
519 while (vpTime::measureTimeMs() - start < 1000) {
520 hDCScreen = GetDC(m_hWnd);
521 if (!hDCScreen)
522 continue;
523 hDCMem = CreateCompatibleDC(hDCScreen);
524 if (!hDCMem) {
525 ReleaseDC(m_hWnd, hDCScreen);
526 continue;
527 }
528
529 // create the pen
530 if (color.id < vpColor::id_unknown)
531 hPen = CreatePen(style, static_cast<int>(thickness), m_colors[color.id]);
532 else {
533 COLORREF gdicolor = RGB(color.R, color.G, color.B);
534 hPen = CreatePen(style, static_cast<int>(thickness), gdicolor);
535 }
536 if (!hPen) {
537 DeleteDC(hDCMem);
538 ReleaseDC(m_hWnd, hDCScreen);
539 continue;
540 }
541 if (!SetBkMode(hDCMem, TRANSPARENT)) {
542 DeleteObject(hPen);
543 DeleteDC(hDCMem);
544 ReleaseDC(m_hWnd, hDCScreen);
545 continue;
546 }
547
548 // select this bmp in memory
549 EnterCriticalSection(&m_criticalSection);
550
551 if (!SelectObject(hDCMem, m_bmp)) {
552 LeaveCriticalSection(&m_criticalSection);
553 DeleteObject(hPen);
554 DeleteDC(hDCMem);
555 ReleaseDC(m_hWnd, hDCScreen);
556 continue;
557 }
558
559 // select the pen
560 if (!SelectObject(hDCMem, hPen)) {
561 LeaveCriticalSection(&m_criticalSection);
562 DeleteObject(hPen);
563 DeleteDC(hDCMem);
564 ReleaseDC(m_hWnd, hDCScreen);
565 continue;
566 }
567 break;
568 }
569 timelost += (vpTime::measureTimeMs() - start);
570#else
571 // get the window's DC
572 hDCScreen = GetDC(m_hWnd);
573 hDCMem = CreateCompatibleDC(hDCScreen);
574 // create the pen
575 if (color.id < vpColor::id_unknown)
576 hPen = CreatePen(style, static_cast<int>(thickness), m_colors[color.id]);
577 else {
578 COLORREF gdicolor = RGB(color.R, color.G, color.B);
579 hPen = CreatePen(style, static_cast<int>(thickness), gdicolor);
580 }
581 SetBkMode(hDCMem, TRANSPARENT);
582
583 // select this bmp in memory
584 EnterCriticalSection(&m_criticalSection);
585 SelectObject(hDCMem, m_bmp);
586
587 // select the pen
588 SelectObject(hDCMem, hPen);
589#endif
590 // Warning: When thickness > 1 and pen style is PS_DASHDOT, the drawing
591 // displays a solid line That's why in that case we implement the dashdot
592 // line manually drawing multiple small lines
593 if (thickness != 1 && style != PS_SOLID) {
594 vpImagePoint ip1_ = ip1;
595 vpImagePoint ip2_ = ip2;
596
597 double size = 10. * m_rscale;
598 double length = sqrt(vpMath::sqr(ip2_.get_i() - ip1_.get_i()) + vpMath::sqr(ip2_.get_j() - ip1_.get_j()));
599 bool vertical_line = (int)ip2_.get_j() == (int)ip1_.get_j();
600 if (vertical_line) {
601 if (ip2_.get_i() < ip1_.get_i()) {
602 std::swap(ip1_, ip2_);
603 }
604 } else if (ip2_.get_j() < ip1_.get_j()) {
605 std::swap(ip1_, ip2_);
606 }
607
608 double diff_j = vertical_line ? 1 : ip2_.get_j() - ip1_.get_j();
609 double deltaj = size / length * diff_j;
610 double deltai = size / length * (ip2_.get_i() - ip1_.get_i());
611 double slope = (ip2_.get_i() - ip1_.get_i()) / diff_j;
612 double orig = ip1_.get_i() - slope * ip1_.get_j();
613
614 if (vertical_line) {
615 for (unsigned int i = (unsigned int)ip1_.get_i(); i < ip2_.get_i(); i += (unsigned int)(2 * deltai)) {
616 double j = ip1_.get_j();
617
618 // Move to the starting point
619 MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), NULL);
620 // Draw the line
621 LineTo(hDCMem, vpMath::round(j / m_rscale), vpMath::round((i + deltai) / m_rscale));
622 }
623 } else {
624 for (unsigned int j = (unsigned int)ip1_.get_j(); j < ip2_.get_j(); j += (unsigned int)(2 * deltaj)) {
625 double i = slope * j + orig;
626 // Move to the starting point
627 MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), NULL);
628 // Draw the line
629 LineTo(hDCMem, vpMath::round((j + deltaj) / m_rscale), vpMath::round((i + deltai) / m_rscale));
630 }
631 }
632 } else {
633 // move to the starting point
634 MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), NULL);
635 // Draw the line
636 LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
637 }
638
639 LeaveCriticalSection(&m_criticalSection);
640
641 DeleteObject(hPen);
642 DeleteDC(hDCMem);
643 ReleaseDC(m_hWnd, hDCScreen);
644}
645
655void vpGDIRenderer::drawRect(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color,
656 bool fill, unsigned int thickness)
657{
658 if (thickness == 0)
659 thickness = 1;
660 // get the window's DC
661 HDC hDCScreen = GetDC(m_hWnd);
662 HDC hDCMem = CreateCompatibleDC(hDCScreen);
663
664 // create the pen
665 HPEN hPen;
666 COLORREF gdicolor = RGB(0, 0, 0);
667
668 if (color.id < vpColor::id_unknown)
669 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
670 else {
671 gdicolor = RGB(color.R, color.G, color.B);
672 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
673 }
674
675 // create an hollow or solid brush (depends on boolean fill)
676 LOGBRUSH lBrush;
677 if (fill) {
678 lBrush.lbStyle = BS_SOLID;
679 if (color.id < vpColor::id_unknown)
680 lBrush.lbColor = m_colors[color.id];
681 else {
682 lBrush.lbColor = gdicolor;
683 }
684 } else
685 lBrush.lbStyle = BS_HOLLOW;
686 HBRUSH hbrush = CreateBrushIndirect(&lBrush);
687
688 // select this bmp in memory
689 EnterCriticalSection(&m_criticalSection);
690 SelectObject(hDCMem, m_bmp);
691
692 // select the brush
693 SelectObject(hDCMem, hbrush);
694 // select the pen
695 SelectObject(hDCMem, hPen);
696
697 // draw the rectangle
698 Rectangle(hDCMem, vpMath::round(topLeft.get_u() / m_rscale), vpMath::round(topLeft.get_v() / m_rscale),
699 vpMath::round((topLeft.get_u() + width) / m_rscale), vpMath::round((topLeft.get_v() + height) / m_rscale));
700
701 // display the result (flush)
702 // BitBlt(hDCScreen, j, i, width, height, hDCMem, j, i, SRCCOPY);
703
704 LeaveCriticalSection(&m_criticalSection);
705
706 DeleteObject(hbrush);
707 DeleteObject(hPen);
708 DeleteDC(hDCMem);
709 ReleaseDC(m_hWnd, hDCScreen);
710}
711
716void vpGDIRenderer::clear(const vpColor &color)
717{
718 vpImagePoint ip;
719 ip.set_i(0);
720 ip.set_j(0);
721 drawRect(ip, m_rwidth, m_rheight, color, true, 0);
722}
723
732void vpGDIRenderer::drawCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
733 unsigned int thickness)
734{
735
736 // get the window's DC
737 HDC hDCScreen = GetDC(m_hWnd);
738 HDC hDCMem = CreateCompatibleDC(hDCScreen);
739
740 // create the pen
741 HPEN hPen;
742 if (color.id < vpColor::id_unknown)
743 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
744 else {
745 COLORREF gdicolor = RGB(color.R, color.G, color.B);
746 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
747 }
748
749 // create an hollow brush
750 LOGBRUSH lBrush;
751 lBrush.lbStyle = BS_HOLLOW;
752 HBRUSH hbrush = CreateBrushIndirect(&lBrush);
753
754 // computes bounding rectangle
755 int radius_ = static_cast<int>(radius);
756 int x1 = vpMath::round(center.get_u() / m_rscale) - radius_ / m_rscale;
757 int y1 = vpMath::round(center.get_v() / m_rscale) - radius_ / m_rscale;
758 int x2 = vpMath::round(center.get_u() / m_rscale) + radius_ / m_rscale;
759 int y2 = vpMath::round(center.get_v() / m_rscale) + radius_ / m_rscale;
760
761 // select this bmp in memory
762 EnterCriticalSection(&m_criticalSection);
763 SelectObject(hDCMem, m_bmp);
764
765 // select the brush
766 SelectObject(hDCMem, hbrush);
767 // select the pen
768 SelectObject(hDCMem, hPen);
769
770 // draw the circle
771 if (fill == false)
772 Ellipse(hDCMem, x1, y1, x2, y2);
773
774 else {
775 while (x2 - x1 > 0) {
776 x1++;
777 x2--;
778 y1++;
779 y2--;
780 Ellipse(hDCMem, x1, y1, x2, y2);
781 }
782 }
783
784 // display the result (flush)
785 // BitBlt(hDCScreen, x1, y1, x2-x1, y2-y1, hDCMem, x1, y1, SRCCOPY);
786
787 LeaveCriticalSection(&m_criticalSection);
788
789 DeleteObject(hbrush);
790 DeleteObject(hPen);
791 DeleteDC(hDCMem);
792 ReleaseDC(m_hWnd, hDCScreen);
793}
794
801void vpGDIRenderer::drawText(const vpImagePoint &ip, const char *text, const vpColor &color)
802{
803 // get the window's DC
804 HDC hDCScreen = GetDC(m_hWnd);
805 HDC hDCMem = CreateCompatibleDC(hDCScreen);
806
807 // select this bmp in memory
808 EnterCriticalSection(&m_criticalSection);
809 SelectObject(hDCMem, m_bmp);
810
811 // Select the font
812 SelectObject(hDCMem, m_hFont);
813
814 // set the text color
815 if (color.id < vpColor::id_unknown)
816 SetTextColor(hDCMem, m_colors[color.id]);
817 else {
818 COLORREF gdicolor = RGB(color.R, color.G, color.B);
819 SetTextColor(hDCMem, gdicolor);
820 }
821
822 // we don't use the bkColor
823 SetBkMode(hDCMem, TRANSPARENT);
824
825 SIZE size;
826 int length = (int)strlen(text);
827
828 // get the displayed string dimensions
829 GetTextExtentPoint32(hDCMem, text, length, &size);
830
831 // displays the string
832 TextOut(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale), text, length);
833
834 // display the result (flush)
835 // BitBlt(hDCScreen, j, i, size.cx, size.cy, hDCMem, j, i, SRCCOPY);
836
837 LeaveCriticalSection(&m_criticalSection);
838
839 DeleteDC(hDCMem);
840 ReleaseDC(m_hWnd, hDCScreen);
841}
842
850void vpGDIRenderer::drawCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness)
851{
852 /* unsigned */ int half_size = static_cast<int>(size / 2 / m_rscale);
853
854 // if half_size is equal to zero, nothing is displayed with the code
855 // just below. So, if half_size is equal to zero we just draw the
856 // pixel.
857 if (half_size) {
858 // get the window's DC
859 HDC hDCScreen = GetDC(m_hWnd);
860 HDC hDCMem = CreateCompatibleDC(hDCScreen);
861
862 // create the pen
863 HPEN hPen;
864 if (color.id < vpColor::id_unknown)
865 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
866 else {
867 COLORREF gdicolor = RGB(color.R, color.G, color.B);
868 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
869 }
870
871 // select this bmp in memory
872 EnterCriticalSection(&m_criticalSection);
873 SelectObject(hDCMem, m_bmp);
874
875 // select the pen
876 SelectObject(hDCMem, hPen);
877
878 // move to the starting point
879 MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale) - half_size, vpMath::round(ip.get_v() / m_rscale), NULL);
880 // Draw the first line (horizontal)
881 LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale) + half_size, vpMath::round(ip.get_v() / m_rscale));
882
883 // move to the starting point
884 MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) - half_size, NULL);
885 // Draw the second line (vertical)
886 LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) + half_size);
887
888 // display the result (flush)
889 // BitBlt(hDCScreen, j-(size/2), i-(size/2), size, size, hDCMem, j-(size/2), i-(size/2), SRCCOPY);
890
891 LeaveCriticalSection(&m_criticalSection);
892
893 DeleteObject(hPen);
894 DeleteDC(hDCMem);
895 ReleaseDC(m_hWnd, hDCScreen);
896 } else {
897 setPixel(ip, color);
898 }
899}
900
908void vpGDIRenderer::drawArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
909 unsigned int h, unsigned int thickness)
910{
911 double a = ip2.get_i() / m_rscale - ip1.get_i() / m_rscale;
912 double b = ip2.get_j() / m_rscale - ip1.get_j() / m_rscale;
913 double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
914
915 // computes the coordinates of the rectangle to blit later
916 // unsigned int x = (j2 >= j1) ? j1 : j2;
917 // unsigned int y = (i2 >= i1) ? i1 : i2;
918 // unsigned int w = (j2 >= j1) ? j2-j1 : j1-j2;
919 // unsigned int h = (i2 >= i1) ? i2-i1 : i1-i2;
920
921 // get the window's DC
922 HDC hDCScreen = GetDC(m_hWnd);
923 HDC hDCMem = CreateCompatibleDC(hDCScreen);
924
925 // create the pen
926 HPEN hPen;
927 if (color.id < vpColor::id_unknown)
928 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
929 else {
930 COLORREF gdicolor = RGB(color.R, color.G, color.B);
931 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
932 }
933
934 // select this bmp in memory
935 EnterCriticalSection(&m_criticalSection);
936 SelectObject(hDCMem, m_bmp);
937
938 // select the pen
939 SelectObject(hDCMem, hPen);
940
941 if ((a == 0) && (b == 0)) {
942 // DisplayCrossLarge(i1,j1,3,col) ;
943 } else {
944 a /= lg;
945 b /= lg;
946
947 vpImagePoint ip3;
948 ip3.set_i(ip2.get_i() / m_rscale - w * a);
949 ip3.set_j(ip2.get_j() / m_rscale - w * b);
950
951 vpImagePoint ip4;
952
953 // double t = 0 ;
954 // while (t<=_l)
955 {
956 ip4.set_i(ip3.get_i() - b * h);
957 ip4.set_j(ip3.get_j() + a * h);
958
959 if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
960 MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), NULL);
961 LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
962 }
963 // t+=0.1 ;
964 }
965
966 // t = 0 ;
967 // while (t>= -_l)
968 {
969 ip4.set_i(ip3.get_i() + b * h);
970 ip4.set_j(ip3.get_j() - a * h);
971
972 if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
973 MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), NULL);
974 LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
975 }
976
977 // t-=0.1 ;
978 }
979 MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), NULL);
980 LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
981 }
982
983 // display the result (flush)
984 // BitBlt(hDCScreen, x, y, w, h, hDCMem, x, y, SRCCOPY);
985
986 LeaveCriticalSection(&m_criticalSection);
987
988 DeleteObject(hPen);
989 DeleteDC(hDCMem);
990 ReleaseDC(m_hWnd, hDCScreen);
991}
992
997void vpGDIRenderer::getImage(vpImage<vpRGBa> &I)
998{
999 // size of image buffer : m_rwidth*m_rheight*4
1000 unsigned int size = m_rwidth * m_rheight * 4;
1001 unsigned char *imBuffer = new unsigned char[size];
1002
1003 // gets the hbitmap's bitmap
1004 GetBitmapBits(m_bmp, static_cast<LONG>(size), (void *)imBuffer);
1005
1006 // resize the destination image as needed
1007 I.resize(m_rheight, m_rwidth);
1008
1009 // copy the content
1010 for (unsigned int i = 0; i < size; i += 4) {
1011 I.bitmap[i >> 2].R = imBuffer[i + 2];
1012 I.bitmap[i >> 2].G = imBuffer[i + 1];
1013 I.bitmap[i >> 2].B = imBuffer[i + 0];
1014 I.bitmap[i >> 2].A = vpRGBa::alpha_default; // default opacity
1015 }
1016
1017 delete[] imBuffer;
1018}
1019#endif
1020#elif !defined(VISP_BUILD_SHARED_LIBS)
1021// Work around to avoid warning: libvisp_core.a(vpGDIRenderer.cpp.o) has no
1022// symbols
1023void dummy_vpGDIRenderer(){};
1024#endif
Class to define RGB colors available for display functionalities.
Definition vpColor.h:152
static const vpColor white
Definition vpColor.h:206
vpColorIdentifier id
Definition vpColor.h:200
static const vpColor red
Definition vpColor.h:211
static const vpColor darkGray
Definition vpColor.h:209
static const vpColor black
Definition vpColor.h:205
static const vpColor cyan
Definition vpColor.h:220
static const vpColor orange
Definition vpColor.h:221
static const vpColor darkRed
Definition vpColor.h:212
static const vpColor blue
Definition vpColor.h:217
static const vpColor lightGray
Definition vpColor.h:207
static const vpColor lightBlue
Definition vpColor.h:216
static const vpColor darkGreen
Definition vpColor.h:215
static const vpColor darkBlue
Definition vpColor.h:218
static const vpColor purple
Definition vpColor.h:222
static const vpColor lightGreen
Definition vpColor.h:213
static const vpColor yellow
Definition vpColor.h:219
@ id_lightBlue
Definition vpColor.h:178
@ id_yellow
Definition vpColor.h:184
@ id_darkGray
Definition vpColor.h:164
@ id_green
Definition vpColor.h:174
@ id_darkRed
Definition vpColor.h:170
@ id_lightGray
Definition vpColor.h:160
@ id_red
Definition vpColor.h:168
@ id_lightRed
Definition vpColor.h:166
@ id_white
Definition vpColor.h:158
@ id_black
Definition vpColor.h:156
@ id_blue
Definition vpColor.h:180
@ id_darkGreen
Definition vpColor.h:176
@ id_gray
Definition vpColor.h:162
@ id_lightGreen
Definition vpColor.h:172
@ id_purple
Definition vpColor.h:190
@ id_orange
Definition vpColor.h:188
@ id_cyan
Definition vpColor.h:186
@ id_darkBlue
Definition vpColor.h:182
@ id_unknown
Definition vpColor.h:193
static const vpColor lightRed
Definition vpColor.h:210
static const vpColor green
Definition vpColor.h:214
static const vpColor gray
Definition vpColor.h:208
Error that can be emitted by the vpDisplay class and its derivatives.
@ depthNotSupportedError
Color depth not supported.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
void set_j(double jj)
double get_j() const
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
void set_i(double ii)
double get_u() const
double get_i() const
double get_v() const
Definition of the vpImage class member functions.
Definition vpImage.h:135
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:795
Type * bitmap
points toward the bitmap
Definition vpImage.h:139
static double sqr(double x)
Definition vpMath.h:124
static int round(double x)
Definition vpMath.h:323
unsigned char B
Blue component.
Definition vpRGBa.h:140
unsigned char R
Red component.
Definition vpRGBa.h:138
unsigned char G
Green component.
Definition vpRGBa.h:139
@ alpha_default
Definition vpRGBa.h:63
unsigned char A
Additionnal component.
Definition vpRGBa.h:141
VISP_EXPORT double measureTimeMs()