merge the formfield patch from ooo-build
[ooovba.git] / canvas / source / directx / dx_9rm.cxx
blobe61c7f8f7714bbfd8b59e3871263dbee499a658d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dx_9rm.cxx,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #if DIRECTX_VERSION == 0x0900
36 #define MAX_TEXTURE_SIZE (2048)
37 #define MIN_TEXTURE_SIZE (32)
38 //#define FAKE_MAX_NUMBER_TEXTURES (2)
39 //#define FAKE_MAX_TEXTURE_SIZE (4096)
41 #define VERTEX_BUFFER_SIZE (341*3) // 1023, the size of the internal
42 // vertex buffer (must be divisable
43 // by 3, as each triangle primitive
44 // has 3 vertices)
47 //////////////////////////////////////////////////////////////////////////////////
48 // includes
49 //////////////////////////////////////////////////////////////////////////////////
50 #include <vcl/syschild.hxx>
51 #include <vcl/window.hxx>
53 #include <canvas/debug.hxx>
54 #include <canvas/verbosetrace.hxx>
55 #include <tools/diagnose_ex.h>
56 #include <osl/thread.h>
58 #include <canvas/elapsedtime.hxx>
59 #include <canvas/canvastools.hxx>
60 #include <canvas/rendering/icolorbuffer.hxx>
61 #include <canvas/rendering/isurface.hxx>
62 #include <canvas/rendering/irendermodule.hxx>
63 #include <basegfx/numeric/ftools.hxx>
64 #include <basegfx/vector/b2dsize.hxx>
65 #include <basegfx/vector/b2isize.hxx>
66 #include <basegfx/point/b2ipoint.hxx>
67 #include <basegfx/range/b2irectangle.hxx>
68 #include <boost/scoped_ptr.hpp>
69 #include <com/sun/star/lang/NoSupportException.hpp>
71 #include "dx_rendermodule.hxx"
72 #include "dx_config.hxx"
74 #undef WB_LEFT
75 #undef WB_RIGHT
77 #include "dx_impltools.hxx"
78 #include <vcl/sysdata.hxx>
80 #if defined(DX_DEBUG_IMAGES)
81 # if OSL_DEBUG_LEVEL > 0
82 # include <imdebug.h>
83 # undef min
84 # undef max
85 # endif
86 #endif
88 using namespace ::com::sun::star;
90 //////////////////////////////////////////////////////////////////////////////////
91 // 'dxcanvas' namespace
92 //////////////////////////////////////////////////////////////////////////////////
94 namespace dxcanvas
96 namespace
98 //////////////////////////////////////////////////////////////////////////////////
99 // monitorSupport
100 //////////////////////////////////////////////////////////////////////////////////
102 class monitorSupport
104 public:
106 monitorSupport() :
107 mhLibrary(LoadLibrary("user32.dll")),
108 mpMonitorFromWindow(NULL)
110 if(mhLibrary)
111 mpMonitorFromWindow = reinterpret_cast<fMonitorFromWindow>(
112 GetProcAddress(
113 mhLibrary,"MonitorFromWindow"));
116 ~monitorSupport()
118 if(mhLibrary)
119 FreeLibrary(mhLibrary);
120 mhLibrary=0;
123 HMONITOR MonitorFromWindow( HWND hwnd )
125 // return adapter_default in case something went wrong...
126 if(!(mpMonitorFromWindow))
127 return HMONITOR(0);
128 // MONITOR_DEFAULTTONEAREST
129 const DWORD dwFlags(0x00000002);
130 return mpMonitorFromWindow(hwnd,dwFlags);
132 private:
134 HINSTANCE mhLibrary;
135 typedef HMONITOR (WINAPI *fMonitorFromWindow )( HWND hwnd, DWORD dwFlags );
136 fMonitorFromWindow mpMonitorFromWindow;
139 monitorSupport aMonitorSupport;
142 class DXRenderModule;
144 //////////////////////////////////////////////////////////////////////////////////
145 // DXSurface
146 //////////////////////////////////////////////////////////////////////////////////
148 /** ISurface implemenation.
150 @attention holds the DXRenderModule via non-refcounted
151 reference! This is safe with current state of affairs, since
152 the canvas::PageManager holds surface and render module via
153 shared_ptr (and makes sure all surfaces are deleted before its
154 render module member goes out of scope).
156 class DXSurface : public canvas::ISurface
158 public:
159 DXSurface( DXRenderModule& rRenderModule,
160 const ::basegfx::B2ISize& rSize );
161 ~DXSurface();
163 virtual bool selectTexture();
164 virtual bool isValid();
165 virtual bool update( const ::basegfx::B2IPoint& rDestPos,
166 const ::basegfx::B2IRange& rSourceRect,
167 ::canvas::IColorBuffer& rSource );
168 virtual ::basegfx::B2IVector getSize();
169 COMReference<IDirect3DTexture9> getTexture() const;
171 private:
172 /// Guard local methods against concurrent acces to RenderModule
173 class ImplRenderModuleGuard : private ::boost::noncopyable
175 public:
176 explicit inline ImplRenderModuleGuard( DXRenderModule& rRenderModule );
177 inline ~ImplRenderModuleGuard();
179 private:
180 DXRenderModule& mrRenderModule;
183 DXRenderModule& mrRenderModule;
184 COMReference<IDirect3DTexture9> mpTexture;
186 ::basegfx::B2IVector maSize;
190 //////////////////////////////////////////////////////////////////////////////////
191 // DXRenderModule
192 //////////////////////////////////////////////////////////////////////////////////
194 /// Default implementation of IDXRenderModule
195 class DXRenderModule : public IDXRenderModule
197 public:
198 explicit DXRenderModule( const ::Window& rWindow );
199 ~DXRenderModule();
201 virtual void lock() const { maMutex.acquire(); }
202 virtual void unlock() const { maMutex.release(); }
204 virtual COMReference<IDirect3DSurface9>
205 createSystemMemorySurface( const ::basegfx::B2IVector& rSize );
206 virtual void disposing();
207 virtual HWND getHWND() const { return mhWnd; }
208 virtual void screenShot();
210 virtual bool flip( const ::basegfx::B2IRectangle& rUpdateArea,
211 const ::basegfx::B2IRectangle& rCurrWindowArea );
213 virtual void resize( const ::basegfx::B2IRange& rect );
214 virtual ::basegfx::B2IVector getPageSize();
215 virtual ::canvas::ISurfaceSharedPtr createSurface( const ::basegfx::B2IVector& surfaceSize );
216 virtual void beginPrimitive( PrimitiveType eType );
217 virtual void endPrimitive();
218 virtual void pushVertex( const ::canvas::Vertex& vertex );
219 virtual bool isError();
221 COMReference<IDirect3DDevice9> getDevice() { return mpDevice; }
223 void flushVertexCache();
224 void commitVertexCache();
226 private:
228 bool create( const ::Window& rWindow );
229 bool createDevice();
230 bool verifyDevice( const UINT nAdapter );
231 UINT getAdapterFromWindow();
233 /** This object represents the DirectX state machine. In order
234 to serialize access to DirectX's global state, a global
235 mutex is required.
237 static ::osl::Mutex maMutex;
239 HWND mhWnd;
240 COMReference<IDirect3DDevice9> mpDevice;
241 COMReference<IDirect3D9> mpDirect3D9;
242 COMReference<IDirect3DSwapChain9> mpSwapChain;
243 COMReference<IDirect3DVertexBuffer9> mpVertexBuffer;
244 ::canvas::ISurfaceSharedPtr mpTexture;
245 ::boost::scoped_ptr<SystemChildWindow> mpWindow;
246 ::basegfx::B2IVector maSize;
247 typedef std::vector<canvas::Vertex> vertexCache_t;
248 vertexCache_t maVertexCache;
249 std::size_t mnCount;
250 int mnBeginSceneCount;
251 bool mbCanUseDynamicTextures;
252 bool mbError;
253 PrimitiveType meType;
254 ::basegfx::B2IVector maPageSize;
255 D3DPRESENT_PARAMETERS mad3dpp;
257 inline bool isDisposed() const { return (mhWnd==NULL); }
259 struct dxvertex
261 float x,y,z,rhw;
262 DWORD diffuse;
263 float u,v;
266 std::size_t maNumVertices;
267 std::size_t maWriteIndex;
268 std::size_t maReadIndex;
271 ::osl::Mutex DXRenderModule::maMutex;
273 //////////////////////////////////////////////////////////////////////////////////
274 // DXSurface::ImplRenderModuleGuard
275 //////////////////////////////////////////////////////////////////////////////////
277 inline DXSurface::ImplRenderModuleGuard::ImplRenderModuleGuard(
278 DXRenderModule& rRenderModule ) :
279 mrRenderModule( rRenderModule )
281 mrRenderModule.lock();
284 inline DXSurface::ImplRenderModuleGuard::~ImplRenderModuleGuard()
286 mrRenderModule.unlock();
289 #ifdef FAKE_MAX_NUMBER_TEXTURES
290 static sal_uInt32 gNumSurfaces = 0;
291 #endif
293 void fillRect( sal_uInt32 *pDest,
294 sal_uInt32 dwWidth,
295 sal_uInt32 dwHeight,
296 sal_uInt32 dwPitch,
297 sal_uInt32 dwColor )
299 for(sal_uInt32 i=0; i<dwWidth; ++i)
301 pDest[i]=dwColor;
302 pDest[((dwHeight-1)*dwPitch)+i]=dwColor;
305 for(sal_uInt32 j=0; j<dwHeight; ++j)
307 pDest[0]=dwColor;
308 pDest[dwWidth-1]=dwColor;
309 pDest += dwPitch;
313 //////////////////////////////////////////////////////////////////////////////////
314 // DXSurface::DXSurface
315 //////////////////////////////////////////////////////////////////////////////////
317 DXSurface::DXSurface( DXRenderModule& rRenderModule,
318 const ::basegfx::B2ISize& rSize ) :
319 mrRenderModule(rRenderModule),
320 mpTexture(NULL),
321 maSize()
323 ImplRenderModuleGuard aGuard( mrRenderModule );
325 #ifdef FAKE_MAX_NUMBER_TEXTURES
326 ++gNumSurfaces;
327 if(gNumSurfaces >= FAKE_MAX_NUMBER_TEXTURES)
328 return;
329 #endif
331 #ifdef FAKE_MAX_TEXTURE_SIZE
332 if(rSize.getX() > FAKE_MAX_TEXTURE_SIZE)
333 return;
334 if(rSize.getY() > FAKE_MAX_TEXTURE_SIZE)
335 return;
336 #endif
338 ENSURE_ARG_OR_THROW(rSize.getX() > 0 && rSize.getY() > 0,
339 "DXSurface::DXSurface(): request for zero-sized surface");
341 COMReference<IDirect3DDevice9> pDevice(rRenderModule.getDevice());
343 IDirect3DTexture9 *pTexture(NULL);
344 if(FAILED(pDevice->CreateTexture(
345 rSize.getX(),
346 rSize.getY(),
347 1,0,D3DFMT_A8R8G8B8,
348 D3DPOOL_MANAGED,
349 &pTexture,NULL)))
350 return;
352 mpTexture=COMReference<IDirect3DTexture9>(pTexture);
353 maSize = rSize;
356 //////////////////////////////////////////////////////////////////////////////////
357 // DXSurface::~DXSurface
358 //////////////////////////////////////////////////////////////////////////////////
360 DXSurface::~DXSurface()
362 ImplRenderModuleGuard aGuard( mrRenderModule );
364 #ifdef FAKE_MAX_NUMBER_TEXTURES
365 gNumSurfaces--;
366 #endif
369 //////////////////////////////////////////////////////////////////////////////////
370 // DXSurface::selectTexture
371 //////////////////////////////////////////////////////////////////////////////////
373 bool DXSurface::selectTexture()
375 ImplRenderModuleGuard aGuard( mrRenderModule );
376 mrRenderModule.flushVertexCache();
377 COMReference<IDirect3DDevice9> pDevice(mrRenderModule.getDevice());
379 if( FAILED(pDevice->SetTexture(0,mpTexture.get())) )
380 return false;
382 return true;
385 //////////////////////////////////////////////////////////////////////////////////
386 // DXSurface::isValid
387 //////////////////////////////////////////////////////////////////////////////////
389 bool DXSurface::isValid()
391 ImplRenderModuleGuard aGuard( mrRenderModule );
393 if(!(mpTexture.is()))
394 return false;
395 return true;
398 //////////////////////////////////////////////////////////////////////////////////
399 // DXSurface::update
400 //////////////////////////////////////////////////////////////////////////////////
402 bool DXSurface::update( const ::basegfx::B2IPoint& rDestPos,
403 const ::basegfx::B2IRange& rSourceRect,
404 ::canvas::IColorBuffer& rSource )
406 ImplRenderModuleGuard aGuard( mrRenderModule );
408 // can't update if surface is not valid, that means
409 // either not existent nor restored...
410 if(!(isValid()))
411 return false;
413 D3DLOCKED_RECT aLockedRect;
414 RECT rect;
415 rect.left = std::max(sal_Int32(0),rDestPos.getX());
416 rect.top = std::max(sal_Int32(0),rDestPos.getY());
417 // to avoid interpolation artifacts from other textures,
418 // the surface manager allocates one pixel gap between
419 // them. Clear that to transparent.
420 rect.right = std::min(maSize.getX(),
421 rect.left + sal_Int32(rSourceRect.getWidth()+1));
422 rect.bottom = std::min(maSize.getY(),
423 rect.top + sal_Int32(rSourceRect.getHeight()+1));
424 const bool bClearRightColumn( rect.right < maSize.getX() );
425 const bool bClearBottomRow( rect.bottom < maSize.getY() );
427 if(SUCCEEDED(mpTexture->LockRect(0,&aLockedRect,&rect,D3DLOCK_NOSYSLOCK)))
429 if(sal_uInt8* pImage = rSource.lock())
431 switch( rSource.getFormat() )
433 case ::canvas::IColorBuffer::FMT_A8R8G8B8:
435 const std::size_t nSourceBytesPerPixel(4);
436 const std::size_t nSourcePitchInBytes(rSource.getStride());
437 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
438 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
440 // calculate the destination memory address
441 sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
443 const sal_uInt32 nNumBytesToCopy(
444 static_cast<sal_uInt32>(
445 rSourceRect.getWidth())*
446 nSourceBytesPerPixel);
447 const sal_uInt64 nNumLines(rSourceRect.getHeight());
449 for(sal_uInt32 i=0; i<nNumLines; ++i)
451 rtl_copyMemory(pDst,pImage,nNumBytesToCopy);
453 if( bClearRightColumn )
455 // to avoid interpolation artifacts
456 // from other textures, the surface
457 // manager allocates one pixel gap
458 // between them. Clear that to
459 // transparent.
460 pDst[nNumBytesToCopy] =
461 pDst[nNumBytesToCopy+1] =
462 pDst[nNumBytesToCopy+2] =
463 pDst[nNumBytesToCopy+3] = 0x00;
465 pDst += aLockedRect.Pitch;
466 pImage += nSourcePitchInBytes;
469 if( bClearBottomRow )
470 rtl_zeroMemory(pDst,nNumBytesToCopy+4);
472 break;
474 case ::canvas::IColorBuffer::FMT_R8G8B8:
476 const std::size_t nSourceBytesPerPixel(3);
477 const std::size_t nSourcePitchInBytes(rSource.getStride());
478 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
479 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
481 // calculate the destination memory address
482 sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
484 const sal_Int32 nNumColumns(
485 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
486 const sal_Int32 nNumLines(
487 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
488 for(sal_Int32 i=0; i<nNumLines; ++i)
490 sal_uInt32 *pDstScanline = reinterpret_cast<sal_uInt32 *>(pDst);
491 sal_uInt8 *pSrcScanline = reinterpret_cast<sal_uInt8 *>(pImage);
493 for(sal_Int32 x=0; x<nNumColumns; ++x)
495 sal_uInt32 color(0xFF000000);
496 color |= pSrcScanline[2]<<16;
497 color |= pSrcScanline[1]<<8;
498 color |= pSrcScanline[0];
499 pSrcScanline += 3;
500 *pDstScanline++ = color;
502 if( bClearRightColumn )
503 *pDstScanline++ = 0xFF000000;
505 pDst += aLockedRect.Pitch;
506 pImage += nSourcePitchInBytes;
509 if( bClearBottomRow )
510 rtl_zeroMemory(pDst,4*(nNumColumns+1));
512 break;
514 case ::canvas::IColorBuffer::FMT_X8R8G8B8:
516 const std::size_t nSourceBytesPerPixel(4);
517 const std::size_t nSourcePitchInBytes(rSource.getStride());
518 pImage += rSourceRect.getMinY()*nSourcePitchInBytes;
519 pImage += rSourceRect.getMinX()*nSourceBytesPerPixel;
521 // calculate the destination memory address
522 sal_uInt8 *pDst = (sal_uInt8*)aLockedRect.pBits;
524 const sal_Int32 nNumLines(
525 sal::static_int_cast<sal_Int32>(rSourceRect.getHeight()));
526 const sal_Int32 nNumColumns(
527 sal::static_int_cast<sal_Int32>(rSourceRect.getWidth()));
528 for(sal_Int32 i=0; i<nNumLines; ++i)
530 sal_uInt32 *pSrc32 = reinterpret_cast<sal_uInt32 *>(pImage);
531 sal_uInt32 *pDst32 = reinterpret_cast<sal_uInt32 *>(pDst);
532 for(sal_Int32 j=0; j<nNumColumns; ++j)
533 pDst32[j] = 0xFF000000 | pSrc32[j];
535 if( bClearRightColumn )
536 pDst32[nNumColumns] = 0xFF000000;
538 pDst += aLockedRect.Pitch;
539 pImage += nSourcePitchInBytes;
542 if( bClearBottomRow )
543 rtl_zeroMemory(pDst,4*(nNumColumns+1));
545 break;
547 default:
548 ENSURE_OR_RETURN(false,
549 "DXSurface::update(): Unknown/unimplemented buffer format" );
550 break;
553 rSource.unlock();
556 return SUCCEEDED(mpTexture->UnlockRect(0));
559 return true;
562 //////////////////////////////////////////////////////////////////////////////////
563 // DXSurface::getSize
564 //////////////////////////////////////////////////////////////////////////////////
566 ::basegfx::B2IVector DXSurface::getSize()
568 return maSize;
571 COMReference<IDirect3DTexture9> DXSurface::getTexture() const
573 return mpTexture;
576 //////////////////////////////////////////////////////////////////////////////////
577 // DXRenderModule::DXRenderModule
578 //////////////////////////////////////////////////////////////////////////////////
580 DXRenderModule::DXRenderModule( const ::Window& rWindow ) :
581 mhWnd(0),
582 mpDevice(),
583 mpDirect3D9(),
584 mpSwapChain(),
585 mpVertexBuffer(),
586 mpTexture(),
587 maSize(),
588 maVertexCache(),
589 mnCount(0),
590 mnBeginSceneCount(0),
591 mbCanUseDynamicTextures(false),
592 mbError( false ),
593 meType( PRIMITIVE_TYPE_UNKNOWN ),
594 maPageSize(),
595 mad3dpp(),
596 maNumVertices( VERTEX_BUFFER_SIZE ),
597 maWriteIndex(0),
598 maReadIndex(0)
600 // TODO(P2): get rid of those fine-grained locking
601 ::osl::MutexGuard aGuard( maMutex );
603 if(!(create(rWindow)))
605 throw lang::NoSupportException(
606 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
607 "Could not create DirectX device!") ),NULL);
610 // allocate a single texture surface which can be used later.
611 // we also use this to calibrate the page size.
612 ::basegfx::B2IVector aPageSize(maPageSize);
613 while(true)
615 mpTexture = ::canvas::ISurfaceSharedPtr(
616 new DXSurface(*this,aPageSize));
617 if(mpTexture->isValid())
618 break;
620 aPageSize.setX(aPageSize.getX()>>1);
621 aPageSize.setY(aPageSize.getY()>>1);
622 if((aPageSize.getX() < MIN_TEXTURE_SIZE) ||
623 (aPageSize.getY() < MIN_TEXTURE_SIZE))
625 throw lang::NoSupportException(
626 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
627 "Could not create DirectX device - "
628 "insufficient texture space!") ),NULL);
631 maPageSize=aPageSize;
633 IDirect3DVertexBuffer9 *pVB(NULL);
634 DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
635 if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
636 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
637 aFVF,
638 D3DPOOL_DEFAULT,
639 &pVB,
640 NULL)) )
642 throw lang::NoSupportException(
643 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
644 "Could not create DirectX device - out of memory!")),NULL);
647 mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
650 //////////////////////////////////////////////////////////////////////////////////
651 // DXRenderModule::~DXRenderModule
652 //////////////////////////////////////////////////////////////////////////////////
654 DXRenderModule::~DXRenderModule()
656 disposing();
659 //////////////////////////////////////////////////////////////////////////////////
660 // DXRenderModule::disposing
661 //////////////////////////////////////////////////////////////////////////////////
663 void DXRenderModule::disposing()
665 if(!(mhWnd))
666 return;
668 mpTexture.reset();
669 mpWindow.reset();
670 mhWnd=NULL;
672 // refrain from releasing the DX9 objects. We're the only
673 // ones holding references to them, and it might be
674 // dangerous to destroy the DX9 device, before all other
675 // objects are dead.
678 //////////////////////////////////////////////////////////////////////////////////
679 // DXRenderModule::create
680 //////////////////////////////////////////////////////////////////////////////////
682 bool DXRenderModule::create( const ::Window& rWindow )
684 // TODO(P2): get rid of those fine-grained locking
685 ::osl::MutexGuard aGuard( maMutex );
687 maVertexCache.reserve(1024);
689 mpWindow.reset(
690 new SystemChildWindow(
691 const_cast<Window *>(&rWindow), 0) );
693 // system child window must not receive mouse events
694 mpWindow->SetMouseTransparent( TRUE );
696 // parent should receive paint messages as well
697 // [PARENTCLIPMODE_NOCLIP], the argument is here
698 // passed as plain numeric value since the stupid
699 // define utilizes a USHORT cast.
700 mpWindow->SetParentClipMode(0x0002);
702 // the system child window must not clear its background
703 mpWindow->EnableEraseBackground( FALSE );
705 mpWindow->SetControlForeground();
706 mpWindow->SetControlBackground();
707 mpWindow->EnablePaint(FALSE);
709 const SystemEnvData *pData = mpWindow->GetSystemData();
710 const HWND hwnd(reinterpret_cast<HWND>(pData->hWnd));
711 mhWnd = const_cast<HWND>(hwnd);
713 ENSURE_OR_THROW( IsWindow( reinterpret_cast<HWND>(mhWnd) ),
714 "DXRenderModule::create() No valid HWND given." );
716 // retrieve position and size of the parent window
717 const ::Size &rSizePixel(rWindow.GetSizePixel());
719 // remember the size of the parent window, since we
720 // need to use this for our child window.
721 maSize.setX(static_cast<sal_Int32>(rSizePixel.Width()));
722 maSize.setY(static_cast<sal_Int32>(rSizePixel.Height()));
724 // let the child window cover the same size as the parent window.
725 mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
727 // TODO(F2): since we would like to share precious hardware
728 // resources, the direct3d9 object should be global. each new
729 // request for a canvas should only create a new swapchain.
730 mpDirect3D9 = COMReference<IDirect3D9>(
731 Direct3DCreate9(D3D_SDK_VERSION));
732 if(!mpDirect3D9.is())
733 return false;
735 // create a device from the direct3d9 object.
736 if(!(createDevice()))
737 return false;
739 mpWindow->Show();
741 return true;
744 //////////////////////////////////////////////////////////////////////////////////
745 // DXRenderModule::verifyDevice
746 //////////////////////////////////////////////////////////////////////////////////
748 bool DXRenderModule::verifyDevice( const UINT nAdapter )
750 ENSURE_OR_THROW( mpDirect3D9.is(),
751 "DXRenderModule::verifyDevice() No valid device." );
753 // ask direct3d9 about the capabilities of hardware devices on a specific adapter.
754 // here we decide if the underlying hardware of the machine 'is good enough'.
755 // since we only need a tiny little fraction of what could be used, this
756 // is basically a no-op.
757 D3DCAPS9 aCaps;
758 if(FAILED(mpDirect3D9->GetDeviceCaps(nAdapter,D3DDEVTYPE_HAL,&aCaps)))
759 return false;
760 if(!(aCaps.MaxTextureWidth))
761 return false;
762 if(!(aCaps.MaxTextureHeight))
763 return false;
764 maPageSize = ::basegfx::B2IVector(aCaps.MaxTextureWidth,aCaps.MaxTextureHeight);
766 // check device against white & blacklist entries
767 D3DADAPTER_IDENTIFIER9 aIdent;
768 if(FAILED(mpDirect3D9->GetAdapterIdentifier(nAdapter,0,&aIdent)))
769 return false;
771 DXCanvasItem aConfigItem;
772 DXCanvasItem::DeviceInfo aInfo;
773 aInfo.nVendorId = aIdent.VendorId;
774 aInfo.nDeviceId = aIdent.DeviceId;
775 aInfo.nDeviceSubSysId = aIdent.SubSysId;
776 aInfo.nDeviceRevision = aIdent.Revision;
778 aInfo.nDriverId = HIWORD(aIdent.DriverVersion.HighPart);
779 aInfo.nDriverVersion = LOWORD(aIdent.DriverVersion.HighPart);
780 aInfo.nDriverSubVersion = HIWORD(aIdent.DriverVersion.LowPart);
781 aInfo.nDriverBuildId = LOWORD(aIdent.DriverVersion.LowPart);
783 if( !aConfigItem.isDeviceUsable(aInfo) )
784 return false;
786 if( aConfigItem.isBlacklistCurrentDevice() )
788 aConfigItem.blacklistDevice(aInfo);
789 return false;
792 aConfigItem.adaptMaxTextureSize(maPageSize);
794 mbCanUseDynamicTextures = (aCaps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0;
796 return true;
800 //////////////////////////////////////////////////////////////////////////////////
801 // DXRenderModule::createDevice
802 //////////////////////////////////////////////////////////////////////////////////
804 bool DXRenderModule::createDevice()
806 // we expect that the caller provides us with a valid HWND
807 ENSURE_OR_THROW( IsWindow(mhWnd),
808 "DXRenderModule::createDevice() No valid HWND given." );
810 // we expect that the caller already created the direct3d9 object.
811 ENSURE_OR_THROW( mpDirect3D9.is(),
812 "DXRenderModule::createDevice() no direct3d?." );
814 // find the adapter identifier from the window.
815 const UINT aAdapter(getAdapterFromWindow());
816 if(aAdapter == static_cast<UINT>(-1))
817 return false;
819 // verify that device possibly works
820 if( !verifyDevice(aAdapter) )
821 return false;
823 // query the display mode from the selected adapter.
824 // we'll later request the backbuffer format to be same
825 // same as the display format.
826 D3DDISPLAYMODE d3ddm;
827 mpDirect3D9->GetAdapterDisplayMode(aAdapter,&d3ddm);
829 // we need to use D3DSWAPEFFECT_COPY here since the canvas-api has
830 // basically nothing to do with efficient resource handling. it tries
831 // to avoid drawing whenevery possible, which is simply not the most
832 // efficient way we could leverage the hardware in this case. it would
833 // be far better to redraw the backbuffer each time we would like to
834 // display the content of the backbuffer, but we need to face reality
835 // here and follow how the canvas was designed.
837 // Strictly speaking, we don't need a full screen worth of
838 // backbuffer here. We could also scale dynamically with
839 // the current window size, but this will make it
840 // necessary to temporarily have two buffers while copying
841 // from the old to the new one. What's more, at the time
842 // we need a larger buffer, DX might not have sufficient
843 // resources available, and we're then left with too small
844 // a back buffer, and no way of falling back to a
845 // different canvas implementation.
846 ZeroMemory( &mad3dpp, sizeof(mad3dpp) );
847 mad3dpp.BackBufferWidth = std::max(sal_Int32(maSize.getX()),
848 sal_Int32(d3ddm.Width));
849 mad3dpp.BackBufferHeight = std::max(sal_Int32(maSize.getY()),
850 sal_Int32(d3ddm.Height));
851 mad3dpp.BackBufferCount = 1;
852 mad3dpp.Windowed = TRUE;
853 mad3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
854 mad3dpp.BackBufferFormat = d3ddm.Format;
855 mad3dpp.EnableAutoDepthStencil = FALSE;
856 mad3dpp.hDeviceWindow = mhWnd;
857 mad3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
859 // now create the device, first try hardware vertex processing,
860 // then software vertex processing. if both queries fail, we give up
861 // and indicate failure.
862 IDirect3DDevice9 *pDevice(NULL);
863 if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
864 D3DDEVTYPE_HAL,
865 mhWnd,
866 D3DCREATE_HARDWARE_VERTEXPROCESSING|
867 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
868 &mad3dpp,
869 &pDevice)))
870 if(FAILED(mpDirect3D9->CreateDevice(aAdapter,
871 D3DDEVTYPE_HAL,
872 mhWnd,
873 D3DCREATE_SOFTWARE_VERTEXPROCESSING|
874 D3DCREATE_MULTITHREADED|D3DCREATE_FPU_PRESERVE,
875 &mad3dpp,
876 &pDevice)))
877 return false;
879 // got it, store it in a safe place...
880 mpDevice=COMReference<IDirect3DDevice9>(pDevice);
882 // After CreateDevice, the first swap chain already exists, so just get it...
883 IDirect3DSwapChain9 *pSwapChain(NULL);
884 pDevice->GetSwapChain(0,&pSwapChain);
885 mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
886 if( !mpSwapChain.is() )
887 return false;
889 // clear the render target [which is the backbuffer in this case].
890 // we are forced to do this once, and furthermore right now.
891 // please note that this is only possible since we created the
892 // backbuffer with copy semantics [the content is preserved after
893 // calls to Present()], which is an unnecessarily expensive operation.
894 LPDIRECT3DSURFACE9 pBackBuffer = NULL;
895 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
896 mpDevice->SetRenderTarget( 0, pBackBuffer );
897 mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
898 pBackBuffer->Release();
900 return true;
903 //////////////////////////////////////////////////////////////////////////////////
904 // DXRenderModule::createSystemMemorySurface
905 //////////////////////////////////////////////////////////////////////////////////
907 COMReference<IDirect3DSurface9> DXRenderModule::createSystemMemorySurface( const ::basegfx::B2IVector& rSize )
909 if(isDisposed())
910 return COMReference<IDirect3DSurface9>(NULL);
912 // please note that D3DFMT_X8R8G8B8 is the only format we're
913 // able to choose here, since GetDC() doesn't support any
914 // other 32bit-format.
915 IDirect3DSurface9 *pSurface(NULL);
916 if( FAILED(mpDevice->CreateOffscreenPlainSurface(
917 rSize.getX(),
918 rSize.getY(),
919 D3DFMT_X8R8G8B8,
920 D3DPOOL_SYSTEMMEM,
921 &pSurface,
922 NULL)) )
924 throw lang::NoSupportException(
925 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
926 "Could not create offscreen surface - out of mem!") ),NULL);
929 return COMReference<IDirect3DSurface9>(pSurface);
932 //////////////////////////////////////////////////////////////////////////////////
933 // DXRenderModule::flip
934 //////////////////////////////////////////////////////////////////////////////////
936 bool DXRenderModule::flip( const ::basegfx::B2IRectangle& rUpdateArea,
937 const ::basegfx::B2IRectangle& /*rCurrWindowArea*/ )
939 // TODO(P2): get rid of those fine-grained locking
940 ::osl::MutexGuard aGuard( maMutex );
942 if(isDisposed() || !mpSwapChain.is())
943 return false;
945 flushVertexCache();
947 // TODO(P2): Might be faster to actually pass update area here
948 RECT aRect =
950 rUpdateArea.getMinX(),
951 rUpdateArea.getMinY(),
952 rUpdateArea.getMaxX(),
953 rUpdateArea.getMaxY()
955 HRESULT hr(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0));
956 if(FAILED(hr))
958 if(hr != D3DERR_DEVICELOST)
959 return false;
961 // interestingly enough, sometimes the Reset() below
962 // *still* causes DeviceLost errors. So, cycle until
963 // DX was kind enough to really reset the device...
966 mpVertexBuffer.reset();
967 hr = mpDevice->Reset(&mad3dpp);
968 if(SUCCEEDED(hr))
970 IDirect3DVertexBuffer9 *pVB(NULL);
971 DWORD aFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1);
972 if( FAILED(mpDevice->CreateVertexBuffer(sizeof(dxvertex)*maNumVertices,
973 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
974 aFVF,
975 D3DPOOL_DEFAULT,
976 &pVB,
977 NULL)) )
979 throw lang::NoSupportException(
980 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
981 "Could not create DirectX device - out of memory!")),NULL);
983 mpVertexBuffer=COMReference<IDirect3DVertexBuffer9>(pVB);
985 // retry after the restore
986 if(SUCCEEDED(mpSwapChain->Present(&aRect,&aRect,NULL,NULL,0)))
987 return true;
990 TimeValue aTimeout;
991 aTimeout.Seconds=1;
992 aTimeout.Nanosec=0;
993 osl_waitThread(&aTimeout);
995 while(hr == D3DERR_DEVICELOST);
997 return false;
1000 return true;
1003 //////////////////////////////////////////////////////////////////////////////////
1004 // DXRenderModule::screenShot
1005 //////////////////////////////////////////////////////////////////////////////////
1007 void DXRenderModule::screenShot()
1011 //////////////////////////////////////////////////////////////////////////////////
1012 // DXRenderModule::resize
1013 //////////////////////////////////////////////////////////////////////////////////
1015 void DXRenderModule::resize( const ::basegfx::B2IRange& rect )
1017 // TODO(P2): get rid of those fine-grained locking
1018 ::osl::MutexGuard aGuard( maMutex );
1020 if(isDisposed())
1021 return;
1023 // don't do anything if the size didn't change.
1024 if(maSize.getX() == static_cast<sal_Int32>(rect.getWidth()) &&
1025 maSize.getY() == static_cast<sal_Int32>(rect.getHeight()))
1026 return;
1028 // TODO(Q2): use numeric cast to prevent overflow
1029 maSize.setX(static_cast<sal_Int32>(rect.getWidth()));
1030 maSize.setY(static_cast<sal_Int32>(rect.getHeight()));
1032 mpWindow->SetPosSizePixel(0,0,maSize.getX(),maSize.getY());
1034 // resize back buffer, if necessary
1035 // -------------------------------------------------------------
1037 // don't attempt to create anything if the
1038 // requested size is NULL.
1039 if(!(maSize.getX()))
1040 return;
1041 if(!(maSize.getY()))
1042 return;
1044 // backbuffer too small (might happen, if window is
1045 // maximized across multiple monitors)
1046 if( sal_Int32(mad3dpp.BackBufferWidth) < maSize.getX() ||
1047 sal_Int32(mad3dpp.BackBufferHeight) < maSize.getY() )
1049 mad3dpp.BackBufferWidth = maSize.getX();
1050 mad3dpp.BackBufferHeight = maSize.getY();
1052 // clear before, save resources
1053 mpSwapChain.reset();
1055 IDirect3DSwapChain9 *pSwapChain(NULL);
1056 if(FAILED(mpDevice->CreateAdditionalSwapChain(&mad3dpp,&pSwapChain)))
1057 return;
1058 mpSwapChain=COMReference<IDirect3DSwapChain9>(pSwapChain);
1060 // clear the render target [which is the backbuffer in this case].
1061 // we are forced to do this once, and furthermore right now.
1062 // please note that this is only possible since we created the
1063 // backbuffer with copy semantics [the content is preserved after
1064 // calls to Present()], which is an unnecessarily expensive operation.
1065 LPDIRECT3DSURFACE9 pBackBuffer = NULL;
1066 mpSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBackBuffer);
1067 mpDevice->SetRenderTarget( 0, pBackBuffer );
1068 mpDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0L);
1069 pBackBuffer->Release();
1073 //////////////////////////////////////////////////////////////////////////////////
1074 // DXRenderModule::getPageSize
1075 //////////////////////////////////////////////////////////////////////////////////
1077 ::basegfx::B2IVector DXRenderModule::getPageSize()
1079 // TODO(P2): get rid of those fine-grained locking
1080 ::osl::MutexGuard aGuard( maMutex );
1081 return maPageSize;
1084 //////////////////////////////////////////////////////////////////////////////////
1085 // DXRenderModule::createSurface
1086 //////////////////////////////////////////////////////////////////////////////////
1088 ::canvas::ISurfaceSharedPtr DXRenderModule::createSurface( const ::basegfx::B2IVector& surfaceSize )
1090 // TODO(P2): get rid of those fine-grained locking
1091 ::osl::MutexGuard aGuard( maMutex );
1093 if(isDisposed())
1094 return ::canvas::ISurfaceSharedPtr();
1096 const ::basegfx::B2IVector& rPageSize( getPageSize() );
1097 ::basegfx::B2ISize aSize(surfaceSize);
1098 if(!(aSize.getX()))
1099 aSize.setX(rPageSize.getX());
1100 if(!(aSize.getY()))
1101 aSize.setY(rPageSize.getY());
1103 if(mpTexture.use_count() == 1)
1104 return mpTexture;
1106 return ::canvas::ISurfaceSharedPtr( new DXSurface(*this,aSize) );
1109 //////////////////////////////////////////////////////////////////////////////////
1110 // DXRenderModule::beginPrimitive
1111 //////////////////////////////////////////////////////////////////////////////////
1113 void DXRenderModule::beginPrimitive( PrimitiveType eType )
1115 // TODO(P2): get rid of those fine-grained locking
1116 ::osl::MutexGuard aGuard( maMutex );
1118 if(isDisposed())
1119 return;
1121 ENSURE_OR_THROW( !mnBeginSceneCount,
1122 "DXRenderModule::beginPrimitive(): nested call" );
1124 ++mnBeginSceneCount;
1125 meType=eType;
1126 mnCount=0;
1129 //////////////////////////////////////////////////////////////////////////////////
1130 // DXRenderModule::endPrimitive
1131 //////////////////////////////////////////////////////////////////////////////////
1133 void DXRenderModule::endPrimitive()
1135 // TODO(P2): get rid of those fine-grained locking
1136 ::osl::MutexGuard aGuard( maMutex );
1138 if(isDisposed())
1139 return;
1141 --mnBeginSceneCount;
1142 meType=PRIMITIVE_TYPE_UNKNOWN;
1143 mnCount=0;
1146 //////////////////////////////////////////////////////////////////////////////////
1147 // DXRenderModule::pushVertex
1148 //////////////////////////////////////////////////////////////////////////////////
1150 void DXRenderModule::pushVertex( const ::canvas::Vertex& vertex )
1152 // TODO(P2): get rid of those fine-grained locking
1153 ::osl::MutexGuard aGuard( maMutex );
1155 if(isDisposed())
1156 return;
1158 switch(meType)
1160 case PRIMITIVE_TYPE_TRIANGLE:
1162 maVertexCache.push_back(vertex);
1163 ++mnCount;
1164 mnCount &= 3;
1165 break;
1168 case PRIMITIVE_TYPE_QUAD:
1170 if(mnCount == 3)
1172 const std::size_t size(maVertexCache.size());
1173 ::canvas::Vertex v0(maVertexCache[size-1]);
1174 ::canvas::Vertex v2(maVertexCache[size-3]);
1175 maVertexCache.push_back(v0);
1176 maVertexCache.push_back(vertex);
1177 maVertexCache.push_back(v2);
1178 mnCount=0;
1180 else
1182 maVertexCache.push_back(vertex);
1183 ++mnCount;
1185 break;
1188 default:
1189 OSL_ENSURE(false,
1190 "DXRenderModule::pushVertex(): unexpected primitive type");
1191 break;
1195 //////////////////////////////////////////////////////////////////////////////////
1196 // DXRenderModule::isError
1197 //////////////////////////////////////////////////////////////////////////////////
1199 bool DXRenderModule::isError()
1201 // TODO(P2): get rid of those fine-grained locking
1202 ::osl::MutexGuard aGuard( maMutex );
1204 return mbError;
1207 //////////////////////////////////////////////////////////////////////////////////
1208 // DXRenderModule::getAdapterFromWindow
1209 //////////////////////////////////////////////////////////////////////////////////
1211 UINT DXRenderModule::getAdapterFromWindow()
1213 HMONITOR hMonitor(aMonitorSupport.MonitorFromWindow(mhWnd));
1214 UINT aAdapterCount(mpDirect3D9->GetAdapterCount());
1215 for(UINT i=0; i<aAdapterCount; ++i)
1216 if(hMonitor == mpDirect3D9->GetAdapterMonitor(i))
1217 return i;
1218 return static_cast<UINT>(-1);
1221 //////////////////////////////////////////////////////////////////////////////////
1222 // DXRenderModule::commitVertexCache
1223 //////////////////////////////////////////////////////////////////////////////////
1225 void DXRenderModule::commitVertexCache()
1227 if(maReadIndex != maWriteIndex)
1229 const std::size_t nVertexStride = sizeof(dxvertex);
1230 const unsigned int nNumVertices = maWriteIndex-maReadIndex;
1231 const unsigned int nNumPrimitives = nNumVertices / 3;
1233 if(FAILED(mpDevice->SetStreamSource(0,mpVertexBuffer.get(),0,nVertexStride)))
1234 return;
1236 if(FAILED(mpDevice->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)))
1237 return;
1239 if(FAILED(mpDevice->BeginScene()))
1240 return;
1242 mbError |= FAILED(mpDevice->DrawPrimitive(D3DPT_TRIANGLELIST,maReadIndex,nNumPrimitives));
1243 mbError |= FAILED(mpDevice->EndScene());
1245 maReadIndex += nNumVertices;
1249 //////////////////////////////////////////////////////////////////////////////////
1250 // DXRenderModule::flushVertexCache
1251 //////////////////////////////////////////////////////////////////////////////////
1253 void DXRenderModule::flushVertexCache()
1255 if(!(maVertexCache.size()))
1256 return;
1258 mbError=true;
1260 if( FAILED(mpDevice->SetRenderState(D3DRS_LIGHTING,FALSE)))
1261 return;
1263 // enable texture alpha blending
1264 if( FAILED(mpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE)))
1265 return;
1267 mpDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
1268 mpDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
1269 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSU ,D3DTADDRESS_CLAMP );
1270 mpDevice->SetSamplerState(0,D3DSAMP_ADDRESSV ,D3DTADDRESS_CLAMP );
1272 // configure the fixed-function pipeline.
1273 // the only 'feature' we need here is to modulate the alpha-channels
1274 // from the texture and the interpolated diffuse color. the result
1275 // will then be blended with the backbuffer.
1276 // fragment color = texture color * diffuse.alpha.
1277 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);
1278 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);
1279 mpDevice->SetTextureStageState(0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE);
1281 // normal combination of object...
1282 if( FAILED(mpDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA)) )
1283 return;
1285 // ..and background color
1286 if( FAILED(mpDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA)) )
1287 return;
1289 // disable backface culling; this enables us to mirror sprites
1290 // by simply reverting the triangles, which, with enabled
1291 // culling, would be invisible otherwise
1292 if( FAILED(mpDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE)) )
1293 return;
1295 mbError=false;
1297 std::size_t nSize(maVertexCache.size());
1298 const std::size_t nVertexStride = sizeof(dxvertex);
1300 const ::basegfx::B2IVector aPageSize(getPageSize());
1301 const float nHalfPixelSizeX(0.5f/aPageSize.getX());
1302 const float nHalfPixelSizeY(0.5f/aPageSize.getY());
1303 vertexCache_t::const_iterator it(maVertexCache.begin());
1305 while( nSize )
1307 DWORD dwLockFlags(D3DLOCK_NOOVERWRITE);
1309 // Check to see if there's space for the current set of
1310 // vertices in the buffer.
1311 if( maNumVertices - maWriteIndex < nSize )
1313 commitVertexCache();
1314 dwLockFlags = D3DLOCK_DISCARD;
1315 maWriteIndex = 0;
1316 maReadIndex = 0;
1319 dxvertex *vertices(NULL);
1320 const std::size_t nNumVertices(
1321 std::min(maNumVertices - maWriteIndex,
1322 nSize));
1323 if(FAILED(mpVertexBuffer->Lock(maWriteIndex*nVertexStride,
1324 nNumVertices*nVertexStride,
1325 (void **)&vertices,
1326 dwLockFlags)))
1327 return;
1329 std::size_t nIndex(0);
1330 while( nIndex < nNumVertices )
1332 dxvertex &dest = vertices[nIndex++];
1333 dest.x=it->x;
1334 dest.y=it->y;
1335 dest.z=it->z;
1336 dest.rhw=1;
1337 const sal_uInt32 alpha(static_cast<sal_uInt32>(it->a*255.0f));
1338 dest.diffuse=D3DCOLOR_ARGB(alpha,255,255,255);
1339 dest.u=static_cast<float>(it->u + nHalfPixelSizeX);
1340 dest.v=static_cast<float>(it->v + nHalfPixelSizeY);
1341 ++it;
1344 mpVertexBuffer->Unlock();
1346 // Advance to the next position in the vertex buffer.
1347 maWriteIndex += nNumVertices;
1348 nSize -= nNumVertices;
1350 commitVertexCache();
1353 maVertexCache.clear();
1357 //////////////////////////////////////////////////////////////////////////////////
1358 // createRenderModule
1359 //////////////////////////////////////////////////////////////////////////////////
1361 IDXRenderModuleSharedPtr createRenderModule( const ::Window& rParent )
1363 return IDXRenderModuleSharedPtr( new DXRenderModule(rParent) );
1367 #endif