存档在 ‘C/C++’ 分类

怎样在DOS平台下置取调色板

2009年11月5日

说实话,在DOS平台下置取调色板可要比在Windows平台下简单多了,而且置了之后决对正确,不会出现象DirectDraw那样置了还未必起作用的情况。

好了,言归正传,我来详细讲述一下置调色板的办法。对于读调色板就不再介绍了,因为每一个优秀的C/C++程序员都不会笨到去读取调色板。调色板是什么样的,随时都掌握在他们的程序中,要什么调色板就设置成什么样的,从来不去读调色板。

假设我们对调色板的定义如下:

uvar8 Palette[256][3];

uvar8表示8位无符号变量,表示范围是0-255。Palette变量中有256种颜色,以Palette[颜色号]来表示。每个颜色中均保存红、 绿、蓝三原色的值。Palette[0][0]就表示第0种颜色的红色值,同样Palette[0][1]就表示第0种颜色的绿色值。

在DOS平台下,设置调色板的办法是多种多样的,以下我将逐一介绍:


方法一:16位DOS平台下,调用中断进行设置

由于16位DOS平台下,主流编程工具Borland C/C++与Turbo C/C++只支持16色,所以显得很无用。所以我们只好自己调用中断进行设置了,源程序如下:void SetPalette(uvar8 pal[256][3])
{
union REGS r;
struct SREGS s;
r.h.ah=0x10;
r.h.al=0x12;
r.x.bx=0;
r.x.cx=256;
s.es=FP_SEG(pal);
r.x.dx=FP_OFF(pal);
int86x(0x10,&r,&r,&s);
}

方法二:16位DOS平台下,直接写DAC进行设置

相比之下,在16位DOS平台下,置调色板最快的手法莫过于直接写DAC了,源程序如下:void SetDac(uvar8 idx,uvar8 red,uvar8 green,uvar8 blue)
{
asm {
mov dx,3c8h
mov al,idx
out dx,al

mov cl,2
inc dx
mov al,red
shr al,cl
out dx,al
mov al,green
shr al,cl
out dx,al
mov al,blue
shr al,cl
out dx,al
}
}

void SetPalette(uvar8 pal[256][3])
{
for(uvar16 i=0;i<256;i++)SetDac(i,pal[i][0],pal[i][1],pal[i][2]);
}

不要问我那倒数第二行为什么要用uvar16来定义i,而不用uvar8,您自己试一下就知道了。


方法三:32位DOS平台下,使用Watcom C/C++编程时直接使用其图形函数进行设置

Watcom C/C++不愧为优秀的32位DOS平台开发工具,它的图形函数直接用来编游戏都没问题,所以速度上也绝对慢不了。源程序如下:void SetPalette(uvar8 pal[256][3])
{
uvar32 pal256[256];
uvar16 i;
for(i=0;i<256;i++)pal256[i]=pal[i][2]/4*0x10000+pal[i][1]/4*0x100+pal[i][0]/4;
_remapallpalette(&pal256);
}
当然,这个程序还未做过优化,留着您自己优化吧!这里我只讲怎么设置调色板。

方法四:32位DOS平台下,调用中断进行设置

不过是方法一的16位转32位吧了,没什么大的变化,源程序如下:void SetPalette(uvar8 pal[256][3])
{
union REGS r;
struct SREGS s;
r.h.ah=0x10;
r.h.al=0x12;
r.w.bx=0;
r.w.cx=256;
s.es=FP_SEG(pal);
r.x.dx=FP_OFF(pal);
int386x(0x10,&r,&r,&s);
}

当然,32位DOS环境也可以直接写DAC以便取得最快的速度,但是32位DOS下的汇编程序是很难写的(其实不难,只不过写出来很长),所以我就偷懒不写了,反正以上四种方法也够用了。

XMS的使用

2009年11月5日

