CSDN博客

img myling

24小时学DX之第二小时——显示一张背景图片

发表于2004/9/14 22:20:00  2652人阅读

#include "stdafx.h"
#include "resource.h"
#define INITGUID
#include
#define SafeRelease(x) if (x) { x->Release(); x=NULL; }


//函数声明
BOOL InitWindow( HINSTANCE hInstance, int nCmdShow );
LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
void DrawImage();
LPCTSTR PicName="E:/CJD/素材/pic/魔兽/1.bmp";

//变量说明
HWND hWnd; //窗口句柄

/*=============================================================================
LPDIRECTDRAW7和LPDIRECTDRAWSURFACE7类型(7是版本号)是在ddraw.h头文件里预定义的,
指向IDirectDraw7和IDirectDrawSurface7类型的长型指针(前面加的LP代表Long Point),
从后面用的是"->"而不是"."也可以看出这一点。

DD是DirectDraw的缩写,DDS是DirectDrawSurface的缩写,
因此习惯上我们把变量名起为lpDD和lpDDSXXX。


虽然VC.net自带的DirectX SDK是8.1版的,
但是由于Microsoft从DirectX 8.0起停止了对DirectDraw的更新,
所以DirectDraw目前的最新版本还是7.0。
===============================================================================*/

LPDIRECTDRAW7 lpDD=NULL;// DirectDraw对象的指针
LPDIRECTDRAWSURFACE7 lpDDSPrimary=NULL;// DirectDraw主页面的指针
LPDIRECTDRAWCLIPPER lpClip=NULL; // DirectDraw 剪裁对象
LPDIRECTDRAWSURFACE7 lpBmp=NULL; // 存放背景图的页面的指针


LPDIRECTDRAWSURFACE7 bitmap_surface(LPCTSTR file_name)
{
?HDC hdc;
?HBITMAP bit;
?LPDIRECTDRAWSURFACE7 surf;
?//载入BMP
?bit=(HBITMAP) LoadImage(NULL,file_name,IMAGE_BITMAP,0,0,
??LR_DEFAULTSIZE|LR_LOADFROMFILE);
?if (!bit)//载入失败,返回NULL
??return NULL;
?//获得BMP尺寸
?BITMAP bitmap;
?GetObject(bit, sizeof(BITMAP), &bitmap );
?//保存BMP尺寸
?int surf_width = bitmap.bmWidth;
?int surf_height = bitmap.bmHeight;

?//创建页面
?HRESULT ddrval;
?DDSURFACEDESC2 ddsd;
?//清空DDSURFACEDESC2结构
?ZeroMemory(&ddsd,sizeof(ddsd));
?ddsd.dwSize = sizeof(DDSURFACEDESC2);
?//设置填充标示
?ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
?//离屏页面
?ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
?//指定宽高
?ddsd.dwWidth =1024;
?ddsd.dwHeight =768;
?//创建离屏页面
?ddrval=lpDD->CreateSurface(&ddsd,&surf,NULL);
?if (ddrval!=DD_OK) {
??//失败的话,释放BMP
??DeleteObject(bit);
??return NULL;
?}
?else //创建成功
?{
??//取得DC
??surf->GetDC(&hdc);
??//与DC取得一致
??HDC bit_dc=CreateCompatibleDC(hdc);
??//
??SelectObject(bit_dc,bit);
??//传送bmp
??BitBlt(hdc,0,0,surf_width,surf_height,bit_dc,0,0,SRCCOPY);
??//释放DC
??surf->ReleaseDC(hdc);
??DeleteDC(bit_dc);
?}
?//释放BMP
?DeleteObject(bit);
?//返回离屏页面指针
?return surf;
}

