Ogre源码剖析之二:初始化Direct3D设备

这个世界或许只是一扇窗……

 

       上一篇我们介绍了Root的创建,和加载插件的方法。没有涉及到Direct3D的内容,那么这篇我准备介绍Ogre是如何初始化Direct3D的,如何初始化一个窗口。就如同我们在学习Direct3D进入实践的第一课:开启一面窗,来绘制整个世界。

        首先在开始之前来温习一下Direct3D的初始化步骤,下面引用《DirectX_9.0_3D游戏开发编程基础》(红龙书)46页:

        下面几点说明怎样初始化Direct3D。根据下边的步骤你能初始化Direct3D

        1.获得一个IDirect3D9接口指针。这个接口用于获得物理设备的信息和创建一个

IDirect3DDevice9接口,它是一个代表我们显示3D图形的物理设备的C++对象。

        2.检查设备能力(D3DCAPS9),搞清楚主显卡是否支持硬件顶点处理。我们需要知道假如它能支持,我们就能创建IDirect3DDevice9接口。

       3.初始化一个D3DPRESENT_PARAMETERS结构实例,这个结构包含了许多数据成员允许我们指定将要创建的IDirect3DDevice9接口的特性。

       4.创建一个基于已经初始化好的D3DPRESENT_PARAMETERS结构的IDirect3DDevice9

象。它是一个代表我们显示3D图形的物理设备的C++对象。

        我们来看看Ogre是如何实现上面4点的。

      接着上篇,找到plugin = OGRE_NEW D3D9Plugin()这一句,可以跟踪到D3D9Plugin::install(),这个方法中的mRenderSystem = OGRE_NEW D3D9RenderSystem( hInst );就是初始化DirectX设备的地方。再次跟踪到D3D9RenderSystem的构造函数中,找到下面代码:

                           if( NULL == (mD3D = Direct3DCreate9(D3D_SDK_VERSION)) )

         Direct3DCreate9(D3D_SDK_VERSION)出现了,初始化了一个IDirect3D9的指针。第一点实现完成。

        对于2,3,4点,Ogre已经对其进行了封装,要直接找到不是很容易,我们来一步步跟踪代码找到实现2,3,4点的地方。

        代码定位到ExampleApplication.h中的mWindow = mRoot->initialise(true);看注释知道这一句是创建一个默认的渲染窗口。

      跟踪到mRoot->initialise中,定位到这一句代码

        mAutoWindow =  mActiveRenderer->_initialise(autoCreateWindow, windowTitle);

      这里我选择的是D3D,所以mActiveRendererD3D9RenderSystem类型,如果不知道它是怎么来的,可以看看上一篇的介绍(说过这个玩意儿很重要了……)。

      好,多态,就会调用下面的方法:

     RenderWindow* D3D9RenderSystem::_initialise( bool autoCreateWindow, const String& windowTitle )

     在这个方法中,好像出现了D3DPRESENT_PARAMETERS的影子,是不是这个呢?

	NameValuePairList miscParams;
			miscParams["colourDepth"] = StringConverter::toString(videoMode->getColourDepth());
			miscParams["FSAA"] = StringConverter::toString(mFSAASamples);
			miscParams["FSAAHint"] = mFSAAHint;
			miscParams["vsync"] = StringConverter::toString(mVSync);
			miscParams["vsyncInterval"] = StringConverter::toString(mVSyncInterval);
			miscParams["useNVPerfHUD"] = StringConverter::toString(mUseNVPerfHUD);
			miscParams["gamma"] = StringConverter::toString(hwGamma);
	miscParams["monitorIndex"] = StringConverter::toString(static_cast<int>(mActiveD3DDriver->getAdapterNumber()));


      再往下看,跟踪到:

autoWindow = _createRenderWindow( windowTitle, width, height, 
fullScreen, &miscParams );

 


      进入_createRenderWindow方法,首先定位到

 

D3D9RenderWindow* renderWindow = OGRE_NEW D3D9RenderWindow(mhInstance);
renderWindow->create(name, width, height, fullScreen, miscParams);

参数mhInstanceGetModuleHandle( "RenderSystem_Direct3D9.dll" ),不多解释。