本来我是不准备写这篇文章的,但冷不妨有位同仁问起,也只好做个回答,顺便借此更新一下网页。

XMS,扩充内存管理规范。在16bit DOS系统下,为了使用640k以外的内存,XMS成了一种最好的手法。

在这里,我不想多讲XMS的实现,只对本文所提供的XMS类做一下使用讲解。

例子可以说明一切:

#include”XMS.H”
void main()
{
FILE *fp;
int i;
char *str;
XMS xms1(1024);                //为xms1指针分配1024k的内存
fp=fopen(“C:\\WIN\\WIN386.SWP”,”rb”);
str=(char *)malloc(1024);
for(i=0;i<1024;i++)
{
fread(str,1,1024,fp);
xms1.put((void *)str,(void *)(i*1024),1024);
//将内存指针str中的1024个字节的内容写到,xms1的第i*1024个字节处
}
fclose(fp);
fp=fopen(“WIN386.SWP”,”wb”);
for(i=0;i<1024;i++)
{
xms1.get((void *)str,(void *)(i*1024),1024);
//将扩充内存xms1中,从第i*1024个字节处开始的1024个字节的内容写到str中
fwrite(str,1,1024,fp);
}
fclose(fp);
}

XMS.H

#if !defined XMS_H
#define XMS_H

class XMS {
int handle;
int move(struct EMB *emb);
public:
XMS(int size);
~XMS();
static int OK;
static int init(void);
static unsigned freesize(void);
static unsigned largestblock(void);
int realloc(int size);
int put(void *dp,void *sp,long leng);
int get(void *dp,void *sp,long leng);
};

#endif

XMS.CPP

#include <dos.h>
#include <alloc.h>

#include “xms.h”

struct EMB {
long Leng;
unsigned SourceHandle;
long SourceOfs;
unsigned DestinHandle;
long DestinOfs;
};

int XMS::OK=0;
static void far *XMSaddr;

int XMS::init(void)
{
static struct REGPACK rg;

rg.r_ax=0x4300;
intr(0x2f,&rg);
if( (rg.r_ax&0x00ff) == 0x80 )
{
rg.r_ax=0x4310;
intr(0x2f,&rg);
XMSaddr=MK_FP(rg.r_es,rg.r_bx);
OK=1;
}
else
OK=0;
return(OK);
}

unsigned XMS::freesize(void)
{
if(OK==0)
return(0);
asm {
mov ah,8
call XMSaddr
}
return _DX;
}

unsigned XMS::largestblock(void)
{
if(OK==0)
return(0);
asm {
mov ah,8
call XMSaddr
}
return _AX;
}

XMS::XMS(int size)
{
if(OK==0)
{
handle=0;
return;
}

asm {
mov ah,9
mov dx,size
call XMSaddr
}
handle=_DX;
}

XMS::~XMS()
{
if(handle==0)
return;

int hd=handle;
asm {
mov ah,0ah
mov dx,hd
call XMSaddr
}
}

int XMS::realloc(int size)
{
if(handle==0)
return(0);

int hd=handle;
asm {
mov ah,0fh
mov bx,size
mov dx,hd
call XMSaddr
}
return _AX;
}

int XMS::move(struct EMB *emb)
{
asm {
push ds
mov ah,0bh
push ds
pop es
lds si,emb
call es:XMSaddr
pop ds
}
return _AX;
}

int XMS::put(void *sp,void *dp,long leng)
{
struct EMB emb;

if(leng&1L)
leng++;
emb.Leng=leng;
emb.SourceHandle=0;
emb.SourceOfs=(long)sp;
emb.DestinHandle=handle;
emb.DestinOfs=(long)dp;
return move(&emb);
}

