Bike-X  0.8
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Util_ImageWindow.cpp
Go to the documentation of this file.
1 /************************************************************************************
2 
3 Filename : Util_ImageWindow.cpp
4 Content : An output object for windows that can display raw images for testing
5 Created : March 13, 2014
6 Authors : Dean Beeler
7 
8 Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
9 
10 Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
12 which is provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
14 
15 You may obtain a copy of the License at
16 
17 http://www.oculusvr.com/licenses/LICENSE-3.1
18 
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
24 
25 *************************************************************************************/
26 #include "../../Include/OVR.h"
27 
28 #include "Util_ImageWindow.h"
29 
30 #if defined(OVR_OS_WIN32)
31 
32 #include <Windows.h>
33 
34 #include "DWrite.h"
35 
36 typedef HRESULT (WINAPI *D2D1CreateFactoryFn)(
37  _In_ D2D1_FACTORY_TYPE,
38  _In_ REFIID,
39  _In_opt_ const D2D1_FACTORY_OPTIONS*,
40  _Out_ ID2D1Factory **
41  );
42 
43 typedef HRESULT (WINAPI *DWriteCreateFactoryFn)(
44  _In_ DWRITE_FACTORY_TYPE factoryType,
45  _In_ REFIID iid,
46  _Out_ IUnknown **factory
47  );
48 
49 
50 namespace OVR { namespace Util {
51 
52 ID2D1Factory* ImageWindow::pD2DFactory = NULL;
53 IDWriteFactory* ImageWindow::pDWriteFactory = NULL;
54 ImageWindow* ImageWindow::globalWindow[4];
56 
57 LRESULT CALLBACK MainWndProc(
58  HWND hwnd,
59  UINT uMsg,
60  WPARAM wParam,
61  LPARAM lParam)
62 {
63  switch (uMsg)
64  {
65  case WM_CREATE:
66  return 0;
67 
68  case WM_PAINT:
69  {
70  LONG_PTR ptr = GetWindowLongPtr( hwnd, GWLP_USERDATA );
71  if( ptr )
72  {
73  ImageWindow* iw = (ImageWindow*)ptr;
74  iw->OnPaint();
75  }
76  }
77 
78  return 0;
79 
80  case WM_SIZE:
81  // Set the size and position of the window.
82  return 0;
83 
84  case WM_DESTROY:
85  // Clean up window-specific data objects.
86  return 0;
87 
88  //
89  // Process other messages.
90  //
91 
92  default:
93  return DefWindowProc(hwnd, uMsg, wParam, lParam);
94  }
95  //return 0;
96 }
97 
98 ImageWindow::ImageWindow( uint32_t width, uint32_t height ) :
99  frontBufferMutex( new Mutex() )
100 {
101 
102  HINSTANCE hInst = LoadLibrary( L"d2d1.dll" );
103  HINSTANCE hInstWrite = LoadLibrary( L"Dwrite.dll" );
104 
105  D2D1CreateFactoryFn createFactory = NULL;
106  DWriteCreateFactoryFn writeFactory = NULL;
107 
108  if( hInst )
109  {
110  createFactory = (D2D1CreateFactoryFn)GetProcAddress( hInst, "D2D1CreateFactory" );
111  }
112 
113  if( hInstWrite )
114  {
115  writeFactory = (DWriteCreateFactoryFn)GetProcAddress( hInstWrite, "DWriteCreateFactory" );
116  }
117 
118  globalWindow[windowCount] = this;
119 
120  ++windowCount;
121 
122  if( pD2DFactory == NULL && createFactory && writeFactory )
123  {
124  createFactory(
125  D2D1_FACTORY_TYPE_MULTI_THREADED,
126  __uuidof(ID2D1Factory),
127  NULL,
128  &pD2DFactory
129  );
130 
131  // Create a DirectWrite factory.
132  writeFactory(
133  DWRITE_FACTORY_TYPE_SHARED,
134  __uuidof(pDWriteFactory),
135  reinterpret_cast<IUnknown **>(&pDWriteFactory)
136  );
137 
138  }
139 
140  resolution = D2D1::SizeU( width, height );
141 
142  SetWindowLongPtr( hWindow, GWLP_USERDATA, (LONG_PTR)this );
143 
144  pRT = NULL;
145  greyBitmap = NULL;
146  colorBitmap = NULL;
147 }
148 
149 ImageWindow::~ImageWindow()
150 {
151  for( int i = 0; i < MaxWindows; ++i )
152  {
153  if( globalWindow[i] == this )
154  {
155  globalWindow[i] = NULL;
156  break;
157  }
158 }
159 
160  if( greyBitmap )
161  greyBitmap->Release();
162 
163  if( colorBitmap )
164  colorBitmap->Release();
165 
166  if( pRT )
167  pRT->Release();
168 
169  {
170  Mutex::Locker locker( frontBufferMutex );
171 
172  while( frames.GetSize() )
173  {
174  Ptr<Frame> aFrame = frames.PopBack();
175  }
176  }
177 
178  delete frontBufferMutex;
179 
180  ShowWindow( hWindow, SW_HIDE );
181  DestroyWindow( hWindow );
182 }
183 
184 void ImageWindow::AssociateSurface( void* surface )
185 {
186  // Assume an IUnknown
187  IUnknown* unknown = (IUnknown*)surface;
188 
189  IDXGISurface *pDxgiSurface = NULL;
190  HRESULT hr = unknown->QueryInterface(&pDxgiSurface);
191  if( hr == S_OK )
192  {
193  D2D1_RENDER_TARGET_PROPERTIES props =
194  D2D1::RenderTargetProperties(
195  D2D1_RENDER_TARGET_TYPE_DEFAULT,
196  D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
197  96,
198  96
199  );
200 
201 
202  pRT = NULL;
203  ID2D1RenderTarget* tmpTarget;
204 
205  hr = pD2DFactory->CreateDxgiSurfaceRenderTarget( pDxgiSurface, &props, &tmpTarget );
206 
207  if( hr == S_OK )
208  {
209  DXGI_SURFACE_DESC desc = {0};
210  pDxgiSurface->GetDesc( &desc );
211  int width = desc.Width;
212  int height = desc.Height;
213 
214  D2D1_SIZE_U size = D2D1::SizeU( width, height );
215 
216  D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat(
217  DXGI_FORMAT_A8_UNORM,
218  D2D1_ALPHA_MODE_PREMULTIPLIED
219  );
220 
221  D2D1_PIXEL_FORMAT colorPixelFormat = D2D1::PixelFormat(
222  DXGI_FORMAT_B8G8R8A8_UNORM,
223  D2D1_ALPHA_MODE_PREMULTIPLIED
224  );
225 
226  D2D1_BITMAP_PROPERTIES bitmapProps;
227  bitmapProps.dpiX = 96;
228  bitmapProps.dpiY = 96;
229  bitmapProps.pixelFormat = pixelFormat;
230 
231  D2D1_BITMAP_PROPERTIES colorBitmapProps;
232  colorBitmapProps.dpiX = 96;
233  colorBitmapProps.dpiY = 96;
234  colorBitmapProps.pixelFormat = colorPixelFormat;
235 
236  HRESULT result = tmpTarget->CreateBitmap( size, bitmapProps, &greyBitmap );
237  if( result != S_OK )
238  {
239  tmpTarget->Release();
240  tmpTarget = NULL;
241  }
242 
243  result = tmpTarget->CreateBitmap( size, colorBitmapProps, &colorBitmap );
244  if( result != S_OK )
245  {
246  greyBitmap->Release();
247  greyBitmap = NULL;
248 
249  tmpTarget->Release();
250  tmpTarget = NULL;
251  }
252  pRT = tmpTarget;
253  }
254  }
255 }
256 
257 void ImageWindow::Process()
258 {
259  if( pRT && greyBitmap )
260  {
261  OnPaint();
262 
263  pRT->Flush();
264  }
265 }
266 
267 void ImageWindow::Complete()
268 {
269  Mutex::Locker locker( frontBufferMutex );
270 
271  if( frames.IsEmpty() )
272  return;
273 
274  if( frames.PeekBack(0)->ready )
275  return;
276 
277  Ptr<Frame> frame = frames.PeekBack(0);
278 
279  frame->ready = true;
280 }
281 
282 void ImageWindow::OnPaint()
283 {
284  Mutex::Locker locker( frontBufferMutex );
285 
286  // Nothing to do
287  if( frames.IsEmpty() )
288  return;
289 
290  if( !frames.PeekFront(0)->ready )
291  return;
292 
293  Ptr<Frame> currentFrame = frames.PopFront();
294 
295  Ptr<Frame> nextFrame = NULL;
296 
297  if( !frames.IsEmpty() )
298  nextFrame = frames.PeekFront(0);
299 
300  while( nextFrame && nextFrame->ready )
301  {
302  // Free up the current frame since it's been removed from the deque
303  currentFrame = frames.PopFront();
304 
305  if( frames.IsEmpty() )
306  break;
307 
308  nextFrame = frames.PeekFront(0);
309  }
310 
311  if( currentFrame->imageData )
312  greyBitmap->CopyFromMemory( NULL, currentFrame->imageData, currentFrame->width );
313 
314  if( currentFrame->colorImageData )
315  colorBitmap->CopyFromMemory( NULL, currentFrame->colorImageData, currentFrame->colorPitch );
316 
317  pRT->BeginDraw();
318 
319  pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
320 
321  pRT->Clear( D2D1::ColorF(D2D1::ColorF::Black) );
322 
323  // This will mirror our image
324  D2D1_MATRIX_3X2_F m;
325  m._11 = -1; m._12 = 0;
326  m._21 = 0; m._22 = 1;
327  m._31 = 0; m._32 = 0;
328  pRT->SetTransform( m );
329 
330  ID2D1SolidColorBrush* whiteBrush;
331 
332  pRT->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White, 1.0f), &whiteBrush );
333 
334  if( currentFrame->imageData )
335  {
336  pRT->FillOpacityMask( greyBitmap, whiteBrush,
337  D2D1_OPACITY_MASK_CONTENT_TEXT_NATURAL,
338  D2D1::RectF( -(FLOAT)resolution.width, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ),
339  //D2D1::RectF( 0.0f, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ),
340  D2D1::RectF( 0.0f, 0.0f, (FLOAT)resolution.width, (FLOAT)resolution.height ) );
341  }
342  else if( currentFrame->colorImageData )
343  {
344  pRT->DrawBitmap( colorBitmap,
345  D2D1::RectF( -(FLOAT)resolution.width, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ) );
346 
347  }
348 
349  pRT->SetTransform(D2D1::Matrix3x2F::Identity());
350 
351  whiteBrush->Release();
352 
353  Array<CirclePlot>::Iterator it;
354 
355  for( it = currentFrame->plots.Begin(); it != currentFrame->plots.End(); ++it )
356  {
357  ID2D1SolidColorBrush* aBrush;
358 
359  pRT->CreateSolidColorBrush( D2D1::ColorF( it->r, it->g, it->b), &aBrush );
360 
361  D2D1_ELLIPSE ellipse;
362  ellipse.point.x = it->x;
363  ellipse.point.y = it->y;
364  ellipse.radiusX = it->radius;
365  ellipse.radiusY = it->radius;
366 
367  if( it->fill )
368  pRT->FillEllipse( &ellipse, aBrush );
369  else
370  pRT->DrawEllipse( &ellipse, aBrush );
371 
372  aBrush->Release();
373  }
374 
375  static const WCHAR msc_fontName[] = L"Verdana";
376  static const FLOAT msc_fontSize = 20;
377 
378  IDWriteTextFormat* textFormat = NULL;
379 
380  // Create a DirectWrite text format object.
381  pDWriteFactory->CreateTextFormat(
382  msc_fontName,
383  NULL,
384  DWRITE_FONT_WEIGHT_NORMAL,
385  DWRITE_FONT_STYLE_NORMAL,
386  DWRITE_FONT_STRETCH_NORMAL,
387  msc_fontSize,
388  L"", //locale
389  &textFormat
390  );
391 
392  D2D1_SIZE_F renderTargetSize = pRT->GetSize();
393 
394  Array<TextPlot>::Iterator textIt;
395  for( textIt = currentFrame->textLines.Begin(); textIt != currentFrame->textLines.End(); ++textIt )
396  {
397  ID2D1SolidColorBrush* aBrush;
398 
399  pRT->CreateSolidColorBrush( D2D1::ColorF( textIt->r, textIt->g, textIt->b), &aBrush );
400 
401  WCHAR* tmpString = (WCHAR*)calloc( textIt->text.GetLength(), sizeof( WCHAR ) );
402  for( unsigned i = 0; i < textIt->text.GetLength(); ++i )
403  {
404  tmpString[i] = (WCHAR)textIt->text.GetCharAt( i );
405  }
406 
407  pRT->DrawTextW( tmpString, (UINT32)textIt->text.GetLength(), textFormat,
408  D2D1::RectF(textIt->x, textIt->y, renderTargetSize.width, renderTargetSize.height), aBrush );
409 
410  free( tmpString );
411 
412  aBrush->Release();
413  }
414 
415  if( textFormat )
416  textFormat->Release();
417 
418  pRT->EndDraw();
419 
420  pRT->Flush();
421 }
422 
423 Ptr<Frame> ImageWindow::lastUnreadyFrame()
424 {
425  static int framenumber = 0;
426 
427  if( frames.GetSize() && !frames.PeekBack( 0 )->ready )
428  return frames.PeekBack( 0 );
429 
430  // Create a new frame if an unready one doesn't already exist
431  Ptr<Frame> tmpFrame = *new Frame( framenumber );
432  frames.PushBack( tmpFrame );
433 
434  ++framenumber;
435 
436  return tmpFrame;
437 }
438 
439 void ImageWindow::UpdateImageBW( const uint8_t* imageData, uint32_t width, uint32_t height )
440 {
441  if( pRT && greyBitmap )
442  {
443  Mutex::Locker locker( frontBufferMutex );
444 
445  Ptr<Frame> frame = lastUnreadyFrame();
446  frame->imageData = malloc( width * height );
447  frame->width = width;
448  frame->height = height;
449  memcpy( frame->imageData, imageData, width * height );
450  }
451 }
452 
453 void ImageWindow::UpdateImageRGBA( const uint8_t* imageData, uint32_t width, uint32_t height, uint32_t pitch )
454 {
455  if( pRT && colorBitmap )
456  {
457  Mutex::Locker locker( frontBufferMutex );
458 
459  Ptr<Frame> frame = lastUnreadyFrame();
460  frame->colorImageData = malloc( pitch * height );
461  frame->width = width;
462  frame->height = height;
463  frame->colorPitch = pitch;
464  memcpy( frame->colorImageData, imageData, pitch * height );
465  }
466 }
467 
468 void ImageWindow::addCircle( float x, float y, float radius, float r, float g, float b, bool fill )
469 {
470  if( pRT )
471  {
472  CirclePlot cp;
473 
474  cp.x = x;
475  cp.y = y;
476  cp.radius = radius;
477  cp.r = r;
478  cp.g = g;
479  cp.b = b;
480  cp.fill = fill;
481 
482  Mutex::Locker locker( frontBufferMutex );
483 
484  Ptr<Frame> frame = lastUnreadyFrame();
485  frame->plots.PushBack( cp );
486  }
487 
488 }
489 
490 void ImageWindow::addText( float x, float y, float r, float g, float b, OVR::String text )
491 {
492  if( pRT )
493  {
494  TextPlot tp;
495 
496  tp.x = x;
497  tp.y = y;
498  tp.r = r;
499  tp.g = g;
500  tp.b = b;
501  tp.text = text;
502 
503  Mutex::Locker locker( frontBufferMutex );
504  Ptr<Frame> frame = lastUnreadyFrame();
505  frame->textLines.PushBack( tp );
506  }
507 }
508 
509 }}
510 
511 #endif //defined(OVR_OS_WIN32)
#define NULL
__BEGIN_NAMESPACE_STD void * memcpy(void *__restrict __dest, const void *__restrict __src, size_t __n) __THROW __nonnull((1
static ImageWindow * globalWindow[4]