📄 nfs.c
字号:
//设置辅助显示信息
pMe->inf[0]='/';pMe->inf[1]='N';pMe->inf[2]='F';pMe->inf[3]='S';pMe->inf[4]='-';pMe->inf[5]='m';pMe->inf[6]='/';
pMe->fps[4]=' ';pMe->fps[5]='f';pMe->fps[6]='p';pMe->fps[7]='s';pMe->fps[8]='\0';
pMe->sysclock[0]='C';pMe->sysclock[1]='l';pMe->sysclock[2]='o';pMe->sysclock[8]='\0';
pMe->frames=-1;//当前秒完成的帧数
pMe->clocksec=-1;//系统时钟
//旋转初始化
pMe->angle=0;
pMe->sin=1;
pMe->cos=1;
}
//=====================================================
//NFS_LoadResources
//=====================================================
#define CHECK_ERROR(e) if((e) != SUCCESS) { nErr = (e); goto Error; }//出错处理
#define CHECK_NULL(e) if((e) == NULL) { nErr = EFAILED; goto Error; }//非空处理
//加载并预处理图片资源
static int NFS_LoadResources(Data *pMe)
{
IBitmap *pbmScreen = NULL,*pbmDib = NULL,*pbmDdb = NULL;
AEEBitmapInfo bi;
int nErr;
uint16 cx,cy,cy2,y,yy;
NativeColor pColor;
//Creat Sprite
CHECK_ERROR(ISHELL_CreateInstance(pMe->a.m_pIShell, AEECLSID_SPRITE, (void**)&pMe->pISprite));//创建sprite实例
//设置pbmScreen
CHECK_NULL(pbmScreen = IDISPLAY_GetDestination(pMe->a.m_pIDisplay));
//设置pbmDib
CHECK_NULL(pbmDib = ISHELL_LoadBitmap(pMe->a.m_pIShell, "res.bmp"));//加载res.bmp 设备无关
CHECK_ERROR(IBITMAP_GetInfo(pbmDib, &bi, sizeof(bi)));//获取图片信息
cx=(uint16)bi.cx;
cy=(uint16)bi.cy;
cy2=cy+cy;
pMe->units=cy/cx;
//由于无法实现矩形到任意四边形贴图,而且图片32X32比较小,所以使用两片三角形贴图模拟完成,凑活用吧
//图片切割示例
/*Image
_______
| / |
|a /b |
|_/___|
*/
//a为图片左上角 b为图片右下角
CHECK_ERROR(IBITMAP_CreateCompatibleBitmap(pbmScreen, &pbmDdb, cx, cy2));//建立兼容位图pbmDdb 设备相关
CHECK_ERROR(IBITMAP_BltIn(pbmDdb, 0, 0, cx, cy, pbmDib, 0, 0, AEE_RO_COPY));//拷贝处理成a的图片
CHECK_ERROR(IBITMAP_BltIn(pbmDdb, 0, cy, cx, cy, pbmDib, 0, 0, AEE_RO_COPY));//拷贝处理成b的图片
IBITMAP_Release(pbmDib);
pbmDib=NULL;
IBITMAP_GetPixel(pbmDdb,0,0,&pColor);//获取图片透明色
//剪切成a
for(yy=0;yy<cy;yy+=cx)
for(y=1;y<cx;y++)//处理右下角为透明
CHECK_ERROR(IBITMAP_DrawHScanline(pbmDdb,y+yy, cx-y+2, cx, pColor, AEE_RO_COPY));
//剪切成b
for(yy=cy;yy<cy2;yy+=cx)
for(y=0;y<cx-1;y++)//处理左上角为透明
CHECK_ERROR(IBITMAP_DrawHScanline(pbmDdb,y+yy, 0, cx-y-2, pColor, AEE_RO_COPY));
//设置sprite 引擎
CHECK_ERROR(IBITMAP_SetTransparencyColor(pbmDdb, pColor));//设置透明色
CHECK_ERROR(ISPRITE_SetSpriteBuffer(pMe->pISprite, SPRITE_SIZE_32X32, pbmDdb));
ISPRITE_SetDestination(pMe->pISprite, pbmScreen);
ISPRITE_SetTransformTable(pMe->pISprite, pMe->pTransform);
//释放位图
IBITMAP_Release(pbmDdb);
IBITMAP_Release(pbmScreen);
return SUCCESS;
Error:
if (pbmScreen) IBITMAP_Release(pbmScreen);
if (pbmDib) IBITMAP_Release(pbmDib);
if (pbmDdb) IBITMAP_Release(pbmDdb);
NFS_UnloadResources(pMe);
return nErr;
}
//=====================================================
//NFS_UnloadResources
//=====================================================
static void NFS_UnloadResources(Data *pMe)
{
ISHELL_CancelTimer(pMe->a.m_pIShell, 0, pMe);
if (pMe->pISprite != NULL)
{
ISPRITE_Release(pMe->pISprite);
pMe->pISprite = NULL;
}
}
//=====================================================
//NFS_Display
//=====================================================
//绘图算法均在此函数完成。
//特别说明:由于本人完全不具备3D知识(丢人啊)而且时间有限,很多算法有待改善,性能还能挖掘
static void NFS_Display(Data *pMe)
{
short scrPos[8];//屏幕射影坐标 每片贴图4个顶点(2D)
short i,sin,cos,bsn,x,y,z;
//计算三角运算值
sin=Sin(pMe);
cos=Cos(pMe);
for(i=0;i<UNITS;i++)//运算所有平面当前远近位置 放入缓冲数组 (共PLANE个)
{
//x,z水平平面旋转 旋转中心(x,z)(0,157)
//x'=x*cos+(y-157)*sin
//y'=x*sin-(y-157)*cos+157
//先求BC两点空间坐标。如果在视野范围则求A点空间坐标,并求贴图中心距离以备进行深度测试
//B点的xz坐标
bsn=D3dPos[i][5]-157;
pMe->bufPos[i][3]=(D3dPos[i][3]*cos-bsn*sin)/256 - pMe->userPos[0];
pMe->bufPos[i][5]=(D3dPos[i][3]*sin+bsn*cos)/256+157 - pMe->userPos[2];
if(pMe->bufPos[i][5]>2000)//向前超出视野则不绘
{ pMe->flag[i]=1; continue;}
//C点的xz坐标
bsn=D3dPos[i][8]-157;
pMe->bufPos[i][6]=(D3dPos[i][6]*cos-bsn*sin)/256 - pMe->userPos[0];
pMe->bufPos[i][8]=(D3dPos[i][6]*sin+bsn*cos)/256+157 - pMe->userPos[2];
if(pMe->bufPos[i][5]+pMe->bufPos[i][8]<-23)//向后超出视野则不绘
{ pMe->flag[i]=1; continue;}
pMe->flag[i]=0;//此片贴图在视野内,为待画
//A点的xz坐标
bsn=D3dPos[i][2]-157;
pMe->bufPos[i][0]=(D3dPos[i][0]*cos-bsn*sin)/256 - pMe->userPos[0];
pMe->bufPos[i][2]=(D3dPos[i][0]*sin+bsn*cos)/256+157 - pMe->userPos[2];
//三点的y坐标不需旋转
pMe->bufPos[i][1]=D3dPos[i][1]-pMe->userPos[1];
pMe->bufPos[i][4]=D3dPos[i][4]-pMe->userPos[1];
pMe->bufPos[i][7]=D3dPos[i][7]-pMe->userPos[1];
//此片贴图中心点(X,Y,Z)坐标
x=pMe->bufPos[i][3]+pMe->bufPos[i][6];
y=pMe->bufPos[i][4]+pMe->bufPos[i][7];
z=pMe->bufPos[i][5]+pMe->bufPos[i][8];
//中心点到USER距离平方
pMe->distance[i]=(x*x+y*y+z*z)>>8;//(移位处理可能是想防止数据过大溢出,汗ing)
}
//贴图由远及近把待画的贴图排序 存放在pMe->order[i]里
//由于本人完全不具备3D知识(丢人啊),也许这就是传说中的"深度测试"吧
x=0;
y=0;
while(1)
{
for(i=0;(pMe->flag[i])&&(i<UNITS);) i++;//找到第一个不为0的
if(i==UNITS) break;
y=i;
for(i++;i<UNITS;i++)
{
if(pMe->flag[i]) continue;
if(pMe->distance[i]>pMe->distance[y]) y=i;
}
pMe->order[x++]=y; pMe->flag[y]=1;
}
//蓝色清屏
IDISPLAY_DrawRect(pMe->a.m_pIDisplay,0,0,4291348480/*蓝色*/,IDF_RECT_FILL);
//由远及近依次绘制待画平面
for(i=0;i<x;i++)
{
y=pMe->order[i];
z=pMe->bufPos[y][4]+pMe->bufPos[y][7]-pMe->bufPos[y][1];
bsn=pMe->bufPos[y][5]+pMe->bufPos[y][8]-pMe->bufPos[y][2];
//*******************四点在屏幕射影坐标*********************
if(pMe->bufPos[y][2]==0) continue;
if(pMe->bufPos[y][5]==0) continue;
if(pMe->bufPos[y][8]==0) continue;
if(z==0) continue;
scrPos[0]=pMe->hW*pMe->bufPos[y][0]/pMe->bufPos[y][2];
scrPos[1]=-pMe->hW*pMe->bufPos[y][1]/pMe->bufPos[y][2];
scrPos[2]=pMe->hW*pMe->bufPos[y][3]/pMe->bufPos[y][5];
scrPos[3]=-pMe->hW*pMe->bufPos[y][4]/pMe->bufPos[y][5];
scrPos[4]=pMe->hW*pMe->bufPos[y][6]/pMe->bufPos[y][8];
scrPos[5]=-pMe->hW*pMe->bufPos[y][7]/pMe->bufPos[y][8];
scrPos[6]=pMe->hW*(pMe->bufPos[y][3]+pMe->bufPos[y][6]-pMe->bufPos[y][0])/bsn;
scrPos[7]=-pMe->hW*z/bsn;
//**********************Sprite贴图**************************
//运算参数可能只适合32X32 sprite (记不清了)
//由于无法实现矩形到任意四边形贴图,图片32X32比较小,所以使用两片三角形贴图模拟完成,凑活用吧
//由贴图四点射影屏幕坐标完成贴图
//ISPRITE贴图算法在纸上完成,已经化简。这里的算法是化简后的。
//a片左上角
pMe->pCmds[0].x = (scrPos[2]+scrPos[4])-16+pMe->hW;
pMe->pCmds[0].y = (scrPos[3]+scrPos[5])-16+pMe->hH;
pMe->pCmds[0].unSpriteIndex = D3dPos[y][9];//材质
pMe->pTransform[0].A = (scrPos[2]-scrPos[0]) << 4;
pMe->pTransform[0].B = (scrPos[4]-scrPos[0]) << 4;
pMe->pTransform[0].C = (scrPos[3]-scrPos[1]) << 4;
pMe->pTransform[0].D = (scrPos[5]-scrPos[1]) << 4;
//b片右下角
pMe->pCmds[1].x = pMe->pCmds[0].x;
pMe->pCmds[1].y = pMe->pCmds[0].y;
pMe->pCmds[1].unSpriteIndex = pMe->pCmds[0].unSpriteIndex+pMe->units;//材质
pMe->pTransform[1].A = (scrPos[6]-scrPos[4])<<4;
pMe->pTransform[1].B = (scrPos[6]-scrPos[2])<<4;
pMe->pTransform[1].C = (scrPos[7]-scrPos[5])<<4;
pMe->pTransform[1].D = (scrPos[7]-scrPos[3])<<4;
//draw
ISPRITE_DrawSprites(pMe->pISprite, pMe->pCmds);
}
//***********************help info*******************************
IDISPLAY_DrawText(pMe->a.m_pIDisplay,AEE_FONT_BOLD,pMe->inf,7,0,0,0,IDF_TEXT_TRANSPARENT|IDF_ALIGN_CENTER);//标题
IDISPLAY_DrawText(pMe->a.m_pIDisplay,AEE_FONT_BOLD,pMe->fps,-1,0,132,0,IDF_TEXT_TRANSPARENT|IDF_ALIGN_RIGHT);//fps
IDISPLAY_DrawText(pMe->a.m_pIDisplay,AEE_FONT_BOLD,pMe->sysclock,-1,0,118,0,IDF_TEXT_TRANSPARENT|IDF_ALIGN_RIGHT);//系统colock
IDISPLAY_Update(pMe->a.m_pIDisplay);
pMe->frames++;//fps当前秒帧数加1
//绘制完成后立即callback显示
ISHELL_SetTimer(pMe->a.m_pIShell, 0, NFS_Display, (void*)pMe);
}
//go round and round
static void NFS_Circu(Data *pMe)
{
ISHELL_SetTimer(pMe->a.m_pIShell, 100, NFS_Circu, (void*)pMe);//100ms旋转一个单位(5度)
//逆时针旋转sin算法
pMe->angle+=pMe->sin*pMe->cos;
if(pMe->angle>17) pMe->cos=-pMe->cos;
if(pMe->angle<1) pMe->sin=-pMe->sin;
}
//KeyEvent
static void NFS_KeyEvent(Data *pMe)
{
ISHELL_SetTimer(pMe->a.m_pIShell, 20, NFS_KeyEvent, (void*)pMe);//20ms按键连击
if(pMe->Key & KEY_LEFT) pMe->userPos[0]-=3;
if(pMe->Key & KEY_RIGHT) pMe->userPos[0]+=3;
if((pMe->Key & KEY_UP)&&(pMe->userPos[2]<-40)) pMe->userPos[2]+=3;
if(pMe->Key & KEY_DOWN) pMe->userPos[2]-=3;
if(pMe->Key & KEY_HIGH) pMe->userPos[1]+=3;
if(pMe->Key & KEY_LOW) pMe->userPos[1]-=3;
}
//fps
static void NFS_Help(Data *pMe)
{
ISHELL_SetTimer(pMe->a.m_pIShell, 1000, NFS_Help, (void*)pMe);//1000ms系统时钟
FLOATTOWSTR(pMe->frames, pMe->buf, 32);
pMe->frames=0;
pMe->fps[0]=pMe->buf[8];
pMe->fps[1]=pMe->buf[9];
pMe->fps[2]=pMe->buf[10];
pMe->fps[3]=pMe->buf[11];
pMe->clocksec++;
if(pMe->clocksec>59) {pMe->clocksec=0;pMe->clockmin++;}
FLOATTOWSTR(pMe->clockmin, pMe->buf, 32);
pMe->sysclock[3]=pMe->buf[10];
pMe->sysclock[4]=pMe->buf[11];
pMe->sysclock[5]=':';
FLOATTOWSTR(pMe->clocksec, pMe->buf, 32);
pMe->sysclock[6]=pMe->buf[10];
pMe->sysclock[7]=pMe->buf[11];
}
#ifdef USE_TRANSFORMS
//0-90度 5度递增 共18个
//正弦*256 (结果0-256)
static const uint8 Table[] = {0,22,44,66,88,108,128,147,165,181,196,210,222,232,241,247,252,255,255};
static short Sin(Data *pMe)
{
if(pMe->sin>0) return Table[pMe->angle];
else return -1*Table[pMe->angle];
}
static short Cos(Data *pMe)
{
if(pMe->cos>0) return Table[18-pMe->angle];
else return -1*Table[18-pMe->angle];
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -