我正试图平均两种颜色。
我原来的(可怕的)工具如下:
//color is a union
int ColorAverage(int c1, int c2) {
color C1(c1);
color C2(c2);
return color(
(unsigned char)(0.5f * C1.a + 0.5f * C2.a),
(unsigned char)(0.5f * C1.r + 0.5f * C2.r),
(unsigned char)(0.5f * C1.g + 0.5f * C2.g),
(unsigned char)(0.5f * C1.b + 0.5f * C2.b)
).c;
}
我目前的解决方案如下(表现更好):
int ColorAverage(int c1, int c2) {
unsigned char* b1 = reinterpret_cast<unsigned char*>(&c1);
unsigned char* b2 = reinterpret_cast<unsigned char*>(&c2);
int value;
unsigned char* bv = reinterpret_cast<unsigned char*>(&value);
bv[0] = (b1[0] + b2[0]) / 2;
bv[1] = (b1[1] + b2[1]) / 2;
bv[2] = (b1[2] + b2[2]) / 2;
bv[3] = (b1[3] + b2[3]) / 2;
return(value);
}
然而,它仍然很慢(大约占我帧时间的3%)。
我确实找到了24位的解决方案,但它不适用于32位(alpha丢失):
#define AVERAGE(a, b) ( ((((a) ^ (b)) & 0xfffefefeL) >> 1) + ((a) & (b)) )
答案 0 :(得分:5)
尝试将掩码扩展到32位,如下所示:
#define AVERAGE(a, b) ( ((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)) )
编辑:我做了一个快速检查,它似乎适用于我的测试用例。顺便说一下好的配方!
答案 1 :(得分:4)
目标是采取以下行动:
(a + b)/ 2 =((a ^ b)&gt;&gt; 1)+(a&amp; b)
并将其应用于整数的所有四个字节。如果这只是一个字节,则右移1位会丢弃最右边的位。但是,在这种情况下,前3个字节的最右边位不会被丢弃---它会移入相邻字节。要记住的想法是,您需要屏蔽每个字节的最后一位,以便在移位期间不会“污染”相邻字节。例如,假设a ^ b是这样的:
a XOR b = 1011 1101 1110 1001
没有掩码的1位右移将如下所示:
(a XOR b)&gt;&gt; 1 = 0101 1110 1111 0100
哪个错了。掩码零超出每个字节的最后一位,因此不会发生这种情况:
(一个XOR b)和0xfefefefe = 1010 1100 1110 1000
然后你可以安全地将这个值转移到右边:
((XOR b)AND 0xfefefefe)= 0101 0110 0111 0100
所以:
#define AVERAGE(a, b) ( ((((a) ^ (b)) & 0xfefefefeL) >> 1) + ((a) & (b)) )
要记住的一点是,C不会将算术右移与逻辑右移与运算符区分开来。您需要确保要转移的整数未签名,为prevent implementation-specific signed-integer shift voodoo。
编辑:我认为@dasblinkenlight可能已经击败了我这个答案。只要小心改变有符号整数,你应该很好。