zoukankan      html  css  js  c++  java
  • 《Windows游戏编程大师技巧》五、DirectX基础知识和令人生畏的COM


    所有的DirectX组件都是以COM实现的,两者环环相扣。

    DirectX基础

    DirectX可能会让身为程序员的你丧失些对硬件的控制能力,但是DirectX比Windows系统自带
    的GDI或MCI快上很多倍,并且也更稳定。在编写Windows游戏的过程中,使用DirectX的方法
    要干净和优雅得多。



    你只要向DirectX发出命令,它就会帮你处理所有细节问题。无论是显卡、声卡、键盘鼠标
    还是网卡,只要是DirectX支持的硬件,就可以被你的程序使用而无需知道其中的奥秘。
    DirectX是如何工作的呢?通过COM技术,以及一套由微软和硬件厂商共同编写的驱动库就
    可以实现。硬件商必须遵守微软的协议才能开发与硬件通信的驱动程序。

    DirectX已经包含了许多组件,包括DirectDraw、DirectSound、DirectInput、DirectShow等等。



    从上图中可以看到在DirectX 8.0版本里,DirectDraw和Direct3D合并为DirectX Graphics。而DirectSound和
    DirectMusic合并为DirectX Audio。并且DirectShow也集成到DirectX里。虽然有很多版本,但我们可以通过
    COM决定究竟使用DirectX 3.0、5.0、6.0或是其他版本。并且各版本只是有些许的差别,学会一个版本就
    能够掌握其他的(除了Direct3D)。但本书不会太多涉及DirectX的内容,毕竟你的整个游戏编程生涯并不会
    与DirectX绑在一起。当你以后使用其他API时仍然可以理解游戏编程的基础技术,这才是本书的终极目标

    从上图中还会发现,DirectX下有两个层叫做HEL(硬件仿真层)和HAL(硬件抽象层)。HAL直接和硬件对话,
    是硬件商提供的设备驱动程序。当硬件支持你要求的功能时HAL才被使用,可以通过DirectX调用直接和它通信。
    例如当你要求绘制一个位图时,硬件数据块复制器能迅速完成这个任务,比软件循环高效得多。HEL则是当硬件
    不支持你要求的功能时被使用。比如当硬件不支持位图旋转时,HEL就会通过软件运算来完成该项任务。显然
    这样处理速度会慢,但关键是这样不会因为硬件不支持而影响你的程序。另外,HAL和HEL之间的切换对用户而言
    是透明的。

    你能想象自行编写驱动程序来支持市场上所有显卡吗?这需要数千人年的工作量,事实上也是不可能完成的。
    DirectX的确是微软和所有硬件商倾注了大量研究和努力的成果,它是超高性能的标准。


    COM:是微软还是魔鬼的杰作?

    虽然C++有许多很酷的OO功能,但很多人仍然不使用或者用错。因此大规模程序的
    编写仍然是个问题,这也是COM模型要解决的困难之一。当修改或升级一部分代码时,
    必须要重新编译生成一个可执行文件,这也是COM要解决的另一个问题。不用重新编译
    程序就能升级COM模块,即插即用。这项技术在底层非常复杂,编写自己的COM对象也
    非常有挑战性,但是COM对象使用起来却是非常容易的。

    一个COM对象事实上就是一套实现了大量接口的C++类。这些接口用于和COM对象交互。
    所有接口必须从一个名为IUnknown接口继承而来。

    struct IUnknown 
    {
         virtual HRESULT __stdcall QueryInterface(const IID &iid, (void**)ip);
         virtual ULONG __stdcall AddRef() = 0;
         virtual ULONG __stdcall Release() = 0;
    }

    QueryInterface根据一个128位的接口标识符iid来返回请求的接口。
    AddRef和Release管理引用计数器跟踪当前COM对象生命周期。

    COM的设计者只是使用虚C++类来实现COM,而不要求用户也必须使用C++来
    访问或者创建它们。只要你创建的是一个和Microsoft C++编译器在创建虚C++
    类时所创建的二进制映像一样的映像,这个COM对象就可以兼容。

    来看一个可以运行的COM对象实例。


    DirectX的COM对象有很多。这些COM对象在安装DirectX时作为动态链接库DLL
    包含在你的系统中。当运行DirectX游戏时,程序会装载DLL,请求接口,然后
    接口的实现函数会被调用从而完成任务。编译时,不需要调用CoCreateInstance
    函数,也不需要对COM进行初始化,从而从操作COM的沉闷工作中解脱出来。
    因此编译时要包含一些库函数.LIB文件,应用程序与DLL中COM对象的桥梁。

    // DEMO5_1.CPP - A ultra minimal working COM example
    // NOTE: not fully COM compliant
    
    // INCLUDES //////////////////////////////////////////////////////////////////////////////////
    
    #include <stdio.h>
    #include <malloc.h>
    #include <iostream>
    #include <objbase.h> // note: you must include this header it contains important constants
                         // you must use in COM programs
    
    using   namespace   std;
    
    // GUIDS /////////////////////////////////////////////////////////////////////////////////////
    
    // these were all generated with GUIDGEN.EXE
    
    // {B9B8ACE1-CE14-11d0-AE58-444553540000}
    const IID IID_IX = 
    { 0xb9b8ace1, 0xce14, 0x11d0, { 0xae, 0x58, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
    
    
    // {B9B8ACE2-CE14-11d0-AE58-444553540000}
    const IID IID_IY = 
    { 0xb9b8ace2, 0xce14, 0x11d0, { 0xae, 0x58, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
    
    // {B9B8ACE3-CE14-11d0-AE58-444553540000}
    const IID IID_IZ = 
    { 0xb9b8ace3, 0xce14, 0x11d0, { 0xae, 0x58, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
    
    
    // INTERFACES ////////////////////////////////////////////////////////////////////////////////
    
    // define the IX interface
    interface IX: IUnknown
    {
    
    virtual void __stdcall fx(void)=0;
    
    }; 
    
    // define the IY interface
    interface IY: IUnknown
    {
    
    virtual void __stdcall fy(void)=0;
    
    }; 
    
    
    // CLASSES AND COMPONENTS ///////////////////////////////////////////////////////////////////
    
    // define the COM object
    class CCOM_OBJECT : public IX,
                        public IY
    {
    public:
    
     CCOM_OBJECT() : ref_count(0) {}
     ~CCOM_OBJECT() {}
    
    private:
    
    virtual HRESULT __stdcall QueryInterface(const IID &iid, void **iface);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();
    
    virtual void __stdcall fx(void) {cout << "Function fx has been called." << endl; }
    virtual void __stdcall fy(void) {cout << "Function fy has been called." << endl; }
    
    int ref_count;
    
    };
    
    // CLASS METHODS ////////////////////////////////////////////////////////////////////////////
    
    HRESULT __stdcall CCOM_OBJECT::QueryInterface(const IID &iid, void **iface)
    {
    	// this function basically casts the this pointer or the Iunknown
    	// pointer into the interface requested, notice the comparison with
    	// the GUIDs generated and defined in the begining of the program
    
    	// requesting the IUnknown base interface
    	if (iid==IID_IUnknown)
    	{
    		cout << "Requesting IUnknown interface" << endl;
    		*iface = (IX*)this;
     
    	} // end if
    
    	// maybe IX?
    	if (iid==IID_IX)
    	{
    		cout << "Requesting IX interface" << endl;
    		*iface = (IX*)this;
    
    	} // end if
    	else  // maybe IY
    	if (iid==IID_IY)
    	{
    		cout << "Requesting IY interface" << endl;
    		*iface = (IY*)this;
    
    	} // end if
    	else
    	{ // cant find it!
    		cout << "Requesting unknown interaface!" << endl;
    		*iface = NULL;
    		return(E_NOINTERFACE);
    	} // end else
    
    	// if everything went well cast pointer to IUnknown and call addref()
    	((IUnknown *)(*iface))->AddRef();
    
    	return(S_OK);
    
    } // end QueryInterface
    
    ////////////////////////////////////////////////////////////////////////////////////////////////
    
    ULONG __stdcall CCOM_OBJECT::AddRef()
    {
    	// increments reference count
    	cout << "Adding a reference" << endl;
    	return(++ref_count);
    
    } // end AddRef
    
    ///////////////////////////////////////////////////////////////////////////////////////////////
    
    ULONG __stdcall CCOM_OBJECT::Release()
    {
    	// decrements reference count
    	cout << "Deleting a reference" << endl;
    	if (--ref_count==0)
    	{
    		delete this;
    		return(0);
    	} // end if
    	else
    		return(ref_count);
    
    } // end Release
    
    ///////////////////////////////////////////////////////////////////////////////////////////////
    
    IUnknown *CoCreateInstance(void)
    {
    	// this is a very basic implementation of CoCreateInstance()
    	// it creates an instance of the COM object, in this case
    	// I decided to start with a pointer to IX -- IY would have
    	// done just as well
    
    	IUnknown *comm_obj = (IX *)new(CCOM_OBJECT);
    
    	cout << "Creating Comm object" << endl;
    
    	// update reference count
    	comm_obj->AddRef();
    
    	return(comm_obj);
    
    } // end CoCreateInstance
    
    ///////////////////////////////////////////////////////////////////////////////////////////////
    
    void main(void)
    {
    
    	// create the main COM object
    	IUnknown *punknown = CoCreateInstance();
    
    	// create two NULL pointers the the IX and IY interfaces
    	IX *pix=NULL;
    	IY *piy=NULL;
    
    	// from the original COM object query for interface IX
    	punknown->QueryInterface(IID_IX, (void **)&pix);
    
    	// try some of the methods of IX
    	pix->fx();
    
    	// release the interface
    	pix->Release();
    
    
    	// now query for the IY interface
    	punknown->QueryInterface(IID_IY, (void **)&piy);
    
    	// try some of the methods
    	piy->fy();
    
    	// release the interface
    	piy->Release();
    
    	// release the COM object itself
    	punknown->Release();
    
    } // end main

  • 相关阅读:
    电路开发软件积累
    .NET移动开发环境搭建
    Microsoft SQL Server Express各版本对比
    .NET IL指令速查表
    C#访问加密的SQLite数据库
    C#中时间计算方法汇总
    最佳C/C++编辑器 source insight3
    常用PHP框架收集
    CSS 中文字体的英文名称 (simhei, simsun) 宋体 微软雅黑等
    Windows下Java JDK8配置环境变量
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157841.html
Copyright © 2011-2022 走看看