views:

151

answers:

2

Hey guys I learned about endianness and am still having difficulty understanding where things could go wrong. I was wondering what sort of things I should look for and how I should go about fixing it. I know I dont need to change anything for loading from text files and things like that but for example here is a snippet of my code for loading a dxt texture I am pretty sure endianness could cause some problems here what things do I need to change and why?

JGDXTHeader* header = (JGDXTHeader*)[data bytes];
width = header->width;
height = header->height;
uint blockSize;
int factor;
GLenum dxt;
uint pixelFormat = header->pixelFormat.fourCC;
if (pixelFormat == 0x31545844){
    dxt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
    blockSize = 8;
    factor = 2;
}else if (pixelFormat == 0x33545844){
    dxt = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
    blockSize = 16;
    factor = 4;
}else if (pixelFormat == 0x35545844){
    dxt = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
    blockSize = 16;
    factor = 4;
}
+1  A: 

Generally speaking, endianness only matters if your data is travelling over some physical interface (e.g. across a network, or to a file), where it may have originated from a platform with a different native endianness. It also occurs if you're trying to do "clever" things with pointer casts, e.g. int a = 0xABCD; char b = *(char *)&a;.

It's not clear from your example where the original data comes from, but I assume that it's been read from a file or somewhere. Really, the best place to deal with endianness conversion is as close to the interface as possible, so in your case, the routine that reads the file and fills the structure. Typically, this can be solved with preprocessor #ifdefs, e.g. in C (I know this is a C++ question, but I'm sure you can find an appropriate equivalent):

#ifdef (LITTLE_ENDIAN)
#define FILE_TO_NATIVE_16(x)  ((((x) & 0xFF) << 8) | ((x) >> 8))
#else
#define FILE_TO_NATIVE_16(x)  (x)
#endif

and so on.

If you isolate the conversion to the interface routines, the rest of your code becomes endian-agnostic.

Oli Charlesworth
It is tagged C, so C code should be perfectly fine. (Eh, I dislike it when people lump C/C++ together in a question)
mathepic
We don't know if it's occuring in his code - it depends on the file format he's loading, and which endianess he intend to support. `pixelFormat == 0x31545844` might work on one platform, while it'd have to be `pixelFormat == 0x44585431` on another platform.
nos
@nos: Yes, you're right. Edited my answer accordingly. However, the solution isn't to modify all the constants, because that quickly becomes a nightmare.
Oli Charlesworth
It depends on the API definition of a DXTexture header. If the pixel format is documented as a uint then the constants *should* be defined as uints which means they are the same regardless of endianness. If the data has come from another machine in binary format, there may be an issue with endianness but the correct place to put the conversion is in the deserialisation.
JeremyP
By the way, in the example, the pixel format constants are backwards. A 4cc code is usually a sequence of 4 ASCII characters. If you reverse the constants in the snippets, you get DXT1, DXT3 and DXT5 respectively. So assuming this is an Intel machine, I'd say the files were stored in network byte order.
JeremyP
Ok but is there anything I should be doing with the width and height? I saw in some of apples demos that they used something like this when loading pvr CFSwapInt32LittleToHost(headr->pvrFormat); would that handle most problems if I just used on numbers that I load from binary?
Justin Meiners
@mathepic - Yeah it's so irritating that people have requirements that means their code needs to work on multiple platforms and with multiple languages. Folks should be forced to choose one language and stick with it! Down with C/C++ interop!
dash-tom-bang
@mathepic and dash=tom-bangIts a common problem accross all programming languages this in Objc which is actually more like C. The concept of endianess is the same in C, C++, and Objc which is why I tagged them together. This is not a language specific question.
Justin Meiners
@user42756: Yes, my advice applies to *all* values derived from a physical interface. At the point that the serialisation/deserialisation occurs, every single value should be explicitly converted to/from the correct endianness. Use of macros (or the equivalent) simplifies the process.
Oli Charlesworth
A: 

It's probably best to save out the data in the first place appropriate to the target platform. I.e. when you create the data files, endian swap all of the fields.

That point aside, I would think that your DXT loader should handle this automatically, since DXTs are generally going to be built on Windows machines which are little endian these days.

dash-tom-bang