DirectX 入门例程

来源:互联网 发布:网络兼职广告 编辑:程序博客网 时间:2024/05/16 01:24

这个事例程序是本人在SDK样例程序中改写的,将其中无关的内容删除。希望对刚入门的学习者有帮助。

DirectX中的Dreaw的使用方法:
我看过几篇文章写得不错,想表达一下我的理解。
DirectX对象是对一个屏幕的控制权的操作,主要的方法有:创建,刷新,卸载。
平面(表面,缓存等几个名称)是一块显存空间,使用的平面有三种:
1、主平面(前平面),前平面是屏幕显示的内容,显卡读取主平面内容显示在屏幕上。
2、辅助平面(后平面),后平面是存放程序将要显示的内容,当辅助平面内容完成后,交换主平面与辅助平面,是屏幕

显示辅助平面的内容,不停的在辅助平面内画,不停的交换,使屏幕不出现闪烁。
3、位图(文字)平面,此平面用来将位图或文字画在一个平面内,需要时将位图或文字拷贝到辅助平面。位图(文字)

平面在创建时大小已经固定,位图平面加在的位图变化后(使用CSurface::DrawBitmap函数),如果尺寸改变,这位图

将要变形(限于此程序,此方法使StretchBlt( hDC, 0, 0, ddsd.dwWidth, ddsd.dwHeight,hDCImage, 0, 0,

bmp.bmWidth, bmp.bmHeight,SRCCOPY )位图变形),文字平面改变文字内容后(使用CSurface::DrawText函数),如果

文字变多则超出部分不能显示,如果变少则前面的文字不能覆盖,本人解决的方式是
GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText ); //得到显示文字的尺寸
dwHeight = sizeText.cx ; //保留字体的大小
dwHeight = sizeText.cy;
得到有效的宽度和高度,在显示时只显示有效部分
 prc.top = 1;
 prc.bottom = g_pTextSurface->GetHeight();
 prc.left = 1;
 prc.right = g_pTextSurface->GetWidth();
 g_pDisplay->Blt( 10, 10, g_pTextSurface, NULL ); //在指定位置显示文字 

下面我是程序

Client.cpp

#include <windows.h>
#include <mmsystem.h>
#include "resource.h"
#include "ddutil.h"

#define SCREEN_WIDTH 800 //创建DirectX的宽度,高度,颜色深度
#define SCREEN_HEIGHT 600
#define SCREEN_BPP 16 //XXXXX(红)XXXXXX(绿)XXXXX(蓝)
#define RGB16_GREEN 0x07E0 //0000,0111,1110,0000
#define RGB16_WHITE 0xFFFF //1111,1111,1111,1111
#define RGB16_BLACK 0x0000 //0000,0000,0000,0000

#define YUNDONG_UP    1  //定义运动的方向
#define YUNDONG_DOWN  2
#define YUNDONG_LEFT  3
#define YUNDONG_RIGHT 4

#define NUM_SPRITES 1 //定义出现的精灵图像个数

struct SPRITE   //定义精灵的运动结构
{
 FLOAT fPosX;  //出现的位置
 FLOAT fPosY;
 FLOAT fVelX;  //水平或垂直运动的速度
 FLOAT fVelY;
 DWORD dwWidth;  //定义的大小;  
 DWORD dwHeight;
 INT iFangXiang;  //精灵运动的方向
};

CDisplay* g_pDisplay;  //创建DirectX类的实例
CSurface* g_pLogoSurface; //创建一个位图表面
CSurface* g_pTextSurface; //创建一个文字表面
SPRITE g_Sprite[NUM_SPRITES]; //创建图像精灵  
DWORD g_dwLastTick ;  //记录时间
BOOL g_bActive;    //判断DirectX是否能活动
BOOL g_bLianJie;   //跳过窗口的判断变量

LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );//窗口的消息处理函数
HRESULT ProcessNextFrame();   //显示下一帧
void UpdateSprite( SPRITE* pSprite, FLOAT fTimeDelta );  //更新精灵的范围的边界情况
HRESULT DisplayFrame();  //显示帧的内容
HRESULT RestoreSurfaces(); //当平面信息丢失时更新平面的内容
VOID FreeDirectDraw();  //释放表面及DirectX实例


