24小时学DX之第四小时——计时器、title

/*==============================================================
?? 24小时学习DX——第3小时
=================================================================*/

#include "stdafx.h"
//#include "resource.h"
#define INITGUID
#include
#include

#define MIN_POS 0.0
#define MAX_POS 50000.0
#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 );
BOOL load_images();
void render_frame();


//变量说明
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主页面的指针
LPDIRECTDRAWSURFACE7 lpDDSBuffer=NULL;// DirectDraw后台缓存页面的指针
LPDIRECTDRAWSURFACE7 back_surf[3]={NULL,NULL,NULL};
RECT rect;

double x_pos=25000; // player位置
double move_rate=0.0; // player运动

void MakeRect (int left, int top, int right, int bottom)
{
?rect.bottom = bottom;
?rect.left = left;
?rect.right = right;
?rect.top = top;
}

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;
}


BOOL load_images()
{
?//载入背景图片
?back_surf[0]=bitmap_surface("E:/CJD/素材/pic/魔兽/1.bmp");
?if (!back_surf[0])
??return FALSE;
?back_surf[1]=bitmap_surface("E:/CJD/素材/pic/魔兽/2.bmp");
?if (!back_surf[1])
??return FALSE;
?back_surf[2]=bitmap_surface("E:/CJD/素材/pic/魔兽/3.bmp");
?if (!back_surf[2])
??return FALSE;
?return TRUE;
}


//画1桢的函数
void render_frame()
{
?RECT rct; //传送图像的区域
?long tile_pos; //tile的位置
?//循环穿过title
?for (int i=0;i<3;i++) {
??//计算title位置
??tile_pos=1024*i+((long) (x_pos)/3072)*3072;
??if (tile_pos+3072
???tile_pos+=3072;
??//在屏幕上?
??if (tile_pos+1024>=x_pos) {
???//是,计算左边的相对位置
???int screen_x=tile_pos-x_pos;
???//如果需要的话进行裁减
???rct.left=0;
???rct.top=0;
???rct.right=1024;
???rct.bottom=768;
???//测试裁减
???if (screen_x<0) {
????rct.left-=screen_x;
????screen_x=0;
???} else if (screen_x+rct.right>1024) {
????rct.right=1024-screen_x;
???}
???//传送位图
???lpDDSBuffer->BltFast(screen_x,0,back_surf[i],&rct,DDBLTFAST_WAIT);
??}
?}
?//换页
?lpDDSPrimary->Flip(0,DDFLIP_WAIT);
}

//************************************************************
//函数:InitDDraw()
//功能:DX初始化函数
//************************************************************
BOOL InitDDraw()
{
?DDSURFACEDESC2 ddsd; // DirectDraw的页面描述
? /*
??? 在一切工作之前,记得加入两个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_FULLSCREEN|DDSCL_EXCLUSIVE|
?? DDSCL_ALLOWREBOOT)!= 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,
??????????????? //此值是如果在320×240×8模式下给VGA Mode 13用的,
?????? //我们通常把它设为0即可
?????
? );
? PS:用IDirectDraw7接口的EnumDisplayModes()函数
???? 可以取得当前可用的模式列表。具体用法请查阅DX的帮助
? */
???? if (lpDD->SetDisplayMode(1024,768,32,85,0)!= DD_OK)
??????? return FALSE; //设置显示模式

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

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

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

??? ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; //后台缓存页面
??? /*
?在创建主页面的时候,附加页面(这里是后台缓存页面)也同时创建了,
?但是他们没有被你调用的CreateSurface()所返回
?你要通过GetAttachedSurface()函数来取得该接口,
?*/
??? if (lpDDSPrimary->GetAttachedSurface(&ddsd.ddsCaps,&lpDDSBuffer)!=DD_OK)
??return FALSE; //创建后台缓存页面
?//载入图片
?if (!load_images())
?? return FALSE;
?return TRUE;
}


void Cleanup(void)
{
?//释放接口
?SafeRelease(back_surf[0]);
?SafeRelease(back_surf[1]);
?SafeRelease(back_surf[2]);
?
?SafeRelease(lpDDSBuffer);
?SafeRelease(lpDDSPrimary);//删除主页面
?SafeRelease(lpDD);//删除ddraw对象
?//ps:与创建的顺序正好相反
}

//************************************************************
//函数:WinMain()
//功能:Windows程序入口函数。创建主窗口,处理消息循环
//************************************************************
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
?MSG msg; //消息
?LONGLONG cur_time; //当前时间
?DWORD time_count; //每桢的毫秒数
?LONGLONG perf_cnt; //计时器执行频率
?BOOL perf_flag=FALSE; //决定用那个计时器的标志
?LONGLONG next_time=0; //渲染下一桢的时间
?LONGLONG last_time=0; //前一桢的时间
?double time_elapsed; //开始以后经历的时间
?double time_scale; //时间因子换算系数

? if ( !InitWindow(hInstance, nCmdShow ) ) return FALSE; //创建主窗口
? //如果创建不成功则返回FALSE并同时退出程序
?
? //performance计数器可不可用?
? if (QueryPerformanceFrequency((LARGE_INTEGER*)&perf_cnt))
? {
?? //可用,设置计数器标志和参数
?? perf_flag=TRUE;
?? time_count=perf_cnt/30;
?? QueryPerformanceCounter((LARGE_INTEGER*)&next_time);
?? time_scale=1.0/perf_cnt;
? } else {
?? // no performance counter, read in using timeGetTime
?? //next_time=timeGetTime();
?? //time_scale=0.001;
?? //time_count=33;
? }
? //保存最后一桢的时间
? last_time=next_time;
? //进入消息循环:
? for(;;)
? {
?if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
?{
??if (msg.message==WM_QUIT) break;
??TranslateMessage(&msg);
??DispatchMessage(&msg);
?}else {
??// 根据计时器标志采用不同的函数
??// 计算最后一桢用了多长时间
??if (perf_flag)
???QueryPerformanceCounter((LARGE_INTEGER *) &cur_time);
??//else
???//cur_time=timeGetTime();
??//到不到画下一桢的时间?
??if (cur_time>next_time) {
???time_elapsed=(cur_time-last_time)*time_scale;
???
???//保存最后一桢的时间
???last_time=cur_time;

???//移动屏幕位置
???x_pos+=move_rate*time_elapsed;
???if (x_pos ????x_pos=MIN_POS;
????move_rate=0;
???}
???if (x_pos>MAX_POS) {
????x_pos=MAX_POS;
????move_rate=0;
???}
???//画桢
???render_frame();
???//设置下一桢的时间
???next_time = cur_time + time_count;
??}
?}
? }
?? return msg.wParam;
}

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

static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
{
?//定义窗口风格:
?WNDCLASS wc;
?wc.style =NULL;//窗体类的风格
?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 = NULL;//MAKEINTRESOURCE(IDR_MENU);//窗口的菜单资源名称
?wc.lpszClassName = "My_Test";//窗口类的名称
?RegisterClass(&wc);//注册窗口

??? //按所给参数创造窗口
???? hWnd = CreateWindow("My_Test",//创建窗口所用的窗口类的名称
?? "24小时学DX_第4个小时",//窗口标题
?? WS_POPUP|WS_MAXIMIZE,//窗口风格,定义为普通型
?? 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:
?? break;
?case WM_KEYDOWN://击键消息
??switch(wParam)
??{
??case VK_ESCAPE:
???PostMessage(hWnd, WM_CLOSE, 0, 0);//给窗口发送WM_CLOSE消息
???break;
??//左右被按下了,改变图片位置,重画
??case VK_LEFT:
???if (move_rate<600.0)
????move_rate+=60.0;
???break;
??case VK_RIGHT:
???if (move_rate>-600.0)
????move_rate-=60.0;
???break;
??}
??break;
?case WM_DESTROY: //如果窗口被人释放…
??Cleanup();
???? PostQuitMessage(0); //给窗口发送WM_QUIT消息
??break;
??? default://调用缺省消息处理过程
??return DefWindowProc(hWnd, message, wParam, lParam);?
?}?
?return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值