int XMS::get(void *dp,void *sp,long leng)
{
int v;
struct EMB emb;

if(leng&1L)
{
char *p,*d;

leng–;
if( leng>0 )
{
emb.Leng=leng;
emb.SourceHandle=handle;
emb.SourceOfs=(long)sp;
emb.DestinHandle=0;
emb.DestinOfs=(long)dp;
move(&emb);
}

p=(char *)malloc(2);
emb.Leng=2L;
emb.SourceHandle=handle;
emb.SourceOfs=(long)sp+leng;
emb.DestinHandle=0;
emb.DestinOfs=(long)p;
v=move(&emb);
d=(char*)dp;
d[leng]=p[0];
free(p);
}
else
{
emb.Leng=leng;
emb.SourceHandle=handle;
emb.SourceOfs=(long)sp;
emb.DestinHandle=0;
emb.DestinOfs=(long)dp;
v=move(&emb);
}
return(v);
}

怎样找出精灵的边缘

2009年11月5日

在很多游戏中,将鼠标移到人物上,人物的边缘上就会出现一道光边。这也就是笔者将要和大家讨论的,如何找出这一边缘。

其实要找出它也不难,在游戏所使用的图片中,都包含有透明色和不透明色两部分,那么问题就很简单了,在透明色和不透明色相接的地方就是边缘。请看下面的程序:

程序功能:画指定区域图像的边缘在指定位置
x,y   :画边缘的坐标地址
x1,y1 :指定区域左上角的坐标
x2,y2 :指定区域右下角的坐标
TColor:透明色
var16 i,j;
uvar16 Color,TColor;
for(i=y1;i<=y2;i++)
for(j=x1;j<=x2;j++)
{
Color=GetPixel(j,i);
if(Color!=TColor) //如果这个点不是透明色
{
if(j==x1||GetPixel(j-1,i)==TColor)PutPixel(j-x1+x-1,i-y1+y  );
if(j==x2||GetPixel(j+1,i)==TColor)PutPixel(j-x1+x+1,i-y1+y  );
if(i==y1||GetPixel(j,i-1)==TColor)PutPixel(j-x1+x  ,i-y1+y-1);
if(i==y2||GetPixel(j,i+1)==TColor)PutPixel(j-x1+x  ,i-y1+y+1);
}
}

高速直线绘制程序

2009年11月5日

程序:罗健军


我特别的感谢罗健军大师,罗健军是一位水平高超的程序设计师。按我的推断,他应该有着丰富、高超的编程经验,远非在下能及。我再次向他表示感谢。

下面的算法中,var16表示有符号16位数据类型;HLine(x,y,n)是画水平线函数;VLine(x,y,n)是画垂直线函数;PutPixel(x,y)是画点函数。请看程序。

void Line(var16 x1,var16 y1,var16 x2,var16 y2)
{
 var16 p,n,x,y,tn;
 if(y1==y2)
 {
  if(x1>x2)
  {
   x=x2;x2=x1;x1=x;
  }
  HLine(x1,y1,x2-x1+1);
  return;
 }
 if(x1==x2)
 {
  if(y1>y2)
  {
   y=y2;y2=y1;y1=y;
  }
  VLine(x1,y1,y2-y1+1);
  return;
 }
 if(abs(y2-y1)<=abs(x2-x1))
 {
  if((y2<y1&&x2<x1)||(y1<=y2&&x1>x2))
  {
   x=x2;y=y2;x2=x1;y2=y1;x1=x;y1=y;
  }
  if(y2>=y1&&x2>=x1)
  {
   x=x2-x1;y=y2-y1;
   p=2*y;n=2*x-2*y;tn=x;
   while(x1<=x2)
   {
    if(tn>=0)tn-=p;
     else {tn+=n;y1++;}
    PutPixel(x1++,y1);
   }
  }
  else
  {
   x=x2-x1;y=y2-y1;
   p=-2*y;n=2*x+2*y;tn=x;
   while(x1<=x2)
   {
    if(tn>=0)tn-=p;
     else {tn+=n;y1--;}
    PutPixel(x1++,y1);
   }
  }
 }
 else
 {
  x=x1;x1=y2;y2=x;y=y1;y1=x2;x2=y;
  if((y2<y1&&x2<x1)||(y1<=y2&&x1>x2))
  {
   x=x2;y=y2;x2=x1;y2=y1;x1=x;y1=y;
  }
  if(y2>=y1&&x2>=x1)
  {
   x=x2-x1;y=y2-y1;p=2*y;n=2*x-2*y;tn=x;
   while(x1<=x2)
   {
    if(tn>=0)tn-=p;
     else {tn+=n;y1++;}
    PutPixel(y1,x1++);
   }
  }
  else
  {
   x=x2-x1;y=y2-y1;p=-2*y;n=2*x+2*y;tn=x;
   while(x1<=x2)
   {
    if(tn>=0)tn-=p;
     else {tn+=n;y1--;}
    PutPixel(y1,x1++);
   }
  }
 }
}