//////////////////////////////////////
//   应用程序入口   //
//////////////////////////////////////
int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )
{
 WNDCLASS wc;
 HWND hWnd;
 HACCEL hAccel;
 MSG msg;
   
 ZeroMemory( &g_Sprite, sizeof(SPRITE) * NUM_SPRITES );
    srand( GetTickCount() );
 

 //////////////////////////////////////
 //   创建游戏窗体   //
 //////////////////////////////////////
 wc.lpszClassName = TEXT("Client"); //窗口类名称
 wc.lpfnWndProc = MainWndProc;  //消息处理函数
 wc.style = CS_VREDRAW | CS_HREDRAW; //窗口的类型
 wc.hInstance = hInst;    //窗口实例(继承)
 wc.hIcon = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) ); //窗口图标
 wc.hCursor = LoadCursor( NULL, IDC_ARROW );    //窗口鼠标
 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //窗口的背景
 wc.lpszMenuName = NULL; //窗口菜单
 wc.cbClsExtra = 0; //保留
 wc.cbWndExtra = 0; //保留

 if( RegisterClass( &wc ) == 0 ) //判断窗口类是否注册成功
  return E_FAIL;


 hWnd = CreateWindow( TEXT("Client"), TEXT("Client1"), //创建窗口
       WS_SYSMENU | WS_MAXIMIZEBOX, 180,110,
       430, 230, NULL, NULL, hInst, NULL );

    if( hWnd == NULL ) //判断窗口是否创建成功
     return E_FAIL;

 ShowWindow( hWnd, nCmdShow ); //显示窗口
 UpdateWindow( hWnd );  //更新窗口
 //以下四行内容显示一个窗口,可删除
 g_bLianJie = false;  //设置窗口退出条件
 while(GetMessage( &msg, NULL, 0, 0 ) && !g_bLianJie) //显示窗口并处理消息
 {
  TranslateMessage( &msg );
  DispatchMessage( &msg );
 }

 hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) ); //创建按键关联表

 //////////////////////////////////
 //   创建DirectDraw  //
 //////////////////////////////////
 HRESULT hr;
 
 g_pDisplay = new CDisplay(); //定义DirectX实例
 //创建一个全屏的窗体
 if( FAILED( hr = g_pDisplay->Create( hWnd, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP ) ) )
  return hr;

 //创建一个平面,并且在画上一个位图资源,用于显示位图
 if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap(&g_pLogoSurface, MAKEINTRESOURCE( IDB_DIRECTX ), 0, 0) ) )
  return hr;
 //设置位图显示时的透明颜色
 if( FAILED( hr = g_pLogoSurface->SetColorKey( RGB16_BLACK ) ) )
  return hr;
 //创建一个平面,并且在输出文字资源,用于显示文字
 if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pTextSurface, NULL, "123456789",
              RGB(0,255,0), RGB(255, 255, 0) ) ) )
  return hr;
 //设置文字显示时的透明颜色(应该与文字背景色一致)
 if( FAILED( hr = g_pTextSurface->SetColorKey( RGB16_GREEN ) ) )
  return hr;

 for( int i = 0; i < NUM_SPRITES; i++ ) //定义精灵初始值
 {
  g_Sprite[i].fPosX = 0.0f;
  g_Sprite[i].fPosY = 0.0f;
        g_Sprite[i].fVelX = 0.0f;
        g_Sprite[i].fVelY = 0.0f;
  g_Sprite[i].dwWidth = g_pLogoSurface->GetWidth(); //得到位图平面的宽度和高度
  g_Sprite[i].dwHeight = g_pLogoSurface->GetHeight();
  g_Sprite[i].iFangXiang = YUNDONG_UP;
 }

 g_dwLastTick = timeGetTime(); //记录当前时间

 while(true)//进入消息循环,以下内容不明白,请有心人帮忙解释一下
 {
  if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) //判断是否收到消息
  {
   //WM_QUIT退出消息
   if( 0 == GetMessage(&msg, NULL, 0, 0 ) ) 
   {
    return (int)msg.wParam;
   }
 
   //翻译并且分派消息
   if( 0 == TranslateAccelerator( hWnd, hAccel, &msg ) ) //是否是按键表对应的消息
   {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
   }
  }
  else
  {
   if( g_bActive )  //当可以重画屏幕时
   {
    if( FAILED( ProcessNextFrame() ) ) //显示下一帧
     return 0;
   }
   else
   {
    WaitMessage();  //等待消息
    g_dwLastTick = timeGetTime(); 
   }
  }
 }
 return 0;
}

