我使用Nvidia nv_dds实用程序加载DDS图像文件以在OpenGL程序中使用。它适用于Windows但在Linux上失败(Ubuntu 12.10)。最初我认为nv_dds存在问题,但后来发现fread()在Linux上读取错误偏移的头字节(GCC 4.7)
这是读取DDS文件标记然后读取DDS标题的块:
// open file
FILE *fp = fopen(filename.c_str(),"rb");
if (fp == NULL) {
return false;
}
// read in file marker, make sure its a DDS file
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0) {
fclose(fp);
return false;
}
// read in DDS header
DDS_HEADER ddsh;
fread(&ddsh, 1,sizeof(DDS_HEADER) , fp);
当我查看DDS_HEADER实例的内容时,我可以看到分配给错误属性的几个实际值,其余的都是垃圾。
然后,如果我注释掉“DDS”标记,请检查fread():
// open file
FILE *fp = fopen(filename.c_str(), "rb");
if (fp == NULL) {
return false;
}
// read in file marker, make sure its a DDS file
/* comment out for test
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0) {
fclose(fp);
return false;
}
*/
// read in DDS header
DDS_HEADER ddsh;
fread(&ddsh, sizeof( DDS_HEADER ),1 , fp);//sizeof( DDS_HEADER )
然后我将图像宽度值变为DDS_HEADER的imageHeight属性。其余属性仍然是垃圾。
当我在Windows机器上测试时,所有这一切都不会发生。 fread()在Linux GCC上的工作方式是否可能与使用MSVC编译器的Windows不同?
答案 0 :(得分:2)
GCC long在编译为32位时为4个字节,在64位时为8个字节。使用可以使用选项-m32或-m64显式目标32或64位。
答案 1 :(得分:1)
我解决了这个问题,因为没有提出有用的意见,我将自己回答这个问题。
我开始怀疑不同编译器之间数据类型大小的差异。然后我发现了这个post。之后我发现DDS头的大小(用GCC编译)是248,比它应该大两倍。(MS规格说它必须是124字节).nv_dds dds头为其成员使用unsigned long:
typedef struct
{
unsigned long dwSize;
unsigned long dwFlags;
unsigned long dwHeight;
unsigned long dwWidth;
unsigned long dwPitchOrLinearSize;
unsigned long dwDepth;
unsigned long dwMipMapCount;
unsigned long dwReserved1[11];
DDS_PIXELFORMAT ddspf;
unsigned long dwCaps1;
unsigned long dwCaps2;
unsigned long dwReserved2[3];
}DDS_HEADER;
因此,似乎MSVC编译器将无符号长整数视为4字节,而Linux上的GCC则为8字节。这里是标题的双倍大小。我把它全部更改为unsigned int(也在DDS_PIXELFORMAT标头中):
typedef struct
{
unsigned int dwSize;
unsigned int dwFlags;
unsigned int dwHeight;
unsigned int dwWidth;
unsigned int dwPitchOrLinearSize;
unsigned int dwDepth;
unsigned int dwMipMapCount;
unsigned int dwReserved1[11];
DDS_PIXELFORMAT ddspf;
unsigned int dwCaps1;
unsigned int dwCaps2;
unsigned int dwReserved2[3];
}DDS_HEADER;
现在一切正常!因此看起来,与某些地方所说的相反,NVidia nv_dds不是跨平台(或/和交叉编译读取),应该完成这个hack以使其在Linux上使用GCC 。
答案 2 :(得分:0)
对于与ABI相关的任务,你应该总是使用在stdint.h中定义的类型名称描述的类型,如int32_t / uint64_t,这可以在不同平台的编译过程中节省很多问题。小端问题)