高速正圆绘制程序

2009年11月5日

程序:罗健军


程序中var32表示有符号32位数,var16表示有符号16位数。x0,y0为圆心坐标,r为半径。PutPixel为画点函数。

曾经长年的使用这段程序,而未向罗健军大师表示感谢,真是感到惭愧!在这里,请各位代表我向他表示感谢。

double SIN45=0.707106781186548;

void Circle(var16 x0,var16 y0,uvar16 r)
{
 var32 tn;
 var16 x,y;
 var16 xmax;
 y=r;x=0;
 xmax=var16(r*SIN45);
 tn=(1-r*2);
 while(x<=xmax)
 {
  if(tn>=0)
  {
   tn+=(6+((x-y)<<2));
   y--;
  }
  else
   tn+=((x<<2)+2);
  PutPixel(x0+y,y0+x);
  PutPixel(x0+x,y0+y);
  PutPixel(x0-x,y0+y);
  PutPixel(x0-y,y0+x);
  PutPixel(x0-y,y0-x);
  PutPixel(x0-x,y0-y);
  PutPixel(x0+x,y0-y);
  PutPixel(x0+y,y0-x);
  x++;
 }
 PutPixel(x0+y,y0+x);
 PutPixel(x0+x,y0+y);
 PutPixel(x0-x,y0+y);
 PutPixel(x0-y,y0+x);
 PutPixel(x0-y,y0-x);
 PutPixel(x0-x,y0-y);
 PutPixel(x0+x,y0-y);
 PutPixel(x0+y,y0-x);
}

高速椭圆绘制程序

2009年11月5日

程序:罗健军


程序中var16为有符号16位数字型,uvar1616位无符号数字型,uvar32为无符号32位数字型,var32为有符号32位数字型。Ellipse参数中的x0,y0为圆心坐标,r1r2分别为横半径和纵半径。PutPixel为画点函数。

void Ellipse(var16 x0,var16 y0,uvar16 r1,uvar16 r2)
{
 uvar32 r,r12,r22;
 var16 x,y,xmax;
 var32 tn;
 x=0;y=r2;
 r12=r1*r1;r22=r2*r2;
 xmax=var16(r12/sqrt(r12+r22));
 tn=r12-2*r2*r12; 
 while(x<=xmax)
 {
  if(tn<0||y==0)tn+=(4*x+2)*r22;
   else
   {
    tn+=(4*x+2)*r22+(1-y)*4*r12;
    y--;
   }   
  PutPixel(x0+x,y0+y);
  PutPixel(x0-x,y0+y);
  PutPixel(x0+x,y0-y);
  PutPixel(x0-x,y0-y);
  x++;
 }
 PutPixel(x0+x,y0+y);
 PutPixel(x0-x,y0+y);
 PutPixel(x0+x,y0-y);
 PutPixel(x0-x,y0-y);
 r=r1;r1=r2;
 r2=(uvar16)r;
 x=0;y=r2;
 r12=r1*r1;r22=r2*r2;
 xmax=var16(r12/sqrt(r12+r22));
 tn=r12-2*r2*r12; 
 while(x<=xmax)
 {
  if(tn<0||y==0)tn+=(4*x+2)*r22;
   else
   {
    tn+=(4*x+2)*r22+(1-y)*4*r12;
    y--;
   }   
  PutPixel(x0+y,y0+x);
  PutPixel(x0+y,y0-x);
  PutPixel(x0-y,y0+x);
  PutPixel(x0-y,y0-x);
  x++;
 } 
 PutPixel(x0+y,y0+x);
 PutPixel(x0+y,y0-x);
 PutPixel(x0-y,y0+x);
 PutPixel(x0-y,y0-x);
}