//************************************************************
//函数:InitDDraw()
//功能:DX初始化函数
//************************************************************
BOOL InitDDraw()
{
?DDSURFACEDESC2 ddsd; // DirectDraw的页面描述
?HRESULT hRet;
? /*
??? 在一切工作之前,记得加入两个lib文件
??? 在菜单Project-Setting下的Link页的Object/Library Modules栏里加入
??? "ddraw.lib"和"dxguid.lib" ,后者可以不加入,而用#define INITGUID代替
??? PS:最好选择setting for All Configurations
??? 这样会在 debug 和 release 下都有效
? */
? /*
??? 如果要使用DirectDraw,必须创建一个DirectDraw对象,它是DirectDraw接口的核心。
??? 用DirectDrawCreateEx( )函数可以创建DirectDraw对象,
??? DirectDrawCreateEx( )函数是在ddraw.h中定义的,它的原型如下:

?????? HRESULT WINAPI DirectDrawCreateEx(
? ?????? GUID FAR *lpGUID, //指向DirectDraw接口的GUID的指针,NULL表示采用默认(当前)
? ?????? LPVOID *lplpDD,?? //用来接受初始化的DirectDraw对象的地址
? ?????? REFIID iid,?????? //IID_IDirectDraw7,当前版本
? ?????? IUnknown FAR *pUnkOuter? //NULL? 保留
??? );
?????? 所有的DirectDraw函数的返回值都是HRESULT类型,它是一个32位的值。
??? 函数调用成功用 "DD_OK"表示,
??? 所有的错误值标志开头都为"DDERR",如:
??? DDERR_DIRECTDRAWALREADYCREATED
??? DDERR_OUTOFMEMORY
? */
? //这里使用了 if (xxx!=DD_OK) 的方法进行错误检测,这是最常用的方法
???? if (DirectDrawCreateEx(NULL,(LPVOID*)&lpDD, IID_IDirectDraw7, NULL)!= DD_OK)
??return FALSE; //创建DirectDraw对象
? /*
? DirectDrawCreate函数调用成功后,lpDD已经指向了一个DirectDraw对象,
? 它是整个DirectDraw接口的最高层领导,以后的步骤都是在它的控制之下。
? 我们用IDirectDraw7::SetCooperativeLevel( )来设置DirectDraw程序对系统的控制级。
? 它的原型如下:
? HRESULT SetCooperativeLevel (HWND hWnd, DWORD dwFlags )
? 第一个参数是窗口句柄,我们给它hWnd,使DirectDraw对象与主窗口联系上。
???? 第二个参数是控制级标志。这里使用DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN,
? 表示我们期望DirectDraw以独占和全屏方式工作。
????
? 控制级描述了DirectDraw是怎样与显示设备及系统作用的。
? DirectDraw控制级一般被用来决定应用程序是运行于全屏模式(必须与独占模式同时使用),
? 还是运行于窗口模式。但DirectDraw的控制级还可设置如下两项:
???? (1)允许按Ctrl+Alt+Del重新启动(仅用于独占模式,为DDSCL_ALLOWREBOOT)。
???? (2)不允许对DirectDraw应用程序最小化或还原 (DDSCL_NOWINDOWCHANGES)。
????
? 普通的控制级(DDSCL_NORMAL)表明我们的DirectDraw应用程序将以窗口的形式运行。
? 在这种控制级下,我们将不能改变显示器分辨率,或进行换页操作(这是一个重要的操作)。
? 除此之外,我们也不能够调用那些会对显存产生激烈反应的函数,如Lock()。
???? 当应用程序为全屏并且独占的控制级时,我们就可以充分的利用硬件资源了。
? 此时其它应用程序仍可创建页面、使用DirectDraw或GDI的函数,只是无法改变显示模式。
? */
???? if (lpDD->SetCooperativeLevel(hWnd,DDSCL_NORMAL)!= DD_OK)
??????? return FALSE; //设置DirectDraw控制级
? /*
? 下一步我们使用IDirectDraw7::SetDisplayMode( )来设置显示模式,其原形为:
? HRESULT SetDisplayMode(
? DWORD dwWidth,
? DWORD dwHeight, //dwWidth and dwHeight用来设置显示模式的宽度和高度。
? DWORD dwBPP, //dwBPP用来设置显示模式的颜色位数。
? DWORD dwRefreshRate, //dwRefreshRate设置屏幕的刷新率,0为使用默认值。
? DWORD dwFlags //dwFlags现在唯一有效的值是DDSDM_STANDARDVGAMODE
? );
? */
???? if (lpDD->SetDisplayMode(1024,768,32,0,DDSDM_STANDARDVGAMODE)!= DD_OK)
??????? return FALSE; //设置显示模式
? /*
? HRESULT CreateClipper(
? DWORD dwFlags, //现在不用,必须设为0
? LPDIRECTDRAWCLIPPER FAR *lplpDDClipper,//指向剪裁器对象的指针
? IUnknown FAR *pUnkOuter // //现在不用,必须设为NULL
? );
? 成功的时候返回DD_OK
? */

? //创剪裁器(必须在设置完DirectDraw控制级后,创建主页面之前进行)
? hRet=lpDD->CreateClipper(NULL,&lpClip,NULL);
? if (hRet != DD_OK) {
?? return FALSE;
? }
? lpClip->SetHWnd(0,hWnd);

??? /*
?? 创建一个页面之前,首先需要填充一个DDSURFACEDESC2结构,
?? 它是DirectDraw Surface Description的缩写,意思是DirectDraw的页面描述。
?? 它的结构非常庞大,这里只能作一个最简单的介绍。
?? 要注意的是在填充此结构前一定要将其清空!
?*/

?//开始创建主页面,先清空页面描述
?ZeroMemory(&ddsd, sizeof(ddsd));

?//填充页面描述
??? ddsd.dwSize = sizeof(ddsd);//给dwSize页面描述的大小
?ddsd.dwFlags = DDSD_CAPS;
??? ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE;//主页面
??? /*
?CreateSurface( )函数的第一个参数是被填充了页面信息的DDSURFACEDESC2结构的地址,
?此处为&ddsd;
?第二个参数是接收主页面指针的地址,此处为&lpDDSPrimary;
?第三个参数现在必须为NULL,为该函数所保留。
??? 如果函数调用成功,lpDDSPrimary将成为一个合法的主页面对象。
?由于在前面已经设置了该程序的工作模式为独占和全屏,
?所以,此时主页面所代表的实际上是我们的整个显示屏幕。
?在主页面上所绘制的图形将立即反映到我们的显示屏幕上。
?*/
???? if (lpDD->CreateSurface(&ddsd,&lpDDSPrimary, NULL) != DD_OK )
????? ?return FALSE; //创建主页面
??? lpDDSPrimary->SetClipper(lpClip);//设置剪裁
?//载入图片
?lpBmp=bitmap_surface(PicName);
?//画图
??? DrawImage();
?return TRUE;
}


