Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
vpD3DRenderer.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
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 http://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  * D3D renderer for windows 32 display
32  *
33  * Authors:
34  * Bruno Renier
35  *
36  *****************************************************************************/
37 #ifndef DOXYGEN_SHOULD_SKIP_THIS
38 
39 #include <algorithm>
40 
41 #include <visp3/core/vpConfig.h>
42 #if ( defined(_WIN32) & defined(VISP_HAVE_D3D9) )
43 
44 #include <visp3/gui/vpD3DRenderer.h>
45 #include <visp3/core/vpColor.h>
46 #include <visp3/core/vpMath.h>
47 
48 /*
49  Be careful, when using :
50 
51  pd3dText->LockRect(0, &d3dLRect, &r, 0)
52  ...
53  pd3dText->UnlockRect(0, &d3dLRect, &r, 0)
54 
55  to write directly to the texture's surface,
56  the pointer returned in d3dLRect points to
57  the beginning of the locked suface and not
58  to the beginning of the texture's surface.
59  That's why setBufferPixel and other accesses
60  to this buffer are done in the locked surface
61  coordinates system.
62 
63  Moreover, when directly writing to a texture's surface,
64  you musn't forget to take the pitch of this texture
65  into account (see Direct3D documentation).
66 
67 */
68 
73 vpD3DRenderer::vpD3DRenderer()
74 {
75  pD3D=NULL;
76  pd3dDevice=NULL;
77  pd3dText=NULL;
78  pd3dVideoText=NULL;
79 
80  //D3D palette
81  vpColor pcolor; // Predefined colors
82  pcolor = vpColor::black;
83  colors[vpColor::id_black] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
84  pcolor = vpColor::lightBlue;
85  colors[vpColor::id_lightBlue] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
86  pcolor = vpColor::blue;
87  colors[vpColor::id_blue] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
88  pcolor = vpColor::darkBlue;
89  colors[vpColor::id_darkBlue] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
90  pcolor = vpColor::cyan;
91  colors[vpColor::id_cyan] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
92  pcolor = vpColor::lightGreen;
93  colors[vpColor::id_lightGreen] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
94  pcolor = vpColor::green;
95  colors[vpColor::id_green] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
96  pcolor = vpColor::darkGreen;
97  colors[vpColor::id_darkGreen] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
98  pcolor = vpColor::lightRed;
99  colors[vpColor::id_lightRed] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
100  pcolor = vpColor::red;
101  colors[vpColor::id_red] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
102  pcolor = vpColor::darkRed;
103  colors[vpColor::id_darkRed] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
104  pcolor = vpColor::white;
105  colors[vpColor::id_white] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
106  pcolor = vpColor::lightGray;
107  colors[vpColor::id_lightGray] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
108  pcolor = vpColor::gray;
109  colors[vpColor::id_gray] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
110  pcolor = vpColor::darkGray;
111  colors[vpColor::id_darkGray] = D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
112  pcolor = vpColor::yellow;
113  colors[vpColor::id_yellow]= D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
114  pcolor = vpColor::orange;
115  colors[vpColor::id_orange]= D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
116  pcolor = vpColor::purple;
117  colors[vpColor::id_purple]= D3DCOLOR_ARGB(0xFF,pcolor.R, pcolor.G, pcolor.B);
118 
119  //initialize the GDI palette
120  pcolor = vpColor::black;
121  colorsGDI[vpColor::id_black] = RGB(pcolor.R, pcolor.G, pcolor.B);
122  pcolor = vpColor::lightBlue;
123  colorsGDI[vpColor::id_lightBlue] = RGB(pcolor.R, pcolor.G, pcolor.B);
124  pcolor = vpColor::blue;
125  colorsGDI[vpColor::id_blue] = RGB(pcolor.R, pcolor.G, pcolor.B);
126  pcolor = vpColor::darkBlue;
127  colorsGDI[vpColor::id_darkBlue] = RGB(pcolor.R, pcolor.G, pcolor.B);
128  pcolor = vpColor::cyan;
129  colorsGDI[vpColor::id_cyan] = RGB(pcolor.R, pcolor.G, pcolor.B);
130  pcolor = vpColor::lightGreen;
131  colorsGDI[vpColor::id_lightGreen] = RGB(pcolor.R, pcolor.G, pcolor.B);
132  pcolor = vpColor::green;
133  colorsGDI[vpColor::id_green] = RGB(pcolor.R, pcolor.G, pcolor.B);
134  pcolor = vpColor::darkGreen;
135  colorsGDI[vpColor::id_darkGreen] = RGB(pcolor.R, pcolor.G, pcolor.B);
136  pcolor = vpColor::lightRed;
137  colorsGDI[vpColor::id_lightRed] = RGB(pcolor.R, pcolor.G, pcolor.B);
138  pcolor = vpColor::red;
139  colorsGDI[vpColor::id_red] = RGB(pcolor.R, pcolor.G, pcolor.B);
140  pcolor = vpColor::darkRed;
141  colorsGDI[vpColor::id_darkRed] = RGB(pcolor.R, pcolor.G, pcolor.B);
142  pcolor = vpColor::white;
143  colorsGDI[vpColor::id_white] = RGB(pcolor.R, pcolor.G, pcolor.B);
144  pcolor = vpColor::lightGray;
145  colorsGDI[vpColor::id_lightGray] = RGB(pcolor.R, pcolor.G, pcolor.B);
146  pcolor = vpColor::gray;
147  colorsGDI[vpColor::id_gray] = RGB(pcolor.R, pcolor.G, pcolor.B);
148  pcolor = vpColor::darkGray;
149  colorsGDI[vpColor::id_darkGray] = RGB(pcolor.R, pcolor.G, pcolor.B);
150  pcolor = vpColor::yellow;
151  colorsGDI[vpColor::id_yellow]= RGB(pcolor.R, pcolor.G, pcolor.B);
152  pcolor = vpColor::orange;
153  colorsGDI[vpColor::id_orange]= RGB(pcolor.R, pcolor.G, pcolor.B);
154  pcolor = vpColor::purple;
155  colorsGDI[vpColor::id_purple]= RGB(pcolor.R, pcolor.G, pcolor.B);
156 
157  //Creates a logical font
158  hFont = CreateFont(18, 0, 0, 0, FW_NORMAL, false, false, false,
159  DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
160  CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
161  DEFAULT_PITCH | FF_DONTCARE, NULL);
162 }
163 
168 vpD3DRenderer::~vpD3DRenderer()
169 {
170  DeleteObject(hFont);
171 
172  if(pd3dDevice != NULL)
173  pd3dDevice->Release();
174  if(pD3D != NULL)
175  pD3D->Release();
176  if(pd3dText != NULL)
177  pd3dText->Release();
178  if(pd3dVideoText != NULL)
179  pd3dVideoText->Release();
180 }
181 
187 unsigned int vpD3DRenderer::supPowerOf2(unsigned int n)
188 {
189  unsigned int i=0;
190  while(n>1)
191  {
192  n>>=1;
193  i++;
194  }
195  return static_cast<unsigned int>(1<<(i+1));
196 }
197 
205 bool vpD3DRenderer::init(HWND hwnd, unsigned int width, unsigned int height)
206 {
207  //simple stuff
208  m_rwidth = width;
209  m_rheight = height;
210  hWnd = hwnd;
211 
212  //D3D initialize
213  if(NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
215  "Can't initialize D3D!");
216 
217  D3DDISPLAYMODE d3ddm;
218  if(FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))
220  "Can't get the adapter's display mode!");
221 
222 
223  D3DPRESENT_PARAMETERS d3dpp;
224  ZeroMemory(&d3dpp, sizeof(d3dpp));
225  d3dpp.BackBufferCount=1;
226  d3dpp.Windowed = TRUE;
227  d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
228  d3dpp.BackBufferFormat = d3ddm.Format;
229 
230  //creates a d3d device
231  if( FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL, hWnd,
232  D3DCREATE_SOFTWARE_VERTEXPROCESSING |
233  D3DCREATE_MULTITHREADED,
234  &d3dpp, &pd3dDevice )))
236  "Can't create the Direct3D device!");
237 
238 
239  //disables scene lightning
240  pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
241 
242 
243  //inits the direct3D view (for 2D rendering)
244  initView((float)m_rwidth,(float)m_rheight);
245 
246 
247  //computes texture size (needs to be a power-of-2 large square)
248  textWidth = supPowerOf2( (m_rwidth>m_rheight) ? m_rwidth : m_rheight );
249 
250  //creates the system memory texture (the one we will directly modify)
251  //unfortunately, needs to be X8R8G8B8 in order to be able to use GDI drawing
252  //functions
253  if( D3DXCreateTexture(pd3dDevice, textWidth, textWidth, D3DX_DEFAULT, 0,
254  D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM , &pd3dText)
255  != D3D_OK)
256  {
258  "Can't create memory texture!");
259  }
260 
261  //creates the video memory texture (the one we will display) -
262  if( D3DXCreateTexture(pd3dDevice, textWidth, textWidth, D3DX_DEFAULT,
263  D3DUSAGE_DYNAMIC ,
264  D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &pd3dVideoText)
265  != D3D_OK)
266  {
268  "Can't create video texture!");
269  }
270 
271  //creates the sprite used to render the texture
272  if(D3DXCreateSprite(pd3dDevice, &pSprite) != S_OK)
274  "Can't create the texture's sprite!");
275 
276 
277 
278  return true;
279 }
280 
281 
282 
283 
289 void vpD3DRenderer::initView(float WindowWidth, float WindowHeight)
290 {
291  D3DXMATRIX Ortho2D;
292  D3DXMATRIX Identity;
293 
294  D3DXMatrixOrthoLH(&Ortho2D, WindowWidth, WindowHeight, 0.0f, 1.0f);
295  D3DXMatrixIdentity(&Identity);
296 
297  if( pd3dDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D) != D3D_OK
298  || pd3dDevice->SetTransform(D3DTS_WORLD, &Identity) != D3D_OK
299  || pd3dDevice->SetTransform(D3DTS_VIEW, &Identity) != D3D_OK)
301  "Can't set the view!");
302 }
303 
304 
311 void vpD3DRenderer::convert(const vpImage<vpRGBa>& I, unsigned char * imBuffer, unsigned int pitch)
312 {
313  if (m_rscale == 1) {
314  for (unsigned int i = 0; i < m_rheight; i++) {
315  unsigned int ii_ = i*pitch;
316  for (unsigned int j = 0; j < m_rwidth; j++) {
317  vpRGBa val = I[i][j];
318  unsigned int index_ = ii_ + j * 4;
319  imBuffer[index_] = val.B;
320  imBuffer[++index_] = val.G;
321  imBuffer[++index_] = val.R;
322  imBuffer[++index_] = val.A;
323  }
324  }
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*pitch;
330  for (unsigned int j = 0; j < m_rwidth; j++) {
331  vpRGBa val = I[i_][j*m_rscale];
332  unsigned int index_ = ii_ + j * 4;
333  imBuffer[index_] = val.B;
334  imBuffer[++index_] = val.G;
335  imBuffer[++index_] = val.R;
336  imBuffer[++index_] = val.A;
337  }
338  }
339  }
340 }
341 
348 void vpD3DRenderer::convert(const vpImage<unsigned char>& I, unsigned char * imBuffer, unsigned int pitch)
349 {
350  if (m_rscale == 1) {
351  for (unsigned int i = 0; i < m_rheight; i++) {
352  unsigned int ii_ = i*pitch;
353  for (unsigned int j = 0; j < m_rwidth; j++) {
354  unsigned char val = I[i][j];
355  unsigned int index_ = ii_ + j * 4;
356  imBuffer[index_] = val;
357  imBuffer[++index_] = val;
358  imBuffer[++index_] = val;
359  imBuffer[++index_] = vpRGBa::alpha_default;
360  }
361  }
362  }
363  else {
364  for (unsigned int i = 0; i < m_rheight; i++) {
365  unsigned int i_ = i*m_rscale;
366  unsigned int ii_ = i*pitch;
367  for (unsigned int j = 0; j < m_rwidth; j++) {
368  unsigned char val = I[i_][j*m_rscale];
369  unsigned int index_ = ii_ + j * 4;
370  imBuffer[index_] = val;
371  imBuffer[++index_] = val;
372  imBuffer[++index_] = val;
373  imBuffer[++index_] = vpRGBa::alpha_default;
374  }
375  }
376  }
377 }
378 
387 void vpD3DRenderer::convertROI(const vpImage<unsigned char>& I, unsigned char * imBuffer, unsigned int pitch,
388  int i_min, int j_min, int i_max, int j_max)
389 {
390  int h = i_max - i_min;
391  int w = j_max - j_min;
392 
393  if (m_rscale == 1) {
394  for (int i = 0; i < h; i++) {
395  unsigned int i_ = i_min + i;
396  unsigned int ii_ = i*pitch;
397  for (int j = 0; j < w; j++) {
398  unsigned char val = I[i_][j_min + j];
399  unsigned int index_ = ii_ + j * 4;
400  imBuffer[index_] = val;
401  imBuffer[++index_] = val;
402  imBuffer[++index_] = val;
403  imBuffer[++index_] = vpRGBa::alpha_default;
404  }
405  }
406  }
407  else {
408  for (int i = 0; i < h; i++) {
409  unsigned int i_ = (i_min + i)*m_rscale;
410  unsigned int ii_ = i*pitch;
411  for (int j = 0; j < w; j++) {
412  unsigned char val = I[i_][(j_min + j)*m_rscale];
413  unsigned int index_ = ii_ + j * 4;
414  imBuffer[index_] = val;
415  imBuffer[++index_] = val;
416  imBuffer[++index_] = val;
417  imBuffer[++index_] = vpRGBa::alpha_default;
418  }
419  }
420  }
421 }
422 
431 void vpD3DRenderer::convertROI(const vpImage<vpRGBa>& I, unsigned char * imBuffer, unsigned int pitch,
432  int i_min, int j_min, int i_max, int j_max)
433 {
434  int h = i_max - i_min;
435  int w = j_max - j_min;
436 
437  if (m_rscale == 1) {
438  for (int i = 0; i < h; i++) {
439  unsigned int i_ = i_min + i;
440  unsigned int ii_ = i*pitch;
441  for (int j = 0; j < w; j++) {
442  vpRGBa val = I[i_][j_min + j];
443  unsigned int index_ = ii_ + j * 4;
444  imBuffer[index_] = val.B;
445  imBuffer[++index_] = val.G;
446  imBuffer[++index_] = val.R;
447  imBuffer[++index_] = vpRGBa::alpha_default;
448  }
449  }
450  }
451  else {
452  for (int i = 0; i < h; i++) {
453  unsigned int i_ = (i_min + i)*m_rscale;
454  unsigned int ii_ = i*pitch;
455  for (int j = 0; j < w; j++) {
456  vpRGBa val = I[i_][(j_min + j)*m_rscale];
457  unsigned int index_ = ii_ + j * 4;
458  imBuffer[index_] = val.B;
459  imBuffer[++index_] = val.G;
460  imBuffer[++index_] = val.R;
461  imBuffer[++index_] = vpRGBa::alpha_default;
462  }
463  }
464  }
465 }
466 
471 void vpD3DRenderer::setImg(const vpImage<vpRGBa>& im)
472 {
473  //if the device has been initialized
474  if(pd3dDevice != NULL)
475  {
476  D3DLOCKED_RECT d3dLRect;
477 
478  RECT r;
479  r.top=0; r.left=0;
480  r.bottom=static_cast<signed long>(m_rheight);
481  r.right=static_cast<signed long>(m_rwidth);
482 
483  //locks the texture to directly access it
484  if(pd3dText->LockRect(0, &d3dLRect, &r, 0)!= D3D_OK)
485  {
486  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
487  return;
488  }
489 
490  //gets the buffer and pitch of the texture
491  unsigned int pitch = static_cast<unsigned int>( d3dLRect.Pitch );
492  unsigned char * buf = (unsigned char *) d3dLRect.pBits;
493 
494  //fills this texture with the image data (converted to bgra)
495  convert(im, buf, pitch);
496 
497  //unlocks the texture
498  if( pd3dText->UnlockRect(0) != D3D_OK)
499  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
500 
501  }
502 }
503 
508 void vpD3DRenderer::setImgROI(const vpImage<vpRGBa>& im, const vpImagePoint &iP, const unsigned int width, const unsigned int height )
509 {
510  //if the device has been initialized
511  if(pd3dDevice != NULL)
512  {
513  D3DLOCKED_RECT d3dLRect;
514 
515  int i_min = std::max((int)ceil(iP.get_i() / m_rscale), 0);
516  int j_min = std::max((int)ceil(iP.get_j() / m_rscale), 0);
517  int i_max = std::min((int)ceil((iP.get_i() + height) / m_rscale), (int)m_rheight);
518  int j_max = std::min((int)ceil((iP.get_j() + width) / m_rscale), (int)m_rwidth);
519 
520  RECT r;
521  r.top = (LONG)i_min; r.left = (LONG)j_min;
522  r.bottom = (LONG)i_max; r.right = (LONG)j_max;
523 
524  //locks the texture to directly access it
525  if(pd3dText->LockRect(0, &d3dLRect, &r, 0)!= D3D_OK)
526  {
527  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
528  return;
529  }
530 
531  //gets the buffer and pitch of the texture
532  unsigned int pitch = static_cast<unsigned int>(d3dLRect.Pitch);
533  unsigned char * buf = (unsigned char *) d3dLRect.pBits;
534 
535  //fills this texture with the image data (converted to bgra)
536  convertROI(im, buf, pitch, i_min, j_min, i_max, j_max);
537 
538  //unlocks the texture
539  if( pd3dText->UnlockRect(0) != D3D_OK)
540  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
541  }
542 }
543 
544 
549 void vpD3DRenderer::setImg(const vpImage<unsigned char>& im)
550 {
551  //if the device has been initialized
552  if(pd3dDevice != NULL)
553  {
554  D3DLOCKED_RECT d3dLRect;
555 
556  RECT r;
557  r.top = 0;
558  r.left = 0;
559  r.bottom = static_cast<LONG>(m_rheight);
560  r.right = static_cast<LONG>(m_rwidth);
561 
562  //locks the texture to directly access it
563  if(pd3dText->LockRect(0, &d3dLRect, &r, 0)!= D3D_OK)
564  {
565  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
566  return;
567  }
568 
569  //gets the buffer and pitch of the texture
570  unsigned int pitch = static_cast<unsigned int>(d3dLRect.Pitch);
571  unsigned char * buf = (unsigned char *) d3dLRect.pBits;
572 
573  //fills this texture with the image data (converted to bgra)
574  convert(im, buf, pitch);
575 
576  //unlocks the texture
577  if( pd3dText->UnlockRect(0) != D3D_OK)
578  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
579  }
580 }
581 
582 
587 void vpD3DRenderer::setImgROI(const vpImage<unsigned char>& im, const vpImagePoint &iP, const unsigned int width, const unsigned int height )
588 {
589  //if the device has been initialized
590  if(pd3dDevice != NULL)
591  {
592  D3DLOCKED_RECT d3dLRect;
593 
594  int i_min = std::max((int)ceil(iP.get_i() / m_rscale), 0);
595  int j_min = std::max((int)ceil(iP.get_j() / m_rscale), 0);
596  int i_max = std::min((int)ceil((iP.get_i() + height) / m_rscale), (int)m_rheight);
597  int j_max = std::min((int)ceil((iP.get_j() + width) / m_rscale), (int)m_rwidth);
598 
599  RECT r;
600  r.top=(LONG)i_min; r.left= (LONG)j_min;
601  r.bottom= (LONG)i_max; r.right= (LONG)j_max;
602 
603  //locks the texture to directly access it
604  if(pd3dText->LockRect(0, &d3dLRect, &r, 0)!= D3D_OK)
605  {
606  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
607  return;
608  }
609 
610  //gets the buffer and pitch of the texture
611  unsigned int pitch = static_cast<unsigned int>( d3dLRect.Pitch );
612  unsigned char * buf = (unsigned char *) d3dLRect.pBits;
613 
614  //fills this texture with the image data (converted to bgra)
615  convertROI(im, buf, pitch, i_min, j_min, i_max, j_max);
616 
617  //unlocks the texture
618  if( pd3dText->UnlockRect(0) != D3D_OK)
619  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
620  }
621 }
622 
628 bool vpD3DRenderer::render()
629 {
630  // Clears the back buffer to a blue color
631  //pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
632 
633  //Begins the scene.
634  pd3dDevice->BeginScene();
635 
636  //Texture rectangle to display
637  RECT r;
638  r.top = 0;
639  r.left = 0;
640  r.bottom = static_cast<LONG>(m_rheight);
641  r.right = static_cast<LONG>(m_rwidth);
642 
643  //Updates the video memory texture with the content of the system
644  //memory texture
645  pd3dDevice->UpdateTexture(pd3dText,pd3dVideoText);
646 
647  //Displays this texture as a sprite
648 
649 #if (D3DX_SDK_VERSION <= 9)
650  pSprite->Begin(); //
651  pSprite->Draw(pd3dVideoText, &r, NULL, NULL, NULL, NULL, 0xFFFFFFFF );
652 #else
653  pSprite->Begin(0);
654  pSprite->Draw(pd3dVideoText, &r, NULL, NULL, 0xFFFFFFFF );
655 #endif
656  pSprite->End();
657 
658  //Ends the scene.
659  pd3dDevice->EndScene();
660  //Presents the backbuffer
661  pd3dDevice->Present( NULL, NULL, NULL, NULL );
662 
663  return true;
664 }
665 
666 
673 void vpD3DRenderer::setPixel(const vpImagePoint &iP,
674  const vpColor &color)
675 {
676  vpImagePoint iPscaled = iP / m_rscale;
677  if(iPscaled.get_i()<0 || iPscaled.get_j()<0 || iPscaled.get_i()>=(int)m_rheight || iPscaled.get_j()>=(int)m_rwidth)
678  {
679  return;
680  }
681 
682  //if the device has been initialized
683  if(pd3dDevice != NULL)
684  {
685  D3DLOCKED_RECT d3dLRect;
686 
687  RECT r;
688 
689  r.top=(LONG)iPscaled.get_i();
690  r.left=(LONG)iPscaled.get_j();
691  r.bottom=(LONG)iPscaled.get_i()+1;
692  r.right=(LONG)iPscaled.get_j()+1;
693 
694  //locks the texture to directly access it
695  if(pd3dText->LockRect(0, &d3dLRect, &r, 0)!= D3D_OK)
696  {
697  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
698  return;
699  }
700 
701  //gets the buffer and pitch of the texture
702  unsigned int pitch = static_cast<unsigned int>( d3dLRect.Pitch );
703  unsigned char * buf = (unsigned char *) d3dLRect.pBits;
704 
705  //the coordinates are in the locked area base
706  setBufferPixel(buf, pitch, 0, 0,color);
707 
708  //unlocks the texture
709  if( pd3dText->UnlockRect(0) != D3D_OK)
710  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
711  }
712 }
713 
721 void vpD3DRenderer::drawLine(const vpImagePoint &ip1,
722  const vpImagePoint &ip2,
723  const vpColor &color,
724  unsigned int thickness, int style)
725 {
726  //if the device has been initialized
727  if(pd3dDevice != NULL)
728  {
729  //Will contain the texture's surface drawing context
730  HDC hDCMem;
731 
732  //The texture's surface
733  IDirect3DSurface9 * pd3dSurf;
734  pd3dText->GetSurfaceLevel(0, &pd3dSurf);
735 
736  //We get its DC
737  pd3dSurf->GetDC(&hDCMem);
738 
739  //create the pen
740  HPEN hPen;
741  if (color.id < vpColor::id_unknown)
742  hPen = CreatePen(style, static_cast<int>(thickness), colorsGDI[color.id]);
743  else {
744  COLORREF gdicolor = RGB(color.R, color.G, color.B);
745  hPen = CreatePen(style, static_cast<int>(thickness), gdicolor);
746  }
747 
748  //we don't use the bkColor
749  SetBkMode(hDCMem, TRANSPARENT);
750 
751  //select the pen
752  SelectObject(hDCMem, hPen);
753 
754  // Warning: When thickness > 1 and pen style is PS_DASHDOT, the drawing displays a solid line
755  // That's why in that case we implement the dashdot line manually drawing multiple small lines
756  if (thickness != 1 && style != PS_SOLID) {
757  double size = 10.*m_rscale;
758  double length = sqrt(vpMath::sqr(ip2.get_i() - ip1.get_i()) + vpMath::sqr(ip2.get_j() - ip1.get_j()));
759  double deltaj = size / length*(ip2.get_j() - ip1.get_j());
760  double deltai = size / length*(ip2.get_i() - ip1.get_i());
761  double slope = (ip2.get_i() - ip1.get_i()) / (ip2.get_j() - ip1.get_j());
762  double orig = ip1.get_i() - slope*ip1.get_j();
763  for (unsigned int j = (unsigned int)ip1.get_j(); j < ip2.get_j(); j += (unsigned int)(2 * deltaj)) {
764  double i = slope*j + orig;
765  //move to the starting point
766  MoveToEx(hDCMem, vpMath::round(j / m_rscale), vpMath::round(i / m_rscale), NULL);
767  //Draw the line
768  LineTo(hDCMem, vpMath::round((j + deltaj) / m_rscale), vpMath::round((i + deltai) / m_rscale));
769  }
770  }
771  else {
772  //move to the starting point
773  MoveToEx(hDCMem, vpMath::round(ip1.get_u() / m_rscale), vpMath::round(ip1.get_v() / m_rscale), NULL);
774  //Draw the line
775  LineTo(hDCMem, vpMath::round(ip2.get_u() / m_rscale), vpMath::round(ip2.get_v() / m_rscale));
776  }
777 
778  //Releases the DC
779  pd3dSurf->ReleaseDC(hDCMem);
780  //Releases the surface's interface
781  pd3dSurf->Release();
782  //Deletes additional objects
783  DeleteObject(hPen);
784  }
785 }
786 
787 
797 void vpD3DRenderer::drawRect(const vpImagePoint &topLeft,
798  unsigned int width, unsigned int height,
799  const vpColor &color, bool fill,
800  unsigned int thickness)
801 {
802  //if the device has been initialized
803  if(pd3dDevice != NULL)
804  {
805  if(fill == false)
806  {
807  drawLine(topLeft, topLeft + vpImagePoint(0, width), color, thickness);
808  drawLine(topLeft + vpImagePoint(0, width), topLeft + vpImagePoint(height, width), color, thickness);
809  drawLine(topLeft + vpImagePoint(height, width), topLeft + vpImagePoint(height, 0), color, thickness);
810  drawLine(topLeft + vpImagePoint(height, 0), topLeft, color, thickness);
811  }
812  else
813  {
814  vpImagePoint topLeftScaled = topLeft / m_rscale;
815  unsigned int widthScaled = width / m_rscale;
816  unsigned int heightScaled = height / m_rscale;
817 
818  if (topLeftScaled.get_i()>(int)m_rheight - 1 || topLeftScaled.get_j()>(int)m_rwidth - 1 || topLeftScaled.get_i() + height<0 || topLeftScaled.get_j() + width<0)
819  {
820  // vpCERROR<<"Invalid parameters!"<<std::endl;
821  return;
822  }
823 
824  D3DLOCKED_RECT d3dLRect;
825 
826  RECT r;
827  r.top = (LONG)((topLeftScaled.get_i()>0) ? topLeftScaled.get_i() : 0);
828  r.left = (LONG)((topLeftScaled.get_j()>0) ? topLeftScaled.get_j() : 0);
829  r.bottom = (LONG)((topLeftScaled.get_i() + heightScaled < (int)m_rheight) ? topLeftScaled.get_i() + heightScaled : m_rheight - 1);
830  r.right = (LONG)((topLeftScaled.get_j() + widthScaled < (int)m_rwidth) ? topLeftScaled.get_j() + widthScaled : m_rwidth - 1);
831 
832  /* unsigned */ int rectW = r.right - r.left;
833  /* unsigned */ int rectH = r.bottom - r.top;
834 
835  //locks the texture to directly access it
836  if (pd3dText->LockRect(0, &d3dLRect, &r, 0) != D3D_OK)
837  {
838  vpCERROR << "D3D : Couldn't lock the texture!" << std::endl;
839  return;
840  }
841 
842  //gets the buffer and pitch of the texture
843  unsigned int pitch = static_cast<unsigned int>(d3dLRect.Pitch);
844  unsigned char * buf = (unsigned char *)d3dLRect.pBits;
845 
846  if(topLeftScaled.get_i()>=0 && topLeftScaled.get_j()+widthScaled < m_rwidth && topLeftScaled.get_i()+heightScaled < m_rheight && topLeftScaled.get_j()>=0)
847  {
848  for (int x = 0; x<rectW; x++) {
849  for (int y = 0; y<rectH; y++)
850  setBufferPixel(buf, pitch, x, y, color);
851  }
852  }
853 
854  //unlocks the texture
855  if (pd3dText->UnlockRect(0) != D3D_OK)
856  vpCERROR << "D3D : Couldn't unlock the texture!" << std::endl;
857  }
858  }
859 }
860 
865 void vpD3DRenderer::clear(const vpColor &color)
866 {
867  //if the device has been initialized
868  if(pd3dDevice != NULL)
869  {
870  D3DLOCKED_RECT d3dLRect;
871 
872  RECT r;
873  r.top = 0;
874  r.left = 0;
875  r.bottom = static_cast<LONG>( m_rheight );
876  r.right = static_cast<LONG>( m_rwidth );
877 
878  //locks the texture to directly access it
879  if(pd3dText->LockRect(0, &d3dLRect, &r, 0)!= D3D_OK)
880  {
881  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
882  return;
883  }
884 
885  //gets the buffer and pitch of the texture
886  unsigned int pitch = static_cast<unsigned int>(d3dLRect.Pitch);
887  long * buf = (long *) ( d3dLRect.pBits );
888 
889  unsigned long c;
890  if (color.id < vpColor::id_unknown)
891  c = colors[color.id];
892  else {
893  c = D3DCOLOR_ARGB(0xFF, color.R, color.G, color.B);
894  }
895  long * end = (long*)(buf + (pitch * m_rheight));
896 
897  //fills the whole image
898  while (buf < end)
899  *buf++ = static_cast<long>( c );
900 
901  //unlocks the texture
902  if( pd3dText->UnlockRect(0) != D3D_OK)
903  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
904  }
905 }
906 
907 
908 
909 //writes current circle pixels using symetry to reduce the algorithm's complexity
910 void vpD3DRenderer::subDrawCircle(int i, int j,
911  int x, int y,
912  vpColor col,
913  unsigned char* buf, unsigned int pitch,
914  unsigned int maxX, unsigned int maxY)
915 {
916  if (x == 0) {
917  setBufferPixel(buf, pitch, i , j+y, col, maxX, maxY);
918  setBufferPixel(buf, pitch, i , j-y, col, maxX, maxY);
919  setBufferPixel(buf, pitch, i+y, j, col, maxX, maxY);
920  setBufferPixel(buf, pitch, i-y, j, col, maxX, maxY);
921  } else
922  if (x == y) {
923  setBufferPixel(buf, pitch, i+x,j+y,col, maxX, maxY);
924  setBufferPixel(buf, pitch, i-x,j+y,col, maxX, maxY);
925  setBufferPixel(buf, pitch, i+x,j-y,col, maxX, maxY);
926  setBufferPixel(buf, pitch, i-x,j-y,col, maxX, maxY);
927  } else
928  if (x < y) {
929  setBufferPixel(buf, pitch, i+x,j+y,col, maxX, maxY);
930  setBufferPixel(buf, pitch, i-x,j+y,col, maxX, maxY);
931  setBufferPixel(buf, pitch, i+x,j-y,col, maxX, maxY);
932  setBufferPixel(buf, pitch, i-x,j-y,col, maxX, maxY);
933  setBufferPixel(buf, pitch, i+y,j+x,col, maxX, maxY);
934  setBufferPixel(buf, pitch, i-y,j+x,col, maxX, maxY);
935  setBufferPixel(buf, pitch, i+y,j-x,col, maxX, maxY);
936  setBufferPixel(buf, pitch, i-y,j-x,col, maxX, maxY);
937  }
938 
939 }
940 
947 void vpD3DRenderer::drawCircle(const vpImagePoint &center, unsigned int radius,
948  const vpColor &color, bool /*fill*/, unsigned int /*thickness*/)
949 {
950  unsigned int radiusScaled = radius / m_rscale;
951  vpImagePoint centerScaled = center / m_rscale;
952  if(radiusScaled<1 || vpMath::round(centerScaled.get_i()+ radiusScaled)<0
953  || vpMath::round(centerScaled.get_i()- radiusScaled) > (int)m_rheight
954  || vpMath::round(centerScaled.get_j()+ radiusScaled)<0
955  || vpMath::round(centerScaled.get_j()- radiusScaled) > (int)m_rwidth)
956  return;
957 
958  //if the device has been initialized
959  if(pd3dDevice != NULL)
960  {
961  D3DLOCKED_RECT d3dLRect;
962 
963  RECT rec;
964  int radiusScaled_ = static_cast<int>(radiusScaled);
965  int rleft = (vpMath::round(centerScaled.get_j()- radiusScaled_) > 0) ? vpMath::round(centerScaled.get_j())- radiusScaled_ : 0;
966  int rtop = (vpMath::round(centerScaled.get_i()- radiusScaled_) > 0) ? vpMath::round(centerScaled.get_i())- radiusScaled_ : 0;
967 
968  rec.top= rtop;
969  rec.left= rleft;
970  rec.bottom=(LONG)((vpMath::round(centerScaled.get_i()+ radiusScaled_) < (int)m_rheight) ? centerScaled.get_i()+ radiusScaled_ : m_rheight-1);
971  rec.right=(LONG)((vpMath::round(centerScaled.get_j()+ radiusScaled_) < (int)m_rwidth) ? centerScaled.get_j()+ radiusScaled_ : m_rwidth-1);
972 
973  //used as maxX and maxY for setBufferPixel
974  unsigned int rectW = static_cast<unsigned int> ( rec.right - rleft );
975  unsigned int rectH = static_cast<unsigned int> ( rec.bottom - rtop );
976 
977  //locks the texture to directly access it
978  if(pd3dText->LockRect(0, &d3dLRect, &rec, 0)!= D3D_OK)
979  {
980  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
981  return;
982  }
983 
984  //gets the buffer and pitch of the texture
985  unsigned int pitch = static_cast<unsigned int>(d3dLRect.Pitch);
986  unsigned char * buf = (unsigned char *) d3dLRect.pBits;
987 
988  // Bresenham 's circle algorithm
989 
990  int x = 0;
991  int y = static_cast<int>(radiusScaled);
992  int p = (3 - (y<<1));
993 
994  vpImagePoint ip;
995  ip.set_i(centerScaled.get_i()-rtop);
996  ip.set_j(centerScaled.get_j()-rleft);
997 
998  subDrawCircle(vpMath::round(ip.get_i()), vpMath::round(ip.get_j()), x, y, color, buf, pitch, rectW, rectH);
999  while(x < y){
1000  x++;
1001  if (p < 0)
1002  {
1003  p += ((x<<1)+1)<<1;
1004  }
1005  else
1006  {
1007  y--;
1008  p += (((x-y)<<1)+1)<<1;
1009  }
1010  subDrawCircle(vpMath::round(ip.get_i()), vpMath::round(ip.get_j()), x, y, color, buf, pitch, rectW, rectH);
1011  }
1012 
1013  //unlocks the texture
1014  if( pd3dText->UnlockRect(0) != D3D_OK)
1015  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
1016  }
1017 }
1018 
1019 
1020 
1027 void vpD3DRenderer::drawText(const vpImagePoint &ip, const char * text,
1028  const vpColor &color)
1029 {
1030  //Will contain the texture's surface drawing context
1031  HDC hDCMem;
1032 
1033  //The texture's surface
1034  IDirect3DSurface9 * pd3dSurf;
1035  pd3dText->GetSurfaceLevel(0, &pd3dSurf);
1036 
1037  //We get its DC
1038  pd3dSurf->GetDC(&hDCMem);
1039 
1040  //Select the font
1041  SelectObject(hDCMem, hFont);
1042 
1043  //set the text color
1044  if (color.id < vpColor::id_unknown)
1045  SetTextColor(hDCMem, colorsGDI[color.id]);
1046  else {
1047  COLORREF gdicolor = RGB(color.R, color.G, color.B);
1048  SetTextColor(hDCMem, gdicolor);
1049  }
1050 
1051  //we don't use the bkColor
1052  SetBkMode(hDCMem, TRANSPARENT);
1053 
1054  SIZE size;
1055  int length = (int) strlen(text);
1056 
1057  //get the displayed string dimensions
1058  GetTextExtentPoint32(hDCMem, text, length, &size);
1059 
1060  //displays the string
1061  TextOut(hDCMem, vpMath::round(ip.get_u() / m_rscale), vpMath::round(ip.get_v() / m_rscale), text, length);
1062 
1063  //Releases the DC
1064  pd3dSurf->ReleaseDC(hDCMem);
1065  //Releases the surface's interface
1066  pd3dSurf->Release();
1067  //Deletes additional objects
1068  DeleteObject(hFont);
1069 }
1070 
1071 
1079 void vpD3DRenderer::drawCross(const vpImagePoint &ip,
1080  unsigned int size,
1081  const vpColor &color, unsigned int thickness)
1082 {
1083  double i = ip.get_i();
1084  double j = ip.get_j();
1085  vpImagePoint ip1, ip2;
1086 
1087  ip1.set_i(i - size / 2);
1088  ip1.set_j(j);
1089  ip2.set_i(i + size / 2);
1090  ip2.set_j(j);
1091  drawLine(ip1, ip2, color, thickness);
1092 
1093  ip1.set_i(i);
1094  ip1.set_j(j - size / 2);
1095  ip2.set_i(i);
1096  ip2.set_j(j + size / 2);
1097 
1098  drawLine(ip1, ip2, color, thickness);
1099 }
1100 
1108 void vpD3DRenderer::drawArrow(const vpImagePoint &ip1,
1109  const vpImagePoint &ip2,
1110  const vpColor &color,
1111  unsigned int w, unsigned int h, unsigned int thickness)
1112 {
1113  double a = ip2.get_i() - ip1.get_i();
1114  double b = ip2.get_j() - ip1.get_j();
1115  double lg = sqrt(vpMath::sqr(a) + vpMath::sqr(b));
1116 
1117  //if ( ( a==0 ) && ( b==0 ) )
1118  if ((std::fabs(a) <= std::numeric_limits<double>::epsilon()) && (std::fabs(b) <= std::numeric_limits<double>::epsilon()))
1119  {
1120  // DisplayCrossLarge(i1,j1,3,col) ;
1121  }
1122  else
1123  {
1124  a /= lg;
1125  b /= lg;
1126 
1127  vpImagePoint ip3;
1128  ip3.set_i(ip2.get_i() - w*a);
1129  ip3.set_j(ip2.get_j() - w*b);
1130 
1131  vpImagePoint ip4;
1132  ip4.set_i(ip3.get_i() - b*h);
1133  ip4.set_j(ip3.get_j() + a*h);
1134 
1135  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
1136  drawLine(ip2, ip4, color, thickness);
1137 
1138  ip4.set_i(ip3.get_i() + b*h);
1139  ip4.set_j(ip3.get_j() - a*h);
1140 
1141  if (lg > 2 * vpImagePoint::distance(ip2, ip4))
1142  drawLine(ip2, ip4, color, thickness);
1143 
1144  drawLine(ip1, ip2, color, thickness);
1145  }
1146 }
1147 
1154 void TextureToRGBa(vpImage<vpRGBa>& I, unsigned char * imBuffer,
1155  unsigned int pitch)
1156 {
1157  unsigned int j = I.getWidth();
1158 
1159  unsigned int k=0;
1160  for(unsigned int i=0; i<I.getHeight()* I.getWidth(); i++)
1161  {
1162  //go to the next line
1163  if(j==0){
1164  k += pitch - (I.getWidth() * 4);
1165  j = I.getWidth();
1166  }
1167 
1168  //simple conversion from bgra to rgba
1169  I.bitmap[i].B = imBuffer[k+0];
1170  I.bitmap[i].G = imBuffer[k+1];
1171  I.bitmap[i].R = imBuffer[k+2];
1172  I.bitmap[i].A = imBuffer[k+3];
1173 
1174  k+=4;
1175  j--;
1176  }
1177 }
1178 
1183 void vpD3DRenderer::getImage(vpImage<vpRGBa> &I)
1184 {
1185  //if the device has been initialized
1186  if(pd3dDevice != NULL)
1187  {
1188 
1189  //resize the destination image as needed
1190  I.resize(m_rheight, m_rwidth);
1191 
1192  D3DLOCKED_RECT d3dLRect;
1193 
1194  RECT r;
1195  r.top = 0;
1196  r.left = 0;
1197  r.bottom = static_cast<LONG>( m_rheight );
1198  r.right = static_cast<LONG>( m_rwidth );
1199 
1200  //locks the whole texture to directly access it
1201  if(pd3dText->LockRect(0, &d3dLRect, &r, 0)!= D3D_OK)
1202  {
1203  vpCERROR<<"D3D : Couldn't lock the texture!"<<std::endl;
1204  return;
1205  }
1206 
1207  //gets the buffer and pitch of the texture
1208  unsigned int pitch = static_cast<unsigned int>(d3dLRect.Pitch);
1209  unsigned char * buf = (unsigned char *) d3dLRect.pBits;
1210 
1211  //fills this image with the texture's data
1212  TextureToRGBa(I,buf, pitch);
1213 
1214  //unlocks the texture
1215  if( pd3dText->UnlockRect(0) != D3D_OK)
1216  vpCERROR<<"D3D : Couldn't unlock the texture!"<<std::endl;
1217  }
1218 }
1219 
1220 #elif !defined(VISP_BUILD_SHARED_LIBS)
1221 // Work arround to avoid warning: libvisp_core.a(vpD3DRenderer.cpp.o) has no symbols
1222 void dummy_vpD3DRenderer() {};
1223 #endif
1224 #endif
double get_v() const
Definition: vpImagePoint.h:268
double get_i() const
Definition: vpImagePoint.h:199
unsigned int getWidth() const
Definition: vpImage.h:226
#define vpCERROR
Definition: vpDebug.h:365
unsigned char B
Blue component.
Definition: vpRGBa.h:155
Type * bitmap
points toward the bitmap
Definition: vpImage.h:134
static const vpColor black
Definition: vpColor.h:157
static const vpColor darkRed
Definition: vpColor.h:164
Class to define colors available for display functionnalities.
Definition: vpColor.h:121
double get_u() const
Definition: vpImagePoint.h:257
static const vpColor lightGray
Definition: vpColor.h:159
static const vpColor darkBlue
Definition: vpColor.h:170
unsigned char G
Green component.
Definition: vpRGBa.h:154
static const vpColor green
Definition: vpColor.h:166
static int round(const double x)
Definition: vpMath.h:249
double get_j() const
Definition: vpImagePoint.h:210
static const vpColor lightRed
Definition: vpColor.h:162
Definition: vpRGBa.h:66
static const vpColor red
Definition: vpColor.h:163
static const vpColor orange
Definition: vpColor.h:173
vpColorIdentifier id
Definition: vpColor.h:152
void set_i(const double ii)
Definition: vpImagePoint.h:163
static const vpColor cyan
Definition: vpColor.h:172
static const vpColor lightGreen
Definition: vpColor.h:165
static double sqr(double x)
Definition: vpMath.h:110
unsigned char A
Additionnal component.
Definition: vpRGBa.h:156
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:903
static const vpColor gray
Definition: vpColor.h:160
static const vpColor darkGray
Definition: vpColor.h:161
void set_j(const double jj)
Definition: vpImagePoint.h:174
Error that can be emited by the vpDisplay class and its derivates.
unsigned char R
Red component.
Definition: vpRGBa.h:153
unsigned int getHeight() const
Definition: vpImage.h:175
static const vpColor darkGreen
Definition: vpColor.h:167
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
static const vpColor yellow
Definition: vpColor.h:171
static const vpColor lightBlue
Definition: vpColor.h:168
static const vpColor purple
Definition: vpColor.h:174
static const vpColor white
Definition: vpColor.h:158
static double distance(const vpImagePoint &iP1, const vpImagePoint &iP2)
Definition: vpImagePoint.h:279
static const vpColor blue
Definition: vpColor.h:169