高速扇形绘制程序

2009年11月5日

程序:罗健军

程序中var16为有符号16位数字型,uvar16为无符号16位数字型。var32为有符号32位数字型。PutPixel为画点函数。

函数Sector入口参数x0,y0为圆心坐标,r为半径。stangle为起始角度,endangle为结束角度。

double SIN45=0.707106781186548;
uvar32 SINV[91]={0,
     17452406,   34899496,   52335956,   69756473,   87155742,  104528463,
    121869343,  139173100,  156434465,  173648177,  190808995,  207911690,
    224951054,  241921895,  258819045,  275637355,  292371704,  309016994,
    325568154,  342020143,  358367949,  374606593,  390731128,  406736643,
    422618261,  438371146,  453990499,  469471562,  484809620,  500000000,
    515038074,  529919264,  544639035,  559192903,  573576436,  587785252,
    601815023,  615661475,  629320391,  642787609,  656059028,  669130606,
    681998360,  694658370,  707106781,  719339800,  731353701,  743144825,
    754709580,  766044443,  777145961,  788010753,  798635510,  809016994,
    819152044,  829037572,  838670567,  848048096,  857167300,  866025403,
    874619707,  882947592,  891006524,  898794046,  906307787,  913545457,
    920504853,  927183854,  933580426,  939692620,  945518575,  951056516,
    956304755,  961261695,  965925826,  970295726,  974370064,  978147600,
    981627183,  984807753,  987688340,  990268068,  992546151,  994521895,
    996194698,  997564050,  998629534,  999390827,  999847695,  1000000000
};
/////////////////////////////////////////////////////////////////////////////////
// 查找表式sin函数
/////////////////////////////////////////////////////////////////////////////////
double Lsin(var16 angle)
{
 double v,f;
 if(angle>360||angle<-360)angle=angle-(angle/360)*360;
 if(angle<0)angle=360+angle;
 if(angle>180)f=-1;else f=1;
 if(angle>90&&angle<=180)angle=180-angle;
  else if(angle>180&&angle<=270)angle=angle-180;
   else if(angle>270)angle=360-angle;
 v=f*SINV[angle]/10.0e8;
 return(v);
}
/////////////////////////////////////////////////////////////////////////////////
// 查找表式cos函数
/////////////////////////////////////////////////////////////////////////////////
double Lcos(var16 angle)
{
 double v,f;
 if(angle>360||angle<-360)angle=angle-(angle/360)*360;
 if(angle<0)angle=360+angle;
 if(angle<270&&angle>90)f=-1;else f=1;
 if(angle>90&&angle<=180)angle=180-angle;
 else if(angle>180&&angle<=270)angle=angle-180;
  else if(angle>270)angle=360-angle;
 angle=90-angle;
 v=f*SINV[angle]/10.0e8;
 return(v);
}
/////////////////////////////////////////////////////////////////////////////////
// 扇形绘制函数
////////////////////////////////////////////////////////////////////////////////
void Sector(var16 x0,var16 y0,uvar16 r,uvar16 stangle,uvar16 endangle)
{
 var16 i,j;
 var16 *xy;
 var16 bx,ex,bxd,exd,bxf,exf,ben;
 var32 tn,x,y;
 var32 xmax;
 y=r; x=0;
 xmax=(var32)(r*SIN45);
 tn=(1-r*2);
 xy=(var16 *)calloc(20,sizeof(var16));
 xy[ 0]=x0+r;xy[1]=y0;
 xy[ 2]=x0;  xy[3]=y0-r;
 xy[ 4]=x0;  xy[5]=y0-r;
 xy[ 6]=x0-r;xy[7]=y0;
 xy[ 8]=x0-r;xy[9]=y0;
 xy[10]=x0;  xy[11]=y0+r;
 xy[12]=x0;  xy[13]=y0+r;
 xy[14]=x0+r;xy[15]=y0;
 bx=stangle/45;
 ex=endangle/45;
 ben=ex-bx-1;
 xy[16]=(var16)(r*Lcos(stangle));
 xy[17]=(var16)(r*Lsin(stangle));
 xy[18]=(var16)(r*Lcos(endangle));
 xy[19]=(var16)(r*Lsin(endangle));
 Line(x0+xy[16],y0-xy[17],x0,y0);
 Line(x0+xy[18],y0-xy[19],x0,y0);
 if(bx==1||bx==2||bx==5||bx==6)bxd=abs(xy[16]);else bxd=abs(xy[17]);
 if(ex==1||ex==2||ex==5||ex==6)exd=abs(xy[18]);else exd=abs(xy[19]);
 if(bx==0||bx==2||bx==4||bx==6)bxf=0;          else bxf=1;
 if(ex==0||ex==2||ex==4||ex==6)exf=1;          else exf=0;
 while(x<=xmax)
 {
  if(tn>=0)
  {
   tn+=(6+((x-y)*4));
   y--;
   xy[0]--;
   xy[3]++;
   xy[5]++;
   xy[6]++;
   xy[8]++;
   xy[11]--;
   xy[13]--;
   xy[14]--;
  }
  else tn+=((x*4)+2);
  if(stangle<endangle)
  {
   j=(bx+1)*2;
   for(i=0;i<ben;i++)
   {
    PutPixel(xy[j],xy[j+1]);
    j+=2;
   }
  }
  else if(stangle>endangle)
  {
   j=(bx+1)*2;
   for(i=bx+1;i<8;i++)
   {
    PutPixel(xy[j],xy[j+1]);
    j+=2;
   }
   j=0;
   for(i=0;i<ex;i++)
   {
    PutPixel(xy[j],xy[j+1]);
    j+=2;
   }
  }
  i=bx*2;
  if( (x>bxd)^bxf )PutPixel(xy[i],xy[i+1]);i=ex*2;
  if( (x>exd)^exf )PutPixel(xy[i],xy[i+1]);x++;
  xy[ 1]--;
  xy[ 2]++;
  xy[ 4]--;
  xy[ 7]--;
  xy[ 9]++;
  xy[10]--;
  xy[12]++;
  xy[15]++;
 }
 free(xy);
}