void Cleanup(void)
{
?//释放接口
?SafeRelease(lpBmp);
?SafeRelease(lpDDSPrimary);//删除主页面
?SafeRelease(lpClip);//删除剪裁
?SafeRelease(lpDD);//删除ddraw对象
?//ps:与创建的顺序正好相反
}


void DrawImage()
{
?if (lpBmp==NULL)
?{
??return;
?}
?//全屏画图
?lpDDSPrimary->Blt(NULL,lpBmp,NULL,DDBLT_WAIT,NULL);
}

//************************************************************
//函数:WinMain( )
//功能:Windows程序入口函数。创建主窗口,处理消息循环
//************************************************************
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
? if ( !InitWindow( hInstance, nCmdShow ) ) return FALSE; //创建主窗口
? //如果创建不成功则返回FALSE并同时退出程序
? MSG msg;
? //进入消息循环:
? for(;;)
? {
?if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
?{
??if ( msg.message==WM_QUIT) break;
??TranslateMessage(&msg);
??DispatchMessage(&msg);
?}
? }
?? return msg.wParam;
}

//************************************************************
//函数:InitWindow( )
//功能:创建窗口
//************************************************************

static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
{
?//定义窗口风格:
?WNDCLASS wc;
?wc.style = CS_VREDRAW|CS_HREDRAW;//窗体类的风格
?wc.lpfnWndProc = (WNDPROC)WinProc; //窗口消息处理函数的指针
?wc.cbClsExtra = 0;//分配给窗口类结构之后的额外字节数
?wc.cbWndExtra = 0;//分配给窗口实例之后的额外字节数
?wc.hInstance = hInstance;//窗口所对应的应用程序的句柄
?wc.hIcon = NULL;//窗口的图标
?wc.hCursor = LoadCursor(NULL, IDC_ARROW); //窗口的鼠标
?wc.hbrBackground = CreateSolidBrush (RGB(0, 0, 0)); //黑色的背景
?wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);//窗口的菜单资源名称
?wc.lpszClassName = "My_Test";//窗口类的名称
?RegisterClass(&wc);//注册窗口

??? //按所给参数创造窗口
???? hWnd = CreateWindow("My_Test",//创建窗口所用的窗口类的名称
?? "24小时学DX_第2个小时",//窗口标题
?? WS_POPUP|WS_CAPTION,//窗口风格,定义为普通型
?? 0,0,//窗口位置的x,y坐标
?? 1024,768,//窗口的宽度,高度
?? NULL,//父窗口句柄
?? NULL,//菜单句柄
?? hInstance,//应用程序句柄
?? NULL);
?if(!hWnd ) return FALSE;
?ShowWindow(hWnd,nCmdShow);//显示窗口
?UpdateWindow(hWnd);//刷新窗口
?InitDDraw();//初始化DX
?return TRUE;
}

//************************************************************
//函数:WinProc( )
//功能:处理窗口消息
//************************************************************

LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
?switch(message)
?{
?case WM_COMMAND:
??switch (LOWORD(wParam))
??{
??
??case IDM_Exit:
??? DestroyWindow(hWnd);
??? break;
??????? case IDM_ChangePic:?
????????? if (PicName=="E:/CJD/素材/pic/魔兽/1.bmp")
???? PicName="E:/CJD/素材/pic/魔兽/2.bmp";
??? else
??????? PicName="E:/CJD/素材/pic/魔兽/1.bmp";
??? lpBmp=bitmap_surface(PicName);
????????? DrawImage();
??? break;
??}
?? break;
?case WM_KEYDOWN://击键消息
??switch(wParam)
??{
??case VK_ESCAPE:
???PostMessage(hWnd, WM_CLOSE, 0, 0);//给窗口发送WM_CLOSE消息
???break;
??}
??break;
?case WM_PAINT://画图消息
??PAINTSTRUCT ps;
??BeginPaint(hWnd, &ps);
??DrawImage();
??EndPaint(hWnd, &ps);
??break;
?case WM_DESTROY: //如果窗口被人释放…
??Cleanup();
???? PostQuitMessage(0); //给窗口发送WM_QUIT消息
??break;
??? default://调用缺省消息处理过程
??return DefWindowProc(hWnd, message, wParam, lParam);?
?}?
?return 0;
}

0 0

相关博文

我的热门文章

img
取 消
img