在上面的话执行完之后,窗口被创建出来了,这个renderWindow将被返回出去。容易看到miscParams被当做了参数继续它的征程,好的,跟踪进去看看:

   void D3D9RenderWindow::create(const String& name, unsigned int width, unsigned int height, bool fullScreen, const NameValuePairList *miscParams)

       先看这个方法的实现,来看看D3D9RenderWindow的保护成员:

protected:
		HINSTANCE					mInstance;				// Process instance
		D3D9Device* 				mDevice;				// D3D9 device wrapper class.
		bool						mDeviceValid;			// Device was validation succeeded.
		HWND						mHWnd;					// Win32 Window handle		
		bool						mIsExternal;			// window not created by Ogre
		bool						mClosed;				// Is this window destroyed.		
		bool						mHidden;				// True if this is hidden render window. 
		bool						mSwitchingFullscreen;	// Are we switching from fullscreen to windowed or vice versa		
		D3DMULTISAMPLE_TYPE			mFSAAType;				// AA type.
		DWORD						mFSAAQuality;			// AA quality.
		UINT						mDisplayFrequency;		// Display frequency.
		bool						mVSync;					// Use vertical sync or not.
		unsigned int				mVSyncInterval;			// The vsync interval.
		bool						mUseNVPerfHUD;			// Use NV Perf HUD.
		DWORD						mWindowedWinStyle;		// Windowed mode window style flags.
		DWORD						mFullscreenWinStyle;	// Fullscreen mode window style flags.		 
		unsigned int				mDesiredWidth;			// Desired width after resizing
		unsigned int				mDesiredHeight;			// Desired height after resizing

   

      现在可以告诉大家的是上面的成员变量对应着D3DPRESENT_PARAMETERS的一些项,D3D9RenderWindow在执行create是会对这些成员变量赋值,然后赋给IDirect3DDevice9对象。

      但是到现在我们还未看到IDirect3DDevice9对象,上面说的第2点,设备检测到底在哪里啊,还有搞了这么一大圈,在搞啥啊?还有啥时候给D3DPRESENT_PARAMETERS赋值?IDirect3DDevice9对象在哪里产生的啊?……

     在D3D9RenderWindow::create(const String& name, unsigned int width, unsigned int height,bool fullScreen, const NameValuePairList *miscParams)中,干了2件大事:1.成员变量赋值,就是将miscParams赋值给成员变量。2.创建了窗口,定位到这一句:

       mHWnd = CreateWindowEx(dwStyleEx, "OgreD3D9Wnd", title.c_str(), getWindowStyle(fullScreen),mLeft, mTop, winWidth, winHeight, parentHWnd, 0, hInst, this);

      熟悉windows编程的码农们该很happy吧。窗口句柄出现了------- mHWnd,窗口就这么创建出来了,请记住这个句柄,后面要用的。

      好,跳出去,再跟踪,想想上面的问题,下面来一个个回答。

      回到RenderWindow* D3D9RenderSystem::_createRenderWindow(const String &name, unsigned int width, unsigned int height, bool fullScreen,const NameValuePairList *miscParams)中,定位到mDeviceManager->linkRenderWindow(renderWindow),   这里出现了新的对象D3D9DeviceManager,它是个管理器,管理着D3D9Device,哦!D3D9Device,这个东西是个重点,赶紧看看它的成员变量:

   

		D3D9DeviceManager*				mDeviceManager;			// The manager of this device instance.
		IDirect3DDevice9*				mDevice;					// Will hold the device interface.				
		UINT							mAdapterNumber;				// The adapter that this device belongs to.	
		HMONITOR						mMonitor;					// The monitor that this device belongs to.
		D3DDEVTYPE						mDeviceType;				// Device type.	
		static HWND						msSharedFocusWindow;		// The shared focus window in case of multiple full screen render windows.
		HWND							mFocusWindow;				// The focus window this device attached to.			
		DWORD							mBehaviorFlags;				// The behavior of this device.		
		D3DPRESENT_PARAMETERS*			mPresentationParams;		// Presentation parameters which the device was created with. May be
																	// an array of presentation parameters in case of multi-head device.				
		UINT							mPresentationParamsCount;	// Number of presentation parameters elements.		
		D3DCAPS9						mD3D9DeviceCaps;			// Device caps.	
		bool							mD3D9DeviceCapsValid;		// True if device caps initialized.				
		D3DDEVICE_CREATION_PARAMETERS	 mCreationParams;			// Creation parameters.
		uint							mLastPresentFrame;			// Last frame that this device present method called.
		bool							mDeviceLost;				// True if device entered lost state.

 

          奶奶的! IDirect3DDevice9,D3DPRESENT_PARAMETERS,D3DCAPS9  都在这个类中啊!那么D3D9Device的作用是什么就知道了吧,它是对D3D设备的一个封装类。

       来继续我们的征程,跟踪到void D3D9DeviceManager::linkRenderWindow(D3D9RenderWindow* renderWindow)方法,看到了D3D9Device* renderDevice,不过只是个指针,没有实例化,定位到renderDevice = selectDevice(renderWindow, renderWindowsGroup); 进入该方法,靠!好长一坨代码,只看这最后几句:

