• 用DirectX绘制使用纹理的立方体


    下面将学习DirectX的3D渲染基础部分,但不会对3D数学或图形理论有太详细的介绍。 首先要了解DirectX中的坐标系,要记住的是DirectX采用左手坐标系。

    在Direct3D中渲染一个场景,涉及到的三维变换有:世界变换、视图变换、投影变换。

    世界变换:三维变换的第一步就是将模型的顶点的局部坐标变换到所有对象都共享的一个坐标系中,也就是从模型空间向世界空间转换。变换到的新的坐标系称为世界坐标系。世界坐标系中的每一个顶点的坐标都以世界坐标系来表示。根据需要,应该将物体进行缩放、旋转、平移后放置到我们想要的位置。

    视图变换:又称为观察变换,即如照相机一般,表示用户在屏幕上看到的内容。我们在世界坐标系中选择一个观察点,世界坐标系将被重新定位到这个观察点的视野中,也就是从世界坐标空间向观察空间的转换。需要注意的是,观察变换实际上是坐标系的变换。但是,Direct3D在处理时是对物体顶点进行矩阵变换,所以观察矩阵需要执行与视点变换相反的变换。例如,我们希望视点沿着z轴负方向移动5个单位,那么相对的就是顶点向z轴正方向移动5个单位。

    投影变换:这是最后一步,在这里将视图变换的结果投影到屏幕上形成2D图像。视景体(field of view, FOV)用于定义在某个特定的位置能够看到的物体的范围,又称为视锥体或观察体。视景体在三维空间由6个面组成,以你的眼睛为视点向前看,依次是投影平面、近平面、远平面。典型的投影变换包括缩放和透视投影。投影变换将视景体变换为一个立方体。因为视景体的近端比远端小,所以会在投影平面上产生了离摄像机近的物体就被放大的效果。

    除此之外,还要理解一些常见的术语,比如顶点缓存、索引缓存、深度缓存、模板缓存、交换链、多重采样、着色器、HLSL,下面将会简要介绍。

    DirectX是一种基于COM(Component Object Model,组件对象模型)的系统,它既不属于驱动程序层,也不属于应用层。DirectX的主要设计目标是提供某种设备的独立性的同时获取很高的速度。COM使Direct3D独立于编程语言和具有向下兼容性,通常把COM对象作为一个接口,可以把它当做达到某种目的的C++类来使用,COM接口都具有前缀大写字母I表示,比如接口ID3DTexture2D。在DirectX的体系结构中,处于DirectX下层的是HAL(Hardware Abstract Layer,硬件抽象层)与HEL(Hardware Emulation Layer,硬件模拟层)。HAL负责检测本机的硬件功能,并以一种独立于设备的方式提供这些功能。HEL负责提供DirectX功能中本机硬件不支持部分的软件模拟实现。从DirectX 8.0起,DirectX就不再提供硬件模拟层HEL模块了,最新的DirectX 11要求硬件必须实现全部DirectX 11的特性,因此现在的DirectX是严重依赖于硬件的。Direct3D是一种低层的图形API,它能让我们利用三维硬件加速来渲染三维世界,可以被看成应用程序和图形设备之间的中介。

    这里必须提到的是,DirectX 9中采用固定图像渲染管线,而DirectX 10与DirectX 11都放弃了固定的渲染管线,可以通过着色器代码改变渲染管线的过程。 在DirectX 9中,提供了两个独立的着色器:顶点着色器与像素着色器,在硬件中有各自的实现,不能通用。而从DirectX 10起,Shader Model 4.0提出了通用着色器的概念,即硬件上仅仅实现一种着色器,每一个着色阶段都利用通用着色器实现核心功能,每个特定的着色阶段都提供各自的额外功能。在通用着色器中,无论是常数、纹理或是缓存都被视为同样的资源直接或者通过采样器传递给着色器代码进行处理,HLSL便是DirectX使用的着色语言,类似C语言。

    顶点着色器:顶点着色阶段将顶点作为输入集,负责处理“逐顶点”的操作,如坐标变换、蒙皮、动画以及顶点光照。顶点着色器的工作是处理一个独立的输入顶点并产生一个独立的输出顶点。顶点着色阶段在渲染管线中必须激活,即便没有对顶点做任何修改,也必须提供一个“不做任何修改”的顶点着色器才能保证渲染管线的正常工作。

    几何着色器:这时由Direct3D 10引入的新的着色阶段,用来在已知的输入顶点的基础上生成新的输入顶点。和顶点着色器不同的是,顶点着色器仅仅处理独立的顶点,而几何着色器的输入则是一个图元(两个顶点的线段、三个顶点的三角形、一个顶点的独立点等),也可以将顶点的邻接点作为输入。

    像素着色器:可以实现丰富的着色技术如逐像素光照和后期处理等。像素着色器可以通过常量、贴图、插值以及其他数据来产生逐像素的输出值。光栅处理器对每一个图元中的每一个像素都会执行一次像素着色器,但是也可以通过程序设置跳过像素着色器的执行。

    计算着色器:是Direct3D 11引入的新着色器,独立于渲染管线之外,和其他着色器一样使用着色器语言实现。计算着色器提供了利用GPU中大量并行处理器进行高速通用计算的能力。

    Direct3D管线中用到的所有资源可分为缓存(buffer)资源和纹理(texture)资源。缓存资源是指一组指定类型的数据的集合,分为顶点缓存、索引缓存、常量缓存。顶点缓存用于存储顶点数据,包括顶点的位置、法线、纹理坐标。纹理资源是一种结构,用于存储纹理。Direct3D有三种纹理类型:一维、二维和三维纹理。一维纹理指只在某一方向上变化,相当于高度为1的二维纹理;二维纹理是指纹理在相互垂直的两个方向上变化,用u表示横向纹理,v表示纵向纹理;三维纹理,其纹理单元为三维纹理体,每个纹理单元用u、v、w向量表示。多重纹理是指事先制定一系列分辨率逐渐减小的纹理图像,纹理采用mipmap方式自动生成,即每个层次的纹理细节(LOD)为小于上一级纹理平方根大小,Direct3D会根据所映射的物体尺寸自动选择使用哪个分辨率的纹理图。

    Direct3D维护着两个纹理缓存,前台缓存(Front Buffer)和后台缓存(Back Buffer)。前台缓存存储着当前显示在屏幕上的图像数据,下一帧的动画则被绘制在后台缓存上。为了避免动画的闪动,当帧的整个场景在后台缓存中绘制好后,后台缓存和前台缓存就互相交换,这样后台缓存中的内容才被完整地呈现在屏幕上。前台缓存与后台缓存组成了交换链

    深度缓存是一个只包含特定像素深度信息而不包含图像数据的纹理。深度值的范围为[0,1],0表示能被观察者看到的最近的位置,1表示能被观察者看到的最远的位置。为了理解这个概念,设想这样一个场景,一个圆圈环绕着一个立方体,显然圆圈会遮挡一部分的立方体,该如何绘制场景了?如果采用传统的画家算法,先画什么,再画什么就不行了。Direct3D在像素级别上提供了一个很好的解决方案,它使用一种叫深度缓存,又叫z-buffer的技术。深度缓存保存着每个像素的深度值,也叫z值,在绘制场景时按深度值绘制就可以了。

    用像素矩阵表示的图像通常会出现“阶梯效应”,比如一条线段的边缘产生了锯齿,发生走样。这里要采用反走样技术,通过采集并使用线段中的点周围的一些像素,减少图像的阶梯效应。Direct3D支持一种称为多重采样的反走样技术,它使用目标像素周围的一些点来生成该像素点的最终颜色。由于这个过程使用了多个像素采样,所以叫多重采样。

    实际的模型可以分为很多个三角形,这些三角形有大量的重复顶点和重复边。如果在顶点缓存中重复保存这些顶点信息,那么显卡将耗费比实际模型体积大得多的空间来保存模型信息。这里必须引入索引缓存的概念,它不能脱离顶点缓存而独立存在。我们需要建立一个顶点缓存,比如一个立方体,顶点缓存中只需要保存8个顶点的信息。除此之外,还需要建立一个缓存来确定每一个顶点对应顶点缓存中的哪一个顶点,这就是索引缓存

    模板是一块特殊的缓存区,称为模板缓存(Stencil Buffer)。模板缓存的作用是限定哪些像素将被绘制到屏幕上而哪些不会。因为模板缓存的容量很小,因此在实际的硬件实现中,并没有一个独立的模板缓存,而是将深度缓存和模板缓存合并成一个深度模板缓存(Depth Stencil Buffer),其中每一个像素的前24位用作深度缓存,而后8位用于模板缓存。

    Direct3D使用由用户自定义的顶点格式,下面是我们将要使用的结构VERTEX。前三个成员变量是顶点的位置,而tu和tv用于表达使用的纹理的坐标,可以使用tu=0.0、tv=0.0指定纹理左上角,tu=1.0、tv=1.0指定纹理右下角。

    struct VERTEX
    {
        float x, y, z;
        float tu, tv;
    };

     

    我们要创建一个四边形,所以需要这样一个结构QUAD,显然vertices保存四个顶点,buffer为顶点缓存,texture为用于着色的纹理贴图。

    struct QUAD
    {
        VERTEX vertices[4];
        LPDIRECT3DVERTEXBUFFER9 buffer;
        LPDIRECT3DTEXTURE9 texture;
    };

     

    基础部分暂时讲到这里,下面看一个例子,还是基于前面的例子,只有game.cpp文件改变了,也是唯一重要的文件。

    DirectSound.h

    View Code
      1 //-----------------------------------------------------------------------------
      2 // File: DSUtil.h
      3 //
      4 // Desc: 
      5 //
      6 // Copyright (c) Microsoft Corp. All rights reserved.
      7 //-----------------------------------------------------------------------------
      8 //
      9 // Note: This file has been edited for use in Beginning Game Programming, Third Edition,
     10 // originally distributed with a 2004 release of DirectX 9.0c SDK.
     11 //
     12 
     13 #ifndef DSUTIL_H
     14 #define DSUTIL_H
     15 
     16 #include <windows.h>
     17 #include <mmsystem.h>
     18 #include <mmreg.h>
     19 #include <dsound.h>
     20 #include <dxerr.h>
     21 
     22 #pragma comment(lib, "dxerr.lib")
     23 #pragma comment(lib, "dsound.lib")
     24 
     25 
     26 //-----------------------------------------------------------------------------
     27 // Classes used by this header
     28 //-----------------------------------------------------------------------------
     29 class CSoundManager;
     30 class CSound;
     31 class CStreamingSound;
     32 class CWaveFile;
     33 
     34 
     35 
     36 
     37 //-----------------------------------------------------------------------------
     38 // Typing macros 
     39 //-----------------------------------------------------------------------------
     40 #define WAVEFILE_READ   1
     41 #define WAVEFILE_WRITE  2
     42 
     43 #define DSUtil_StopSound(s)         { if(s) s->Stop(); }
     44 #define DSUtil_PlaySound(s)         { if(s) s->Play( 0, 0 ); }
     45 #define DSUtil_PlaySoundLooping(s)  { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
     46 
     47 
     48 
     49 
     50 //-----------------------------------------------------------------------------
     51 // Name: class CSoundManager
     52 // Desc: 
     53 //-----------------------------------------------------------------------------
     54 class CSoundManager
     55 {
     56 protected:
     57     LPDIRECTSOUND8 m_pDS;
     58 
     59 public:
     60     CSoundManager();
     61     ~CSoundManager();
     62 
     63     HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel );
     64 
     65     inline  LPDIRECTSOUND8 GetDirectSound() { return m_pDS; }
     66 
     67     HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, 
     68         DWORD dwPrimaryBitRate );
     69 
     70     HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0,
     71         GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
     72 };
     73 
     74 
     75 
     76 
     77 //-----------------------------------------------------------------------------
     78 // Name: class CSound
     79 // Desc: Encapsulates functionality of a DirectSound buffer.
     80 //-----------------------------------------------------------------------------
     81 class CSound
     82 {
     83 protected:
     84     LPDIRECTSOUNDBUFFER* m_apDSBuffer;
     85     DWORD                m_dwDSBufferSize;
     86     CWaveFile*           m_pWaveFile;
     87     DWORD                m_dwNumBuffers;
     88     DWORD                m_dwCreationFlags;
     89 
     90     HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
     91 
     92 public:
     93     CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers,
     94         CWaveFile* pWaveFile, DWORD dwCreationFlags );
     95     virtual ~CSound();
     96 
     97     HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
     98     LPDIRECTSOUNDBUFFER GetFreeBuffer();
     99 
    100     HRESULT Play( DWORD dwPriority = 0, DWORD dwFlags = 0, LONG lVolume = 0, 
    101         LONG lFrequency = -1, LONG lPan = 0 );
    102     HRESULT Stop();
    103     HRESULT Reset();
    104     BOOL    IsSoundPlaying();
    105 };
    106 
    107 
    108 //-----------------------------------------------------------------------------
    109 // Name: class CWaveFile
    110 // Desc: Encapsulates reading or writing sound data to or from a wave file
    111 //-----------------------------------------------------------------------------
    112 class CWaveFile
    113 {
    114 public:
    115     WAVEFORMATEX* m_pwfx;        // Pointer to WAVEFORMATEX structure
    116     HMMIO         m_hmmio;       // MM I/O handle for the WAVE
    117     MMCKINFO      m_ck;          // Multimedia RIFF chunk
    118     MMCKINFO      m_ckRiff;      // Use in opening a WAVE file
    119     DWORD         m_dwSize;      // The size of the wave file
    120     MMIOINFO      m_mmioinfoOut;
    121     DWORD         m_dwFlags;
    122     BOOL          m_bIsReadingFromMemory;
    123     BYTE*         m_pbData;
    124     BYTE*         m_pbDataCur;
    125     ULONG         m_ulDataSize;
    126     CHAR*         m_pResourceBuffer;
    127 
    128 protected:
    129     HRESULT ReadMMIO();
    130     HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
    131 
    132 public:
    133     CWaveFile();
    134     ~CWaveFile();
    135 
    136     HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
    137     HRESULT Close();
    138 
    139     HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
    140     HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
    141 
    142     DWORD   GetSize();
    143     HRESULT ResetFile();
    144     WAVEFORMATEX* GetFormat() { return m_pwfx; };
    145 };
    146 
    147 
    148 
    149 
    150 #endif // DSUTIL_H

     

    DirectSound.cpp

    View Code
       1 //-----------------------------------------------------------------------------
       2 // File: DSUtil.cpp
       3 //
       4 // Desc: DirectSound framework classes for reading and writing wav files and
       5 //       playing them in DirectSound buffers. Feel free to use this class 
       6 //       as a starting point for adding extra functionality.
       7 //
       8 // Copyright (c) Microsoft Corp. All rights reserved.
       9 //-----------------------------------------------------------------------------
      10 //
      11 // Note: This file has been edited for use in Beginning Game Programming, Third Edition,
      12 // originally distributed with a 2004 release of DirectX 9.0c SDK.
      13 //
      14 
      15 #define STRICT
      16 #include <windows.h>
      17 #include <mmsystem.h>
      18 #include "DirectSound.h"
      19 
      20 
      21 //-----------------------------------------------------------------------------
      22 // Miscellaneous helper functions
      23 //-----------------------------------------------------------------------------
      24 #define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
      25 #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
      26 #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
      27 
      28 
      29 //-----------------------------------------------------------------------------
      30 // Name: CSoundManager::CSoundManager()
      31 // Desc: Constructs the class
      32 //-----------------------------------------------------------------------------
      33 CSoundManager::CSoundManager()
      34 {
      35     m_pDS = NULL;
      36 }
      37 
      38 //-----------------------------------------------------------------------------
      39 // Name: CSoundManager::~CSoundManager()
      40 // Desc: Destroys the class
      41 //-----------------------------------------------------------------------------
      42 CSoundManager::~CSoundManager()
      43 {
      44     SAFE_RELEASE( m_pDS ); 
      45 }
      46 
      47 //-----------------------------------------------------------------------------
      48 // Name: CSoundManager::Initialize()
      49 // Desc: Initializes the IDirectSound object and also sets the primary buffer
      50 //       format.  This function must be called before any others.
      51 //-----------------------------------------------------------------------------
      52 HRESULT CSoundManager::Initialize( HWND  hWnd, 
      53                                    DWORD dwCoopLevel )
      54 {
      55     HRESULT             hr;
      56 
      57     SAFE_RELEASE( m_pDS );
      58 
      59     // Create IDirectSound using the primary sound device
      60     if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
      61         return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
      62 
      63     // Set DirectSound coop level 
      64     if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
      65         return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );   
      66 
      67     return S_OK;
      68 }
      69 
      70 
      71 
      72 
      73 //-----------------------------------------------------------------------------
      74 // Name: CSoundManager::SetPrimaryBufferFormat()
      75 // Desc: Set primary buffer to a specified format 
      76 //       !WARNING! - Setting the primary buffer format and then using this
      77 //                   same dsound object for DirectMusic messes up DirectMusic! 
      78 //       For example, to set the primary buffer format to 22kHz stereo, 16-bit
      79 //       then:   dwPrimaryChannels = 2
      80 //               dwPrimaryFreq     = 22050, 
      81 //               dwPrimaryBitRate  = 16
      82 //-----------------------------------------------------------------------------
      83 HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels, 
      84                                                DWORD dwPrimaryFreq, 
      85                                                DWORD dwPrimaryBitRate )
      86 {
      87     HRESULT             hr;
      88     LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
      89 
      90     if( m_pDS == NULL )
      91         return CO_E_NOTINITIALIZED;
      92 
      93     // Get the primary buffer 
      94     DSBUFFERDESC dsbd;
      95     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
      96     dsbd.dwSize        = sizeof(DSBUFFERDESC);
      97     dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER;
      98     dsbd.dwBufferBytes = 0;
      99     dsbd.lpwfxFormat   = NULL;
     100        
     101     if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
     102         return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
     103 
     104     WAVEFORMATEX wfx;
     105     ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); 
     106     wfx.wFormatTag      = (WORD) WAVE_FORMAT_PCM; 
     107     wfx.nChannels       = (WORD) dwPrimaryChannels; 
     108     wfx.nSamplesPerSec  = (DWORD) dwPrimaryFreq; 
     109     wfx.wBitsPerSample  = (WORD) dwPrimaryBitRate; 
     110     wfx.nBlockAlign     = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
     111     wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);
     112 
     113     if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
     114         return DXTRACE_ERR( TEXT("SetFormat"), hr );
     115 
     116     SAFE_RELEASE( pDSBPrimary );
     117 
     118     return S_OK;
     119 }
     120 
     121 
     122 
     123 //-----------------------------------------------------------------------------
     124 // Name: CSoundManager::Create()
     125 // Desc: 
     126 //-----------------------------------------------------------------------------
     127 HRESULT CSoundManager::Create( CSound** ppSound, 
     128                                LPTSTR strWaveFileName, 
     129                                DWORD dwCreationFlags, 
     130                                GUID guid3DAlgorithm,
     131                                DWORD dwNumBuffers )
     132 {
     133     HRESULT hr;
     134     HRESULT hrRet = S_OK;
     135     DWORD   i;
     136     LPDIRECTSOUNDBUFFER* apDSBuffer     = NULL;
     137     DWORD                dwDSBufferSize = NULL;
     138     CWaveFile*           pWaveFile      = NULL;
     139 
     140     if( m_pDS == NULL )
     141         return CO_E_NOTINITIALIZED;
     142     if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
     143         return E_INVALIDARG;
     144 
     145     apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
     146     if( apDSBuffer == NULL )
     147     {
     148         hr = E_OUTOFMEMORY;
     149         goto LFail;
     150     }
     151 
     152     pWaveFile = new CWaveFile();
     153     if( pWaveFile == NULL )
     154     {
     155         hr = E_OUTOFMEMORY;
     156         goto LFail;
     157     }
     158 
     159     pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
     160 
     161     if( pWaveFile->GetSize() == 0 )
     162     {
     163         // Wave is blank, so don't create it.
     164         hr = E_FAIL;
     165         goto LFail;
     166     }
     167 
     168     // Make the DirectSound buffer the same size as the wav file
     169     dwDSBufferSize = pWaveFile->GetSize();
     170 
     171     // Create the direct sound buffer, and only request the flags needed
     172     // since each requires some overhead and limits if the buffer can 
     173     // be hardware accelerated
     174     DSBUFFERDESC dsbd;
     175     ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
     176     dsbd.dwSize          = sizeof(DSBUFFERDESC);
     177     dsbd.dwFlags         = dwCreationFlags;
     178     dsbd.dwBufferBytes   = dwDSBufferSize;
     179     dsbd.guid3DAlgorithm = guid3DAlgorithm;
     180     dsbd.lpwfxFormat     = pWaveFile->m_pwfx;
     181     
     182     // DirectSound is only guarenteed to play PCM data.  Other
     183     // formats may or may not work depending the sound card driver.
     184     hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
     185 
     186     // Be sure to return this error code if it occurs so the
     187     // callers knows this happened.
     188     if( hr == DS_NO_VIRTUALIZATION )
     189         hrRet = DS_NO_VIRTUALIZATION;
     190             
     191     if( FAILED(hr) )
     192     {
     193         // DSERR_BUFFERTOOSMALL will be returned if the buffer is
     194         // less than DSBSIZE_FX_MIN and the buffer is created
     195         // with DSBCAPS_CTRLFX.
     196         
     197         // It might also fail if hardware buffer mixing was requested
     198         // on a device that doesn't support it.
     199         DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
     200                     
     201         goto LFail;
     202     }
     203 
     204     // Default to use DuplicateSoundBuffer() when created extra buffers since always 
     205     // create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if 
     206     // DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
     207     if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
     208     {
     209         for( i=1; i<dwNumBuffers; i++ )
     210         {
     211             if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
     212             {
     213                 DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
     214                 goto LFail;
     215             }
     216         }
     217     }
     218     else
     219     {
     220         for( i=1; i<dwNumBuffers; i++ )
     221         {
     222             hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[i], NULL );
     223             if( FAILED(hr) )
     224             {
     225                 DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
     226                 goto LFail;
     227             }
     228         }
     229    }
     230     
     231     // Create the sound
     232     *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );
     233     
     234     SAFE_DELETE_ARRAY( apDSBuffer );
     235     return hrRet;
     236 
     237 LFail:
     238     // Cleanup
     239     SAFE_DELETE( pWaveFile );
     240     SAFE_DELETE_ARRAY( apDSBuffer );
     241     return hr;
     242 }
     243 
     244 
     245 
     246 //-----------------------------------------------------------------------------
     247 // Name: CSound::CSound()
     248 // Desc: Constructs the class
     249 //-----------------------------------------------------------------------------
     250 CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, 
     251                 DWORD dwNumBuffers, CWaveFile* pWaveFile, DWORD dwCreationFlags )
     252 {
     253     DWORD i;
     254 
     255     m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
     256     if( NULL != m_apDSBuffer )
     257     {
     258         for( i=0; i<dwNumBuffers; i++ )
     259             m_apDSBuffer[i] = apDSBuffer[i];
     260     
     261         m_dwDSBufferSize = dwDSBufferSize;
     262         m_dwNumBuffers   = dwNumBuffers;
     263         m_pWaveFile      = pWaveFile;
     264         m_dwCreationFlags = dwCreationFlags;
     265         
     266         FillBufferWithSound( m_apDSBuffer[0], FALSE );
     267     }
     268 }
     269 
     270 
     271 
     272 
     273 //-----------------------------------------------------------------------------
     274 // Name: CSound::~CSound()
     275 // Desc: Destroys the class
     276 //-----------------------------------------------------------------------------
     277 CSound::~CSound()
     278 {
     279     for( DWORD i=0; i<m_dwNumBuffers; i++ )
     280     {
     281         SAFE_RELEASE( m_apDSBuffer[i] ); 
     282     }
     283 
     284     SAFE_DELETE_ARRAY( m_apDSBuffer ); 
     285     SAFE_DELETE( m_pWaveFile );
     286 }
     287 
     288 
     289 
     290 
     291 //-----------------------------------------------------------------------------
     292 // Name: CSound::FillBufferWithSound()
     293 // Desc: Fills a DirectSound buffer with a sound file 
     294 //-----------------------------------------------------------------------------
     295 HRESULT CSound::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger )
     296 {
     297     HRESULT hr; 
     298     VOID*   pDSLockedBuffer      = NULL; // Pointer to locked buffer memory
     299     DWORD   dwDSLockedBufferSize = 0;    // Size of the locked DirectSound buffer
     300     DWORD   dwWavDataRead        = 0;    // Amount of data read from the wav file 
     301 
     302     if( pDSB == NULL )
     303         return CO_E_NOTINITIALIZED;
     304 
     305     // Make sure we have focus, and we didn't just switch in from
     306     // an app which had a DirectSound device
     307     if( FAILED( hr = RestoreBuffer( pDSB, NULL ) ) ) 
     308         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
     309 
     310     // Lock the buffer down
     311     if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize, 
     312                                  &pDSLockedBuffer, &dwDSLockedBufferSize, 
     313                                  NULL, NULL, 0L ) ) )
     314         return DXTRACE_ERR( TEXT("Lock"), hr );
     315 
     316     // Reset the wave file to the beginning 
     317     m_pWaveFile->ResetFile();
     318 
     319     if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
     320                                         dwDSLockedBufferSize, 
     321                                         &dwWavDataRead ) ) )           
     322         return DXTRACE_ERR( TEXT("Read"), hr );
     323 
     324     if( dwWavDataRead == 0 )
     325     {
     326         // Wav is blank, so just fill with silence
     327         FillMemory( (BYTE*) pDSLockedBuffer, 
     328                     dwDSLockedBufferSize, 
     329                     (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
     330     }
     331     else if( dwWavDataRead < dwDSLockedBufferSize )
     332     {
     333         // If the wav file was smaller than the DirectSound buffer, 
     334         // we need to fill the remainder of the buffer with data 
     335         if( bRepeatWavIfBufferLarger )
     336         {       
     337             // Reset the file and fill the buffer with wav data
     338             DWORD dwReadSoFar = dwWavDataRead;    // From previous call above.
     339             while( dwReadSoFar < dwDSLockedBufferSize )
     340             {  
     341                 // This will keep reading in until the buffer is full 
     342                 // for very short files
     343                 if( FAILED( hr = m_pWaveFile->ResetFile() ) )
     344                     return DXTRACE_ERR( TEXT("ResetFile"), hr );
     345 
     346                 hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
     347                                         dwDSLockedBufferSize - dwReadSoFar,
     348                                         &dwWavDataRead );
     349                 if( FAILED(hr) )
     350                     return DXTRACE_ERR( TEXT("Read"), hr );
     351 
     352                 dwReadSoFar += dwWavDataRead;
     353             } 
     354         }
     355         else
     356         {
     357             // Don't repeat the wav file, just fill in silence 
     358             FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead, 
     359                         dwDSLockedBufferSize - dwWavDataRead, 
     360                         (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
     361         }
     362     }
     363 
     364     // Unlock the buffer, we don't need it anymore.
     365     pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
     366 
     367     return S_OK;
     368 }
     369 
     370 
     371 
     372 
     373 //-----------------------------------------------------------------------------
     374 // Name: CSound::RestoreBuffer()
     375 // Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was 
     376 //       restored.  It can also NULL if the information is not needed.
     377 //-----------------------------------------------------------------------------
     378 HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
     379 {
     380     HRESULT hr;
     381 
     382     if( pDSB == NULL )
     383         return CO_E_NOTINITIALIZED;
     384     if( pbWasRestored )
     385         *pbWasRestored = FALSE;
     386 
     387     DWORD dwStatus;
     388     if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
     389         return DXTRACE_ERR( TEXT("GetStatus"), hr );
     390 
     391     if( dwStatus & DSBSTATUS_BUFFERLOST )
     392     {
     393         // Since the app could have just been activated, then
     394         // DirectSound may not be giving us control yet, so 
     395         // the restoring the buffer may fail.  
     396         // If it does, sleep until DirectSound gives us control.
     397         do 
     398         {
     399             hr = pDSB->Restore();
     400             if( hr == DSERR_BUFFERLOST )
     401                 Sleep( 10 );
     402         }
     403         while( ( hr = pDSB->Restore() ) == DSERR_BUFFERLOST );
     404 
     405         if( pbWasRestored != NULL )
     406             *pbWasRestored = TRUE;
     407 
     408         return S_OK;
     409     }
     410     else
     411     {
     412         return S_FALSE;
     413     }
     414 }
     415 
     416 
     417 
     418 
     419 //-----------------------------------------------------------------------------
     420 // Name: CSound::GetFreeBuffer()
     421 // Desc: Finding the first buffer that is not playing and return a pointer to 
     422 //       it, or if all are playing return a pointer to a randomly selected buffer.
     423 //-----------------------------------------------------------------------------
     424 LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
     425 {
     426     if( m_apDSBuffer == NULL )
     427         return FALSE; 
     428     DWORD i;
     429     for( i=0; i<m_dwNumBuffers; i++ )
     430     {
     431         if( m_apDSBuffer[i] )
     432         {  
     433             DWORD dwStatus = 0;
     434             m_apDSBuffer[i]->GetStatus( &dwStatus );
     435             if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
     436                 break;
     437         }
     438     }
     439 
     440     if( i != m_dwNumBuffers )
     441         return m_apDSBuffer[ i ];
     442     else
     443         return m_apDSBuffer[ rand() % m_dwNumBuffers ];
     444 }
     445 
     446 
     447 
     448 //-----------------------------------------------------------------------------
     449 // Name: CSound::Play()
     450 // Desc: Plays the sound using voice management flags.  Pass in DSBPLAY_LOOPING
     451 //       in the dwFlags to loop the sound
     452 //-----------------------------------------------------------------------------
     453 HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan )
     454 {
     455     HRESULT hr;
     456     BOOL    bRestored;
     457 
     458     if( m_apDSBuffer == NULL )
     459         return CO_E_NOTINITIALIZED;
     460 
     461     LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
     462 
     463     if( pDSB == NULL )
     464         return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
     465 
     466     // Restore the buffer if it was lost
     467     if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
     468         return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
     469 
     470     if( bRestored )
     471     {
     472         // The buffer was restored, so we need to fill it with new data
     473         if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
     474             return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
     475     }
     476 
     477     if( m_dwCreationFlags & DSBCAPS_CTRLVOLUME )
     478     {
     479         pDSB->SetVolume( lVolume );
     480     }
     481 
     482     if( lFrequency != -1 && 
     483         (m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
     484     {
     485         pDSB->SetFrequency( lFrequency );
     486     }
     487     
     488     if( m_dwCreationFlags & DSBCAPS_CTRLPAN )
     489     {
     490         pDSB->SetPan( lPan );
     491     }
     492     
     493     return pDSB->Play( 0, dwPriority, dwFlags );
     494 }
     495 
     496 
     497 
     498 //-----------------------------------------------------------------------------
     499 // Name: CSound::Stop()
     500 // Desc: Stops the sound from playing
     501 //-----------------------------------------------------------------------------
     502 HRESULT CSound::Stop()
     503 {
     504     if( m_apDSBuffer == NULL )
     505         return CO_E_NOTINITIALIZED;
     506 
     507     HRESULT hr = 0;
     508 
     509     for( DWORD i=0; i<m_dwNumBuffers; i++ )
     510         hr |= m_apDSBuffer[i]->Stop();
     511 
     512     return hr;
     513 }
     514 
     515 
     516 
     517 
     518 //-----------------------------------------------------------------------------
     519 // Name: CSound::Reset()
     520 // Desc: Reset all of the sound buffers
     521 //-----------------------------------------------------------------------------
     522 HRESULT CSound::Reset()
     523 {
     524     if( m_apDSBuffer == NULL )
     525         return CO_E_NOTINITIALIZED;
     526 
     527     HRESULT hr = 0;
     528 
     529     for( DWORD i=0; i<m_dwNumBuffers; i++ )
     530         hr |= m_apDSBuffer[i]->SetCurrentPosition( 0 );
     531 
     532     return hr;
     533 }
     534 
     535 
     536 
     537 
     538 //-----------------------------------------------------------------------------
     539 // Name: CSound::IsSoundPlaying()
     540 // Desc: Checks to see if a buffer is playing and returns TRUE if it is.
     541 //-----------------------------------------------------------------------------
     542 BOOL CSound::IsSoundPlaying()
     543 {
     544     BOOL bIsPlaying = FALSE;
     545 
     546     if( m_apDSBuffer == NULL )
     547         return FALSE; 
     548 
     549     for( DWORD i=0; i<m_dwNumBuffers; i++ )
     550     {
     551         if( m_apDSBuffer[i] )
     552         {  
     553             DWORD dwStatus = 0;
     554             m_apDSBuffer[i]->GetStatus( &dwStatus );
     555             bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
     556         }
     557     }
     558 
     559     return bIsPlaying;
     560 }
     561 
     562 
     563 
     564 //-----------------------------------------------------------------------------
     565 // Name: CWaveFile::CWaveFile()
     566 // Desc: Constructs the class.  Call Open() to open a wave file for reading.  
     567 //       Then call Read() as needed.  Calling the destructor or Close() 
     568 //       will close the file.  
     569 //-----------------------------------------------------------------------------
     570 CWaveFile::CWaveFile()
     571 {
     572     m_pwfx    = NULL;
     573     m_hmmio   = NULL;
     574     m_pResourceBuffer = NULL;
     575     m_dwSize  = 0;
     576     m_bIsReadingFromMemory = FALSE;
     577 }
     578 
     579 
     580 
     581 
     582 //-----------------------------------------------------------------------------
     583 // Name: CWaveFile::~CWaveFile()
     584 // Desc: Destructs the class
     585 //-----------------------------------------------------------------------------
     586 CWaveFile::~CWaveFile()
     587 {
     588     Close();
     589 
     590     if( !m_bIsReadingFromMemory )
     591         SAFE_DELETE_ARRAY( m_pwfx );
     592 }
     593 
     594 
     595 
     596 
     597 //-----------------------------------------------------------------------------
     598 // Name: CWaveFile::Open()
     599 // Desc: Opens a wave file for reading
     600 //-----------------------------------------------------------------------------
     601 HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
     602 {
     603     HRESULT hr;
     604 
     605     m_dwFlags = dwFlags;
     606     m_bIsReadingFromMemory = FALSE;
     607 
     608     if( m_dwFlags == WAVEFILE_READ )
     609     {
     610         if( strFileName == NULL )
     611             return E_INVALIDARG;
     612         SAFE_DELETE_ARRAY( m_pwfx );
     613 
     614         m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
     615 
     616         if( NULL == m_hmmio )
     617         {
     618             HRSRC   hResInfo;
     619             HGLOBAL hResData;
     620             DWORD   dwSize;
     621             VOID*   pvRes;
     622 
     623             // Loading it as a file failed, so try it as a resource
     624             if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
     625             {
     626                 if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
     627                     return DXTRACE_ERR( TEXT("FindResource"), E_FAIL );
     628             }
     629 
     630             if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
     631                 return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
     632 
     633             if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) ) 
     634                 return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
     635 
     636             if( NULL == ( pvRes = LockResource( hResData ) ) )
     637                 return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
     638 
     639             m_pResourceBuffer = new CHAR[ dwSize ];
     640             memcpy( m_pResourceBuffer, pvRes, dwSize );
     641 
     642             MMIOINFO mmioInfo;
     643             ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
     644             mmioInfo.fccIOProc = FOURCC_MEM;
     645             mmioInfo.cchBuffer = dwSize;
     646             mmioInfo.pchBuffer = (CHAR*) m_pResourceBuffer;
     647 
     648             m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
     649         }
     650 
     651         if( FAILED( hr = ReadMMIO() ) )
     652         {
     653             // ReadMMIO will fail if its an not a wave file
     654             mmioClose( m_hmmio, 0 );
     655             return DXTRACE_ERR( TEXT("ReadMMIO"), hr );
     656         }
     657 
     658         if( FAILED( hr = ResetFile() ) )
     659             return DXTRACE_ERR( TEXT("ResetFile"), hr );
     660 
     661         // After the reset, the size of the wav file is m_ck.cksize so store it now
     662         m_dwSize = m_ck.cksize;
     663     }
     664     else
     665     {
     666         m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF  | 
     667                                                   MMIO_READWRITE | 
     668                                                   MMIO_CREATE );
     669         if( NULL == m_hmmio )
     670             return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
     671 
     672         if( FAILED( hr = WriteMMIO( pwfx ) ) )
     673         {
     674             mmioClose( m_hmmio, 0 );
     675             return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
     676         }
     677                         
     678         if( FAILED( hr = ResetFile() ) )
     679             return DXTRACE_ERR( TEXT("ResetFile"), hr );
     680     }
     681 
     682     return hr;
     683 }
     684 
     685 
     686 
     687 //-----------------------------------------------------------------------------
     688 // Name: CWaveFile::ReadMMIO()
     689 // Desc: Support function for reading from a multimedia I/O stream.
     690 //       m_hmmio must be valid before calling.  This function uses it to
     691 //       update m_ckRiff, and m_pwfx. 
     692 //-----------------------------------------------------------------------------
     693 HRESULT CWaveFile::ReadMMIO()
     694 {
     695     MMCKINFO        ckIn;           // chunk info. for general use.
     696     PCMWAVEFORMAT   pcmWaveFormat;  // Temp PCM structure to load in.       
     697 
     698     m_pwfx = NULL;
     699 
     700     if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
     701         return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
     702 
     703     // Check to make sure this is a valid wave file
     704     if( (m_ckRiff.ckid != FOURCC_RIFF) ||
     705         (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
     706         return DXTRACE_ERR( TEXT("mmioFOURCC"), E_FAIL ); 
     707 
     708     // Search the input file for for the 'fmt ' chunk.
     709     ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
     710     if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
     711         return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
     712 
     713     // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
     714     // if there are extra parameters at the end, we'll ignore them
     715        if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
     716            return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
     717 
     718     // Read the 'fmt ' chunk into <pcmWaveFormat>.
     719     if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat, 
     720                   sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
     721         return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
     722 
     723     // Allocate the waveformatex, but if its not pcm format, read the next
     724     // word, and thats how many extra bytes to allocate.
     725     if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
     726     {
     727         m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
     728         if( NULL == m_pwfx )
     729             return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
     730 
     731         // Copy the bytes from the pcm structure to the waveformatex structure
     732         memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
     733         m_pwfx->cbSize = 0;
     734     }
     735     else
     736     {
     737         // Read in length of extra bytes.
     738         WORD cbExtraBytes = 0L;
     739         if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
     740             return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
     741 
     742         m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
     743         if( NULL == m_pwfx )
     744             return DXTRACE_ERR( TEXT("new"), E_FAIL );
     745 
     746         // Copy the bytes from the pcm structure to the waveformatex structure
     747         memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
     748         m_pwfx->cbSize = cbExtraBytes;
     749 
     750         // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
     751         if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
     752                       cbExtraBytes ) != cbExtraBytes )
     753         {
     754             SAFE_DELETE( m_pwfx );
     755             return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
     756         }
     757     }
     758 
     759     // Ascend the input file out of the 'fmt ' chunk.
     760     if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
     761     {
     762         SAFE_DELETE( m_pwfx );
     763         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
     764     }
     765 
     766     return S_OK;
     767 }
     768 
     769 
     770 
     771 
     772 //-----------------------------------------------------------------------------
     773 // Name: CWaveFile::GetSize()
     774 // Desc: Retuns the size of the read access wave file 
     775 //-----------------------------------------------------------------------------
     776 DWORD CWaveFile::GetSize()
     777 {
     778     return m_dwSize;
     779 }
     780 
     781 
     782 
     783 
     784 //-----------------------------------------------------------------------------
     785 // Name: CWaveFile::ResetFile()
     786 // Desc: Resets the internal m_ck pointer so reading starts from the 
     787 //       beginning of the file again 
     788 //-----------------------------------------------------------------------------
     789 HRESULT CWaveFile::ResetFile()
     790 {
     791     if( m_bIsReadingFromMemory )
     792     {
     793         m_pbDataCur = m_pbData;
     794     }
     795     else 
     796     {
     797         if( m_hmmio == NULL )
     798             return CO_E_NOTINITIALIZED;
     799 
     800         if( m_dwFlags == WAVEFILE_READ )
     801         {
     802             // Seek to the data
     803             if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
     804                             SEEK_SET ) )
     805                 return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
     806 
     807             // Search the input file for the 'data' chunk.
     808             m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
     809             if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
     810               return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
     811         }
     812         else
     813         {
     814             // Create the 'data' chunk that holds the waveform samples.  
     815             m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
     816             m_ck.cksize = 0;
     817 
     818             if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) ) 
     819                 return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
     820 
     821             if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
     822                 return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
     823         }
     824     }
     825     
     826     return S_OK;
     827 }
     828 
     829 
     830 
     831 
     832 //-----------------------------------------------------------------------------
     833 // Name: CWaveFile::Read()
     834 // Desc: Reads section of data from a wave file into pBuffer and returns 
     835 //       how much read in pdwSizeRead, reading not more than dwSizeToRead.
     836 //       This uses m_ck to determine where to start reading from.  So 
     837 //       subsequent calls will be continue where the last left off unless 
     838 //       Reset() is called.
     839 //-----------------------------------------------------------------------------
     840 HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
     841 {
     842     if( m_bIsReadingFromMemory )
     843     {
     844         if( m_pbDataCur == NULL )
     845             return CO_E_NOTINITIALIZED;
     846         if( pdwSizeRead != NULL )
     847             *pdwSizeRead = 0;
     848 
     849         if( (BYTE*)(m_pbDataCur + dwSizeToRead) > 
     850             (BYTE*)(m_pbData + m_ulDataSize) )
     851         {
     852             dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
     853         }
     854         
     855         CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
     856         
     857         if( pdwSizeRead != NULL )
     858             *pdwSizeRead = dwSizeToRead;
     859 
     860         return S_OK;
     861     }
     862     else 
     863     {
     864         MMIOINFO mmioinfoIn; // current status of m_hmmio
     865 
     866         if( m_hmmio == NULL )
     867             return CO_E_NOTINITIALIZED;
     868         if( pBuffer == NULL || pdwSizeRead == NULL )
     869             return E_INVALIDARG;
     870 
     871         if( pdwSizeRead != NULL )
     872             *pdwSizeRead = 0;
     873 
     874         if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
     875             return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
     876                 
     877         UINT cbDataIn = dwSizeToRead;
     878         if( cbDataIn > m_ck.cksize ) 
     879             cbDataIn = m_ck.cksize;       
     880 
     881         m_ck.cksize -= cbDataIn;
     882     
     883         for( DWORD cT = 0; cT < cbDataIn; cT++ )
     884         {
     885             // Copy the bytes from the io to the buffer.
     886             if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
     887             {
     888                 if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
     889                     return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
     890 
     891                 if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
     892                     return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
     893             }
     894 
     895             // Actual copy.
     896             *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
     897             mmioinfoIn.pchNext++;
     898         }
     899 
     900         if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
     901             return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
     902 
     903         if( pdwSizeRead != NULL )
     904             *pdwSizeRead = cbDataIn;
     905 
     906         return S_OK;
     907     }
     908 }
     909 
     910 
     911 
     912 
     913 //-----------------------------------------------------------------------------
     914 // Name: CWaveFile::Close()
     915 // Desc: Closes the wave file 
     916 //-----------------------------------------------------------------------------
     917 HRESULT CWaveFile::Close()
     918 {
     919     if( m_dwFlags == WAVEFILE_READ )
     920     {
     921         mmioClose( m_hmmio, 0 );
     922         m_hmmio = NULL;
     923         SAFE_DELETE_ARRAY( m_pResourceBuffer );
     924     }
     925     else
     926     {
     927         m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
     928 
     929         if( m_hmmio == NULL )
     930             return CO_E_NOTINITIALIZED;
     931 
     932         if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
     933             return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
     934     
     935         // Ascend the output file out of the 'data' chunk -- this will cause
     936         // the chunk size of the 'data' chunk to be written.
     937         if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
     938             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
     939     
     940         // Do this here instead...
     941         if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
     942             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
     943         
     944         mmioSeek( m_hmmio, 0, SEEK_SET );
     945 
     946         if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
     947             return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
     948     
     949         m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
     950 
     951         if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) ) 
     952         {
     953             DWORD dwSamples = 0;
     954             mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
     955             mmioAscend( m_hmmio, &m_ck, 0 ); 
     956         }
     957     
     958         // Ascend the output file out of the 'RIFF' chunk -- this will cause
     959         // the chunk size of the 'RIFF' chunk to be written.
     960         if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
     961             return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
     962     
     963         mmioClose( m_hmmio, 0 );
     964         m_hmmio = NULL;
     965     }
     966 
     967     return S_OK;
     968 }
     969 
     970 
     971 
     972 
     973 //-----------------------------------------------------------------------------
     974 // Name: CWaveFile::WriteMMIO()
     975 // Desc: Support function for reading from a multimedia I/O stream
     976 //       pwfxDest is the WAVEFORMATEX for this new wave file.  
     977 //       m_hmmio must be valid before calling.  This function uses it to
     978 //       update m_ckRiff, and m_ck.  
     979 //-----------------------------------------------------------------------------
     980 HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
     981 {
     982     DWORD    dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
     983     MMCKINFO ckOut1;
     984     
     985     dwFactChunk = (DWORD)-1;
     986 
     987     // Create the output file RIFF chunk of form type 'WAVE'.
     988     m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');       
     989     m_ckRiff.cksize = 0;
     990 
     991     if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
     992         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
     993     
     994     // We are now descended into the 'RIFF' chunk we just created.
     995     // Now create the 'fmt ' chunk. Since we know the size of this chunk,
     996     // specify it in the MMCKINFO structure so MMIO doesn't have to seek
     997     // back and set the chunk size after ascending from the chunk.
     998     m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
     999     m_ck.cksize = sizeof(PCMWAVEFORMAT);   
    1000 
    1001     if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
    1002         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
    1003     
    1004     // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type. 
    1005     if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
    1006     {
    1007         if( mmioWrite( m_hmmio, (HPSTR) pwfxDest, 
    1008                        sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
    1009             return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
    1010     }   
    1011     else 
    1012     {
    1013         // Write the variable length size.
    1014         if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest, 
    1015                              sizeof(*pwfxDest) + pwfxDest->cbSize ) != 
    1016                              ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
    1017             return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
    1018     }  
    1019     
    1020     // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
    1021     if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
    1022         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
    1023     
    1024     // Now create the fact chunk, not required for PCM but nice to have.  This is filled
    1025     // in when the close routine is called.
    1026     ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
    1027     ckOut1.cksize = 0;
    1028 
    1029     if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
    1030         return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
    1031     
    1032     if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) != 
    1033                     sizeof(dwFactChunk) )
    1034          return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
    1035     
    1036     // Now ascend out of the fact chunk...
    1037     if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
    1038         return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
    1039        
    1040     return S_OK;
    1041 }
    1042 
    1043 
    1044 
    1045 
    1046 //-----------------------------------------------------------------------------
    1047 // Name: CWaveFile::Write()
    1048 // Desc: Writes data to the open wave file
    1049 //-----------------------------------------------------------------------------
    1050 HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
    1051 {
    1052     UINT cT;
    1053 
    1054     if( m_bIsReadingFromMemory )
    1055         return E_NOTIMPL;
    1056     if( m_hmmio == NULL )
    1057         return CO_E_NOTINITIALIZED;
    1058     if( pnSizeWrote == NULL || pbSrcData == NULL )
    1059         return E_INVALIDARG;
    1060 
    1061     *pnSizeWrote = 0;
    1062     
    1063     for( cT = 0; cT < nSizeToWrite; cT++ )
    1064     {       
    1065         if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
    1066         {
    1067             m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
    1068             if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
    1069                 return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
    1070         }
    1071 
    1072         *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
    1073         (BYTE*)m_mmioinfoOut.pchNext++;
    1074 
    1075         (*pnSizeWrote)++;
    1076     }
    1077 
    1078     return S_OK;
    1079 }

     

    DirectX.h

    View Code
      1 #pragma once
      2 
      3 //header files
      4 #define WIN32_EXTRA_LEAN
      5 #define DIRECTINPUT_VERSION 0x0800
      6 #include <windows.h>
      7 #include <d3d9.h>
      8 #include <d3dx9.h>
      9 #include <dxerr.h>
     10 #include <dinput.h>
     11 #include <xinput.h>
     12 #include <ctime>
     13 #include <iostream>
     14 #include <iomanip>
     15 #include "DirectSound.h"
     16 using namespace std;
     17 
     18 //libraries
     19 #pragma comment(lib,"winmm.lib")
     20 #pragma comment(lib,"user32.lib")
     21 #pragma comment(lib,"gdi32.lib")
     22 #pragma comment(lib,"dxguid.lib")
     23 #pragma comment(lib,"d3d9.lib")
     24 #pragma comment(lib,"d3dx9.lib")
     25 #pragma comment(lib, "dxerr.lib")
     26 #pragma comment(lib,"dinput8.lib")
     27 #pragma comment(lib,"xinput.lib")
     28 
     29 //program values
     30 extern const string APPTITLE;
     31 extern const int SCREENW;
     32 extern const int SCREENH;
     33 extern bool gameover;
     34 
     35 //macro to detect key presses
     36 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
     37 
     38 //Direct3D objects
     39 extern LPDIRECT3D9 d3d; 
     40 extern LPDIRECT3DDEVICE9 d3ddev; 
     41 extern LPDIRECT3DSURFACE9 backbuffer;
     42 extern LPD3DXSPRITE spriteobj;
     43 
     44 //DirectSound object
     45 extern CSoundManager *dsound;
     46 
     47 //sprite structure
     48 struct SPRITE
     49 {
     50     float x,y;
     51     int frame, columns;
     52     int width, height;
     53     float scaling, rotation;
     54     int startframe, endframe;
     55     int starttime, delay;
     56     int direction;
     57     float velx, vely;
     58     D3DCOLOR color;
     59 
     60     SPRITE() 
     61     {
     62         frame = 0;
     63         columns = 1;
     64         width = height = 0;
     65         scaling = 1.0f;
     66         rotation = 0.0f;
     67         startframe = endframe = 0;
     68         direction = 1;
     69         starttime = delay = 0;
     70         velx = vely = 0.0f;
     71         color = D3DCOLOR_XRGB(255,255,255);
     72     }
     73 };
     74 
     75 //Direct3D functions
     76 bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen);
     77 void Direct3D_Shutdown();
     78 LPDIRECT3DSURFACE9 LoadSurface(string filename);
     79 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);
     80 LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));
     81 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, 
     82     int framenum, int framew, int frameh, int columns);
     83 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay);
     84 
     85 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, 
     86     int frame = 0, int columns = 1, float rotation = 0.0f, float scaling = 1.0f, 
     87     D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));
     88 
     89 //bounding box collision detection
     90 int Collision(SPRITE sprite1, SPRITE sprite2);
     91 
     92 //distance based collision detection
     93 bool CollisionD(SPRITE sprite1, SPRITE sprite2);
     94 
     95 //DirectInput objects, devices, and states
     96 extern LPDIRECTINPUT8 dinput;
     97 extern LPDIRECTINPUTDEVICE8 dimouse;
     98 extern LPDIRECTINPUTDEVICE8 dikeyboard;
     99 extern DIMOUSESTATE mouse_state;
    100 extern XINPUT_GAMEPAD controllers[4];
    101 
    102 //DirectInput functions
    103 bool DirectInput_Init(HWND);
    104 void DirectInput_Update();
    105 void DirectInput_Shutdown();
    106 bool Key_Down(int);
    107 int Mouse_Button(int);
    108 int Mouse_X();
    109 int Mouse_Y();
    110 void XInput_Vibrate(int contNum = 0, int amount = 65535);
    111 bool XInput_Controller_Found();
    112 
    113 //game functions
    114 bool Game_Init(HWND window);
    115 void Game_Run(HWND window);
    116 void Game_End();
    117 
    118 
    119 //font functions
    120 LPD3DXFONT MakeFont(string name, int size);
    121 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));
    122 
    123 //DirectSound functions
    124 bool DirectSound_Init(HWND hwnd);
    125 void DirectSound_Shutdown();
    126 CSound* LoadSound(string filename);
    127 void PlaySound(CSound *sound);
    128 void LoopSound(CSound *sound);
    129 void StopSound(CSound *sound);

     

    DirectX.cpp

    View Code
      1 #include "DirectX.h"
      2 #include <iostream>
      3 #include <string>
      4 using namespace std;
      5 
      6 //DirectSound object
      7 CSoundManager *dsound = NULL;
      8 
      9 //Direct3D variables
     10 LPDIRECT3D9 d3d = NULL; 
     11 LPDIRECT3DDEVICE9 d3ddev = NULL; 
     12 LPDIRECT3DSURFACE9 backbuffer = NULL;
     13 LPD3DXSPRITE spriteobj;
     14 
     15 //DirectInput variables
     16 LPDIRECTINPUT8 dinput = NULL;
     17 LPDIRECTINPUTDEVICE8 dimouse = NULL;
     18 LPDIRECTINPUTDEVICE8 dikeyboard = NULL;
     19 DIMOUSESTATE mouse_state;
     20 char keys[256];
     21 XINPUT_GAMEPAD controllers[4];
     22 
     23 
     24 bool Direct3D_Init(HWND window, int width, int height, bool fullscreen)
     25 {
     26     //initialize Direct3D
     27     d3d = Direct3DCreate9(D3D_SDK_VERSION);
     28     if (!d3d) return false;
     29 
     30     //set Direct3D presentation parameters
     31     D3DPRESENT_PARAMETERS d3dpp; 
     32     ZeroMemory(&d3dpp, sizeof(d3dpp));
     33     d3dpp.hDeviceWindow = window;
     34     d3dpp.Windowed = (!fullscreen);
     35     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
     36     d3dpp.EnableAutoDepthStencil = 1;
     37     d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
     38     d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
     39     d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
     40     d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
     41     d3dpp.BackBufferCount = 1;
     42     d3dpp.BackBufferWidth = width;
     43     d3dpp.BackBufferHeight = height;
     44 
     45     //create Direct3D device
     46     d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
     47         D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
     48     if (!d3ddev) return false;
     49 
     50 
     51     //get a pointer to the back buffer surface
     52     d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
     53 
     54     //create sprite object
     55     D3DXCreateSprite(d3ddev, &spriteobj);
     56 
     57     return 1;
     58 }
     59 
     60 void Direct3D_Shutdown()
     61 {
     62     if (spriteobj) spriteobj->Release();
     63 
     64     if (d3ddev) d3ddev->Release();
     65     if (d3d) d3d->Release();
     66 }
     67 
     68 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source)
     69 {
     70     //get width/height from source surface
     71     D3DSURFACE_DESC desc;
     72     source->GetDesc(&desc);
     73 
     74     //create rects for drawing
     75     RECT source_rect = {0, 0, (long)desc.Width, (long)desc.Height };
     76     RECT dest_rect = { (long)x, (long)y, (long)x+desc.Width, (long)y+desc.Height};
     77     
     78     //draw the source surface onto the dest
     79     d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE);
     80 
     81 }
     82 
     83 LPDIRECT3DSURFACE9 LoadSurface(string filename)
     84 {
     85     LPDIRECT3DSURFACE9 image = NULL;
     86     
     87     //get width and height from bitmap file
     88     D3DXIMAGE_INFO info;
     89     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
     90     if (result != D3D_OK)
     91         return NULL;
     92 
     93     //create surface
     94     result = d3ddev->CreateOffscreenPlainSurface(
     95         info.Width,         //width of the surface
     96         info.Height,        //height of the surface
     97         D3DFMT_X8R8G8B8,    //surface format
     98         D3DPOOL_DEFAULT,    //memory pool to use
     99         &image,             //pointer to the surface
    100         NULL);              //reserved (always NULL)
    101 
    102     if (result != D3D_OK) return NULL;
    103 
    104     //load surface from file into newly created surface
    105     result = D3DXLoadSurfaceFromFile(
    106         image,                  //destination surface
    107         NULL,                   //destination palette
    108         NULL,                   //destination rectangle
    109         filename.c_str(),       //source filename
    110         NULL,                   //source rectangle
    111         D3DX_DEFAULT,           //controls how image is filtered
    112         D3DCOLOR_XRGB(0,0,0),   //for transparency (0 for none)
    113         NULL);                  //source image info (usually NULL)
    114 
    115     //make sure file was loaded okay
    116     if (result != D3D_OK) return NULL;
    117 
    118     return image;
    119 }
    120 
    121 
    122 LPDIRECT3DTEXTURE9 LoadTexture(std::string filename, D3DCOLOR transcolor)
    123 {  
    124     LPDIRECT3DTEXTURE9 texture = NULL;
    125 
    126     //get width and height from bitmap file
    127     D3DXIMAGE_INFO info;
    128     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
    129     if (result != D3D_OK) return NULL;
    130 
    131     //create the new texture by loading a bitmap image file
    132     D3DXCreateTextureFromFileEx( 
    133         d3ddev,                //Direct3D device object
    134         filename.c_str(),      //bitmap filename
    135         info.Width,            //bitmap image width
    136         info.Height,           //bitmap image height
    137         1,                     //mip-map levels (1 for no chain)
    138         D3DPOOL_DEFAULT,       //the type of surface (standard)
    139         D3DFMT_UNKNOWN,        //surface format (default)
    140         D3DPOOL_DEFAULT,       //memory class for the texture
    141         D3DX_DEFAULT,          //image filter
    142         D3DX_DEFAULT,          //mip filter
    143         transcolor,            //color key for transparency
    144         &info,                 //bitmap file info (from loaded file)
    145         NULL,                  //color palette
    146         &texture );            //destination texture
    147 
    148     //make sure the bitmap textre was loaded correctly
    149     if (result != D3D_OK) return NULL;
    150 
    151     return texture;
    152 }
    153 
    154 
    155 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, int framenum, int framew, int frameh, int columns)
    156 {
    157     D3DXVECTOR3 position( (float)destx, (float)desty, 0 );
    158     D3DCOLOR white = D3DCOLOR_XRGB(255,255,255);
    159 
    160     RECT rect;
    161      rect.left = (framenum % columns) * framew;
    162     rect.top = (framenum / columns) * frameh;
    163     rect.right = rect.left + framew;
    164     rect.bottom = rect.top + frameh;
    165 
    166     spriteobj->Draw( texture, &rect, NULL, &position, white);
    167 }
    168 
    169 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay)
    170 {
    171     if ((int)GetTickCount() > starttime + delay)
    172     {
    173         starttime = GetTickCount();
    174 
    175         frame += direction;
    176         if (frame > endframe) frame = startframe;
    177         if (frame < startframe) frame = endframe;
    178     }    
    179 }
    180 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, 
    181     int frame, int columns, float rotation, float scaling, D3DCOLOR color)
    182 {
    183     //create a scale vector
    184     D3DXVECTOR2 scale( scaling, scaling );
    185 
    186     //create a translate vector
    187     D3DXVECTOR2 trans( x, y );
    188 
    189     //set center by dividing width and height by two
    190     D3DXVECTOR2 center( (float)( width * scaling )/2, (float)( height * scaling )/2);
    191 
    192     //create 2D transformation matrix
    193     D3DXMATRIX mat;
    194     D3DXMatrixTransformation2D( &mat, NULL, 0, &scale, &center, rotation, &trans );
    195     
    196     //tell sprite object to use the transform
    197     spriteobj->SetTransform( &mat );
    198 
    199     //calculate frame location in source image
    200     int fx = (frame % columns) * width;
    201     int fy = (frame / columns) * height;
    202     RECT srcRect = {fx, fy, fx + width, fy + height};
    203 
    204     //draw the sprite frame
    205     spriteobj->Draw( image, &srcRect, NULL, NULL, color );
    206 }
    207 
    208 //bounding  box collision detection
    209 int Collision(SPRITE sprite1, SPRITE sprite2)
    210 {
    211     RECT rect1;
    212     rect1.left = (long)sprite1.x;
    213     rect1.top = (long)sprite1.y;
    214     rect1.right = (long)sprite1.x + sprite1.width * sprite1.scaling;
    215     rect1.bottom = (long)sprite1.y + sprite1.height * sprite1.scaling;
    216 
    217     RECT rect2;
    218     rect2.left = (long)sprite2.x;
    219     rect2.top = (long)sprite2.y;
    220     rect2.right = (long)sprite2.x + sprite2.width * sprite2.scaling;
    221     rect2.bottom = (long)sprite2.y + sprite2.height * sprite2.scaling;
    222 
    223     RECT dest; //ignored
    224     return IntersectRect(&dest, &rect1, &rect2);
    225 }
    226 
    227 
    228 bool CollisionD(SPRITE sprite1, SPRITE sprite2)
    229 {
    230     double radius1, radius2;
    231 
    232     //calculate radius 1
    233     if (sprite1.width > sprite1.height)
    234         radius1 = (sprite1.width * sprite1.scaling) / 2.0;
    235     else
    236         radius1 = (sprite1.height * sprite1.scaling) / 2.0;
    237 
    238     //center point 1
    239     double x1 = sprite1.x + radius1;
    240     double y1 = sprite1.y + radius1;
    241     D3DXVECTOR2 vector1(x1, y1);
    242 
    243     //calculate radius 2
    244     if (sprite2.width > sprite2.height)
    245         radius2 = (sprite2.width * sprite2.scaling) / 2.0;
    246     else
    247         radius2 = (sprite2.height * sprite2.scaling) / 2.0;
    248 
    249     //center point 2
    250     double x2 = sprite2.x + radius2;
    251     double y2 = sprite2.y + radius2;
    252     D3DXVECTOR2 vector2(x2, y2);
    253 
    254     //calculate distance
    255     double deltax = vector1.x - vector2.x;
    256     double deltay = vector2.y - vector1.y;
    257     double dist = sqrt((deltax * deltax) + (deltay * deltay));
    258 
    259     //return distance comparison
    260     return (dist < radius1 + radius2);
    261 }
    262 
    263 bool DirectInput_Init(HWND hwnd)
    264 {
    265     //initialize DirectInput object
    266     DirectInput8Create(
    267         GetModuleHandle(NULL), 
    268         DIRECTINPUT_VERSION, 
    269         IID_IDirectInput8,
    270         (void**)&dinput,
    271         NULL);
    272 
    273     //initialize the keyboard
    274     dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL);
    275     dikeyboard->SetDataFormat(&c_dfDIKeyboard);
    276     dikeyboard->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
    277     dikeyboard->Acquire();
    278 
    279     //initialize the mouse
    280     dinput->CreateDevice(GUID_SysMouse, &dimouse, NULL);
    281     dimouse->SetDataFormat(&c_dfDIMouse);
    282     dimouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
    283     dimouse->Acquire();
    284     d3ddev->ShowCursor(false);
    285 
    286     return true;
    287 }
    288 
    289 void DirectInput_Update()
    290 {
    291     //update mouse
    292     dimouse->Poll();
    293     if (!SUCCEEDED(dimouse->GetDeviceState(sizeof(DIMOUSESTATE),&mouse_state)))
    294     {
    295         //mouse device lose, try to re-acquire
    296         dimouse->Acquire();
    297     }
    298 
    299     //update keyboard
    300     dikeyboard->Poll();
    301     if (!SUCCEEDED(dikeyboard->GetDeviceState(256,(LPVOID)&keys)))
    302     {
    303         //keyboard device lost, try to re-acquire
    304         dikeyboard->Acquire();
    305     }
    306 
    307     //update controllers
    308     for (int i=0; i< 4; i++ )
    309     {
    310         ZeroMemory( &controllers[i], sizeof(XINPUT_STATE) );
    311 
    312         //get the state of the controller
    313         XINPUT_STATE state;
    314         DWORD result = XInputGetState( i, &state );
    315 
    316         //store state in global controllers array
    317         if (result == 0) controllers[i] = state.Gamepad;
    318     }
    319 }
    320 
    321 
    322 int Mouse_X()
    323 {
    324     return mouse_state.lX;
    325 }
    326 
    327 int Mouse_Y()
    328 {
    329     return mouse_state.lY;
    330 }
    331 
    332 int Mouse_Button(int button)
    333 {
    334     return mouse_state.rgbButtons[button] & 0x80;
    335 }
    336 
    337 bool Key_Down(int key) 
    338 {
    339     return (bool)(keys[key] & 0x80);
    340 }
    341 
    342 
    343 void DirectInput_Shutdown()
    344 {
    345     if (dikeyboard) 
    346     {
    347         dikeyboard->Unacquire();
    348         dikeyboard->Release();
    349         dikeyboard = NULL;
    350     }
    351     if (dimouse) 
    352     {
    353         dimouse->Unacquire();
    354         dimouse->Release();
    355         dimouse = NULL;
    356     }
    357 }
    358 
    359 bool XInput_Controller_Found()
    360 {
    361     XINPUT_CAPABILITIES caps;
    362     ZeroMemory(&caps, sizeof(XINPUT_CAPABILITIES));
    363     XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps);
    364     if (caps.Type != 0) return false;
    365     
    366     return true;
    367 }
    368 
    369 void XInput_Vibrate(int contNum, int amount)
    370 {
    371     XINPUT_VIBRATION vibration;
    372     ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) );
    373     vibration.wLeftMotorSpeed = amount;
    374     vibration.wRightMotorSpeed = amount; 
    375     XInputSetState( contNum, &vibration );
    376 }
    377 
    378 LPD3DXFONT MakeFont(string name, int size)
    379 {
    380     LPD3DXFONT font = NULL;
    381 
    382     D3DXFONT_DESC desc = {
    383         size,                   //height
    384         0,                      //width
    385         0,                      //weight
    386         0,                      //miplevels
    387         false,                  //italic
    388         DEFAULT_CHARSET,        //charset
    389         OUT_TT_PRECIS,          //output precision
    390         CLIP_DEFAULT_PRECIS,    //quality
    391         DEFAULT_PITCH,          //pitch and family
    392         ""                      //font name
    393     };
    394 
    395     strcpy(desc.FaceName, name.c_str());
    396 
    397     D3DXCreateFontIndirect(d3ddev, &desc, &font);
    398 
    399     return font;
    400 }
    401 
    402 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color)
    403 {
    404     //figure out the text boundary
    405     RECT rect = { x, y, 0, 0 };
    406     font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color); 
    407 
    408     //print the text
    409     font->DrawText(spriteobj, text.c_str(), text.length(), &rect, DT_LEFT, color); 
    410 }
    411 
    412 bool DirectSound_Init(HWND hwnd)
    413 {
    414     //create DirectSound manager object
    415     dsound = new CSoundManager();
    416 
    417     //initialize DirectSound
    418     HRESULT result;
    419     result = dsound->Initialize(hwnd, DSSCL_PRIORITY);
    420     if (FAILED(result))
    421         return false;
    422 
    423     //set the primary buffer format
    424     result = dsound->SetPrimaryBufferFormat(2, 22050, 16);
    425     if (FAILED(result))
    426         return false;
    427 
    428     return true;
    429 }
    430 
    431 void DirectSound_Shutdown()
    432 {
    433     if (dsound)
    434         delete dsound;
    435 }
    436 
    437 CSound* LoadSound(string filename)
    438 {
    439     HRESULT result;
    440 
    441     //create local reference to wave data
    442     CSound *wave = NULL;
    443 
    444     //attempt to load the wave file
    445     char s[255];
    446     sprintf(s, "%s", filename.c_str());
    447     result = dsound->Create(&wave, s);
    448     if (FAILED(result))
    449         wave = NULL;
    450 
    451     return wave;
    452 }
    453 
    454 void PlaySound(CSound *sound)
    455 {
    456     sound->Play();
    457 }
    458 
    459 void LoopSound(CSound *sound)
    460 {
    461     sound->Play(0, DSBPLAY_LOOPING);
    462 }
    463 
    464 void StopSound(CSound *sound)
    465 {
    466     sound->Stop();
    467 }

     

    main.cpp

    View Code
     1 #include "DirectX.h"
     2 using namespace std;
     3 
     4 bool gameover = false;
     5 
     6 //windows event handling function
     7 LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     8 {
     9     switch (message)
    10     {
    11     case WM_DESTROY:
    12         gameover = true;
    13         PostQuitMessage(0);
    14         return 0;
    15     }
    16 
    17     return DefWindowProc(hwnd, message, wParam, lParam);
    18 }
    19 
    20 
    21 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
    22 {
    23     //set the windows properties
    24     WNDCLASSEX wc;
    25     wc.cbSize = sizeof(WNDCLASSEX);
    26     wc.style = CS_HREDRAW | CS_VREDRAW;
    27     wc.lpfnWndProc = (WNDPROC)WinProc;
    28     wc.cbClsExtra = 0;
    29     wc.cbWndExtra = 0;
    30     wc.hInstance = hInstance;
    31     wc.hIcon = NULL;
    32     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    33     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    34     wc.lpszMenuName = NULL;
    35     wc.lpszClassName = APPTITLE.c_str();
    36     wc.hIconSm = NULL;
    37     RegisterClassEx(&wc);
    38 
    39     //determine the resolution of the clients desktop screen
    40     int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    41     int screenHeight = GetSystemMetrics(SM_CYSCREEN);
    42 
    43     //place the window in the middle of screen
    44     int posX = (GetSystemMetrics(SM_CXSCREEN) - SCREENW) / 2;
    45     int posY = (GetSystemMetrics(SM_CYSCREEN) - SCREENH) / 2;
    46 
    47     //Create a window
    48     HWND window;
    49     window = CreateWindow(APPTITLE.c_str(), APPTITLE.c_str(),
    50         WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, posX, posY, SCREENW, SCREENH,
    51         NULL, NULL, hInstance, NULL); 
    52     if (window == 0)
    53         return false;
    54 
    55     //display the window
    56     ShowWindow(window, nCmdShow);
    57     UpdateWindow(window);
    58 
    59     //initialize the game
    60     if (!Game_Init(window))
    61         return 0;
    62 
    63     //main message loop
    64     MSG msg;
    65     while (!gameover)
    66     {
    67         //process windows events
    68         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    69         {
    70             //handle any event messages
    71             TranslateMessage(&msg);
    72             DispatchMessage(&msg);
    73         }
    74 
    75         //process game loop
    76         Game_Run(window);
    77     }
    78 
    79     //free game resources
    80     Game_End();
    81 
    82     return msg.wParam;
    83 }

     

    下面是game.cpp文件,先看开头部分。宏定义D3DFVF_MYVERTEX表示顶点流的类型,D3DFVF_XYZ与D3DFVF_TEX1分别代表顶点位置与纹理坐标。这里的cube数组是立方体的顶点信息,由6个面组成。

     1 #include "DirectX.h"
     2 using namespace std;
     3 
     4 const string APPTITLE = "Direct3D Cube";
     5 const int SCREENW = 1024;
     6 const int SCREENH = 576;
     7 
     8 DWORD screentimer = timeGetTime();
     9 
    10 //vertex and quad definitions
    11 #define D3DFVF_MYVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
    12 
    13 struct VERTEX
    14 {
    15     float x, y, z;
    16     float tu, tv;
    17 };
    18 
    19 struct QUAD
    20 {
    21     VERTEX vertices[4];
    22     LPDIRECT3DVERTEXBUFFER9 buffer;
    23     LPDIRECT3DTEXTURE9 texture;
    24 };
    25 
    26 VERTEX cube[] = {
    27     {-1.0f, 1.0f,-1.0f, 0.0f,0.0f},     //side 1
    28     { 1.0f, 1.0f,-1.0f, 1.0f,0.0f },
    29     {-1.0f,-1.0f,-1.0f, 0.0f,1.0f },
    30     { 1.0f,-1.0f,-1.0f, 1.0f,1.0f },
    31     
    32     {-1.0f, 1.0f, 1.0f, 1.0f,0.0f },    //side 2
    33     {-1.0f,-1.0f, 1.0f, 1.0f,1.0f },
    34     { 1.0f, 1.0f, 1.0f, 0.0f,0.0f },
    35     { 1.0f,-1.0f, 1.0f, 0.0f,1.0f },
    36     
    37     {-1.0f, 1.0f, 1.0f, 0.0f,0.0f },    //side 3
    38     { 1.0f, 1.0f, 1.0f, 1.0f,0.0f },
    39     {-1.0f, 1.0f,-1.0f, 0.0f,1.0f },
    40     { 1.0f, 1.0f,-1.0f, 1.0f,1.0f },
    41     
    42     {-1.0f,-1.0f, 1.0f, 0.0f,0.0f },    //side 4
    43     {-1.0f,-1.0f,-1.0f, 1.0f,0.0f },
    44     { 1.0f,-1.0f, 1.0f, 0.0f,1.0f },
    45     { 1.0f,-1.0f,-1.0f, 1.0f,1.0f },
    46 
    47     { 1.0f, 1.0f,-1.0f, 0.0f,0.0f },    //side 5
    48     { 1.0f, 1.0f, 1.0f, 1.0f,0.0f },
    49     { 1.0f,-1.0f,-1.0f, 0.0f,1.0f },
    50     { 1.0f,-1.0f, 1.0f, 1.0f,1.0f },
    51     
    52     {-1.0f, 1.0f,-1.0f, 1.0f,0.0f },    //side 6
    53     {-1.0f,-1.0f,-1.0f, 1.0f,1.0f },
    54     {-1.0f, 1.0f, 1.0f, 0.0f,0.0f },
    55     {-1.0f,-1.0f, 1.0f, 0.0f,1.0f }
    56 };
    57 
    58 QUAD *quads[6];
    59 D3DXVECTOR3 cameraSource;
    60 D3DXVECTOR3 cameraTarget;

     

     函数SetVertex调用SetPosition设置四边形的顶点信息。CreateVertex用于创建顶点。

     1 void SetPosition(QUAD* quad, int ivert, float x, float y, float z)
     2 {
     3     quad->vertices[ivert].x = x;
     4     quad->vertices[ivert].y = y;
     5     quad->vertices[ivert].z = z;
     6 }
     7 
     8 void SetVertex(QUAD *quad, int ivert, float x, float y, float z, float tu, float tv)
     9 {
    10     SetPosition(quad, ivert, x, y, z);
    11     quad->vertices[ivert].tu = tu;
    12     quad->vertices[ivert].tv = tv;
    13 }
    14 
    15 VERTEX CreateVertex(float x, float y, float z, float tu, float tv)
    16 {
    17     VERTEX vertex;
    18     vertex.x = x;
    19     vertex.y = y;
    20     vertex.z = z;
    21     vertex.tu = tu;
    22     vertex.tv = tv;
    23     
    24     return vertex;
    25 }

     

    在下面的CreateQuad函数中,首先使用D3DXCreateTextureFromFile用图片文件创建了纹理,然后赋值给quad->texture。接着用CreateVertexBuffer创建了顶点缓存并赋值给quad->buffer,quad由3部分组成,下面就剩下顶点信息vertices了。下面对quad->vertices进行了默认的初始化工作,我们实际使用的顶点数据来源于之前的cube数组。

     1 QUAD* CreateQuad(char *textureFilename)
     2 {
     3     QUAD *quad = (QUAD*)malloc(sizeof(QUAD));
     4 
     5     //load the texture
     6     D3DXCreateTextureFromFile(d3ddev, textureFilename, &quad->texture);
     7 
     8     //create vertex buffer for quad
     9     d3ddev->CreateVertexBuffer(
    10         4*sizeof(VERTEX),
    11         0,
    12         D3DFVF_MYVERTEX, D3DPOOL_DEFAULT,
    13         &quad->buffer, NULL);
    14 
    15     //create the four corners of this quad triangle strip
    16     quad->vertices[0] = CreateVertex(-1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
    17     quad->vertices[1] = CreateVertex(1.0f, 1.0f, 0.0f, 1.0f, 0.0f);
    18     quad->vertices[2] = CreateVertex(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f);
    19     quad->vertices[3] = CreateVertex(1.0f, -1.0f, 0.0f, 1.0f, 1.0f);
    20 
    21     return quad;
    22 }
    23 
    24 void DeleteQuad(QUAD *quad)
    25 {
    26     if (quad == NULL)
    27         return;
    28 
    29     if (quad->buffer != NULL)
    30         quad->buffer->Release();
    31 
    32     if (quad->texture != NULL)
    33         quad->texture->Release();
    34 
    35     free(quad);
    36 }

     

    下面的函数DrawQuad用于绘制四边形。首先,需要把初始化好的顶点信息传递给顶点缓存,这里定义了一个临时指针变量temp,然后调用lock函数来锁住顶点缓冲区,同时使用temp指向了顶点缓存。然后,就可以用memcpy给这个代表顶点缓存的temp赋值了,最后要Unlock才行。接着用SetTexture设置使用的纹理,用SetStreamSource设置流源,使Direct3D知道顶点的来源以及需要渲染多少顶点。最后,绘制流源指定的基元(primitive),即基础图元。在DirectX中,基础图元只有点、线、三角形,这里使用三角形条的方式绘制四边形。传入的参数0代表索引,2代表两个三角形,而参数TRIANGLESTRIP也能换成TRIANGLELIST,只是绘制方式不同,下面就是区别。三角形列表需要6个顶点来绘制一个四边形,而三角形条只需要4个顶点信息。

     1 void DrawQuad(QUAD *quad)
     2 {
     3     //fill vertex buffer with quad vertices
     4     void *temp = NULL;
     5     quad->buffer->Lock(0, sizeof(quad->vertices), (void**)&temp, 0);
     6     memcpy(temp, quad->vertices, sizeof(quad->vertices));
     7     quad->buffer->Unlock();
     8 
     9     //draw the textured dual triangle strip
    10     d3ddev->SetTexture(0, quad->texture);
    11     d3ddev->SetStreamSource(0, quad->buffer, 0, sizeof(VERTEX));
    12     d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
    13 }

     

    SetIdentity函数最后使用了SetTransform,下面还会使用,这个函数用于在渲染之前进行矩阵转换,你不妨再看看前面的世界变换、视图变换、投影变换这些概念。D3DXMatrixTranslation用于设置平移矩阵,将设置的矩阵信息保存在矩阵matWorld中。D3DTS_WORLD是一个宏定义,这段就表示进行世界变换的操作。

     1 void SetIdentity()
     2 {
     3     //set default position, scale, rotation
     4     D3DXMATRIX matWorld;
     5     D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f);
     6     d3ddev->SetTransform(D3DTS_WORLD, &matWorld);
     7 }
     8 
     9 void ClearScene(D3DXCOLOR color)
    10 {
    11     d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1.0f, 0);
    12 }

     

    下面的SetCamera函数用于设置相机信息,显然这里的相机是虚拟的,用视图变换来表示。看到D3DXMatrixLookAtLH这个重要的函数,这个函数最终得到一个用于视图变换的观察矩阵matView,参数cameraSource表示相机的位置(观察点),cameraTarget表示相机朝着什么方向看的向量,updir代表当前世界方向向上的向量,默认为(0, 1, 0)。最后,通过SetTransform(D3DTS_VIEW,&matView)进行了视图变换。

     1 void SetCamera(float x, float y, float z, float lookx, float looky, float lookz)
     2 {
     3     D3DXMATRIX matView;
     4     D3DXVECTOR3 updir(0.0f, 1.0f, 0.0f);
     5 
     6     //move the camera
     7     cameraSource.x = x;
     8     cameraSource.y = y;
     9     cameraSource.z = z;
    10 
    11     //point the camera
    12     cameraTarget.x = lookx;
    13     cameraTarget.y = looky;
    14     cameraTarget.z = lookz;
    15 
    16     //set up the camera view matrix
    17     D3DXMatrixLookAtLH(&matView, &cameraSource, &cameraTarget, &updir);
    18     d3ddev->SetTransform(D3DTS_VIEW, &matView);
    19 }

     

    最后还有一个投影变换,使用SetTransform(D3DTS_PROJECTION, &matProj)完成,Projection就是投影的意思。参数fieldOfView代表视景体,aspectRatio代表图像的宽高比,nearRange与farRange代表近平面与远平面。

    1 void SetPerspective(float fieldOfView, float aspectRatio, float nearRange, float farRange)
    2 {
    3     //set the perspective so things in the distance will look smaller
    4     D3DXMATRIX matProj;
    5     D3DXMatrixPerspectiveFovLH(&matProj, fieldOfView, aspectRatio, nearRange, farRange);
    6     d3ddev->SetTransform(D3DTS_PROJECTION, &matProj);
    7 }

     

    下面这个函数用于初始化立方体,调用CreateQuad函数创建了带纹理贴图的四边形,然后用cube数组对这些四边形的顶点赋值。

     1 void Init_Cube()
     2 {
     3     for (int q = 0; q < 6; q++)
     4     {
     5         int i = q*4;
     6         quads[q] = CreateQuad("cube.bmp");
     7         for (int v = 0; v < 4; v++)
     8         {
     9             quads[q]->vertices[v] = CreateVertex(
    10                 cube[i].x, cube[i].y, cube[i].z,
    11                 cube[i].tu, cube[i].tv);
    12             i++;
    13         }
    14     }
    15 }

     

    我们还要做一件事,就是让立方体旋转起来。在Rotate_Cube中,xrot、yrot、zrot组成了旋转需要的旋转轴,而我们对3D物体进行旋转还需要进行旋转的旋转矩阵matRot。这里还设置了平移矩阵matTrans,不过这里暂时没有平移。函数D3DXMatrixRotationYawPitchRoll用于创建旋转矩阵,最后用matRot*matTrans来得到一个组合了平移与旋转的矩阵matWorld。

     1 void Rotate_Cube()
     2 {
     3     static float xrot = 0.0f;
     4     static float yrot = 0.0f;
     5     static float zrot = 0.0f;
     6 
     7     //rotate the x and y axes
     8     xrot += 0.2f;
     9     yrot += 0.00f;
    10 
    11     //create the matrices
    12     D3DXMATRIX matWorld;
    13     D3DXMATRIX matTrans;
    14     D3DXMATRIX matRot;
    15 
    16     //get an identity matrix
    17     D3DXMatrixTranslation(&matTrans, 0.0f, 0.0f, 0.0f);
    18 
    19     //rotate the cube
    20     D3DXMatrixRotationYawPitchRoll(&matRot,D3DXToRadian(xrot),D3DXToRadian(yrot),D3DXToRadian(zrot));
    21     matWorld = matRot * matTrans;
    22 
    23     //complete the operation
    24     d3ddev->SetTransform(D3DTS_WORLD, &matWorld);
    25 }

     

    下面是Game_Init函数,可以直接从SetCamera开始看起。如果改变SetCamera函数的参数,就能使图像放大与缩小。

     1 bool Game_Init(HWND window)
     2 {
     3     srand(time(NULL));
     4 
     5     //initialize Direct3D
     6     if (!Direct3D_Init(window, SCREENW, SCREENH, false))
     7     {
     8         MessageBox(window,"Error initializing Direct3D",APPTITLE.c_str(),0);
     9         return false;
    10     }
    11 
    12     //initialize DirectInput
    13     if (!DirectInput_Init(window))
    14     {
    15         MessageBox(window,"Error initializing DirectInput",APPTITLE.c_str(),0);
    16         return false;
    17     }
    18 
    19     //initialize DirectSound
    20     if (!DirectSound_Init(window))
    21     {
    22         MessageBox(window,"Error initializing DirectSound",APPTITLE.c_str(),0);
    23         return false;
    24     }
    25 
    26     //position the camera
    27     SetCamera(0.0f, 2.0f, -4.0f, 0, 0, 0);
    28 
    29     float ratio = (float)SCREENW / (float)SCREENH;
    30     SetPerspective(45.0f, ratio, 0.1f, 10000.0f);
    31 
    32     //turn dynamic lighting off, z-buffer on
    33     d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
    34     d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);
    35 
    36     //set the Direct3D stream to use the custom vertex
    37     d3ddev->SetFVF(D3DFVF_MYVERTEX);
    38 
    39     //convert the cube values into quads
    40     Init_Cube();
    41 
    42     return true;
    43 }

     

    函数Game_Run变得很简单,先Rotate_Cube使立方体产生旋转效果,接着在for循环中DrawQuad绘制立方体的6个面就可以了。

     1 void Game_Run(HWND window)
     2 {
     3     if (!d3ddev) return;
     4     DirectInput_Update();
     5     d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
     6 
     7     //slow rendering to approximately 60 fps
     8     if (timeGetTime() > screentimer + 14)
     9     {
    10         screentimer = GetTickCount();
    11 
    12         Rotate_Cube();
    13 
    14         //start rendering
    15         if (d3ddev->BeginScene())
    16         {
    17            for (int n = 0; n < 6; n++)
    18            {
    19                DrawQuad(quads[n]);
    20            }
    21 
    22             //stop rendering
    23             d3ddev->EndScene();
    24             d3ddev->Present(NULL, NULL, NULL, NULL);
    25         }
    26     }
    27 
    28     //exit with escape key or controller Back button
    29     if (KEY_DOWN(VK_ESCAPE)) gameover = true;
    30     if (controllers[0].wButtons & XINPUT_GAMEPAD_BACK) gameover = true;
    31 
    32 }

     

    最后是Game_End函数

    1 void Game_End()
    2 {
    3     for (int q = 0; q < 6; q++)
    4         DeleteQuad(quads[q]);
    5     DirectSound_Shutdown();
    6     DirectInput_Shutdown();
    7     Direct3D_Shutdown();
    8 }

     

    本文只是用DirectX 9的知识简单的绘制了一个立方体,如果不使用纹理图片,直接使用顶点颜色信息也是可以的。下面是运行截图,源代码,参考自游戏编程入门。

     

  • 相关阅读:
    EditText被输入法覆盖的解决方法
    计算屏幕大小
    [转]在adt-bundle-linux建立工程找不到ADB & R文件
    3.18 迷茫的方向
    安卓笔记:Fragment
    安卓学习笔记:转Android LayoutInflater详解
    Android布局大全(转)
    第二章 Android基本应用开发与解析
    Datetime中offset-naive与offset-aware时间的计算
    Python日期操作datetime
  • 原文地址:https://www.cnblogs.com/shihui142857/p/2939538.html
Copyright © 2020-2023  润新知