//////////////////////////////////////////////
//   游戏窗体消息处理函数   //
//////////////////////////////////////////////
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
 HDC hdc;
 PAINTSTRUCT ps;

 switch (msg)
 {
  case WM_KEYDOWN: //当任意键按下时退出开始的窗口
   g_bLianJie = true;
   return 0L;
  case WM_PAINT: //重画屏幕消息与DirectX无关
  {
   hdc = BeginPaint(hWnd, &ps); //得到DC
   HFONT hFont = CreateFont(30,0,0,0,0,0,0,0,0,0,0,0,0,"宋体"); //创建字体
   SelectObject(hdc, hFont); //设置字体
   DeleteObject(hFont); //删除字体
   //GetClientRect( hWnd, &rect );
   SetTextColor(hdc, RGB(0, 0, 0)); //设置颜色
   TextOut(hdc, 100, 50, "欢迎使用游戏", 12); //显示文字
   SetTextColor(hdc, RGB(0, 0, 255));
   TextOut(hdc, 100, 100, "我的DirectXDraw", 15);

   EndPaint( hWnd, &ps); //删除DC
            return 0L;
  }
  case WM_COMMAND: 
   switch ( LOWORD(wParam) )
   {
    case IDM_EXIT: //按键表中的退出消息
     PostMessage( hWnd, WM_CLOSE, 0, 0 );
     return 0L;
    case IDM_UP: //按键表中的向上消息
     g_Sprite[0].fVelX = 0.0f; //水平不运动
     g_Sprite[0].fVelY = -100.0f; //竖直向上
     g_Sprite[0].iFangXiang = YUNDONG_UP; //运动方向
     break;
    case IDM_DOWN: //按键表中的向下消息
     g_Sprite[0].fVelX = 0.0f;
     g_Sprite[0].fVelY = 100.0f;
     g_Sprite[0].iFangXiang = YUNDONG_DOWN;
     break;
    case IDM_LEFT: //按键表中的向左消息
     g_Sprite[0].fVelX = -100.0f;
     g_Sprite[0].fVelY = 0.0f;
     g_Sprite[0].iFangXiang = YUNDONG_LEFT;
     break;
    case IDM_RIGHT: //按键表中的向右消息
     g_Sprite[0].fVelX = 100.0f;
     g_Sprite[0].fVelY = 0.0f;
     g_Sprite[0].iFangXiang = YUNDONG_RIGHT;
     break;
   }
   break;
  case WM_SIZE: //尺寸改变时
   if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam )
    g_bActive = FALSE;
   else
    g_bActive = TRUE;
        case WM_SETCURSOR: //鼠标隐藏
            // Hide the cursor in fullscreen
            SetCursor( NULL );
   return TRUE;
  case WM_SYSCOMMAND: //系统消息,不可少
   switch( wParam )
   {
    case SC_MONITORPOWER:
     return TRUE;
   }
   break;
  case WM_DESTROY: //窗口释放消息
            PostQuitMessage( 0 ); //抛出窗口退出消息
   FreeDirectDraw(); //释放平面
            return 0L;
 }
 return DefWindowProc(hWnd, msg, wParam, lParam); //系统默认详细处理
}

//////////////////////////////////
//   显示下一帧   //
//////////////////////////////////
HRESULT ProcessNextFrame() 
{
 HRESULT hr;

 DWORD dwCurrTick = timeGetTime(); //得到当前时间 
 DWORD dwTickDiff = dwCurrTick - g_dwLastTick; //显示暂停时间

 if( dwTickDiff == 0 ) //没有暂停退出
  return S_OK;

 g_dwLastTick = dwCurrTick; //重新得到当前时间
 for( int i = 0; i < NUM_SPRITES; i++ ) 
  UpdateSprite( &g_Sprite[i], dwTickDiff / 1000.0f ); //循环更新精灵的运动位置

 if( FAILED( hr = DisplayFrame() ) ) //显示屏幕的内容
 {
  if( hr != DDERR_SURFACELOST ) //判断屏幕信息是否丢失
   return hr;

  RestoreSurfaces(); //重新刷新表面内容
 }
 
 return S_OK;
}

