for (i =0; i <8; i++) {
for (j =0; j <8; j++) {
checkImage[i][j][0] = (GLubyte)255;
checkImage[i][j][1] = (GLubyte)0;
checkImage[i][j][2] = (GLubyte)0;
}
}
现在的问题是,代码是如何自动产生颜色的黑白值的?
0x8的二进制是1000,表达式 i & 0x8 只有在i值的高位为1时才能得到1000,否则全为0000。 因此表达式 (i & 0x8) == 0 只在i值的高位为1时才返回false,否则为true。上面的说法是严格从语义的角度来进行的解释,但不好理解,没有太多实际意义。而实际上,对位与操作符“&”,更好的理解是,位与操作符“&”经常用于通过选择特定位为0的屏蔽因子而屏蔽特定的位,从而留下只关心的位。例如,对于例中所选择的屏蔽因子0x8,二进制为1000,
1100 (i)
& 1000 (屏蔽因子)
----
1000 (低3位被屏蔽掉,只剩最高位)
因为低3位为000,因此,无论i为何值,位与后的结果其低3位必为0值,而最高位则可保留原值。因此,通过与0x8位与,我们将i值的低3位全部屏蔽了,而只关心i值的千分位。这样,表达式
(i & 0x8) == 0
的意思是,i的千分位是否为0?
同样,表达式(j & 0x8) == 0 的意思是,j的千分位是否为0?
位或操作符“|”通常用于将特定位打开。如,下面将最低位打开。
0100 (i)
| 0001 (打开因子)
----
0101 (最低位必然为1,从而打开最低位)
位异或操作符“^”在操作数不同时返回1,在操作数相同时返回0。通常用于反转特定的位。
0101 (i)
| 0011 (反转因子)
----
0110 (将最低2位反转)
回到我们的例子,对于
c = ((((i &0x8) ==0) ^ ((j &0x8)) ==0)) *255;
设 i & 0x8 == 0 的值为a,则表达式变为
c = ((a ^ ((j &0x8)) ==0)) *255;
设 ((j & 0x8)) 的值为b,则表达式变为
c = ((a ^ b ==0)) *255;
因为 == 优先于 ^,因此将先算 b == 0,设 b == 0 的值为d,则表达式变为
c = ((a ^ d)) *255;
很明显,例子代码中的书写格式并不规范,一是 ((j & 0x8)) 的括号重复; 二是a ^ b ==0 让读者去猜^与==到底哪个优先,在编译器中也检测出该问题而发出警告; 三是((a ^ c)) *255的括号再次重复。综上,例子代码的公式可改为:
c = ( ( (i &0x8) ==0 ) ^ ( (j &0x8) ==0) ) *255;
含义比较清楚了,i的千分位是否为0?j的千分位是否为0?将它们异或后再乘以255。最后结果是,只有1真1假时,才得到255即白色,否则为黑色。也即当i或j中有且仅有一个的千分位为1时才会产生白色。
不同字长的最高位为1的值分别有:
二进制 字长 十六进制 十进制
1000 4 0x8 8
10000000 8 0x80 128
100000000000 12 0x800 2048
1000000000000000 16 0x8000 32768
……
而在字长为4、最高位为1时,可能的值如下:
二进制 十六进制 十进制
1000 0x8 8
1001 0x9 9
1010 0xA 10
1011 0xB 11
1100 0xC 12
1101 0xD 13
1110 0xE 14
1111 0xF 15
1xxx
& 1000
————
1000
因此,当字长为4,行i或列j中有且仅有一个存在8到15的值域时才会产生白色。因此就有第0行中8至15列的白色方格:
checkImage[0][8][0] = FF, checkImage[0][8][1] = FF, checkImage[0][8][2] = FF
checkImage[0][9][0] = FF, checkImage[0][9][1] = FF, checkImage[0][9][2] = FF
checkImage[0][10][0] = FF, checkImage[0][10][1] = FF, checkImage[0][10][2] = FF
checkImage[0][11][0] = FF, checkImage[0][11][1] = FF, checkImage[0][11][2] = FF
checkImage[0][12][0] = FF, checkImage[0][12][1] = FF, checkImage[0][12][2] = FF
checkImage[0][13][0] = FF, checkImage[0][13][1] = FF, checkImage[0][13][2] = FF
checkImage[0][14][0] = FF, checkImage[0][14][1] = FF, checkImage[0][14][2] = FF
checkImage[0][15][0] = FF, checkImage[0][15][1] = FF, checkImage[0][15][2] = FF
16的二进制是10000,是第一个字长超过4的数。(准确地说,0xF只能表示0-15的数,16-255的数必须用0xFF的范围来表示。)对于它,
00010000 (16)
& 00001000 (屏蔽因子0x8)
------
00000000
虽然最高位为1,但经0x8屏蔽后,结果为0,false。
来看24,这是字长超过4,且二进制的千分位为1的第一个数。
00011000
& 00001000
------
00001000
结果为true,白色。因此有
checkImage[0][24][0] = FF, checkImage[0][24][1] = FF, checkImage[0][24][2] = FF
checkImage[0][25][0] = FF, checkImage[0][25][1] = FF, checkImage[0][25][2] = FF
checkImage[0][26][0] = FF, checkImage[0][26][1] = FF, checkImage[0][26][2] = FF
checkImage[0][27][0] = FF, checkImage[0][27][1] = FF, checkImage[0][27][2] = FF
checkImage[0][28][0] = FF, checkImage[0][28][1] = FF, checkImage[0][28][2] = FF
checkImage[0][29][0] = FF, checkImage[0][29][1] = FF, checkImage[0][29][2] = FF
checkImage[0][30][0] = FF, checkImage[0][3