二维世界中的旋转

2009年11月5日

首先,在解析几何中我们可以找到以下公式:

x’=x*cos(ang)-y*sin(ang)
y’=x*sin(ang)+y*cos(ang)

这个公式是以原点(0,0)为中心,将点(x,y)旋转ang度,旋转后的坐标为(x’,y’)。不过这只是以原点为中心进行旋转的,如果我们想以任意点为中心旋转呢!公式变形如下:

x’=zx+(x-zx)*cos(ang)-(y-zy)*sin(ang)
y’=zy+(x-zx)*sin(ang)+(y-zy)*cos(ang)

好,这也就是我们想要的结果了。以(zx,zy)为中心,将点(x,y)旋转ang度,旋转后的坐标为(x’,y’)

由于在标准C/C++库中,sincos所要求的参数为弧度,而并非角度,所以我们需要一个转换。

弧度=角度*圆周率/180

按以上,最后的标准C/C++程序如下:

float x,y;           //原始点坐标
float rx,ry;         //旋转中心点坐标
float nx,ny;         //旋转后的点坐标
float ang;           //旋转角度(0-360)
float as,ac;
……

as=sin(ang*M_PI/180.0);
ac=cos(ang*M_PI/180.0);

nx=rx+((x-rx)*ac-(y-ry)*as);
ny=ry+((x-rx)*as+(y-ry)*ac);