//////////////////////////////////////////
//   更新精灵的运动位置   //
//          //
// 参数:精灵结构指针,屏幕未更新时间  //
//////////////////////////////////////////
void UpdateSprite( SPRITE* pSprite, FLOAT fTimeDelta )
{
 pSprite->fPosX += pSprite->fVelX * fTimeDelta;//计算新的位置
 pSprite->fPosY += pSprite->fVelY * fTimeDelta;
 
 //以下判断是否超出屏幕的范围
 if( pSprite->fPosX < 0.0f ) 
 {
  pSprite->fPosX = FLOAT( SCREEN_WIDTH -1 - pSprite->dwWidth/2 );
 }

    if( pSprite->fPosX >= SCREEN_WIDTH - pSprite->dwWidth/2 )
    {
        pSprite->fPosX = 0;
    }

    if( pSprite->fPosY < 0 )
    {
        pSprite->fPosY = FLOAT( SCREEN_HEIGHT - 1 - pSprite->dwHeight/2 );
    }

    if( pSprite->fPosY > SCREEN_HEIGHT - pSprite->dwHeight/2 )
    {
        pSprite->fPosY = 0;
    }  
}

//////////////////////////////////////
//   显示帧的内容   //
//////////////////////////////////////
HRESULT DisplayFrame()
{
 HRESULT hr;
 RECT prc;

 g_pDisplay->Clear( 0x3F1F ); //使用指定的颜色覆盖屏幕

 for( int i =0; i < NUM_SPRITES; i++ )//循环显示每一个精灵
 {
  if ( g_Sprite[i].iFangXiang == YUNDONG_UP ) //显示箭头的方向
  { 
   prc.left=1;   //在平面位图中的位置 
   prc.top=1;
   prc.bottom = g_Sprite[i].dwHeight / 2;
   prc.right = g_Sprite[i].dwWidth / 2;
  }
  else if( g_Sprite[i].iFangXiang == YUNDONG_DOWN )
  {
   prc.top = g_Sprite[i].dwHeight / 2 + 1;
   prc.left = 1;
   prc.bottom = g_Sprite[i].dwHeight;
   prc.right = g_Sprite[i].dwWidth / 2;
  }
  else if( g_Sprite[i].iFangXiang == YUNDONG_RIGHT )
  {
   prc.top = 1;
   prc.left = g_Sprite[i].dwWidth / 2 + 1;
   prc.bottom = g_Sprite[i].dwHeight / 2;
   prc.right = g_Sprite[i].dwWidth;
  }
  else if( g_Sprite[i].iFangXiang == YUNDONG_LEFT )
  {
   prc.top = g_Sprite[i].dwHeight / 2 + 1;
   prc.left = g_Sprite[i].dwWidth / 2 + 1;
   prc.bottom = g_Sprite[i].dwHeight;
   prc.right = g_Sprite[i].dwWidth;
  }
  g_pDisplay->Blt( (DWORD)g_Sprite[i].fPosX, (DWORD)g_Sprite[i].fPosY, //显示精灵
       g_pLogoSurface, &prc );
 }
 prc.top = 1;
 prc.bottom = g_pTextSurface->GetHeight();
 prc.left = 1;
 prc.right = g_pTextSurface->GetWidth();
 g_pDisplay->Blt( 10, 10, g_pTextSurface, NULL ); //在指定位置显示文字


 if( FAILED(hr = g_pDisplay->Present() ) ) //呈现这一帧图像
  return hr;
 return S_OK;
}

//////////////////////////////////
//   更新表面   //
//////////////////////////////////
HRESULT RestoreSurfaces()
{
 HRESULT hr;
 
 if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces() ) ) //实例恢复所有表面
  return hr;
 if( FAILED( hr = g_pTextSurface->DrawText( NULL, "2935629", RGB( 0, 0, 0 ), RGB( 255, 255, 255 ) ) ) )
  return hr;
 if( FAILED( hr = g_pLogoSurface->DrawBitmap( MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )
  return hr;
 return S_OK;
}

//////////////////////////////////////
//   释放表面及实例   //
//////////////////////////////////////
VOID FreeDirectDraw()
{
 for( int i =0; i < NUM_SPRITES; i++ )
  SAFE_DELETE( g_pLogoSurface );
 SAFE_DELETE( g_pTextSurface );
 SAFE_DELETE( g_pDisplay );
}

ddutil.h

//-----------------------------------------------------------------------------
// File: ddutil.cpp
//
// Desc: Routines for loading bitmap and palettes from resources
//
// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#ifndef DDUTIL_H
#define DDUTIL_H

#define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } } //释放对象的宏
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

#include <ddraw.h>

//-----------------------------------------------------------------------------
// Classes defined in this header file
//-----------------------------------------------------------------------------
class CDisplay; //DirectX对象类
class CSurface; //平面对象类


//-----------------------------------------------------------------------------
// Name: class CDisplay
// Desc: Class to handle all DDraw aspects of a display, including creation of
//       front and back buffers, creating offscreen surfaces and palettes,
//       and blitting surface and displaying bitmaps.
//-----------------------------------------------------------------------------
class CDisplay
{
protected:
    LPDIRECTDRAW7        m_pDD; //DirectX对象
    LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer; //DirectX对象的前平面对象
    LPDIRECTDRAWSURFACE7 m_pddsBackBuffer; //DirectX对象的后平面对象

    HWND                 m_hWnd; //窗口的句柄

public:
    CDisplay();
    ~CDisplay();

    // 返回DirectX实例对应的DirectX对象
    LPDIRECTDRAW7        GetDirectDraw()     { return m_pDD; } 
 //创建DirectX对象
    HRESULT Create( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
                               DWORD dwBPP );
    virtual HRESULT DestroyObjects(); //释放DirectX对象

    //创建位图平面
    HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
                               DWORD dwDesiredWidth,
          DWORD dwDesiredHeight );
 //创建文字平面
    HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
                             TCHAR* strText,
           COLORREF crBackground,
           COLORREF crForeground );

    //清除屏幕
    HRESULT Clear( DWORD dwColor = 0L );
 //将表面对象显示在屏幕上
    HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
           RECT* prc, DWORD dwFlags=0 );
 //将平面实例显示到屏幕上
    HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc );
 //显示缓存平面的内容(交换前后平面)
    HRESULT Present();
};

 


