资源相关,先来张外部调用接口的图
文档里有更具体的用法
游戏基本都是引擎+资源组成的,为了管理,资源一般都会打包,防止丢失容易管理
bool CALL HGE_Impl::Resource_AttachPack(const char *filename, const char *password)
{
char *szName;
CResourceList *resItem=res;
unzFile zip;
szName=Resource_MakePath(filename);
strupr(szName);//把字符串里的内容转换成大写
while(resItem)
{
if(!strcmp(szName,resItem->filename)) return false;//遍历资源列表,如果已经载入了就退出
resItem=resItem->next;
}
zip=unzOpen(szName);
if(!zip) return false;
unzClose(zip);
resItem=new CResourceList;
strcpy(resItem->filename, szName);
if(password) strcpy(resItem->password, password);
else resItem->password[0]=0;
resItem->next=res;
res=resItem;
return true;
}
附加一个包到资源列表,并不是把资源载入内存了,只是把包放在资源列表里
里面会有一个检测操作,检测这个包里是有文件的,unzOpen后返回指向第一个资源的句柄
void CALL HGE_Impl::Resource_RemovePack(const char *filename)
{
char *szName;
CResourceList *resItem=res, *resPrev=0;
szName=Resource_MakePath(filename);
strupr(szName);
while(resItem)
{
if(!strcmp(szName,resItem->filename))
{
if(resPrev) resPrev->next=resItem->next;
else res=resItem->next;
delete resItem;
break;
}
resPrev=resItem;
resItem=resItem->next;
}
}
去掉附加的包~,遍历列表删除节点就行
void CALL HGE_Impl::Resource_RemoveAllPacks()
{
CResourceList *resItem=res, *resNextItem;
while(resItem)
{
resNextItem=resItem->next;
delete resItem;
resItem=resNextItem;
}
res=0;
}
去掉所有附加的包,直接清空了资源列表
void* CALL HGE_Impl::Resource_Load(const char *filename, DWORD *size)
{
static char *res_err="Can't load resource: %s";
CResourceList *resItem=res;
char szName[_MAX_PATH];
char szZipName[_MAX_PATH];
unzFile zip;
unz_file_info file_info;
int done, i;
void *ptr;
HANDLE hF;
if(filename[0]=='\\' || filename[0]=='/' || filename[1]==':') goto _fromfile; // skip absolute paths
// Load from pack
strcpy(szName,filename);
strupr(szName);
for(i=0; szName[i]; i++) { if(szName[i]=='/') szName[i]='\\'; }// '/'和'\'转化,本身在windows里没有区别,都可以表示路径
while(resItem)
{
zip=unzOpen(resItem->filename);//返回一个句柄
done=unzGoToFirstFile(zip);//把句柄定位到包里的第一个文件
while(done==UNZ_OK)
{
unzGetCurrentFileInfo(zip, &file_info, szZipName, sizeof(szZipName), NULL, 0, NULL, 0);//获取文件信息和路径
strupr(szZipName);
for(i=0; szZipName[i]; i++) { if(szZipName[i]=='/') szZipName[i]='\\'; }//在转一下 \和/
if(!strcmp(szName,szZipName))//验证是不是要载入的文件
{
if(unzOpenCurrentFilePassword(zip, resItem->password[0] ? resItem->password : 0) != UNZ_OK)
{//解压密码不对贴出错误信息然后退出
unzClose(zip);
sprintf(szName, res_err, filename);
_PostError(szName);
return 0;
}
ptr = malloc(file_info.uncompressed_size);//分配内存,资源未压缩的大小
if(!ptr)
{//分配失败。。
unzCloseCurrentFile(zip);
unzClose(zip);
sprintf(szName, res_err, filename);
_PostError(szName);
return 0;
}
if(unzReadCurrentFile(zip, ptr, file_info.uncompressed_size) < 0)//读出文件,成功后返回0
{
unzCloseCurrentFile(zip);
unzClose(zip);
free(ptr);
sprintf(szName, res_err, filename);
_PostError(szName);
return 0;
}
unzCloseCurrentFile(zip);
unzClose(zip);
if(size) *size=file_info.uncompressed_size;
return ptr;
}
done=unzGoToNextFile(zip);//不是的话句柄后移继续找
}
unzClose(zip);
resItem=resItem->next;
}
// Load from file 直接读一个文件
_fromfile:
//过程和上面差不多,只不过用windows的接口直接读取了,获取的也是文件句柄
hF = CreateFile(Resource_MakePath(filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
if(hF == INVALID_HANDLE_VALUE)
{
sprintf(szName, res_err, filename);
_PostError(szName);
return 0;
}
file_info.uncompressed_size = GetFileSize(hF, NULL);
ptr = malloc(file_info.uncompressed_size);
if(!ptr)
{
CloseHandle(hF);
sprintf(szName, res_err, filename);
_PostError(szName);
return 0;
}
if(ReadFile(hF, ptr, file_info.uncompressed_size, &file_info.uncompressed_size, NULL ) == 0)
{
CloseHandle(hF);
free(ptr);
sprintf(szName, res_err, filename);
_PostError(szName);
return 0;
}
CloseHandle(hF);
if(size) *size=file_info.uncompressed_size;
return ptr;
}
把资源载入内存,两种载入方式,一种是从包里载入,会有类似解压然后提取资源的操作
另一种是直接载入资源,从文件载入(不在包内的)
成功后返回资源指针,并且通过参数传出大小(size)信息,指针是void的,需要大小信息给它正确寻址
void CALL HGE_Impl::Resource_Free(void *res)
{
if(res) free(res);
}
释放资源
char* CALL HGE_Impl::Resource_MakePath(const char *filename)
{
int i;
//生成一个带路径的文件名
if(!filename)
strcpy(szTmpFilename, szAppPath);
else if(filename[0]=='\\' || filename[0]=='/' || filename[1]==':')
strcpy(szTmpFilename, filename);
else
{
strcpy(szTmpFilename, szAppPath);
if(filename) strcat(szTmpFilename, filename);
}
for(i=0; szTmpFilename[i]; i++) { if(szTmpFilename[i]=='/') szTmpFilename[i]='\\'; }
return szTmpFilename;
}
生成完整的路径
char* CALL HGE_Impl::Resource_EnumFiles(const char *wildcard)
{
if(wildcard)
{
if(hSearch) { FindClose(hSearch); hSearch=0; }
hSearch=FindFirstFile(Resource_MakePath(wildcard), &SearchData);//重新创建搜索句柄,在文件夹下搜索指定的文件,SearchData保存搜索信息
//vc里还有一个FindFirstFileEx函数,使用附加属性搜索
if(hSearch==INVALID_HANDLE_VALUE) { hSearch=0; return 0; }//无效返回值
//如果搜到的是文件夹,就继续往下搜(递归调用空参数的函数),如果是文件则返回文件名
if(!(SearchData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) return SearchData.cFileName;
else return Resource_EnumFiles();
}
else
{
if(!hSearch) return 0;
for(;;)
{ //继续在上次生成的句柄位置往下搜下一个文件,如果不是文件夹则返回文件名
if(!FindNextFile(hSearch, &SearchData)) { FindClose(hSearch); hSearch=0; return 0; }
if(!(SearchData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) return SearchData.cFileName;
}
}
}
char* CALL HGE_Impl::Resource_EnumFolders(const char *wildcard)
{
if(wildcard)
{
if(hSearch) { FindClose(hSearch); hSearch=0; }
hSearch=FindFirstFile(Resource_MakePath(wildcard), &SearchData);
if(hSearch==INVALID_HANDLE_VALUE) { hSearch=0; return 0; }
//搜的是文件夹,这个是文件操作里处理文件夹的统一操作,判断属性是文件夹,且文件名不是'.'和'..'
//这个很奇怪啊,三个点的也建不了文件夹。。。不明白为什么都这样写
if((SearchData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
strcmp(SearchData.cFileName,".") && strcmp(SearchData.cFileName,".."))
return SearchData.cFileName;
else return Resource_EnumFolders();
}
else
{
if(!hSearch) return 0;
for(;;)
{
if(!FindNextFile(hSearch, &SearchData)) { FindClose(hSearch); hSearch=0; return 0; }
if((SearchData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
strcmp(SearchData.cFileName,".") && strcmp(SearchData.cFileName,".."))
return SearchData.cFileName;
}
}
}
这两个一起,一个是找到指定路径下的文件,一个是找文件夹,具体的注释里有写
HGE资源操作主要用zlib的库,从包里载入文件。