我们边看程序边讲解,程序的框架是用vc6的windows application生成的hello World改写的。这里没有解释程序在Alt+Tab切换一次后图片不见的问题,也没有说为什么用BltFast而没用Blt,同样也没有说AddRef()函数是干什么的。没用g_lpdd->CreatePalette(,,,,);函数时,用256色即#define BPP 8时,可能会有颜色失真,而16位色/时就不必用这个函数了!也不会有颜色失真。不过先这样用着,以后我在解释。
// directx.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include <ddraw.h>
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//---------------------全局变量和一些预定义宏---------------------------------------
//这两个预定义宏是为了方便释放指针用的在下面的FreeDraw()函数中有用
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
//显示模式的设定640×480×8
#define WIDTH 640
#define HEIGHT 480
#define BPP 8
//试试#define BPP 16会有什么效果??
//没用g_lpdd->CreatePalette(,,,,);函数时,用256色即#define BPP 8时,可能会有颜色失真,而16位色//时就不必用这个函数了!也不会有颜色失真。
HRESULT initDirectDraw(HINSTANCE hInst);//初始化DirectDraw
HRESULT MainLoop();//熟称GameLoop
void FreeDraw();//释放所有DirectDraw的指针
LPDIRECTDRAW7 g_lpdd;//指向实体的指针
LPDIRECTDRAWSURFACE7 g_lpFrontSurface;//A page
LPDIRECTDRAWSURFACE7 g_lpBackSurface;//B page
LPDIRECTDRAWSURFACE7 g_lpOffScreen;//用于后台的离屏页面
BOOL g_bActive=TRUE;//决定mainloop是否运行的标志
//-----------------------------------------------------------------------------
//Function:iniDirectDraw()
//用于初始化
//完成任务:创建g_lpdd指针实体、获取显示模式、设置显示模式、制作页面信息
// 创建主表面对象、提取后台缓存表面指针、用图片创建离屏页面
HRESULT initDirectDraw(HINSTANCE hInst)
{
HRESULT hr;
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
ZeroMemory(&ddsd,sizeof(ddsd));
ZeroMemory(&ddscaps,sizeof(ddscaps));
FreeDraw();
//创建g_lpdd指针实体
if(FAILED(hr = DirectDrawCreateEx(NULL, (void**)&g_lpdd,IID_IDirectDraw7, NULL)))
return E_FAIL;
//获取显示模式
if(FAILED(hr = g_lpdd->SetCooperativeLevel(GetActiveWindow(),DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN)))
return E_FAIL;
//设置显示模式
if(FAILED(hr = g_lpdd->SetDisplayMode(WIDTH,HEIGHT,BPP,0,0)))
return E_FAIL;
//制作页面信息
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1 ;
//创建主表面对象
if(FAILED(hr = g_lpdd->CreateSurface(&ddsd,&g_lpFrontSurface,NULL)))
return E_FAIL;
//提取后台缓存表面指针
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
if(FAILED(hr = g_lpFrontSurface->GetAttachedSurface(&ddscaps,&g_lpBackSurface)))
return E_FAIL;
g_lpBackSurface->AddRef();//没有他似乎也能运行正常?
//用图片创建离屏页面
HBITMAP hbm=NULL;
BITMAP bmp;
// IDB_BITMAP1是图片资源
hbm = (HBITMAP) LoadImage( GetModuleHandle(NULL), MAKEINTRESOURCE( IDB_BITMAP1 ),
IMAGE_BITMAP, 1500, 280, //图片读取进来后变形成多大的尺寸width,height
LR_CREATEDIBSECTION );
GetObject( hbm, sizeof(bmp), &bmp );
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
ddsd.dwWidth = bmp.bmWidth ;
ddsd.dwHeight = bmp.bmHeight ;
hr = g_lpdd->CreateSurface(&ddsd,&g_lpOffScreen,NULL);
if(FAILED(hr))
{
if(hr == DDERR_OUTOFVIDEOMEMORY)
{//这是最后机会
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if(FAILED(hr = g_lpdd->CreateSurface(&ddsd, &g_lpOffScreen, NULL )))
return E_FAIL;
}
}
HDC hdc;
HDC hdcImage;
hdcImage = CreateCompatibleDC(NULL);
SelectObject(hdcImage, hbm);
g_lpOffScreen->Restore();
g_lpOffScreen->GetSurfaceDesc(&ddsd);
if((hr = g_lpOffScreen->GetDC(&hdc))==DD_OK)
{
StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, 0, 0,
bmp.bmWidth ,bmp.bmHeight , SRCCOPY);
g_lpOffScreen->ReleaseDC(hdc);
}
DeleteDC(hdcImage);
return S_OK;
}
//这里的宏在最上面定义了
void FreeDraw()
{
SAFE_RELEASE(g_lpFrontSurface);
SAFE_RELEASE(g_lpBackSurface);
SAFE_RELEASE(g_lpOffScreen);
SAFE_RELEASE(g_lpdd);
}
//Function:MainLoop()
//
//
HRESULT MainLoop()
{
HRESULT hRet;
RECT rect;
rect.left =0;
rect.top = 0;
rect.right = 150;
rect.bottom = 140;
//从离屏页面把存在OffScreen的图片取出rect举行位置的图片,拷贝到后台缓存中
g_lpBackSurface->BltFast(0,0,g_lpOffScreen,&rect,DDBLTFAST_NOCOLORKEY);
//后台缓存画上了图象,那么就Flip放到前台让他显示出来
g_lpFrontSurface->Flip(NULL, 0 );
return S_OK;
}
//