//-----------------------------------------------------------------------------
// Name: class CSurface
// Desc: Class to handle aspects of a DirectDrawSurface.
//-----------------------------------------------------------------------------
class CSurface
{
    LPDIRECTDRAWSURFACE7 m_pdds; //平面对象
    DDSURFACEDESC2       m_ddsd; //平面结构
    BOOL                 m_bColorKeyed; //是否使用透明颜色

 DWORD     dwWidth; //表面的有效宽度和高度
 DWORD     dwHeight;

public:
    LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; } //返回平面对象
    BOOL                 IsColorKeyed()    { return m_bColorKeyed; }//返回是否使用透明颜色
 DWORD     GetWidth()     { return dwWidth; } //返回表面的有效宽度和高度
 DWORD     GetHeight()    { return dwHeight; }
    HRESULT DrawBitmap( HBITMAP hBMP ); //在表面画位图
    HRESULT DrawBitmap( TCHAR* strBMP ); 
    HRESULT DrawText( HFONT hFont, TCHAR* strText, //在平面设置文字
                COLORREF crBackground, COLORREF crForeground );

    HRESULT SetColorKey( COLORREF crColorKey ); //设置透明颜色

    HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd ); //创建表面对象

    CSurface();
    ~CSurface();
};

#endif // DDUTIL_H

ddutil.cpp

//-----------------------------------------------------------------------------
// File: ddutil.cpp
//
// Desc: DirectDraw framewark classes. Feel free to use this class as a
//       starting point for adding extra functionality.
//
//
// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#include <tchar.h>
#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include "ddutil.h"


//-----------------------------------------------------------------------------
// Name: CDisplay()
// Desc:
//-----------------------------------------------------------------------------
CDisplay::CDisplay()
{
    m_pDD                = NULL; //设置初值
    m_pddsFrontBuffer    = NULL;
    m_pddsBackBuffer     = NULL;
}


//-----------------------------------------------------------------------------
// Name: ~CDisplay()
// Desc:
//-----------------------------------------------------------------------------
CDisplay::~CDisplay()
{
    DestroyObjects();
}


//-----------------------------------------------------------------------------
// Name: DestroyObjects()
// Desc: 释放已建立的对象
//-----------------------------------------------------------------------------
HRESULT CDisplay::DestroyObjects()
{
    SAFE_RELEASE( m_pddsBackBuffer );
    SAFE_RELEASE( m_pddsFrontBuffer );

    if( m_pDD )  
        m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );//取消与窗口的关联

    SAFE_RELEASE( m_pDD );

    return S_OK;
}


