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

📄 nfs.c

📁 一个用纯c写的模拟3d程序,利用了些扩大缩小来模拟浮点数
💻 C
📖 第 1 页 / 共 2 页
字号:
   //设置辅助显示信息
   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 + -