非静态类成员函数指针解决方案

2009年11月5日

众所周知,我们无法定义一个指向类的非静态成员函数。在Borland C/C++中,Bolrand公司添加了关键字__closure用来定义这种特殊的指针。在Visual C/C++中虽然也有解决方染,但是使用麻烦,且不易于使用。网络上下存在很多解决方案,但作者均未看到较为好用的解决方案。

本文即提供一种于x86-32平台下的解决方案,使用方式类似于Borland C/C++,十分方便。代码在Borland C/C++ 5.82Microsoft C/C++ 14.0 (Visual C/C++ 8.0)下测试通过。


#include<stdio.h>
#include<stddef.h>

class _Object{};

#if defined(SetEventCall)||defined(CallEvent)||defined(DefineEvent)
    #error SetEventCall,CallEvent,DefineEvent 已经定义
#endif//

#ifdef __BORLANDC__

    #define SetEventCall(event_obj,event_func)              event_obj=event_func
    #define CallEvent(event_obj)                            event_obj
    #define DefineEvent(name,result,intro)                  result (__closure *name)intro

#else

    #pragma warning(disable:4311)

    template <typename T> struct EventFunc
    {
        unsigned __int32 this_address;
        unsigned __int32 func_address;

        _Object *This;
        T Func;

        EventFunc()
        {   
            this_address=offsetof(EventFunc,This);
            this_address+=(unsigned __int32)this;

            func_address=offsetof(EventFunc,Func);
            func_address+=(unsigned __int32)this;
        }
    };

    #define SetEventCall(event_obj,event_func)      {   \
                                                        unsigned __int32 this_address=event_obj.this_address;   \
                                                        unsigned __int32 func_address=event_obj.func_address;   \
                                                        \
                                                        {   \
                                                            __asm mov eax,this_address  \
                                                            __asm mov ebx,this  \
                                                            __asm mov [eax],ebx \
\
                                                            __asm mov eax,func_address  \
                                                            __asm mov ebx,event_func    \
                                                            __asm mov [eax],ebx \
                                                        }   \
                                                    }

    #define CallEvent(event_obj)                    (event_obj.This->*(event_obj.Func))             //(*(event_obj.This).*(event_obj.Func))

    #define DefineEvent(name,result,intro)          EventFunc<result (_Object:: *)intro> name;
#endif//__BORLANDC__

class Button
{
public:

    DefineEvent(OnClick,void,(Button *,int));     //定义事件,原型为: void OnClick(Button *,int)

public:

    Button()
    {
        printf("Button this=%p\n",this);
    }

    void TestButtonClick()
    {
        CallEvent(OnClick)(this,0);               //呼叫OnClick,原型为: OnClick(this,0)
    }
};

class Test
{
    Button *button;

public:

    void OnButtonClick(Button *but,int)
    {
        printf("Test::OnButtonClick,this=%p,but=%p\n",this,but);
    };

public:

    Test()
    {
        printf("Test this=%p\n",this);

        button=new Button;

        SetEventCall(button->OnClick,OnButtonClick);              //设定button->OnClick事件的处理函数为OnButtonClick

        button->TestButtonClick();
    }
};