// No matching device found -> create new one.
		if (renderDevice == NULL)
		{
			renderDevice = OGRE_NEW D3D9Device(this, nAdapterOrdinal, direct3D9->GetAdapterMonitor(nAdapterOrdinal), devType, extraFlags);
			mRenderDevices.push_back(renderDevice);
			if (mActiveDevice == NULL)			
				setActiveDevice(renderDevice);											
		}		

 

       D3D9Device对象是创建出来了,但是它的成员变量是在哪里创建的呢?    别急,我们先跳出这恶心的一坨代码。    

   注意这部分代码:

// Link the windows group to the new device.
		for (uint i = 0; i < renderWindowsGroup.size(); ++i)
		{
			D3D9RenderWindow* currWindow = renderWindowsGroup[i];

			currWindow->setDevice(renderDevice);
			renderDevice->attachRenderWindow(currWindow);
			renderDevice->setAdapterOrdinalIndex(currWindow, i);
		}

 

           我们只是创建一个渲染窗口,有时需要创建多个渲染窗口,上面的for循环就是干这个事的,这里不讲多窗口的事。上面代码可以读出的重要信息是:窗口对象D3D9RenderWindow和设备对象D3D9Device是你中有我,我中有你。renderDevice->attachRenderWindow(currWindow)方法中,将窗口对象和相关设备资源加入了一个哈希表:RenderWindowToResourcesMap,后面还需要用到这个哈希表,关于这个表大家可以看代码,不多介绍。

       注意,重点来了。

      renderDevice->acquire();

      进入该方法,跟踪到void D3D9Device::updatePresentationParameters(),定位到renderWindow->buildPresentParameters(&renderWindowResources->presentParameters),执行这一句后就将 D3D9RenderWindow中的成员变量赋值给renderWindowResources->presentParameters,renderWindowResources上面已经简单介绍过了。跳出该方法,定位到                  mPresentationParams[renderWindowResources->presentParametersIndex] = renderWindowResources->presentParameters;

mPresentationParams是个D3DPRESENT_PARAMETERS指针,这里当做数组来用。它的初始化是:

            mPresentationParams = OGRE_ALLOC_T(D3DPRESENT_PARAMETERS, mMapRenderWindowToResources.size(), MEMCATEGORY_RENDERSYS);

      因为Ogre是支持多窗口渲染的,所以要这样搞。记着这个mPresentationParams,它目前有一个数组成员,值为renderWindowResources->presentParameters。跳出方法updatePresentationParameters(),定位到createD3D9Device(),不用说,这个就是创建D3D设备的地方。

      看下面代码:

hr = pD3D9->CreateDevice(mAdapterNumber, mDeviceType, mFocusWindow,
			mBehaviorFlags, mPresentationParams, &mDevice);
 

         mFocusWindow就是D3D9RenderWindow创建出来的mHWnd,不清楚的这个句柄怎么来的,再看看上面的介绍吧。

       继续往下看代码,看到很多if (FAILED(hr)),这个就是在检测硬件设备,也就是第2点,一个个的检测,如果你的机子是老掉牙的,那么会抛个异常给你,告诉你,你的电脑玩不了D3D设备的OGRE。

       好了第4点也找到了,第3点也介绍了。

       下面付个图看看调用到createD3D9Device的堆栈,如图:

  

         经过上面的步骤,我们明白了Ogre是如何创建渲染窗口的,是如何初始化D3D设备的,有点复杂,搞懂了还是觉得很有收获的。先写到这里,下一篇介绍一下渲染循环:   mRoot->startRendering();

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值