⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gp_draw.cpp

📁 圣剑二完整的游戏代码。附作者写的三篇文章。游戏的开发过程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//********************************************
//	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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -