这个问题还是很麻烦的。
endian:字节存储顺序,端模式。
Little-Endian 和 Big-Endian 表示的是计算机字节顺序, 所谓的字节顺序指的是长度跨越多个字节的数据的存放形式(若只有一个字节则不需考虑字节序的问题)。 对于整型、长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节); 而 Little endian 则相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。
大部分人在实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。 TCP/IP 各层协议将字节序定义为 Big-Endian,因此 TCP/IP 协议中使用的字节序通常称之为网络字节序。
对于一些更小的经过包装的像素格式,在显示设备上能够节省存储空间和有更快处理速度。 这种经过包装的像素格式仍然可以在一些 PC 硬件中找到,并且在将来也可能发挥作用。
经过包装的像素格式把颜色数据尽可能地压缩的更小。例如: GL_UNSIGNED_BYTE_3_3_2 格式用 3 位存储第一个成分,3 位存储第二个成分,2 位存储第三个成分。 颜色成分的顺序依靠于 glDrawPixels 函数中设置的 format 参数(如有 GL_RGB, GL_BGR 等)。 颜色成分的顺序是从最高位到最低位。GL_UNSIGNED_BYTE_2_3_3_REV 反转了这个顺序,即把最后的那个颜色成分用头两位表示。
case ECF_A8R8G8B8: // 小端模式
colorformat = GL_BGRA_EXT;
if (Driver->Version > 101)
type = GL_UNSIGNED_INT_8_8_8_8_REV; // 高位取到低位 ARGB,然后反向存入 BGRA
internalformat = GL_RGBA;
break;
case ECF_R8G8B8A8: // 小端模式
colorformat = GL_RGBA;
if (Driver->Version > 101)
type = GL_UNSIGNED_INT_8_8_8_8; // 高位取到低位 RGBA,然后存入 RGBA
internalformat = GL_RGBA;
break;
例如,假设从内存地址 0x0000 开始有以下数据:0x12 0x34 0xab 0xcd。 如果我们去读取一个地址为 0x0000 的四个字节变量,若字节序为 big-endian,则读出结果为 0x1234abcd; 若字节序位 little-endian,则读出结果为 0xcdab3412。
bool IsBig_Endian()
{
unsigned short test = 0x1122;
if (*( (unsigned char*) &test ) == 0x11)
return TRUE;
else
return FALSE; // windows
}
//! Converts a 32bit (A8R8G8B8) color to a 16bit A1R5G5B5 color
inline u16 A8R8G8B8toA1R5G5B5(u32 color)
{
return (u16)(( color & 0x80000000) >> 16|
( color & 0x00F80000) >> 9 |
( color & 0x0000F800) >> 6 |
( color & 0x000000F8) >> 3);
}
void CColorConverter::convert_R8G8B8A8toA1B5G5R5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[3] >> 3; // Little-Endian
s32 g = sB[2] >> 3;
s32 b = sB[1] >> 3;
s32 a = sB[0] >> 3;
dB[0] = (a << 15) | (b << 10) | (g << 5) | (r);
sB += 4;
dB += 1;
}
}
void CColorConverter::convert_A8R8G8B8toR5G6B5(const void* sP, s32 sN, void* dP)
{
u8 * sB = (u8 *)sP;
u16* dB = (u16*)dP;
for (s32 x = 0; x < sN; ++x)
{
s32 r = sB[2] >> 3;
s32 g = sB[1] >> 2;
s32 b = sB[0] >> 3;
dB[0] = (r << 11) | (g << 5) | (b);
sB += 4;
dB += 1;
}
}
void CColorConverter::convert_R8G8B8toR8G8B8A8(const void* sP, s32 sN, void* dP)
{
u8* sB = (u8*)sP;
u32* dB = (u32*)dP;
for (s32 x = 0; x < sN; ++x)
{
*dB = 0x000000ff | (sB[0] << 24) | (sB[1] << 16) | (sB[2] << 8);
sB += 3;
++dB;
}
}
吭人的 Irrlicht(Irrlicht 表示很委屈,因为这些格式刚好和 OpenGL 可以对应上)。
enum ECOLOR_FORMAT NOTE: Byte order in memory is usually flipped (it's probably correct in bitmap files, but flipped on reading). So for example ECF_A8R8G8B8 is BGRA in memory same as in DX9's D3DFMT_A8R8G8B8 format.
Irrlicht 这些格式刚好和 OpenGL 可以对应上
bool COGLES2Driver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,
GLenum& pixelType, void(**converter)(const void*, s32, void*)) const
{
bool supported = false;
pixelFormat = GL_RGBA;
pixelType = GL_UNSIGNED_BYTE; // 每个字节取,直接就是内存顺序 RGBA
*converter = 0;
switch (format)
{
case ECF_A1R5G5B5:
// 先转化为 R5G5B5A1 然后从高位到低位 5_5_5_1 为 RGBA。
supported = true;
pixelFormat = GL_RGBA;
pixelType = GL_UNSIGNED_SHORT_5_5_5_1;
*converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1;
break;
case ECF_R5G6B5:
// 高位到低位,刚好对应小端模式。
supported = true;
pixelFormat = GL_RGB;
pixelType = GL_UNSIGNED_SHORT_5_6_5;
break;
case ECF_R8G8B8:
// 高位到低位,刚好对应小端模式。
supported = true;
pixelFormat = GL_RGB;
pixelType = GL_UNSIGNED_BYTE;
break;
case ECF_R8G8B8A8:
// 内存里面要先反转一下,对应 RGBA
supported = true;
pixelType = GL_UNSIGNED_BYTE;
pixelFormat = GL_RGBA; // little-endian??
*converter = CColorConverter::convert_R8G8B8A8toR8G8B8A8_BEND; // 新加的代码逻辑,也跟着反过来。
break;
case ECF_A8R8G8B8:
supported = true;
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_IMG_texture_format_BGRA8888) ||
queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_format_BGRA8888) ||
queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_APPLE_texture_format_BGRA8888))
{
// 直接就可以,免去转换过程。
pixelFormat = GL_BGRA; // 是反过来的,little-endian??
}
else
{
pixelFormat = GL_RGBA; // Android little-endian??
*converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8; // 也是反过来的。
}
pixelType = GL_UNSIGNED_BYTE;
break;
}
...
}