//-----------------------------------------------------------------------------
// Name: CreateFullScreenDisplay()
// Desc: 创建DirectX对象
// 参数:窗口句柄,屏幕宽度,高度,深度
//-----------------------------------------------------------------------------
HRESULT CDisplay::Create( HWND hWnd, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP )
{
    HRESULT hr;

    // 释放已建立的对象
    DestroyObjects();

    // 创建DirectX对象(NULL,DirectX对象指针,DirectX对象类型,NULL)
    if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
                                         IID_IDirectDraw7, NULL ) ) )
        return E_FAIL;

    // 设置关联的窗口(窗口句柄,方式
    hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
    if( FAILED(hr) )
        return E_FAIL;

    // 设置显示的模式(设置颜色时应与深度位数相对应)
    if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
        return E_FAIL;

    // 创建前平面结构
    DDSURFACEDESC2 ddsd;
    ZeroMemory( &ddsd, sizeof( ddsd ) );
    ddsd.dwSize            = sizeof( ddsd ); //设置结构长度
    ddsd.dwFlags           = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; //有效选项
    ddsd.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | //方式
                             DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
    ddsd.dwBackBufferCount = 1; //后平面个数
 
 //创建前平面(平面结构指针,前平面指针,NULL)
    if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, 
                                           NULL ) ) )
        return E_FAIL;

    // 设置平面信息结构
    DDSCAPS2 ddscaps;
    ZeroMemory( &ddscaps, sizeof( ddscaps ) );
    ddscaps.dwCaps = DDSCAPS_BACKBUFFER; //设置为后平面

 //创建后平面对象
    if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
                                                            &m_pddsBackBuffer ) ) )
        return E_FAIL;

    m_pddsBackBuffer->AddRef(); //向系统申请加1

    m_hWnd      = hWnd; //保存场口句柄
    return S_OK;
}
   

//-----------------------------------------------------------------------------
// Name: CDisplay::CreateSurfaceFromBitmap()
// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
//       Use MAKEINTRESOURCE() to pass a constant into strBMP.
// Desc: 通过位图创建一个位图平面
// 参数:平面类指针,位图字符串,希望使用的宽度,希望使用的高度
//-----------------------------------------------------------------------------
HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
                                           TCHAR* strBMP,                                           
                                           DWORD dwDesiredWidth,
                                           DWORD dwDesiredHeight )
{
    HRESULT        hr;
    HBITMAP        hBMP = NULL;
    BITMAP         bmp;
    DDSURFACEDESC2 ddsd;

    if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL ) //判断创建条件
        return E_INVALIDARG;

    *ppSurface = NULL; //清除前面的内容

    //  从资源中调用位图
    hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
                                IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
                                LR_CREATEDIBSECTION );
    if( hBMP == NULL )
    {
  //从文件中调用位图
        hBMP = (HBITMAP) LoadImage( NULL, strBMP,
                                    IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
                                    LR_LOADFROMFILE | LR_CREATEDIBSECTION );
        if( hBMP == NULL )
            return E_FAIL;
    }

    //得到位图句柄
    GetObject( hBMP, sizeof(bmp), &bmp );

    // 从位图创建平面结构
    ZeroMemory( &ddsd, sizeof(ddsd) );
    ddsd.dwSize         = sizeof(ddsd); //设置结构尺寸
    ddsd.dwFlags        = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; //有效信息
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    ddsd.dwWidth        = bmp.bmWidth; //平面的宽度和高度(不能更改)
    ddsd.dwHeight       = bmp.bmHeight;

    (*ppSurface) = new CSurface(); //创建新平面
    if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) ) //通过结构创建平面
    {
        delete (*ppSurface);
        return hr;
    }

    // 将位图画入平面
    if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP ) ) )
    {
        DeleteObject( hBMP );
        return hr;
    }

    DeleteObject( hBMP ); //删除位图指针

    return S_OK;
}


//-----------------------------------------------------------------------------
// Name: CDisplay::CreateSurfaceFromText()
// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
//       GDI font if hFont is NULL.
// Desc: 通过文字创建一个文字平面
// 参数:平面类指针,字体,文字内容,背景颜色,前景颜色
//-----------------------------------------------------------------------------
HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
                                         HFONT hFont, TCHAR* strText,
                                         COLORREF crBackground, COLORREF crForeground )
{
    HDC                  hDC  = NULL;
    LPDIRECTDRAWSURFACE7 pDDS = NULL;
    HRESULT              hr;
    DDSURFACEDESC2       ddsd;
    SIZE                 sizeText;

    if( m_pDD == NULL || strText == NULL || ppSurface == NULL )//判断条件
        return E_INVALIDARG;

    *ppSurface = NULL;//清除前面的内容

    hDC = GetDC( NULL ); //创建设备DC

    if( hFont )
        SelectObject( hDC, hFont ); //如果没有设置字体,则使用默认字体

    GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText ); //得到显示文字的尺寸
    ReleaseDC( NULL, hDC );

    // Create a DirectDrawSurface for this bitmap
    ZeroMemory( &ddsd, sizeof(ddsd) );
    ddsd.dwSize         = sizeof(ddsd); //设置结构尺寸
    ddsd.dwFlags        = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;//有效信息
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    ddsd.dwWidth        = sizeText.cx;//平面的宽度和高度(不能更改)
    ddsd.dwHeight       = sizeText.cy;

    (*ppSurface) = new CSurface();
    if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) ) //通过结构创建平面
    {
        delete (*ppSurface);
        return hr;
    }

    // 将文字写入平面
    if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, crBackground, crForeground ) ) )
        return hr;

    return S_OK;
}


