📄 gp_draw.cpp
字号:
//********************************************
// 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 + -