www.gusucode.com > VC++游戏圣剑英雄传2双刃剑源程序+开发文档-源码程序 > VC++游戏圣剑英雄传2双刃剑源程序+开发文档-源码程序\code\source\GAMELIB\Gp_draw.cpp
//Download by http://www.NewXing.com //******************************************** // DirectDraw相关处理函数 // softboy 创建于2000年1月25日 //******************************************** #include <windows.h> #include <stdio.h> #include <fstream.h> #include <ddraw.h> #include "ddutil.h" #include "gp_init.h" #include "gp_draw.h" #include "gp_input.h" #include "gp_alpha.h" #include "gp_text.h" #include "gp_other.h" //*****************游戏显示属性***************** DWORD ColorKey=RGB(255,0,255); //透明色 WORD ColorKey16; //16位透明色 bool Is555 = true; //是否是555格式 long nFrames=0; //帧数测试 RECT RectScreen={0,0,ScreenWidth,ScreenHeight}; //全屏显示的目标矩形 RECT RectWindow; //窗口显示的目标矩阵 POINT g_pointClient; //窗口和客户区的偏移 //*****************DDraw变量******************** LPDIRECTDRAW lpDD; //DirectDraw对象 LPDIRECTDRAWSURFACE lpDDSPrimary; // 主页面 LPDIRECTDRAWSURFACE lpDDSBack=NULL; // 后台页面 extern LPDIRECTDRAWSURFACE lpDDSSour, lpDDSTemp; //****************Lock 相关********************* WORD *GraphBuffer = 0; // 绘图缓冲区 int GraphPitch = 0; // 缓冲区跨度 int GraphWidth = 0; //页面宽度 int GraphHeight = 0; //页面高度 DDSURFACEDESC ddsd; HRESULT ddrval; //16位RGB换算 WORD RGB16(WORD r, WORD g, WORD b) { //简单 if( Is555 ) //rrrrr|ggggg|bbbbb 0xf8 = 11111000b return ((r&0xf8)<<7) | ((g&0xf8)<<2) | ((b&0xf8)>>3); else //rrrrr|gggggg|bbbbb 0xfc = 11111100 return ((r&0xf8)<<8) | ((g&0xfc)<<3) | ((b&0xf8)>>3); } //24位转16位 WORD RGB16(DWORD color) { WORD r,g,b; //也比较简单 r=(WORD)(color>>16); g=(WORD)(color>>8); b=(WORD)color; if( Is555 ) return ((r&0xf8)<<7) | ((g&0xf8)<<2) | ((b&0xf8)>>3); else return ((r&0xf8)<<8) | ((g&0xfc)<<3) | ((b&0xf8)>>3); } //功能:获得位图文件的尺寸大小 //参数:窗口句柄,位图文件名,返回位图宽度,返回位图高度(引用参数) BOOL LoadBitmapFileInfo(HWND hwnd, LPCTSTR filename, int &dx, int &dy) { FILE *fp; if( (fp=fopen(filename, "rb"))==NULL ) { char b[MAX_PATH*2]; sprintf(b,"Error open BMP file: %s",filename); MessageBox(hwnd,b,"Load file info!",MB_OK); return FALSE; } //读入文件头 BITMAPFILEHEADER bmpFileHeader; fread(&bmpFileHeader, sizeof(bmpFileHeader), 1, fp); //检查BM标志 char *ptr=(char*)&bmpFileHeader.bfType; if(*ptr!='B' || *++ptr!='M') { MessageBox(hwnd,"Invalid bitmap file!","error",MB_OK); return FALSE; } //信息头 BITMAPINFOHEADER bmpInfoHeader; fread(&bmpInfoHeader, sizeof(bmpInfoHeader), 1, fp); fclose(fp); //宽度,高度 dx=bmpInfoHeader.biWidth; dy=bmpInfoHeader.biHeight; return TRUE; } //********************************* //功能:创建页面 //参数:要创建的页面指针,宽度,高度,文件名,内存标志 BOOL CreateBitmap(LPDIRECTDRAWSURFACE &lpTemp,int x,int y,char *BitmapFile, DWORD MemoryFlag ) { DDSURFACEDESC ddsd; HRESULT ddrval; //获得位图文件的尺寸 if( x == 0 && y == 0 ) if( LoadBitmapFileInfo(hWnd, BitmapFile, x, y)==FALSE ) return FALSE; //创建一个页面 ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | MemoryFlag; ddsd.dwWidth = x; ddsd.dwHeight = y; ddrval = lpDD->CreateSurface( &ddsd, &lpTemp, NULL ); if( ddrval != DD_OK ) { return initFail(BitmapFile); } if( BitmapFile!=NULL ) DDReLoadBitmap(lpTemp,BitmapFile); return TRUE; } //*********************************************************** //功能:位图拷贝 //参数:目标表面,目标x,目标y,原表面,拷贝范围,是否带透明色 void Blt(LPDIRECTDRAWSURFACE SS,int x,int y, LPDIRECTDRAWSURFACE DS,RECT rcRect,DWORD Flag) { //边界检查 if( x<0 ) { rcRect.left = rcRect.left - x; x=0; } else if( x+ rcRect.right - rcRect.left > ScreenWidth ) { rcRect.right = rcRect.left + ScreenWidth - x; } if( y<0 ) { rcRect.top = rcRect.top - y; y=0; } else if( y+ rcRect.bottom - rcRect.top > ScreenHeight ) { rcRect.bottom = rcRect.top + ScreenHeight - y; } while( 1 ) { ddrval = SS->BltFast( x, y, DS, &rcRect, Flag); if( ddrval == DD_OK ) { return; } if( ddrval == DDERR_SURFACELOST ) { ddrval = restoreAll(); if( ddrval != DD_OK ) { return; } } if( ddrval != DDERR_WASSTILLDRAWING ) { return; } } } //*********************************************************** //功能:快速位图拷贝 //参数:目标表面,目标x,目标y,原表面,拷贝范围,是否带透明色 void BltFast(LPDIRECTDRAWSURFACE SS,int x,int y, LPDIRECTDRAWSURFACE DS,RECT rcRect,DWORD Flag) { //边界检查 if( x<0 ) { rcRect.left = rcRect.left - x; x=0; } else if( x+ rcRect.right - rcRect.left > ScreenWidth ) { rcRect.right = rcRect.left + ScreenWidth - x; } if( y<0 ) { rcRect.top = rcRect.top - y; y=0; } else if( y+ rcRect.bottom - rcRect.top > ScreenHeight ) { rcRect.bottom = rcRect.top + ScreenHeight - y; } SS->BltFast( x, y, DS, &rcRect, Flag); } //*********************************************************** //功能:带缩放的位图拷贝 //参数:目标表面,目标矩阵,原表面,拷贝范围,是否带透明色 BOOL SBlt(LPDIRECTDRAWSURFACE SS,RECT sr, LPDIRECTDRAWSURFACE DS,RECT dr,BOOL Flag) { DWORD Flags= (Flag==FALSE)?0:DDBLT_KEYSRC; //边界检查 int SWidth=sr.right-sr.left, SHeight=sr.bottom-sr.top; int DWidth=dr.right-dr.left, DHeight=dr.bottom-dr.top; if( sr.left<0 ) { dr.left += (DWidth * (-sr.left)) / SWidth; sr.left=0; } if( sr.top<0 ) { dr.top += (DHeight * (-sr.top)) / SHeight; sr.top=0; } if( sr.right > ScreenWidth ) { dr.right -= (DWidth * (sr.right-ScreenWidth)) / SWidth; sr.right=ScreenWidth; } if( sr.bottom > ScreenHeight ) { dr.bottom -= (DHeight *(sr.bottom-ScreenHeight)) / SHeight; sr.bottom=ScreenHeight; } while( 1 ) { ddrval = SS->Blt( &sr, DS, &dr, Flags, 0); if( ddrval == DD_OK ) { return TRUE; } if( ddrval == DDERR_SURFACELOST ) { ddrval = restoreAll(); if( ddrval != DD_OK ) { return TRUE; } } if( ddrval != DDERR_WASSTILLDRAWING ) { return FALSE; } } if(ddrval != DD_OK) { return FALSE; } } //*********************************************************** //功能:带缩放的位图拷贝(不带边界检查) //参数:目标表面,目标x,目标y,原表面,拷贝范围,是否带透明色 BOOL _SBlt(LPDIRECTDRAWSURFACE SS,RECT sr, LPDIRECTDRAWSURFACE DS,RECT dr,BOOL Flag) { DWORD Flags= (Flag==FALSE)?0:DDBLT_KEYSRC; while( 1 ) { ddrval = SS->Blt( &sr, DS, &dr, Flags, 0); if( ddrval == DD_OK ) { return TRUE; } if( ddrval == DDERR_SURFACELOST ) { ddrval = restoreAll(); if( ddrval != DD_OK ) { return TRUE; } } if( ddrval != DDERR_WASSTILLDRAWING ) { return FALSE; } } } //***************************************************** //功能:翻转页面 void Flip(void) { HRESULT ddrval; while( 1 ) { ddrval = lpDDSPrimary->Flip( NULL, 0 ); if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { ddrval = restoreAll(); if( ddrval != DD_OK ) { break; } } if( ddrval != DDERR_WASSTILLDRAWING ) { break; } } } //******************** //功能:恢复系统页面 HRESULT restoreAll( void ) { HRESULT ddrval; if( lpDDSPrimary ) ddrval = lpDDSPrimary->Restore(); if( lpDDSBack ) ddrval = lpDDSBack->Restore(); return ddrval; } //******************************************** //功能:清屏 //参数:目标表面,颜色值 void Clrscr(LPDIRECTDRAWSURFACE surf,WORD color ) { DDBLTFX ddbltfx; ddbltfx.dwSize=sizeof(ddbltfx); ddbltfx.dwFillColor=color; surf->Blt(NULL,NULL,NULL,DDBLT_COLORFILL,&ddbltfx); } //------------------------------- //功能:更新到屏幕 //参数:目标表面,更新范围 void _UpdateScreen(LPDIRECTDRAWSURFACE lpSurf, RECT DestRect) { if( WindowMode==0 ) //全屏 { Blt(lpDDSPrimary, 0, 0, lpSurf, DestRect, false); } else //窗口 { lpDDSPrimary->Blt( &RectWindow, lpSurf, &DestRect, DDBLTFAST_NOCOLORKEY, 0); } } ///////////////////////////////////////////////////////////////// //画元素 ///////////////////////////////////////////////////////////////// void PutPixel(LPDIRECTDRAWSURFACE surf, int x, int y, WORD color) { BeginDraw(surf); EndDraw(surf); GraphBuffer[GraphPitch*y+x]=color; } //设置一个点的颜色为color void _PutPixel(int x, int y, WORD color) { GraphBuffer[GraphPitch*y+x]=color; } //画圆 void Circle(LPDIRECTDRAWSURFACE surf, int x0, int y0, int r,WORD color) { long flag; int x,y,xmax; static double SIN45=0.707106781186548; y=r; x=0; xmax=(int)(r*SIN45); //只需要扫描45度的角 flag=(1-r*2); //soft也是害人,一句注释都没有,我找了半天才知道: //这其实是一个很出名的算法 //名字是Bresenham算法 //我只说个大概 //详细的就要自己去找这方面的解释 if( BeginDraw(surf) ) { while( x<=xmax ) //循环的条件,让x一直加,加到xmax为止,也就是从0度到45度 { if(flag>=0) // |y { // | flag+=(6+((x-y)<<2)); // \ ..... / y--; // . | . } // . \ | / . else // . \|/ . flag+=((x<<2)+2); //--.---+---.-- 仔细看看这些点的排列 // . /|\ . x //画8个点,也许是4个点(有重复的点) // . / | \ . _PutPixel(x0+y, y0+x, color); // . | . _PutPixel(x0+x, y0+y, color); // / ..... \ _PutPixel(x0-x, y0+y, color); // | _PutPixel(x0-y, y0+x, color); // | _PutPixel(x0-y, y0-x, color); //可以先看看下面的画线的函数然后再看这个,这 _PutPixel(x0-x, y0-y, color); //样比较好懂。想要画出这个圆来,关键是决定下 _PutPixel(x0+x, y0-y, color); //一个点该放到什么位置,这里有一个出名的判断 _PutPixel(x0+y, y0-x, color); //方法:Midpoint 方法………… x++; //这儿放不下这么多的内容了,自己去找关于计算 } //机图形学的书来看吧。 EndDraw(surf); //或者要是你拿到的这份源代码中有一个叫圣二源 } //程序导读的文件的话,读读吧,里面有的。 } //画线 void Line(LPDIRECTDRAWSURFACE surf, int left, int top, int right, int bottom, WORD color) { register int t; int distance; int x=0,y=0,delta_x,delta_y,incx,incy; delta_x =right-left; delta_y=bottom-top; //根据x和y的变化量设置x和y的增长方式(每次加1还是减1或者是不变) if(delta_x>0) incx=1; else if (delta_x==0) incx=0; else { delta_x=-delta_x; incx=-1; } if (delta_y>0) incy=1; else if (delta_y==0) incy=0; else { delta_y=-delta_y; incy=-1; } if(delta_x>delta_y) distance=delta_x; else distance=delta_y; //开始画线了 //一样的Bresenham算法 //看看右边的图先 if( BeginDraw(surf) ) { //两个端点也要画 for (t=0; t<distance+2; t++) { //画点 _PutPixel(left, top, color); // o------- | x+=delta_x; // p1 -------- | delta_y y+=delta_y; // ------- p2 | if(x>distance) // -------o | { //------------------------------------ x-=distance; // delta_x left+=incx; //这是一个基本的示意图 } //接着来,看当delta_y<delta_x的时候,就会有x轴 if(y>distance) //方向的水平线,那么什么时候才让y++呢? { //比较简单的就是让x增加delta_x/delta_y的时候才 y-=distance; //让y++,当然这是个不精确的想法,不过这个算法 top+=incy; //确是以这个为基础的。只不过是换了种方式而已,用 } //的是加减法,不是除法。对照这个图,看看算法, } //明白了吗?-------------------------------- EndDraw(surf); //害人的soft,我为了看懂这个算法,翻了好多的书 } //哦:)一句注释都没有,怎么说也要给个算法的名字 } //嘛,真是的。不是哪,开玩笑的。 //不过为了放这个大面积的注释,我可花了不少的功夫 //画矩形 void Rectangle(LPDIRECTDRAWSURFACE surf, int x1, int y1, int x2, int y2, WORD color) { Line(surf, x1, y1, x2, y1, color); Line(surf, x1, y1, x1, y2, color); Line(surf, x2, y1, x2, y2, color); Line(surf, x1, y2, x2, y2, color); } //功能:画实心矩形 //参数:目标表面,x1,y1,x2,y2,颜色 void Bar(LPDIRECTDRAWSURFACE surf, int x1, int y1, int x2, int y2, WORD color) { DDBLTFX ddbltfx; RECT dest; ddbltfx.dwSize = sizeof( ddbltfx ); ddbltfx.dwFillColor = color; //用指定的颜色填充 dest.left = x1; dest.top = y1; dest.right = x2; dest.bottom = y2; if ( FAILED( surf->Blt( &dest, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx ) ) ) { return; } } //-------------------------------------------------------- //初始化失败的处理函数 BOOL initFail(char *str) { FreeDDraw(); MessageBox( hWnd, str, "Init Fail", MB_OK ); DestroyWindow( hWnd ); return FALSE; } //--------------------------------------------------------------// ////////////////////////////////////////////////////////////////// //--------------------------------------------------------------// //功能:获取一个表面的大小 //参数:目标表面,返回宽,返回高 //返回:表面跨距 int GetSurfaceSize(LPDIRECTDRAWSURFACE surf,int &x,int &y) { DDSURFACEDESC ddsd; HRESULT ddrval; ddsd.dwSize=sizeof(ddsd); ddrval=surf->GetSurfaceDesc(&ddsd); if( ddrval == DD_OK ) { x=ddsd.dwWidth; y=ddsd.dwHeight; return ddsd.lPitch>>1; //不说了 } return false; } //**************************** //获取一个表面的宽度 int GetSurfaceWidth(LPDIRECTDRAWSURFACE surf) { DDSURFACEDESC ddsd; HRESULT ddrval; ddsd.dwSize=sizeof(ddsd); ddrval=surf->GetSurfaceDesc(&ddsd); if( ddrval == DD_OK ) { return ddsd.dwWidth; } return false; } //**************************** //获取一个表面的高度 int GetSurfaceHeight(LPDIRECTDRAWSURFACE surf) { DDSURFACEDESC ddsd; HRESULT ddrval; ddsd.dwSize=sizeof(ddsd); ddrval=surf->GetSurfaceDesc(&ddsd); if( ddrval == DD_OK ) { return ddsd.dwHeight; } return false; } //************************************ //开页面缓冲区,然后直接在缓冲区中操作 bool BeginDraw(LPDIRECTDRAWSURFACE lpSur) { ddsd.dwSize = sizeof(ddsd); while( 1 ) { ddrval = lpSur->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL ); //锁定 if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { ddrval = restoreAll(); if( ddrval != DD_OK ) return( false ); } } GraphBuffer = (WORD *)ddsd.lpSurface; //内存指针 GraphWidth = ddsd.dwWidth; //宽度 GraphHeight = ddsd.dwHeight; //高度 GraphPitch = ddsd.lPitch >> 1; //lPitch以Byte为单位计数的, //GraphPitch以WORD为单位。所以GraphPitch = lPitch / 2; return( true ); } //****************** //关闭缓冲区 bool EndDraw(LPDIRECTDRAWSURFACE lpSur) { ddrval = lpSur->Unlock( NULL ); //解锁 if( ddrval != DD_OK ) return( false ); return true; } //--------------------------------------------------------------// ////////////////////////////////////////////////////////////////// //--------------------------------------------------------------// //功能:以单色填充页面 //参数:目标表面,颜色 void FillSurface(LPDIRECTDRAWSURFACE surf, DWORD color) { WORD color16=RGB16(color); //转化成16色 if( BeginDraw(surf) ) { for( int i=0; i<GraphHeight; i++) for(int j=0; j<GraphWidth; j++) GraphBuffer[i*GraphPitch+j] = color16; //直接填充 EndDraw(surf); } } //以单色填充页面 void FillSurface(LPDIRECTDRAWSURFACE surf, WORD color) { if( BeginDraw(surf) ) { for( int i=0; i<GraphHeight; i++) for(int j=0; j<GraphWidth; j++) GraphBuffer[i*GraphPitch+j] = color; //直接填充 EndDraw(surf); } } //--------------------------------------------------------------// ////////////////////////////////////////////////////////////////// //--------------------------------------------------------------// //功能:特效淡入 //参数:风格,延时(缺省),颜色(缺省) void FadeIn(int Style, int time, WORD Color) { switch( Style ) { case 0: //无效果 break; case 1: //百叶窗 ScreenIn(); break; case 2: //淡入淡出 ColorIn(time, Color); break; } } //功能:特效淡出 //参数:风格,延时(缺省),目标表面(缺省) void FadeOut(int Style, int time, LPDIRECTDRAWSURFACE lpSurf) { switch( Style ) { case 0: //无效果 break; case 1: //百叶窗 ScreenOut(lpSurf); break; case 2: //淡入淡出 ColorOut(lpSurf, time); break; } } //--------------------------------------------------------------// ////////////////////////////////////////////////////////////////// //--------------------------------------------------------------// //淡入(time=每一帧的时间) void ColorIn(int time, WORD Color) { unsigned int alpha=2, oldtick, newtick; WORD *lpSurf, *lpTemp, BlackColor=Color; //建立临时页面 LPDIRECTDRAWSURFACE Temp; CreateBitmap(Temp, ScreenWidth, ScreenHeight); //保存到临时页面 if( WindowMode==0 ) //全屏 Blt(Temp, 0, 0, lpDDSPrimary, RectScreen, false); else Blt(Temp, 0, 0, lpDDSPrimary, RectWindow, false); if( BeginDraw(lpDDSBack) ) { lpSurf=GraphBuffer; EndDraw(lpDDSBack); } if( BeginDraw(Temp) ) { lpTemp=GraphBuffer; EndDraw(Temp); } oldtick=timeGetTime(); //起始时间 for(int i=0; i<16; i++) { //把主表面的点和传近来的点进行alpha混合到lpDDSBack for(int j=0; j<ScreenWidth*ScreenHeight; j++) { lpSurf[j]=Alpha_Pixel(BlackColor, lpTemp[j], alpha); } //延时 newtick=timeGetTime(); while( newtick-oldtick < (unsigned int)(time * i) ) { newtick=timeGetTime(); } //更新屏幕 _UpdateScreen(); //自动跳桢 i=(newtick-oldtick)/time; //alpha增加 alpha=i*2+2; if( i >= 15 ) //结束 { alpha=31; for(int j=0; j<ScreenWidth*ScreenHeight; j++) { lpSurf[j]=Alpha_Pixel(BlackColor, lpTemp[j], alpha); } _UpdateScreen(); break; } } //释放 _RELEASE( Temp ); } //淡出(time=每一帧的时间) void ColorOut(LPDIRECTDRAWSURFACE dest, int time) { unsigned int alpha=2, oldtick, newtick; WORD *lpSour, *lpDest, *lpBack; if( WindowMode != 0 ) //窗口 { Blt(lpDDSSour, 0,0, lpDDSPrimary, RectWindow, false); } else { Blt(lpDDSSour, 0,0, lpDDSPrimary, RectScreen, false); } if( BeginDraw(lpDDSSour) ) { lpSour=GraphBuffer; EndDraw(lpDDSSour); } if( BeginDraw(dest) ) { lpDest=GraphBuffer; EndDraw(dest); } if( BeginDraw(lpDDSTemp) ) { lpBack=GraphBuffer; EndDraw(lpDDSTemp); } oldtick=timeGetTime(); for(int i=0; i<16; i++) { for(int j=0; j<ScreenWidth*ScreenHeight; j++) { //看看上面的函数对比一下 //这个是从屏幕逐渐变化到dest页面 lpBack[j]=Alpha_Pixel(lpDest[j], lpSour[j], alpha); } //延时 newtick=timeGetTime(); while( newtick-oldtick < (unsigned int)(time*i) ) { newtick=timeGetTime(); } //更新屏幕 _UpdateScreen(lpDDSTemp); //自动跳桢 i=(newtick-oldtick)/time; alpha=i*2+2; if( i >= 15 ) //结束 { alpha=31; for(int j=0; j<ScreenWidth*ScreenHeight; j++) { lpBack[j]=Alpha_Pixel(lpDest[j], lpSour[j], alpha); } _UpdateScreen(lpDDSTemp); break; } } } //--------------------------------------------------------------// ////////////////////////////////////////////////////////////////// //--------------------------------------------------------------// //残像淡入(suf:目标页面,step:残像的多少,time:延时 20左右) void ScreenIn(int Step,int Time) { long T1=0, T2=0; int tmp=ScreenHeight/Step; WORD *Dest; T1=T2=timeGetTime(); //取页面指针 if( BeginDraw(lpDDSBack) ) { Dest=(WORD *)GraphBuffer; EndDraw(lpDDSBack); } for( int j=0; j<tmp; j++) { //延时 while( T1-T2<Time ) { T1=timeGetTime(); } T2=T1; for(int i=0; i<Step; i++) memset(&Dest[ScreenWidth*i*tmp+ScreenWidth*j], 0, ScreenWidth*2); _UpdateScreen(); //更新屏幕 } } //残像淡出(开始页面,目标页面,残像数,延时) void ScreenOut(LPDIRECTDRAWSURFACE dest,int Step,int Time) { long T1, T2; WORD *Dest,*Sour; T1=T2=timeGetTime(); //临时页面 LPDIRECTDRAWSURFACE lpDDSTemp; CreateBitmap(lpDDSTemp, ScreenWidth, ScreenHeight); if( WindowMode != 0 ) //窗口 { Blt(lpDDSTemp, 0,0, dest, RectScreen, false); Blt(lpDDSBack, 0,0, lpDDSPrimary, RectWindow, false); } else { Blt(lpDDSTemp, 0,0, dest, RectScreen, false); Blt(lpDDSBack, 0,0, lpDDSPrimary, RectScreen, false); } //取目标页面指针 if( BeginDraw(lpDDSBack) ) { Sour=(WORD *)GraphBuffer; EndDraw(lpDDSBack); } //取目标页面指针 if( BeginDraw(lpDDSTemp) ) { Dest=(WORD *)GraphBuffer; EndDraw(lpDDSTemp); } for( int j=0; j<ScreenHeight/Step; j++) { //延时 while( T1-T2<Time ) { T1=timeGetTime(); } T2=T1; for(int i=0; i<Step; i++) { int sult=ScreenWidth*i*(ScreenHeight/Step)+ScreenWidth*j; memcpy( &Sour[sult], &Dest[sult], ScreenWidth*2); } _UpdateScreen(); //更新屏幕 } //释放 _RELEASE( lpDDSTemp ); } //--------------------------------------------------------------// ////////////////////////////////////////////////////////////////// //--------------------------------------------------------------// //把一个表面顺时针旋转90度(本函数仅限于正方型矩阵) void RolSurface(LPDIRECTDRAWSURFACE SS,int w) { WORD *Surf,*Temp; int Width; LPDIRECTDRAWSURFACE DS; //取页面指针 if( BeginDraw(SS) ) { Surf=(WORD *)GraphBuffer; Width=GraphPitch; EndDraw(SS); } CreateBitmap(DS, w, w, NULL, DDSCAPS_SYSTEMMEMORY); //取页面指针 if( BeginDraw(DS) ) { Temp=(WORD *)GraphBuffer; EndDraw(DS); } _asm{ mov edi, Temp //指针保存到esi和edi中 mov esi, Surf mov ebx, 0 //两个循环变量i,j _loop1: mov ecx, 0 _loop2: mov eax, Width //eax放的是要翻转的表面的跨度 mul ebx //i*Width+j add eax, ecx shl eax, 1 //乘2 push eax //压栈:(i*Width+j)*2 mov eax, w //正方行的边长 dec eax //减一 sub eax, ecx //减j mul Width //乘上跨度 add eax, ebx //加上i shl eax, 1 //eax=((w-1-j)*Width+i)*2 mov dx, [esi+eax] //dx放的是当前点的位置 pop eax //恢复eax的值,eax = (i*Width+j)*2 mov [edi+eax], dx //放到新表面的相应点 inc ecx //j++ cmp ecx, w //j<w吗? jnz _loop2 //还没有就还是在第二层循环 inc ebx //否则,i++ cmp ebx, w //i<w吗? jnz _loop1 //还没有就继续循环 } memcpy(Surf, Temp, (Width*w)*2); //把temp复制到surf上 //free(Temp); } //下面三个inline函数得到R,G,B的值 inline unsigned char GetRed(WORD color) { if( Is555 ) return (color>>7) & 0xff; else return (color>>8) & 0xff; } inline unsigned char GetGreen(WORD color) { if( Is555 ) return (color>>2) & 0xff; else return (color>>3) & 0xff; } inline unsigned char GetBlue(WORD color) { return (color & 0x1f) << 3; } // 功能:将一个16位的DirectDraw表面,存为一张24位BMP位图 // 输入:表面指针,输出的文件名 // 输出:是否成功 bool SaveToBitmapFile(LPDIRECTDRAWSURFACE lpSurface, char* filename) { WORD* lpBuffer; // 表面指针 int nPitch; // 表面跨距 int nWidth, nHeight; // 表面宽高 // 打开文件s FILE* fp; if( (fp=fopen(filename, "wb")) != NULL ) { // 锁定表面 DDSURFACEDESC ddsd; ddsd.dwSize = sizeof(ddsd); HRESULT ddrval = lpSurface->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL ); if( ddrval == DD_OK ) { lpBuffer = (WORD *)ddsd.lpSurface; nWidth = ddsd.dwWidth; nHeight = ddsd.dwHeight; //lPitch以Byte为单位计数的,GraphPitch以WORD为单位。所以GraphPitch = lPitch / 2; nPitch = ddsd.lPitch >> 1; } // 保存文件头 BITMAPFILEHEADER FileHeader; FileHeader.bfType = 'BM'; FileHeader.bfSize = nWidth * nHeight * 3 + 0x36; FileHeader.bfReserved1 = 0; FileHeader.bfReserved2 = 0; FileHeader.bfOffBits = 0x36; fwrite(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp); // 保存文件信息 BITMAPINFOHEADER Header; Header.biSize = sizeof(BITMAPINFOHEADER); // 结构的大小 Header.biWidth = nWidth; // 宽 Header.biHeight = nHeight; // 高 Header.biPlanes = 1; // 固定 Header.biBitCount = 24; // 颜色数 Header.biCompression = BI_RGB; // 是否压缩 Header.biSizeImage = nWidth * nHeight * 3; // 图片的大小 Header.biXPelsPerMeter = 0; Header.biYPelsPerMeter = 0; Header.biClrUsed = 0; Header.biClrImportant = 0; fwrite(&Header, Header.biSize, 1, fp); // 写入具体内容(从下向上存放) fseek(fp, 0x36, SEEK_SET); WORD word; lpBuffer += nWidth * (nHeight - 1); for(int i=0; i<nHeight; i++) { for(int j=0; j<nWidth; j++) { word = *lpBuffer; fputc( GetBlue( word ), fp); // 蓝 fputc( GetGreen( word ), fp); // 绿 fputc( GetRed( word ), fp); // 红 lpBuffer++; } lpBuffer -= nPitch*2; // 指针转到上一行的开始 } fclose(fp); // 解锁表面 ddrval = lpSurface->Unlock( NULL ); return true; } return false; }