关于gmc结构

博客探讨了GMC结构中的索引查找方法,重点介绍了资源数据,如动画和图片,与其他类型数据的区别。地图和NPC数据常以32*32的倍数分割,源码包含了丰富的RPG素材。战斗背景尺寸为320*200,灵感来自仙剑98,地图资源多取自轩辕剑之舞。示例代码提供了VC6平台下读取和释放资源的方法。
摘要由CSDN通过智能技术生成
例如伏魔记
(数据是可以用c直接读取的)
0x0 :lib
0x3 伏魔记 00 0
0x0E 全局色彩字节数: 2或4,建议选择4
0x0F 非零有压缩,0无压缩,建议选择有压缩1
0x10开始 三字节索引(与lib一致索引)(unsigned char resType ,unsigned char type ,unsigned char index) ...;

0x2000 开始 四字节地址(相对文件头偏移) (unsigned int mDataOffset)...

typedef struct GMCheadstru{char ckHeadstr[3];//校验GMC
char gamename[9];//游戏名
unsigned short sizeofIndexArea;//索引区域大小
unsigned char sizeofPixcel;// 像素字节数
unsigned char isComressed;//非零为有deflate压缩,0为无压缩
} GMChead; //16字节信息头 
GMChead myGMChead;

typedef struct GMCIndexStru{unsigned char resType ;unsigned char objType;unsigned char index;}GMCIndex;
GMCIndex AllGMCIndex[2726]; //与lib一致的索引,0x10开始, (0x2000-16)的索引空间最多2725个资源
unsigned int AllGMCAddr[2725];//地址是真实地址,0x2000开始 

初始化读取如下:
   FILE* file;
    /* 装载源文件数据到缓冲区 */
    if((file = fopen("dat.gmc", "rb")) == NULL)
    {
        printf("Can\'t open %s!\n", "dat.gmc");
        return -1;
    }
// 测试文件头
 fread(&myGMChead,16,1,file);
  char testStr[4];
memset (testStr,0,4);
memcpy(testStr,myGMChead.ckHeadstr,3);
if(stricmp(testStr,"GMC")){
        printf("不是有效GMC文件\n", argv[1]);
        return -1;
}
//判断像素字节大小
 if(myGMChead.sizeofPixcel!=4){
 printf("不支持的像素字节数 status:%d","");
return -1;
 }
//读取索引和地址
 fseek(file,16,SEEK_SET);
 fread(&AllGMCIndex,0x2000-16,1,file);
fseek(file,0X2000,SEEK_SET);
 fread(&AllGMCAddr,2725<<2,1,file);


索引查找方法

unsigned int getGMCAddr(int rType, int otype, int oindex){
	int i=0;
	int j=0;
	while(i<2725&&(j=AllGMCIndex[i].resType)<15){
		if(AllGMCIndex[i].resType==rType&&AllGMCIndex[i].objType==otype
			&&AllGMCIndex[i].index==oindex) return AllGMCAddr[i];
			i++;
	}
	return 0;
}

读取案例:

int resaddress=getGMCAddr(5,2,1);
printf("mySrs resaddress=%d\n",(int)resaddress);
fseek(file,resaddress,SEEK_SET);
Srs *mySrs=readSrs(file);
 resaddress=getGMCAddr(7,1,1);
printf("mPic resaddress=%d\n",(int)resaddress);
fseek(file,resaddress,SEEK_SET);
   Pic*mPic=readpic(file);
#include "zlib\zlib.h"
#pragma comment(lib,"zlib\\Release\\zlib.lib")
使用了zlib读取需导入zlib库

资源数据只有动画 和图片数据不一样,其他例如脚本、NPC、地图等数据与lib一致。

地图图片分割为32*32,npc大多数也是32的倍数,最常见RPG素材是32分割,源码中已经收集齐几乎所有符合这种RPG彩色的NPC素材和地图素材。
战斗背景320*200(来源于仙剑98图片资源),也就是主窗口至少320*200(因为仙剑98也是这么大窗口)

地图资源多数是来源于轩辕剑之枫之舞地图。

pic数据 mDataOffset +0

头6字节,依次是

mWidth,mHeight,mNumber,mTransparent
typedef struct Picheadstru{unsigned short  mWidth ;
unsigned short mHeight;
 unsigned char mNumber;
 unsigned char mTransparent;} Pichead;

typedef struct pixcelstru{unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char alpha;} Pixcel;

typedef struct picstr{Pichead myPHead;
Pixcel * pixs;
} Pic;

mDataOffset +6 是像素数据,可以压缩

例如读取案例

