Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpGDIRenderer.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * GDI renderer for windows 32 display
32 */
33
34#include <visp3/core/vpConfig.h>
35#define GDI_ROBUST
36#if (defined(VISP_HAVE_GDI))
37
38#ifndef DOXYGEN_SHOULD_SKIP_THIS
39
40#include <visp3/gui/vpGDIRenderer.h>
41
43
47vpGDIRenderer::vpGDIRenderer() : m_bmp(nullptr), m_bmp_width(0), m_bmp_height(0), timelost(0)
48{
49 // if the screen depth is not 32bpp, throw an exception
50 int bpp = GetDeviceCaps(GetDC(nullptr), BITSPIXEL);
51 if (bpp != 32)
53 "vpGDIRenderer supports only 32bits depth: screen is %dbits depth!", bpp);
54
55 InitializeCriticalSection(&m_criticalSection);
56
57 // initialize GDI the palette
58 vpColor pcolor; // Predefined colors
59
60 pcolor = vpColor::black;
61 m_colors[vpColor::id_black] = RGB(pcolor.R, pcolor.G, pcolor.B);
62 pcolor = vpColor::lightBlue;
63 m_colors[vpColor::id_lightBlue] = RGB(pcolor.R, pcolor.G, pcolor.B);
64 pcolor = vpColor::blue;
65 m_colors[vpColor::id_blue] = RGB(pcolor.R, pcolor.G, pcolor.B);
66 pcolor = vpColor::darkBlue;
67 m_colors[vpColor::id_darkBlue] = RGB(pcolor.R, pcolor.G, pcolor.B);
68 pcolor = vpColor::cyan;
69 m_colors[vpColor::id_cyan] = RGB(pcolor.R, pcolor.G, pcolor.B);
70 pcolor = vpColor::lightGreen;
71 m_colors[vpColor::id_lightGreen] = RGB(pcolor.R, pcolor.G, pcolor.B);
72 pcolor = vpColor::green;
73 m_colors[vpColor::id_green] = RGB(pcolor.R, pcolor.G, pcolor.B);
74 pcolor = vpColor::darkGreen;
75 m_colors[vpColor::id_darkGreen] = RGB(pcolor.R, pcolor.G, pcolor.B);
76 pcolor = vpColor::lightRed;
77 m_colors[vpColor::id_lightRed] = RGB(pcolor.R, pcolor.G, pcolor.B);
78 pcolor = vpColor::red;
79 m_colors[vpColor::id_red] = RGB(pcolor.R, pcolor.G, pcolor.B);
80 pcolor = vpColor::darkRed;
81 m_colors[vpColor::id_darkRed] = RGB(pcolor.R, pcolor.G, pcolor.B);
82 pcolor = vpColor::white;
83 m_colors[vpColor::id_white] = RGB(pcolor.R, pcolor.G, pcolor.B);
84 pcolor = vpColor::lightGray;
85 m_colors[vpColor::id_lightGray] = RGB(pcolor.R, pcolor.G, pcolor.B);
86 pcolor = vpColor::gray;
87 m_colors[vpColor::id_gray] = RGB(pcolor.R, pcolor.G, pcolor.B);
88 pcolor = vpColor::darkGray;
89 m_colors[vpColor::id_darkGray] = RGB(pcolor.R, pcolor.G, pcolor.B);
90 pcolor = vpColor::yellow;
91 m_colors[vpColor::id_yellow] = RGB(pcolor.R, pcolor.G, pcolor.B);
92 pcolor = vpColor::orange;
93 m_colors[vpColor::id_orange] = RGB(pcolor.R, pcolor.G, pcolor.B);
94 pcolor = vpColor::purple;
95 m_colors[vpColor::id_purple] = RGB(pcolor.R, pcolor.G, pcolor.B);
96
97 m_rwidth = 0;
98 m_rheight = 0;
99}
100
104vpGDIRenderer::~vpGDIRenderer()
105{
106 // Deletes the critical section object
107 DeleteCriticalSection(&m_criticalSection);
108 // Deletes the bitmap
109 DeleteObject(m_bmp);
110 // Deletes the font object
111 DeleteObject(m_hFont);
112}
113
120bool vpGDIRenderer::init(HWND hWindow, unsigned int width, unsigned int height)
121{
122 timelost = 0.;
123 m_hWnd = hWindow;
124
125 m_rwidth = width;
126 m_rheight = height;
127
128 // creates the font
129 m_hFont = CreateFont(18, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
130 CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, nullptr);
131 return true;
132}
133
138void vpGDIRenderer::setImg(const vpImage<vpRGBa> &I)
139{
140 // converts the image into a HBITMAP
141 convert(I, m_bmp);
142}
143
151void vpGDIRenderer::setImgROI(const vpImage<vpRGBa> &I, const vpImagePoint &iP, unsigned int width, unsigned int height)
152{
153 // converts the image into a HBITMAP
154 convertROI(I, iP, width, height);
155}
156
161void vpGDIRenderer::setImg(const vpImage<unsigned char> &I)
162{
163 // converts the image into a HBITMAP
164 convert(I, m_bmp);
165}
166
174void vpGDIRenderer::setImgROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
175 unsigned int height)
176{
177 // converts the image into a HBITMAP
178 convertROI(I, iP, width, height);
179}
180
184bool vpGDIRenderer::render()
185{
186 // gets the window's DC
187 PAINTSTRUCT ps;
188 HDC hDCScreen = BeginPaint(m_hWnd, &ps);
189
190 // create a memory DC
191 HDC hDCMem = CreateCompatibleDC(hDCScreen);
192
193 // selects this bmp in memory
194 EnterCriticalSection(&m_criticalSection);
195 SelectObject(hDCMem, m_bmp);
196
197 // blits it on the window's DC
198 BitBlt(hDCScreen, 0, 0, static_cast<int>(m_rwidth), static_cast<int>(m_rheight), hDCMem, 0, 0, SRCCOPY);
199
200 LeaveCriticalSection(&m_criticalSection);
201 // DeleteDC(hDCMem);
202 DeleteObject(hDCMem);
203
204 EndPaint(m_hWnd, &ps);
205
206 return true;
207}
208
214void vpGDIRenderer::convert(const vpImage<vpRGBa> &I, HBITMAP &hBmp)
215{
216 // allocate the buffer
217 unsigned char *imBuffer = new unsigned char[m_rwidth * m_rheight * 4];
218
219 if (m_rscale == 1) {
220 for (unsigned int i = 0, k = 0; i < m_rwidth * m_rheight * 4; i += 4, ++k) {
221 imBuffer[i + 0] = I.bitmap[k].B;
222 imBuffer[i + 1] = I.bitmap[k].G;
223 imBuffer[i + 2] = I.bitmap[k].R;
224 imBuffer[i + 3] = I.bitmap[k].A;
225 }
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
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>(static_cast<int>(ceil(iP.get_i() / m_rscale)), 0);
260 int j_min = std::max<int>(static_cast<int>(ceil(iP.get_j() / m_rscale)), 0);
261 int i_max = std::min<int>(static_cast<int>(ceil((iP.get_i() + height) / m_rscale)), static_cast<int>(m_rheight));
262 int j_max = std::min<int>(static_cast<int>(ceil((iP.get_j() + width) / m_rscale)), static_cast<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 + static_cast<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 }
289 else {
290 for (int i = 0; i < h; ++i) {
291 unsigned int i_ = (i_min + i) * m_rscale;
292 unsigned int ii_ = i * w;
293 for (int j = 0; j < w; ++j) {
294 vpRGBa val = I[i_][(j_min + j) * m_rscale];
295 unsigned int index_ = (ii_ + j) * 4;
296 imBuffer[index_] = val.B;
297 imBuffer[++index_] = val.G;
298 imBuffer[++index_] = val.R;
299 imBuffer[++index_] = val.A;
300 }
301 }
302 }
303
304 // updates the bitmap's pixel data
305 updateBitmapROI(imBuffer, i_min, j_min, w, h);
306
307 // we don't need this buffer anymore
308 delete[] imBuffer;
309}
310
316void vpGDIRenderer::convert(const vpImage<unsigned char> &I, HBITMAP &hBmp)
317{
318 // allocate the buffer
319 unsigned char *imBuffer = new unsigned char[m_rwidth * m_rheight * 4];
320
321 if (m_rscale == 1) {
322 for (unsigned int i = 0, k = 0; i < m_rwidth * m_rheight * 4; i += 4, ++k) {
323 imBuffer[i + 0] = I.bitmap[k];
324 imBuffer[i + 1] = I.bitmap[k];
325 imBuffer[i + 2] = I.bitmap[k];
326 imBuffer[i + 3] = vpRGBa::alpha_default;
327 }
328 }
329 else {
330 for (unsigned int i = 0; i < m_rheight; ++i) {
331 unsigned int i_ = i * m_rscale;
332 unsigned int ii_ = i * m_rwidth;
333 for (unsigned int j = 0; j < m_rwidth; ++j) {
334 unsigned char val = I[i_][j * m_rscale];
335 unsigned int index_ = (ii_ + j) * 4;
336 imBuffer[index_] = val;
337 imBuffer[++index_] = val;
338 imBuffer[++index_] = val;
339 imBuffer[++index_] = vpRGBa::alpha_default;
340 }
341 }
342 }
343
344 // updates the bitmap's pixel data
345 updateBitmap(hBmp, imBuffer, m_rwidth, m_rheight);
346
347 // we don't need this buffer anymore
348 delete[] imBuffer;
349}
350
358void vpGDIRenderer::convertROI(const vpImage<unsigned char> &I, const vpImagePoint &iP, unsigned int width,
359 unsigned int height)
360{
361 int i_min = std::max<int>(static_cast<int>(ceil(iP.get_i() / m_rscale)), 0);
362 int j_min = std::max<int>(static_cast<int>(ceil(iP.get_j() / m_rscale)), 0);
363 int i_max = std::min<int>(static_cast<int>(ceil((iP.get_i() + height) / m_rscale)), static_cast<int>(m_rheight));
364 int j_max = std::min<int>(static_cast<int>(ceil((iP.get_j() + width) / m_rscale)), static_cast<int>(m_rwidth));
365
366 int h = i_max - i_min;
367 int w = j_max - j_min;
368
369 // allocate the buffer
370 unsigned char *imBuffer = new unsigned char[w * h * 4];
371
372 if (m_rscale == 1) {
373 for (int i = 0; i < h; ++i) {
374 unsigned int i_ = i_min + i;
375 unsigned int ii_ = i * w;
376 for (int j = 0; j < w; ++j) {
377 unsigned char val = I[i_][j_min + j];
378 unsigned int index_ = (ii_ + j) * 4;
379 imBuffer[index_] = val;
380 imBuffer[++index_] = val;
381 imBuffer[++index_] = val;
382 imBuffer[++index_] = vpRGBa::alpha_default;
383 }
384 }
385 }
386 else {
387 for (int i = 0; i < h; ++i) {
388 unsigned int i_ = (i_min + i) * m_rscale;
389 unsigned int ii_ = i * w;
390 for (int j = 0; j < w; ++j) {
391 unsigned char val = I[i_][(j_min + j) * m_rscale];
392 unsigned int index_ = (ii_ + j) * 4;
393 imBuffer[index_] = val;
394 imBuffer[++index_] = val;
395 imBuffer[++index_] = val;
396 imBuffer[++index_] = vpRGBa::alpha_default;
397 }
398 }
399 }
400
401 // updates the bitmap's pixel data
402 updateBitmapROI(imBuffer, i_min, j_min, w, h);
403
404 // we don't need this buffer anymore
405 delete[] imBuffer;
406}
407
418bool vpGDIRenderer::updateBitmap(HBITMAP &hBmp, unsigned char *imBuffer, unsigned int w, unsigned int h)
419{
420 // the bitmap may only be accessed by one thread at the same time
421 // that's why we enter critical section
422 EnterCriticalSection(&m_criticalSection);
423
424 // if the existing bitmap object is of the right size
425 if ((m_bmp_width == w) && (m_bmp_height == h) && w != 0 && h != 0) {
426 // just replace the content
427 SetBitmapBits(hBmp, w * h * 4, imBuffer);
428 }
429 else {
430 if (hBmp != nullptr) {
431 // delete the old BITMAP
432 DeleteObject(hBmp);
433 }
434 // create a new BITMAP from this buffer
435 if ((hBmp = CreateBitmap(static_cast<int>(w), static_cast<int>(h), 1, 32, (void *)imBuffer)) == nullptr)
436 return false;
437
438 m_bmp_width = w;
439 m_bmp_height = h;
440 }
441
442 LeaveCriticalSection(&m_criticalSection);
443 return true;
444}
445
457bool vpGDIRenderer::updateBitmapROI(unsigned char *imBuffer, int i_min, int j_min, int w, int h)
458{
459 HBITMAP htmp = CreateBitmap(w, h, 1, 32, (void *)imBuffer);
460
461 // get the window's DC
462 HDC hDCScreen = GetDC(m_hWnd);
463 HDC hDCMem = CreateCompatibleDC(hDCScreen);
464 HDC hDCMem2 = CreateCompatibleDC(hDCScreen);
465
466 // select this bmp in memory
467 EnterCriticalSection(&m_criticalSection);
468 SelectObject(hDCMem, m_bmp);
469 SelectObject(hDCMem2, htmp);
470
471 BitBlt(hDCMem, j_min, i_min, w, h, hDCMem2, 0, 0, SRCCOPY);
472 LeaveCriticalSection(&m_criticalSection);
473
474 DeleteDC(hDCMem);
475 ReleaseDC(m_hWnd, hDCScreen);
476 DeleteObject(htmp);
477
478 return true;
479}
480
487void vpGDIRenderer::setPixel(const vpImagePoint &iP, const vpColor &color)
488{
489 // get the window's DC
490 HDC hDCScreen = GetDC(m_hWnd);
491 HDC hDCMem = CreateCompatibleDC(hDCScreen);
492
493 // select this bmp in memory
494 EnterCriticalSection(&m_criticalSection);
495 SelectObject(hDCMem, m_bmp);
496
497 if (color.id < vpColor::id_unknown)
498 SetPixel(hDCMem, vpMath::round(iP.get_u() / m_rscale), vpMath::round(iP.get_v() / m_rscale), m_colors[color.id]);
499 else {
500 COLORREF gdicolor = RGB(color.R, color.G, color.B);
501 SetPixel(hDCMem, vpMath::round(iP.get_u() / m_rscale), vpMath::round(iP.get_v() / m_rscale), gdicolor);
502 }
503 // display the result (flush)
504 // BitBlt(hDCScreen, x, y, 1, 1, hDCMem, x, y, SRCCOPY);
505
506 LeaveCriticalSection(&m_criticalSection);
507
508 DeleteDC(hDCMem);
509 ReleaseDC(m_hWnd, hDCScreen);
510}
511
520void vpGDIRenderer::drawLine(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color,
521 unsigned int thickness, int style)
522{
523 HDC hDCScreen = nullptr, hDCMem = nullptr;
524 HPEN hPen = nullptr;
525#ifdef GDI_ROBUST
526 double start = vpTime::measureTimeMs();
527 while (vpTime::measureTimeMs() - start < 1000) {
528 hDCScreen = GetDC(m_hWnd);
529
530 if (!hDCScreen)
531 continue;
532 hDCMem = CreateCompatibleDC(hDCScreen);
533 if (!hDCMem) {
534 ReleaseDC(m_hWnd, hDCScreen);
535 continue;
536 }
537
538 // create the pen
539 if (color.id < vpColor::id_unknown)
540 hPen = CreatePen(style, static_cast<int>(thickness), m_colors[color.id]);
541 else {
542 COLORREF gdicolor = RGB(color.R, color.G, color.B);
543 hPen = CreatePen(style, static_cast<int>(thickness), gdicolor);
544 }
545 if (!hPen) {
546 DeleteDC(hDCMem);
547 ReleaseDC(m_hWnd, hDCScreen);
548 continue;
549 }
550 if (!SetBkMode(hDCMem, TRANSPARENT)) {
551 DeleteObject(hPen);
552 DeleteDC(hDCMem);
553 ReleaseDC(m_hWnd, hDCScreen);
554 continue;
555 }
556
557 // select this bmp in memory
558 EnterCriticalSection(&m_criticalSection);
559
560 if (!SelectObject(hDCMem, m_bmp)) {
561 LeaveCriticalSection(&m_criticalSection);
562 DeleteObject(hPen);
563 DeleteDC(hDCMem);
564 ReleaseDC(m_hWnd, hDCScreen);
565 continue;
566 }
567
568 // select the pen
569 if (!SelectObject(hDCMem, hPen)) {
570 LeaveCriticalSection(&m_criticalSection);
571 DeleteObject(hPen);
572 DeleteDC(hDCMem);
573 ReleaseDC(m_hWnd, hDCScreen);
574 continue;
575 }
576 break;
577 }
578 timelost += (vpTime::measureTimeMs() - start);
579#else
580 // get the window's DC
581 hDCScreen = GetDC(m_hWnd);
582 hDCMem = CreateCompatibleDC(hDCScreen);
583 // create the pen
584 if (color.id < vpColor::id_unknown)
585 hPen = CreatePen(style, static_cast<int>(thickness), m_colors[color.id]);
586 else {
587 COLORREF gdicolor = RGB(color.R, color.G, color.B);
588 hPen = CreatePen(style, static_cast<int>(thickness), gdicolor);
589 }
590 SetBkMode(hDCMem, TRANSPARENT);
591
592 // select this bmp in memory
593 EnterCriticalSection(&m_criticalSection);
594 SelectObject(hDCMem, m_bmp);
595
596 // select the pen
597 SelectObject(hDCMem, hPen);
598#endif
599 // Warning: When thickness > 1 and pen style is PS_DASHDOT, the drawing
600 // displays a solid line That's why in that case we implement the dashdot
601 // line manually drawing multiple small lines
602 if (thickness != 1 && style != PS_SOLID) {
603 vpImagePoint ip1_ = ip1;
604 vpImagePoint ip2_ = ip2;
605
606 double size = 10. * m_rscale;
607 double length = sqrt(vpMath::sqr(ip2_.get_i() - ip1_.get_i()) + vpMath::sqr(ip2_.get_j() - ip1_.get_j()));
608 bool vertical_line = static_cast<int>(ip2_.get_j()) == static_cast<int>(ip1_.get_j());
609 if (vertical_line) {
610 if (ip2_.get_i() < ip1_.get_i()) {
611 std::swap(ip1_, ip2_);
612 }
613 }
614 else if (ip2_.get_j() < ip1_.get_j()) {
615 std::swap(ip1_, ip2_);
616 }
617
618 double diff_j = vertical_line ? 1 : ip2_.get_j() - ip1_.get_j();
619 double deltaj = size / length * diff_j;
620 double deltai = size / length * (ip2_.get_i() - ip1_.get_i());
621 double slope = (ip2_.get_i() - ip1_.get_i()) / diff_j;
622 double orig = ip1_.get_i() - slope * ip1_.get_j();
623
624 if (vertical_line) {
625 for (unsigned int i = static_cast<unsigned int>(ip1_.get_i()); i < ip2_.get_i(); i += static_cast<unsigned int>(2 * deltai)) {
626 double j = ip1_.get_j();
627
628 // Move to the starting point
629 MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), nullptr);
630 // Draw the line
631 LineTo(hDCMem, vpMath::round(j / m_rscale), vpMath::round((i + deltai) / m_rscale));
632 }
633 }
634 else {
635 for (unsigned int j = static_cast<unsigned int>(ip1_.get_j()); j < ip2_.get_j(); j += static_cast<unsigned int>(2 * deltaj)) {
636 double i = slope * j + orig;
637 // Move to the starting point
638 MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), nullptr);
639 // Draw the line
640 LineTo(hDCMem, vpMath::round((j + deltaj) / m_rscale), vpMath::round((i + deltai) / m_rscale));
641 }
642 }
643 }
644 else {
645 // move to the starting point
646 MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), nullptr);
647 // Draw the line
648 LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
649 }
650
651 LeaveCriticalSection(&m_criticalSection);
652
653 DeleteObject(hPen);
654 DeleteDC(hDCMem);
655 ReleaseDC(m_hWnd, hDCScreen);
656}
657
667void vpGDIRenderer::drawRect(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color,
668 bool fill, unsigned int thickness)
669{
670 if (thickness == 0)
671 thickness = 1;
672 // get the window's DC
673 HDC hDCScreen = GetDC(m_hWnd);
674 HDC hDCMem = CreateCompatibleDC(hDCScreen);
675
676 // create the pen
677 HPEN hPen;
678 COLORREF gdicolor = RGB(0, 0, 0);
679
680 if (color.id < vpColor::id_unknown)
681 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
682 else {
683 gdicolor = RGB(color.R, color.G, color.B);
684 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
685 }
686
687 // create an hollow or solid brush (depends on boolean fill)
688 LOGBRUSH lBrush;
689 if (fill) {
690 lBrush.lbStyle = BS_SOLID;
691 if (color.id < vpColor::id_unknown)
692 lBrush.lbColor = m_colors[color.id];
693 else {
694 lBrush.lbColor = gdicolor;
695 }
696 }
697 else
698 lBrush.lbStyle = BS_HOLLOW;
699 HBRUSH hbrush = CreateBrushIndirect(&lBrush);
700
701 // select this bmp in memory
702 EnterCriticalSection(&m_criticalSection);
703 SelectObject(hDCMem, m_bmp);
704
705 // select the brush
706 SelectObject(hDCMem, hbrush);
707 // select the pen
708 SelectObject(hDCMem, hPen);
709
710 // draw the rectangle
711 Rectangle(hDCMem, vpMath::round(topLeft.get_u() / m_rscale), vpMath::round(topLeft.get_v() / m_rscale),
712 vpMath::round((topLeft.get_u() + width) / m_rscale), vpMath::round((topLeft.get_v() + height) / m_rscale));
713
714 // display the result (flush)
715 // BitBlt(hDCScreen, j, i, width, height, hDCMem, j, i, SRCCOPY);
716
717 LeaveCriticalSection(&m_criticalSection);
718
719 DeleteObject(hbrush);
720 DeleteObject(hPen);
721 DeleteDC(hDCMem);
722 ReleaseDC(m_hWnd, hDCScreen);
723}
724
729void vpGDIRenderer::clear(const vpColor &color)
730{
731 vpImagePoint ip;
732 ip.set_i(0);
733 ip.set_j(0);
734 drawRect(ip, m_rwidth, m_rheight, color, true, 0);
735}
736
745void vpGDIRenderer::drawCircle(const vpImagePoint &center, unsigned int radius, const vpColor &color, bool fill,
746 unsigned int thickness)
747{
748
749 // get the window's DC
750 HDC hDCScreen = GetDC(m_hWnd);
751 HDC hDCMem = CreateCompatibleDC(hDCScreen);
752
753 // create the pen
754 HPEN hPen;
755 if (color.id < vpColor::id_unknown)
756 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
757 else {
758 COLORREF gdicolor = RGB(color.R, color.G, color.B);
759 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
760 }
761
762 // create an hollow brush
763 LOGBRUSH lBrush;
764 lBrush.lbStyle = BS_HOLLOW;
765 HBRUSH hbrush = CreateBrushIndirect(&lBrush);
766
767 // computes bounding rectangle
768 int radius_ = static_cast<int>(radius);
769 int x1 = vpMath::round(center.get_u() / m_rscale) - radius_ / m_rscale;
770 int y1 = vpMath::round(center.get_v() / m_rscale) - radius_ / m_rscale;
771 int x2 = vpMath::round(center.get_u() / m_rscale) + radius_ / m_rscale;
772 int y2 = vpMath::round(center.get_v() / m_rscale) + radius_ / m_rscale;
773
774 // select this bmp in memory
775 EnterCriticalSection(&m_criticalSection);
776 SelectObject(hDCMem, m_bmp);
777
778 // select the brush
779 SelectObject(hDCMem, hbrush);
780 // select the pen
781 SelectObject(hDCMem, hPen);
782
783 // draw the circle
784 if (fill == false)
785 Ellipse(hDCMem, x1, y1, x2, y2);
786
787 else {
788 while (x2 - x1 > 0) {
789 x1++;
790 x2--;
791 y1++;
792 y2--;
793 Ellipse(hDCMem, x1, y1, x2, y2);
794 }
795 }
796
797 // display the result (flush)
798 // BitBlt(hDCScreen, x1, y1, x2-x1, y2-y1, hDCMem, x1, y1, SRCCOPY);
799
800 LeaveCriticalSection(&m_criticalSection);
801
802 DeleteObject(hbrush);
803 DeleteObject(hPen);
804 DeleteDC(hDCMem);
805 ReleaseDC(m_hWnd, hDCScreen);
806}
807
814void vpGDIRenderer::drawText(const vpImagePoint &ip, const char *text, const vpColor &color)
815{
816 // get the window's DC
817 HDC hDCScreen = GetDC(m_hWnd);
818 HDC hDCMem = CreateCompatibleDC(hDCScreen);
819
820 // select this bmp in memory
821 EnterCriticalSection(&m_criticalSection);
822 SelectObject(hDCMem, m_bmp);
823
824 // Select the font
825 SelectObject(hDCMem, m_hFont);
826
827 // set the text color
828 if (color.id < vpColor::id_unknown)
829 SetTextColor(hDCMem, m_colors[color.id]);
830 else {
831 COLORREF gdicolor = RGB(color.R, color.G, color.B);
832 SetTextColor(hDCMem, gdicolor);
833 }
834
835 // we don't use the bkColor
836 SetBkMode(hDCMem, TRANSPARENT);
837
838 SIZE size;
839 int length = static_cast<int>(strlen(text));
840
841 // get the displayed string dimensions
842 GetTextExtentPoint32(hDCMem, text, length, &size);
843
844 // displays the string
845 TextOut(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale), text, length);
846
847 // display the result (flush)
848 // BitBlt(hDCScreen, j, i, size.cx, size.cy, hDCMem, j, i, SRCCOPY);
849
850 LeaveCriticalSection(&m_criticalSection);
851
852 DeleteDC(hDCMem);
853 ReleaseDC(m_hWnd, hDCScreen);
854}
855
863void vpGDIRenderer::drawCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness)
864{
865 /* unsigned */ int half_size = static_cast<int>(size / 2 / m_rscale);
866
867 // if half_size is equal to zero, nothing is displayed with the code
868 // just below. So, if half_size is equal to zero we just draw the
869 // pixel.
870 if (half_size) {
871 // get the window's DC
872 HDC hDCScreen = GetDC(m_hWnd);
873 HDC hDCMem = CreateCompatibleDC(hDCScreen);
874
875 // create the pen
876 HPEN hPen;
877 if (color.id < vpColor::id_unknown)
878 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
879 else {
880 COLORREF gdicolor = RGB(color.R, color.G, color.B);
881 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
882 }
883
884 // select this bmp in memory
885 EnterCriticalSection(&m_criticalSection);
886 SelectObject(hDCMem, m_bmp);
887
888 // select the pen
889 SelectObject(hDCMem, hPen);
890
891 // move to the starting point
892 MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale) - half_size, vpMath::round(ip.get_v() / m_rscale), nullptr);
893 // Draw the first line (horizontal)
894 LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale) + half_size, vpMath::round(ip.get_v() / m_rscale));
895
896 // move to the starting point
897 MoveToEx(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) - half_size, nullptr);
898 // Draw the second line (vertical)
899 LineTo(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale) + half_size);
900
901 // display the result (flush)
902 // BitBlt(hDCScreen, j-(size/2), i-(size/2), size, size, hDCMem, j-(size/2), i-(size/2), SRCCOPY);
903
904 LeaveCriticalSection(&m_criticalSection);
905
906 DeleteObject(hPen);
907 DeleteDC(hDCMem);
908 ReleaseDC(m_hWnd, hDCScreen);
909 }
910 else {
911 setPixel(ip, color);
912 }
913}
914
924void vpGDIRenderer::drawArrow(const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int w,
925 unsigned int h, unsigned int thickness)
926{
927 double a = ip2.get_i() / m_rscale - ip1.get_i() / m_rscale;
928 double b = ip2.get_j() / m_rscale - ip1.get_j() / m_rscale;
929 double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
930
931 // computes the coordinates of the rectangle to blit later
932 // unsigned int x = (j2 >= j1) ? j1 : j2;
933 // unsigned int y = (i2 >= i1) ? i1 : i2;
934 // unsigned int w = (j2 >= j1) ? j2-j1 : j1-j2;
935 // unsigned int h = (i2 >= i1) ? i2-i1 : i1-i2;
936
937 // get the window's DC
938 HDC hDCScreen = GetDC(m_hWnd);
939 HDC hDCMem = CreateCompatibleDC(hDCScreen);
940
941 // create the pen
942 HPEN hPen;
943 if (color.id < vpColor::id_unknown)
944 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), m_colors[color.id]);
945 else {
946 COLORREF gdicolor = RGB(color.R, color.G, color.B);
947 hPen = CreatePen(PS_SOLID, static_cast<int>(thickness), gdicolor);
948 }
949
950 // select this bmp in memory
951 EnterCriticalSection(&m_criticalSection);
952 SelectObject(hDCMem, m_bmp);
953
954 // select the pen
955 SelectObject(hDCMem, hPen);
956
957 if ((a == 0) && (b == 0)) {
958 // DisplayCrossLarge(i1,j1,3,col) ;
959 }
960 else {
961 a /= lg;
962 b /= lg;
963
964 vpImagePoint ip3;
965 ip3.set_i(ip2.get_i() / m_rscale - w * a);
966 ip3.set_j(ip2.get_j() / m_rscale - w * b);
967
968 vpImagePoint ip4;
969
970 // double t = 0 ;
971 // while (t<=_l)
972 {
973 ip4.set_i(ip3.get_i() - b * h);
974 ip4.set_j(ip3.get_j() + a * h);
975
976 if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
977 MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), nullptr);
978 LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
979 }
980 // t+=0.1 ;
981 }
982
983 // t = 0 ;
984 // while (t>= -_l)
985 {
986 ip4.set_i(ip3.get_i() + b * h);
987 ip4.set_j(ip3.get_j() - a * h);
988
989 if (lg > 2 * vpImagePoint::distance(ip2 / m_rscale, ip4)) {
990 MoveToEx(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale), nullptr);
991 LineTo(hDCMem, vpMath::round(ip4.get_u()), vpMath::round(ip4.get_v()));
992 }
993
994 // t-=0.1 ;
995 }
996 MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), nullptr);
997 LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
998 }
999
1000 // display the result (flush)
1001 // BitBlt(hDCScreen, x, y, w, h, hDCMem, x, y, SRCCOPY);
1002
1003 LeaveCriticalSection(&m_criticalSection);
1004
1005 DeleteObject(hPen);
1006 DeleteDC(hDCMem);
1007 ReleaseDC(m_hWnd, hDCScreen);
1008}
1009
1014void vpGDIRenderer::getImage(vpImage<vpRGBa> &I)
1015{
1016 // size of image buffer : m_rwidth*m_rheight*4
1017 unsigned int size = m_rwidth * m_rheight * 4;
1018 unsigned char *imBuffer = new unsigned char[size];
1019
1020 // gets the hbitmap's bitmap
1021 GetBitmapBits(m_bmp, static_cast<LONG>(size), (void *)imBuffer);
1022
1023 // resize the destination image as needed
1024 I.resize(m_rheight, m_rwidth);
1025
1026 // copy the content
1027 for (unsigned int i = 0; i < size; i += 4) {
1028 I.bitmap[i >> 2].R = imBuffer[i + 2];
1029 I.bitmap[i >> 2].G = imBuffer[i + 1];
1030 I.bitmap[i >> 2].B = imBuffer[i + 0];
1031 I.bitmap[i >> 2].A = vpRGBa::alpha_default; // default opacity
1032 }
1033
1034 delete[] imBuffer;
1035}
1036
1037END_VISP_NAMESPACE
1038#endif
1039#elif !defined(VISP_BUILD_SHARED_LIBS)
1040// Work around to avoid warning: libvisp_gui.a(vpGDIRenderer.cpp.o) has no symbols
1041void dummy_vpGDIRenderer() { }
1042#endif
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
static const vpColor white
Definition vpColor.h:193
static const vpColor red
Definition vpColor.h:198
static const vpColor darkGray
Definition vpColor.h:196
static const vpColor cyan
Definition vpColor.h:207
static const vpColor orange
Definition vpColor.h:208
static const vpColor darkRed
Definition vpColor.h:199
static const vpColor blue
Definition vpColor.h:204
static const vpColor lightGray
Definition vpColor.h:194
static const vpColor lightBlue
Definition vpColor.h:203
static const vpColor darkGreen
Definition vpColor.h:202
static const vpColor darkBlue
Definition vpColor.h:205
static const vpColor purple
Definition vpColor.h:209
static const vpColor lightGreen
Definition vpColor.h:200
static const vpColor yellow
Definition vpColor.h:206
@ id_lightBlue
Definition vpColor.h:173
@ id_yellow
Definition vpColor.h:176
@ id_darkGray
Definition vpColor.h:166
@ id_green
Definition vpColor.h:171
@ id_darkRed
Definition vpColor.h:169
@ id_lightGray
Definition vpColor.h:164
@ id_red
Definition vpColor.h:168
@ id_lightRed
Definition vpColor.h:167
@ id_white
Definition vpColor.h:163
@ id_black
Definition vpColor.h:162
@ id_blue
Definition vpColor.h:174
@ id_darkGreen
Definition vpColor.h:172
@ id_gray
Definition vpColor.h:165
@ id_lightGreen
Definition vpColor.h:170
@ id_purple
Definition vpColor.h:179
@ id_orange
Definition vpColor.h:178
@ id_cyan
Definition vpColor.h:177
@ id_darkBlue
Definition vpColor.h:175
@ id_unknown
Definition vpColor.h:181
static const vpColor lightRed
Definition vpColor.h:197
static const vpColor black
Definition vpColor.h:192
static const vpColor green
Definition vpColor.h:201
static const vpColor gray
Definition vpColor.h:195
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:131
static double sqr(double x)
Definition vpMath.h:203
static int round(double x)
Definition vpMath.h:413
unsigned char B
Blue component.
Definition vpRGBa.h:327
unsigned char R
Red component.
Definition vpRGBa.h:325
unsigned char G
Green component.
Definition vpRGBa.h:326
@ alpha_default
Definition vpRGBa.h:76
unsigned char A
Additional component.
Definition vpRGBa.h:328
VISP_EXPORT double measureTimeMs()