void main(int,char **)
{
    Test *test;

#ifdef __BORLANDC__
    printf("Compiler: Borland C/C++ or Turbo C/C++ %d.%d%d\n",(__BORLANDC__>>8),((__BORLANDC__&0xF0)>>4),(__BORLANDC__&0x0F));
#endif
#ifdef _MSC_VER
    printf("Compiler: Microsoft C/C++ %.2f (Visual C/C++ %.2f)\n",_MSC_VER/100.f,_MSC_VER/100.f-6);
#endif//

    printf("Compile Time: %s %s\n\n",__DATE__,__TIME__);

    test=new Test;

    delete test;
}

Compiler: Borland C/C++ or Turbo C/C++ 5.82
Compile Time: Dec 23 2006 17:34:48

Test this=00902D50
Button this=00902D64
Test::OnButtonClick,this=00902D50,but=00902D64

Compiler: Microsoft C/C++ 14.00 (Visual C/C++ 8.00)
Compile Time: Dec 23 2006 17:34:00

Test this=003826D0
Button this=00382700
Test::OnButtonClick,this=003826D0,but=00382700

DirectDraw7初始化

2009年11月5日

//—————————————————————————
#include <windows.h>
#include <ddraw.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#pragma hdrstop

//—————————————————————————

#pragma argsused

#define GAMENAME    “DirectDraw 7 窗口示例”
#define ScreenWidth 640
#define ScreenHigh  480
#define ScreenColor 32
#define WINDOWSTYLE WS_VISIBLE|WS_THICKFRAME|WS_SYSMENU|WS_MINIMIZEBOX

IDirectDraw         *_DirectDraw=NULL;
IDirectDraw7        *DirectDraw;
IDirectDrawSurface7 *PrimarySurface;
DDSURFACEDESC2      ddsd;

bool InitDirectDraw(HWND hwnd)
{
if(DirectDrawCreate(NULL,&_DirectDraw,NULL)!=DD_OK)return(false);
if(_DirectDraw->QueryInterface(IID_IDirectDraw7,(void **)&DirectDraw)!=DD_OK)
{
_DirectDraw->Release();
return(false);
}

if(DirectDraw->SetCooperativeLevel(hwnd,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN)!=DD_OK)
{
DirectDraw->Release();
_DirectDraw->Release();
return(false);
}

if(DirectDraw->SetDisplayMode(ScreenWidth,ScreenHigh,ScreenColor,0,0)!=DD_OK)
{
DirectDraw->Release();
_DirectDraw->Release();
return(false);
}

memset(&ddsd,0,sizeof(DDSURFACEDESC2));

ddsd.dwSize             =sizeof(DDSURFACEDESC2);
ddsd.dwFlags            =DDSD_CAPS;
ddsd.ddsCaps.dwCaps     =DDSCAPS_PRIMARYSURFACE;

if(DirectDraw->CreateSurface(&ddsd,&PrimarySurface,NULL)!=DD_OK)
{
DirectDraw->Release();
_DirectDraw->Release();
return(false);
}

return(true);
}

void CloseDirectDraw()
{
PrimarySurface->Release();
DirectDraw->Release();
_DirectDraw->Release();
}

HWND InitWindow(HINSTANCE hinstance)
{
HWND hwnd;
WNDCLASSEX wc;

wc.cbSize=sizeof(WNDCLASSEX);
wc.style=0;
wc.lpfnWndProc=(WNDPROC)DefWindowProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hinstance;
wc.hIcon=LoadIcon(NULL,NULL);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND;
wc.lpszMenuName=0;
wc.lpszClassName=”绝情创作群”;
wc.hIconSm=LoadIcon(hinstance,IDI_APPLICATION);

RegisterClassEx(&wc);
hwnd=CreateWindowEx(NULL,”绝情创作群”,GAMENAME,WINDOWSTYLE,0,0,ScreenWidth,ScreenHigh,0,0,hinstance,0);

ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);

return(hwnd);
}

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;

hwnd=InitWindow(hInstance);
InitDirectDraw(hwnd);

//………….

CloseDirectDraw();
return(0);
}
//—————————————————————————