Pic* readpic(FILE* file){ //测试 当sizeofPixcel==4时图片
	    uLong flen;
    unsigned char* fbuf = NULL;
    uLong ulen;
    unsigned char* ubuf = NULL;
	Pic* myPic;
    if((myPic= (Pic*)malloc(sizeof(Pic) )) == NULL)
    {
 printf("No enough memory! myPic\n");
        return 0;
	}

 fread(&myPic->myPHead,6,1,file); //读取图片头
printf("pic w=%d,h=%d,n=%d,t=%d\n",(int)myPic->myPHead.mWidth,(int)myPic->myPHead.mHeight,
	  (int) myPic->myPHead.mNumber,(int)myPic->myPHead.mTransparent);

 if(!myGMChead.isComressed){//未压缩

	 int picpixsize=myPic->myPHead.mWidth*myPic->myPHead.mHeight
	* myPic->myPHead.mNumber<<2;

 if((myPic->pixs= (Pixcel*)malloc(picpixsize) )== NULL)
    {
        printf("No enough memory! 未压缩 myPic.pixs\n");
free(myPic);
        return 0;
    }
fread(myPic->pixs,picpixsize,1,file); //直接读取


 }else	{//已压缩
  fread(&ulen,4, 1, file); /* 获取解压后数据大小*/
    fread(&flen,4, 1, file);    /* 获取已压缩数据流大小 */
printf("l=%d\n",flen);
    if((fbuf = (unsigned char*)malloc(sizeof(unsigned char) * flen)) == NULL)
    {
		fseek(file,ftell(file)-14,SEEK_SET);
        printf("No enough memory! 已压缩fbuf\n");
free(myPic);
        return 0;
    }
    fread(fbuf, 1, flen, file);//读取已压缩数据
  //  memcpy(&ulen,fbuf+ flen-4, 4);    /* 获取缓冲区大小 */
//printf("解压像素字节数=%d\n",ulen);
    /* 解压缩数据 */
	int failed_number=0;
    while(failed_number < 4)
    {
        if((ubuf = (unsigned char*)malloc(sizeof(unsigned char) * ulen)) == NULL)
        {
            printf("No dest enough memory 已解压像素内存 ubuf!\n");
free(myPic);
            return 0;
        }

        if(uncompress(ubuf, &ulen, fbuf, flen) != Z_OK)
        {
            printf("Uncompress %s failed,try allocate more space!\n", "dat.gmc");
            free(ubuf);
            ubuf = NULL;
            /*失败后分配两倍空间*/
            ulen <<=1; 
            failed_number++;
        }
        else
        {
            break;
        }
    }
	if(failed_number==4){
		printf("解压数据失败!数据已损坏\n");
fseek(file,ftell(file)-flen-14,SEEK_SET);
free(fbuf);
free(myPic);
   return 0;
	}

free(fbuf);//释放已压缩数据的缓存
 myPic->pixs=(Pixcel *)ubuf;/* 保存解压缩后的数据到目标文件 */
		}
//测试像素(0,1)红值
//printf( "(0,1)像素 r=%d\n",(myPic->pixs+(1*myPic->myPHead.mWidth+0))->red);
return myPic;
}

用完后释放

void freePic(Pic* desPic){
    free( desPic->pixs); //测试结束释放像素内存
 free( desPic);//测试结束释放Pic内存
}
srs数据mDataOffset +0是数据头,依次
mType,mIndex ,mFrameNum,mImageNum ,mStartFrame ,mEndFrame
mDataOffset +6是帧数据,大小7*mFrameNum
typedef struct srsHeadstru {
unsigned char mType;
unsigned char mIndex ;
unsigned char mFrameNum;
unsigned char mImageNum ;
unsigned char mStartFrame ;
unsigned char mEndFrame; } SrsHead;

typedef struct frameStru{unsigned short x;
 unsigned short y;
unsigned char Show;
unsigned char  nShow;
unsigned char  PICid;} SrsFrame;
typedef struct SrsStru{SrsHead srshead;SrsFrame * mframes;Pic** pics;}  Srs;

mDataOffset +6+7*mFrameNum是图片数据
读取srs方法
Srs * readSrs(FILE* file) {
Srs* mySrs;
    if((mySrs= (Srs*)malloc(sizeof(Srs) )) == NULL)
    {
printf("No enough memory! mySrs\n");
return 0;
}
 fread(&mySrs->srshead,6,1,file);
    if((mySrs->mframes= (SrsFrame*)malloc(7*mySrs->srshead.mFrameNum )) == NULL)
    {free(mySrs);
printf("No enough memory! mySrs->mframes\n");
return 0;
}	
 int i;//必须循环读取,因为编译器结构体大小判断不准,每帧读取7字节
for (i=0;i<mySrs->srshead.mFrameNum;i++)fread(mySrs->mframes,7/*必须数字7*/ ,1,file);
    if((mySrs->pics= (Pic**)malloc( mySrs->srshead.mImageNum<<2)) == NULL)
    {
free(mySrs->mframes);
free(mySrs);
printf("No enough memory! mySrs->pics\n");
return 0;
}
 Pic * Frampic;
 for (i=0;i<mySrs->srshead.mImageNum;i++){
if(( Frampic=readpic(file))==NULL){
 int j; for (j=0;j<i;j++)freePic(mySrs->pics[j]);
free(mySrs->pics);
free(mySrs->mframes);
free(mySrs);
printf("fail to load Srs Pic ! no.%d\n,ftell=%d",i+1,(int)ftell(file));
return 0;
}
mySrs->pics[i]=Frampic;
 }
return mySrs;
}


用完后释放

void freeSrs(Srs * desSrs){
 int i;
 for (i=0;i<desSrs->srshead.mImageNum;i++){
freePic(desSrs->pics[i]);
 }
 free(desSrs->mframes);
 free(desSrs);
}

例子源码vc6(亲测,已编译通过)

链接:https://pan.baidu.com/s/1hM_rrrcYRy0fndG5PWSNgA 密码:j0g9

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值