转至:http://blog.sina.com.cn/s/blog_7948916001015cyh.html
1.获取表面的像素格式
函数:HRESULT IDIRECTDRAWSURFACE7::GpixelFormat(LPDDPIXELFORMAT lpDDPixelFormat)
DDPIXELFORMAT 比较重要的域有:
DWORD dwSize:调用函数之前必须设置为DDPIXELFORMAT结构的大小
DWORD dwFlags:可以是一下值
DDPF_ALPHA 像素格式描述一个只有alpha的表面
DDPF_PALETTEINDEXED8 画面是8位色彩索引,普遍
DDPF_RGB 像素格式中的RGB数据有效
DDPF_ZBUFFER 像素格式描述一个Z缓冲画面
DWORD dwRGBBitGount RGB中红绿蓝的位数
下面就是测试的代码:
ey:
DDPIXELFORMAT ddpixel;
memset(&ddpixel,0,sizeof(ddpixel));
ddpixel.dwSize = sizeof(ddpixel);
lpdds_primary->GetPixelFormat(&ddpixel);
if(ddpixel.dwFlags & DDPF_RGB)
{
switch(ddpixel.dwRGBBitCount)
{
case 15:
{} break;
case 16:
{} break;
case 24:
{} break;
case 32:
{} break;
deault:
break;
}
}
else if(ddpixel.dwFlags & DDPF_PALETTEINDEXED8)
{
}
else
{
}
2.绘图
1.获取了像素格式,在上面我们已经讨论过怎么做了
2.锁定表面,使用Lock ()函数
3.建立16bitRGB字,使用自写的宏 _RGB16BIT565
4.写像素,这意味着采用一个USHORT指针定位主缓冲,将写入VRAM缓冲
5.解锁主表面,调用Unlock();
ey:
void plot_pixel16(int x,int y int r,int g,int b,LPDIRECTDRAWSURFACE7 lpdds)
{
DDSURFACEDESC2 ddsd;
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize(sizeof(ddsd));
USHORT pixel = _RGB16BIT565(r,g,b);
lpdds->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL);
USHORT *video_buffer = ddsd.lpSurface;
videl_buffer[x+y*(ddsd.lpitch>>1)] = pixel;
lpdds->Unlock(NULL);
}
但是这个函数实在太慢,因为每次函数都需要加锁解锁,这要花费很多时间,更好的办法是当所有操作之前
加锁一个,当所有的操作都完成之后解锁一次,下面是对函数的一点点改进
ey:
inline void plot_pixel16_Fast16(int x,int y int r,int g,int b,USHORT*video_buffer,int lpitch)
{
USHORT pixel = _RGB16BIT565(r,g,b);
videl_buffer[x+y*(lpitch>>1)] = pixel;
}
更好的,你可以在lpitch移位之前就处理
ey:
int lpitch16 = lpitch>>1;
inline void plot_pixel16_Fast16(int x,int y int r,int g,int b,USHORT*video_buffer,int lpitch16)
{
USHORT pixel = _RGB16BIT565(r,g,b);
videl_buffer[x+y*lpitch16] = pixel;
}
用16bit模式向屏幕写点是不用调色板的,下面就是一个例子
ey:
int main()
{
DDSURFACEDESC2 ddsd;
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if(FAILED(lpddsprimary->Lock(NULL,&ddsd,DDLOCK_WIAT | DDLOCK_SURFACEMEMORYPTR,NULL))
{
return ;
}
int lpitch16 = (int)ddsd.lpitch>>1;
USHORT *video_buffer = (USHORT*)ddsd.lpSuface;
for(int i=0;i<1000;i++)
{
int r = rand()%6;
int g = rand()%6;
int b = rand()%6;
int y = rand()H0;
int x = rand()d0;
plot_pixel16_Fast16(x,y,r,g,b,video_buffer,lpitch16);
}
if(FAILED(lpddsprimary->Unlock()))
{
return
}
}
同理,我们也可以有32位色彩的处理方式
#define _RGB32BIT(a,r,g,b) (b+ (g<<8) + (r<<16) + (a<<24))
UINT lpitch32 = (UINT)ddsd.lpitch>>2;
inline void plot_pixel32(int x,int y,int a int r,int g,int b,UINT*video_buffer,int lpitch32)
{
UINT pixel = _RGB32BIT(a,r,g,b);
videl_buffer[x+y*lpitch32] = pixel;
}
3.双缓冲
在离屏缓冲中绘制图像,然后将其拷贝到显示表面的处理过程称作双缓冲技术。
首先创建640x480x8模式下的双缓冲代码
UCHAR *double_buffer = (UCHAR*)malloc(640*480);
或者
UCHAR *double_buffer = new UCHAR[640*480];
然后把double_buffer里的代码拷贝到primary_buffer,但是这里需要一点小小的措施,因为mempitch或者主表
面的步长刚好是640的时候才行,否则需要一行一行地拷贝
ey:
if(mempitch == 640)
{
memcpy((void*)primary_buffer,(void *)double_buffer,640*480);
}
else
{
for(int y=0;y<480;y++)
{
memcpy((void*)primary_buffer,(void *)double_buffer,640);
primary_buffer += mempitch;
double_buffer += 640;
}
}
4.表面动态
离屏表面--后备缓冲:指的是一些用在动画链中的表面,它们具有和主表面一样的尺寸和色深,当创建主表面
的时候也创建它们,它们都是主表面的页面切换中的环节。
从技术上讲,可以在切换链中创建任意个后备缓冲,但是VRAM会用完,标准是两个,不过3个性能更佳!
创建后备缓冲,必须创建DirectDraw的复杂表面(complex-surface)
1.将DDSD_BACKBUFFERCOUNT加到ddsd的dwFlags,后备缓冲的数目
2.将DDSCAPS_COMPLEX | DDSCAPS_FLIP加到ddsd.ddsCaps_dwCaps上
3.调用 HRESULT::IDIRECTDRAWSURFACE::GetAttachedSurface(LPDDSCAPS2 lpDDSCaps,LPDIRECTDRAWSURFACE7
FAR*lplpDDAttachedSurface )
lpDDSCaps是DDSCAPS2结构中包含所需表面特性的标志
ey:
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;
LPDIRECTDRAWSURFACE7 lpddsback = NULL;
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount = 1;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL))){ return ;}
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
if(FAILED(lpddsprimary->GetAttachSurface(&ddsd.ddsCaps,&lpddsback))){ return ;}
接下来你就可以想操作主表面一个操作后备缓冲,当然得先Lock,操作完后还得Unlock.
5.页面切换
如今有了主显示表面和后备缓冲的复杂表面,就可以进行页面切换了。
1.清楚后备缓冲
2.将场景渲染到后备缓冲
3.用后备缓冲表面切换掉主表面
4.锁定在某个fps(例如30)
5.重复第一步
可以使用HRESULT IDIRECTDRAWSUFACE7::Flip(IDIRECTDRAWSUFACE7 lpDDSurfaceTargetoverride,
DWORD dwFlags);
在交换链中用下一个关联的表面切换主表面
第一个参数用来实现切换到另外一个表面,而不是同一个表面的关联表面(后备缓冲)。
dwFlags一般设置为DDFLIP_WAIT:强迫硬件不在出现问题时立即返回,而是等待到直到页面切换为止。
ey:
while(FAILED(lpddsprimary->Flip(NULL,DDLIP_WAIT)));
下面就是一个例子,使用了页面切换的技术
ey:
int Game_Main()
{
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if(FAILED(lpddsback->Lock(NULL,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR)))
{
return;
}
UCHAR *back_buffer = (UCHAR*)ddsd.lpSurface;
if(ddsd.lpitch == 640) //后备反冲清零
{
memset(back_buffer,0,640*480);
}
else
{
UCHAR* dest_ptr = back_buffer;
for(int index = 0;index<480;index++)
{
memset(dest_ptr,0,640);
dest_ptr += ddsd.lpitch;
}
}
for(int i = 0;i<5000;i++) //绘点
{
int x = rand()d0;
int y = rand()H0;
int col = rand()%6;
back_buffer[x+y*ddsd.lpitch] = col;
}
if(FAILED(lpddsback->Unlock(NULL))
{
return ;
}
while(FAILED(lpddprimary->Flip(NULL,DDFLIP_WAIT))); //切换交换链
return 1;
}
6 使用blitter
ey:8x8x256的位图,将这个图像拷贝到视频缓冲或者离屏表面的(x,y)处,分辨率640x480
UCHAR *bitmap[8*8];
UCHAR *video_buffer;
for(int index_y =0;index_y<8;index_y++)
{
for(int index_x =0;index_x<8;index_x++)
{
video[x+index_x+(y+index_y)*640] = bitmap[x+y*8];
}
}
但是这个函数实在是太慢了,下面的或许更好一点
ey:
void bit8x8(int x,int y,UCHAR*video_buffer,UCHAR *bitmap)
{
video_buffer += x+(y<<9)+(y<<7); //这里目标指针已经移到了(x,y)
for(int index_y=0;index_y<8;index_y++)
{
for(int index_x=0;index_x<8;index_x++)
{
if(pixel = bitmap[index_x])
{
video_buffer[index_x] = pixel;
}
}
video_buffer+=640;
bitmap+=8;
}
}
但是这个函数只能工作在640*480的分辨率下,且只能对8位位图起作用
7. 使用blitter进行内存填充
DirectDraw两个用于显存移动的函数IDIRECTDRAWSURFACE7::Blt()和BltFast()
HRESULT Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE7 lpDDSrcSurface,
LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx);
lpDestRect:定义了左上角和右下角的RECT结构,如果参数是NULL,将指向整个目标表面
lpDDSrcSurface:源LPDIRECTDRAWSURFACE7 接口地址
lpSrcRect:定义了左上角和右下角的RECT结构,如果参数是NULL,将指向整个源表面
dwFlags:决定了DDBLTFX的有效成员,控制标志,可以是以下值
DDBLT_COLORFILL:使用DDBLTFX结构中dwFillColor成员作为填充目标表面上的RGB颜色
DDBLT_ROTATIONANGLE:使用dwRotationAngle成员作为表面旋转角
DDBLT_KEYSRC:使用和源表面相关的色彩关键字
DDBLT_WAIT:等待知道bit能被执行,即使忙也不返回错误信息
lpDDBltFx:包含blitter所需要的信息结构
HRESULT BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE7 lpDDSrcSurface,
LPRECT lpSrcRect,DWORD dwTrans);
dwTrans:是blitter的操作类型
DDBLTFAST_SRCCOLORKEY 指定一次使用源色彩键的透明blit
DDBLTFAST_NOCOLORKEY 不使用透明的标准blit
DDBLTFAST_WAIT 直到blit能被执行
1.将要填充的色彩索引或者RGB编码的颜色放进DDBLTFX的dwFillColor字段
2.将RECT结构设置为目标表面上的填充区域
3.从接口指针调用bit
ey:
DDBLTFX ddbltfx;
RECT rcDest;
memset(&ddbltfx,0,sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = color;
rcDest.left = x1;
rcDest.top = y1;
rcDest.right = x2;
rcDest.bottom = y2;
lpddsprimary->Blt(&rcDest,NULL,NULL,DDBLTFX_WAIT | DDBLTFX_COLORFILL,&ddbltfx);
8.基础剪裁知识
剪裁:不画那些落在视口或者窗口之外的像素或图像元素
DirectDraw提供IDirectDrawClipper接口下的DirectDraw裁剪器,需要做的就是创建一个IDirectDrawClipper
传给他有效的剪裁区域,然后和表面关联,这样Blt()的时候,他将按剪裁器裁剪
ey:裁剪640*480*8
void Blit_Clipper(int x,int y,//位图坐标
int width,int height,//位图大小
UCHAR *bitmap,//位图数据
UCHAR *video_buffer,//表面内存
int mempitch//表面步长
)
{
if((x>=640 || y>=480) || (x+wight<=0) || (y+height<=0))
{
return ;
}
int x1 = x;
int x2 = x+weight-1;
int y1 = y;
int y2 = y+height-1;
if(x1<0)
x1 = 0;
if(y1<0)
y1 = 0;
if(x2>=640)
x2 = 640;
if(y2>=480)
y2 = 480;
int x_off = x1-x;
int y_off = y1-y;
int dx = x2 - x1;
int dy = y2 - y1;
video_buffer += (x1+y1*640); //表面开始坐标
bitmap += (x_off + y_off*width);//位图开始坐标
for(int i=0;i<=dy;i++)
{
for(int j=0;j<=dx;j++)
{
if(pixel = bitmap[j])
video_buffer[j] = pixel;
}
bitmap += width;
video_buffer += mempitch;
}
}
9 使用IDirectDrawClipper进行Direct裁剪
设置DirctDraw 裁剪器对象
1.创建DirectDraw裁剪器对象
2.创建裁剪序列
3.用IDIRECTDRAWCLIPPER::SetClipList()将裁剪序列发送给裁剪器
4.用IDIRECTDRAWCLIPPER::SetClipper()将裁剪器同窗口和表面相关联
创建IDirectDrawClipper接口的函数
HRESULT IDIRECTDRAW7::CreateClipper(DWORD dwFlags, //总是为0
LPDIRECTDRAWCLIPPER FAR*lplpDDClipper,//返回的接口地址
IUnKnown FAR* pUnkOuter //高级 ,设置为0
)
ey:
LPDIRECTDRAWCLIPPER lpddclipper = NULL;
if(lpdd->CreateClipper(NULL,lpddclipper,NULL)) return ;
创建裁剪序列,是RECT结构的列表,DirectDraw的blitter系统的这些区域内进行blit,要创建它,需要填充
RGNDATA的数据结构
typedef struct _RGNDATA
{
RGNDATAHEADER rhd;
char Buffer[1];
} RGNDATA; 这个一个可变大小的数据结构,Buffer[]的长度是任意的,实际长度放在rdh中
typedef struct _RGNDATAHEADER
{
DWORD dwSize; //sizeof(RGNDATAHEADER )
DWORD iType; //RDH_RECTANGLES
DWORD nCount; //RECT的数量
DWORD nRgnSize;//sizeof(RECT)*nCount
RECT rcBound; //在所有的RECT周围创建一个边框并存储在rcBound中
}RGNDATAHEADER ;
一旦RGNDATA结构好了,就可以通过IDIRECTDRAWCLIPPER::SetClipList()发送给创建好的裁剪器
HRESULT SetClipList(LPRGNDATA lpClipList,DWORD dwFlags)
最后关联到表面
HRESULT IDIRECTDRAWSURFACE7::setClipper(LPDIRECTDRAWCLIPPER lpDDClipper);
ey:
LPDIRECTDRAWCLIPPER DDraw_Clipper(LPDIRECTDRAWSURFACE7 lpdds,int rect_nums,LPRECT clip_list)
{
LPDIRECTDRAWCLIPPER lpddclipper;
LPRGNDATA rgn_data;
if(FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)) return ;
rgn_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+sizeof(RECT)*rect_nums);
memcpy(rgn_data->Buffer,clip_list,sizeof(RECT)*rect_nums);
rgn_data->rdh.dwSize = sizeof(RGNDATAHEADER);
rgn_data->rdh.iType = RDH_RECTANGLES;
rgn_data->rdh.nCount = rect_nums;
rgn_data->rdh.nRgnSize = rect_nums*sizeof(RECT);
rgn_data->rdh.rcBound.left = 64000;
rgn_data->rdh.rcBound.top = 64000;
rgn_data->rdh.rcBound.right = -64000;
rgn_data->rdh.rcBound.bottom = -64000;
for(int index = 0;index<rect_nums;index++)
{
if(clip_list[index].left<rgn_data->rdh.rcBound.left)
rgn_data->rdh.rcBound.left = clip_list[index].left;
if(clip_list[index].right>rgn_data->rdh.rcBound.right)
rgn_data->rdh.rcBound.right = clip_list[index].right;
if(clip_list[index].top<rgn_data->rdh.rcBound.top)
rgn_data->rdh.rcBound.top = clip_list[index].top;
if(clip_list[index].bottom>rgn_data->rdh.rcBound.bottom)
rgn_data->rdh.rcBound.bottom = clip_list[index].bottom;
}
if(FAILED(lpddclipper->SetClipList(rgn_data,0)))
{
free(rgn_data);
return ;
}
if(FAILED(lpdds->SetClipper(lpddClipper)))
{
free(rgn_data);
return ;
}
free(rgn_data);
return lpddClipper;
}
10.使用位图
位图.BMP格式:位图文件头 BITMAPFILEHEADER,存放图像的总体信息
位图信息段 BITMAPINFO:包含BITMAPINFOHEADER和调色板信息部分(有的话)
位图数据区域:数据逐行排列,有时是颠倒的,可以通过BITMAPINOFHEADER.biHeight判断
+号表示颠倒,-号表示正常
读取位图文件,我们先创建一个位图文件的额结构体
typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader;
BITMAPINFOHEADER bitmapinfoheader;
PALETTEENTRY palette[256];
UCHAR *buffer
}BITMAP_FILE,*BITMAP_FILE_PTR;
读取位图的函数:
int Load_Bitmap_File(BITMAP_FILE_PTR bitmap,char * filename)
{
int file_handle;// 文件句柄
int index; //循环变量
UCHAR *temp_buffer = NULL;
OFSTRUCT file_data; //用来保存文件信息
if((file_handle=OpenFile(filename,&file_data,OF_READ))==-1)//打开文件
{
return 0;
}
_lread(file_handle,&bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));//读取头文件
if(bitmap->bitmapfileheader.bfType!=BITMAP_ID)//检测打开的是不是一个位图文件
{
_lclose(file_handle);
return 0;
}
_lread(file_handle,&bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));//读取信息头文件
if(bitmap->bitmapinfoheader.biBitCount == 8)//加载调色板信息
{
_lread(file_handle,&bitmap->palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
for(index=0;index<MAX_COLORS_PALETTE;index++)
{
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
}
}
_lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);//检测是不是自身的文件
//读取图片文件
if(bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16 || bitmap->bitmapinfoheader.biBitCount==24)
{
if(bitmap->buffer)
{
free(bitmap->buffer);
}
if(!(bitmap->buffer = (UCHAR*)malloc(bitmap->bitmapinfoheader.biSizeImage)))
{
_lclose(file_handle);
return 0;
}
_lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
}
else
{
return 0;
}
#if 0
printf("\nfilename:%s \nsize=%d \nWidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
filename,
bitmap->BITMAPINFOHEADER.nSizeImage,
bitmap->BITMAPINFOHEADER.biWidth,
bitmap->BITMAPINFOHEADER.biHeight,
bitmap->BITMAPINFOHEADER.biBitCount,
bitmap->BITMAPINFOHEADER.biClrUsed,
bitmap->BITMAPINFOHEADER.biClrImportant
);
#endif
_lclose(file_handle);
Flip_Bitmap(bitmap->buffer,bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8),bitmap->bitmapinfoheader.biHeight);
return 1;
}
//处理上下颠倒的图片
int Flip_Bitmap(UCHAR *image,int bytes_per_line,int height)
{
UCHAR*buffer;
int index;
if(!(buffer=(UCHAR*)malloc(bytes_per_line*height)))
{
return 0;
}
memcpy(buffer,image,bytes_per_line*height);
for(index=0;index<height;index++)
{
memcpy(&image[((height-1)-index)*bytes_per_line],&buffer[index*bytes_per_line],bytes_per_line);
}
free(buffer);
return 1;
}
int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
{
if(bitmap->buffer)
{
free(bitmap->buffer);
bitmap->buffer = NULL;
}
return 1;
}
11.离屏表面
创建离屏表面
1.DDSURFACEDESC2.dwFlags = (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT)
2.DDSURFACEDESE2.dwWidth和DDSURFACEDESC2.ddwHeight设置为所请求的大小
3.DDSURFACEDESC2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | memory_flags,memory_flags可以是创建在
VRAM中VIDEOMEMORY,可以是系统内存中SYSTEMMEMORY;
ey:创建任何类型的表面
LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width,int height,int mem_flags)
{
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWSURFACE7 lpdds;
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = width;
ddsd.dwHeight = height;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
if(FAILED(lpdd->CreateSurface(&ddsd,&lpdds,NULL)))
{
return ;
}
DDCOLORKEY color_key;
color_key.dwColorSpaceLowValue = 0;
color_key.dwColorSpaceHeightValues = 0;
lpdds->SetColorKey(DDCKEY_SRCBLT,&color_key);
return lpdds;
}
12.色彩键
源色彩键:选择单一的色彩索引或者一定范围的RGB色彩作为源图像的透明色,然后,将源blit向目标时,不
拷贝有透明色的像素
IDIRECTDRAWSURFACE7::SetColorKey();
typedef struct _DDCOLORKEY
{
DWORD dwColorSpaceLowValue;
DWORD dwColorSpaceHeightValue;
}DDCOLORKEY,FAR *LPDDCOLORKEY;
13.色彩效果
色彩动画是指在运行中对调色板进行操作,如更改或轮转,例如:发光物质,闪烁的灯光等许多效果。
写一个函数,实现功能:
1.创建最多256盏的闪光灯,
2.每盏灯有亮灭的状态,之间有一段延时
3.通过ID能打开或者关闭任何一盏灯
4.终止一盏灯并收回资源
存储每一盏灯的数据结构:
typedef struct BLINKER_TYPE
{
int color_index;
PALETTEENTRY on_color;
PALETTEENTRY off_color;
int on_time;
int off_time;
int counter; //记录状态转变的次数
int state;
}BLINKER,*BLINKER_PTR;
下面是代码:
int Blink_Colors(int command,BLINKER_PTR new_light,int id)
{
static BLINKER light[256];
static int initialized = 0;
if(!initialized)
{
initialized = 1;
memset((void *)light,0,sizeof(light));
}
switch (command)
{
case BLINKER_ADD:
{
for(int index_light=0;index_light<256;index_light++)
{
if(light[index_light].state == 0)
{
light[index_light] = *new_light;
light[index_light].counter = 0;
light[index_light].state = -1;
lpddpal->SetEntries(0,light[index_light].color_index,1,&light[index_light].off_color);
}
}
}
break;
case BLINKER_DELETE:
if(light[id].state!=0)
{
memset((void*)&light[id],0,sizeof(BLINKER));
return id;
}
else
{
return -1;
}
break;
case BLINKER_UPDATE:
{
if(light[id].state!=0)
{
light[id].on_color = new_light->on_color;
light[id].off_color = new_light->off_color;
light[id].on_time = new_light->on_time;
light[id].off_time = new_light->off_time;
if(light[id].state == -1)
{
lpddpal->SetEntries(0,light[id].color_index,1,&light[id].off_color);
}
else
{
lpddpal->SetEntries(0,light[id].color_index,1,&light[id].on_color);
}
return id;
}
else
{
return -1;
}
}
break;
case BLINKER_RUN:
{
for(int index=0;index<256;index++)
{
if(light[index].state == -1)
{
if(++light[index].counter >= light[index].off_time)
{
light[index].counter = 0;
light[index].state = -light[index].state;
lpddpal->SetEntries(0,light[index].color_index,1,&light[index].on_color);
}
}
else if(light[index].state == 1)
{
if(++light[index].counter >= light[index].on_time)
{
light[index].counter = 0;
light[index].state = -light[index].state;
lpddpal->SetEntries(0,light[index].color_index,1,&light[index].off_color);
}
}
}
}
break;
default: break;
}
return 1;
}
//色彩效果
BLINKER temp;
PALETTEENTRY red = {235,0,0,PC_NOCOLLAPSE};
PALETTEENTRY green = {0,255,0,PC_NOCOLLAPSE};
PALETTEENTRY black = {0,0,0,PC_NOCOLLAPSE};
temp.color_index = 250;
temp.on_color = red;
temp.off_color = black;
temp.on_time = 300;
temp.off_time = 300;
int red_id = Blink_Colors(BLINKER_ADD,&temp,0);
temp.color_index = 251;
temp.on_color = green;
temp.off_color = black;
temp.on_time = 600;
temp.off_time = 600;
int green_id = Blink_Colors(BLINKER_ADD,&temp,0);
然后在Game_Main()中使用 Blink_Colors(BLINKER_RUN, NULL, 0);