//-----------------------------------------------------------------------------
// Name: 交换前后平面
// 参数:
//-----------------------------------------------------------------------------
HRESULT CDisplay::Present()
{
    HRESULT hr;

    if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer ) //判断条件
        return E_POINTER;

    while( 1 )
    {
        hr = m_pddsFrontBuffer->Flip( NULL, 0 ); //将前后平面交换,来显示刚刚画好的屏幕

        if( hr == DDERR_SURFACELOST ) //平面丢失了
        { 
            m_pddsFrontBuffer->Restore(); //恢复平面
            m_pddsBackBuffer->Restore();
        }

        if( hr != DDERR_WASSTILLDRAWING )
            return hr;
    }
}


//-----------------------------------------------------------------------------
// Name: 将平面位图画到后平面上
// 参数: 后平面上的x坐标,后平面上的y坐标,平面对象,位图(文字)平面上的一个矩形区域,方式
//-----------------------------------------------------------------------------
HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
                       DWORD dwFlags )
{
    if( NULL == m_pddsBackBuffer )
        return E_POINTER;

 //将平面位图中的prc矩形区域画到后平面的x,y位置上
    return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
}


//-----------------------------------------------------------------------------
// Name: 将平面类对应的位图画到后平面上
// Desc: 后平面上的x坐标,后平面上的y坐标,平面类对象指针,位图(文字)平面上的一个矩形区域
//-----------------------------------------------------------------------------
HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
{
    if( NULL == pSurface )
        return E_INVALIDARG;

    if( pSurface->IsColorKeyed() ) //将平面实例上的位图画到后平面上
        return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );//清除透明色
    else
        return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );//不清除透明色
}


//-----------------------------------------------------------------------------
// Name: 使用指定的颜色填充屏幕
// 参数: 颜色值
//-----------------------------------------------------------------------------
HRESULT CDisplay::Clear( DWORD dwColor )
{
    if( NULL == m_pddsBackBuffer )
        return E_POINTER;

    // Erase the background
    DDBLTFX ddbltfx;
    ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
    ddbltfx.dwSize      = sizeof(ddbltfx);
    ddbltfx.dwFillColor = dwColor; //定义颜色
 //使用颜色填充平面
    return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
}


//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
CSurface::CSurface()
{
    m_pdds = NULL;
    m_bColorKeyed = NULL; //只能为NULL,不能为FALSE
 dwWidth = 0;
 dwHeight = 0;
}

 


//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
CSurface::~CSurface()
{
    SAFE_RELEASE( m_pdds );
}

 

//-----------------------------------------------------------------------------
// Name: 创建平面类的实例
// 参数:DirectX对象,平面的结构指针
//-----------------------------------------------------------------------------
HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
{
    HRESULT hr;

    // Create the DDraw surface创建一个平面
    if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
        return hr;

    // Use the passed size, unless zero
    dwWidth  = pddsd->dwWidth;  //保留平面的尺寸
    dwHeight = pddsd->dwHeight;

    // Prepare the DDSURFACEDESC structure//定义平面实例对应的平面对象的结构
    m_ddsd.dwSize = sizeof(m_ddsd);

    // Get the DDSURFACEDESC structure for this surface//保存平面对象的结构
    m_pdds->GetSurfaceDesc( &m_ddsd );

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: CSurface::DrawBitmap()向平面画一个位图
// 参数:位图的句柄
// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
//       bitmap if nessasary
// 注意:位图尺寸大于表面的尺寸时位图尺寸变小
//-----------------------------------------------------------------------------
HRESULT CSurface::DrawBitmap( HBITMAP hBMP )
{
    HDC            hDCImage;
    HDC            hDC;
    BITMAP         bmp;
    DDSURFACEDESC2 ddsd;
    HRESULT        hr;

    if( hBMP == NULL || m_pdds == NULL )
        return E_INVALIDARG;

    // Make sure this surface is restored.//平面刷新
    if( FAILED( hr = m_pdds->Restore() ) )
        return hr;

    // Get the surface.description
    ddsd.dwSize  = sizeof(ddsd); //定义并得到表面的信息
    m_pdds->GetSurfaceDesc( &ddsd );

    if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )//判断位图的格式
        return E_NOTIMPL;

    // Select bitmap into a memoryDC so we can use it.
    hDCImage = CreateCompatibleDC( NULL ); //创建兼容设备
    if( NULL == hDCImage )
        return E_FAIL;

    SelectObject( hDCImage, hBMP ); //设置为位图设备

    // Get size of the bitmap
    GetObject( hBMP, sizeof(bmp), &bmp );//得到位图的信息

    // Stretch the bitmap to cover this surface
    if( FAILED( hr = m_pdds->GetDC( &hDC ) ) ) //得到平面的DC
        return hr;

    StretchBlt( hDC, 0, 0, ddsd.dwWidth, ddsd.dwHeight, // 画到DC上
                hDCImage, 0, 0, bmp.bmWidth, bmp.bmHeight,
    SRCCOPY );

    if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )//释放
        return hr;

    DeleteDC( hDCImage );//释放

    return S_OK;
}

 


//-----------------------------------------------------------------------------
// Name: CSurface::DrawText()
// Desc: Draws a text string on a DirectDraw surface using hFont or the default
//       GDI font if hFont is NULL. 
// 说明:将文字画到平面上
// 参数:字体,文字,背景色,字体色
//-----------------------------------------------------------------------------
HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
                            COLORREF crBackground, COLORREF crForeground )
{
    HDC     hDC = NULL;
    HRESULT hr;

    if( m_pdds == NULL || strText == NULL )
        return E_INVALIDARG;

    // Make sure this surface is restored.
    if( FAILED( hr = m_pdds->Restore() ) ) //刷新表面
        return hr;

    if( FAILED( hr = m_pdds->GetDC( &hDC ) ) ) //得到DC
        return hr;

    // Set the background and foreground color
    SetBkColor( hDC, crBackground ); //设置背景色
    SetTextColor( hDC, crForeground ); //设置字体色

    if( hFont )
        SelectObject( hDC, hFont ); //设置字体

    // Use GDI to draw the text on the surface
    TextOut( hDC, 0, 0, strText, _tcslen(strText) ); //输出文字

 SIZE sizeText;
    GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText ); //得到显示文字的尺寸
 dwHeight = sizeText.cx ; //保留字体的大小
 dwHeight = sizeText.cy;

    if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
        return hr;

    return S_OK;
}


//-------------------------------------------------
// Name: 向平面画一个位图
// 参数:位图的字符描述
//-------------------------------------------------
HRESULT CSurface::DrawBitmap( TCHAR* strBMP )
{
    HBITMAP hBMP;
    HRESULT hr;

    if( m_pdds == NULL || strBMP == NULL )
        return E_INVALIDARG;

 //尝试从资源中加载位图,如果失败,尝试从一个文件中加载
    //  Try to load the bitmap as a resource, if that fails, try it as a file
    hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
                                IMAGE_BITMAP, 0, 0,
                                LR_CREATEDIBSECTION );
    if( hBMP == NULL )
    {
        hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
                                    0, 0,
                                    LR_LOADFROMFILE | LR_CREATEDIBSECTION );
        if( hBMP == NULL )
            return E_FAIL;
    }

    // Draw the bitmap on this surface  在平面上画一个位图
    if( FAILED( hr = DrawBitmap( hBMP ) ) )
    {
        DeleteObject( hBMP );
        return hr;
    }

    DeleteObject( hBMP );

    return S_OK;
}

 


//-----------------------------------------------------------------------------
// Name: 设置平面的透明颜色
// 参数: 透明颜色值
//-----------------------------------------------------------------------------
HRESULT CSurface::SetColorKey( COLORREF crColorKey )
{
    if( NULL == m_pdds )
        return E_POINTER;

    m_bColorKeyed = TRUE; //使用透明颜色

    DDCOLORKEY ddck;

    ddck.dwColorSpaceLowValue  = crColorKey;
    ddck.dwColorSpaceHighValue = crColorKey;
   
    return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );//设置透明颜色
}

资源文件

 我的程序http://dl2.csdn.net/down4/20070629/29185221595.rar

原创粉丝点击