JavaScript Canvas Bit Manipulation |
Written by Ian Elliot | |||
Monday, 09 August 2021 | |||
Page 2 of 2
Beyond 32 BitsSo what exactly happens if you try to work with bitwise operators on values that aren't representable as 32-bit integers? To do this the JavaScript interpreter calls the internal ToInt32 function, which you can't use in your programs. This performs an "intelligent" conversion to a 32-bit integer with the following restrictions:
You will also be pleased to learn that, as true evaluates to 1 and false to 0, you can use the bitwise logical operators on Boolean values as long as you remember that true is 1 and false 0. For example: var c = 0xF & (1===1); is 1 as (1===1) evaluates to 0x01. However, notice that due to JavaScript’s use of the idea of truthy or falsey, values that are considered to be true can be any non-zero value. The only real problem with JavaScript's bitwise operators is that, due to the restriction to 32 bits, they are not especially fast because of the need to be converted from floating point double precision to 32-bit integer and then back again. MasksSo what do you use the bitwise logical operators for? You often encounter the problem of setting or clearing particular bits in a value. The value is usually stored in a variable that is usually regarded as a status variable or flag. You can set and unset bits in a flag using another value usually called a mask that defines the bits to be changed. For example, if you only want to change the first (least significant) bit then the mask would be 0x01. If you wanted to change the first and second bits the mask would be 0x03 and so on. To work out the correct hexadecimal value needed for any particular mask, you can use the parseInt function with a radix of 2. For example: a=parseInt("1",2); sets a to 0x01 and: a=parseInt("11",2); sets a to 0x03 and so on. In general, just write down a string of 0s and 1s with a 1 in the positions you want to change and use parseInt to convert it to a mask value. Now that you have a mask what do you do with it? Suppose the mask contains a value that in binary has a 1 at each bit location you want to change. Then: flag | mask; returns a bit pattern with the bits that the mask specifies set to 1. Notice that the bits that the mask doesn't specify are left at their original values. This is often expressed as the mask sets the bits it specifies. For example: var mask=parseInt("11",2); var flag = 0xFFF0; var result = flag | mask; sets result to 0xFFF3, i.e. it sets the first (least significant) two bits. If you use: flag & ~mask; then the bits specified in the mask are set to 0 - or unset if you prefer. Notice that you have to apply a NOT operator to the mask. For example: var mask=parseInt("11",2); var flag = 0xFFFF; var result = flag & ~mask; sets result to 0xFFFC, i.e. it unsets the first two bits. As well as setting and unsetting particular bits, you might also want to "flip" specified bits, i.e. negate them so that if the bit was a 1 it is changed to a 0 and vice versa. You can do this using the XOR operator, so: flag ^ mask flips the bits specified by the mask. For example: var mask=parseInt("11",2); var flag = 0xFFFF; var result = flag ^ mask; alert(result.toString(16)); sets result to 0xFFFC because it changes the lower two bits from 1s to 0s. Again, bits not specified by the mask are unaffected. Of course, in each case you don't have to use a variable to specify the mask, you could just use a numeric literal. For example, instead of: var flag = 0xFFFF; var result = flag ^ mask; you can write: var result = flag ^ 0xFFFF; Also if you want to update the flag rather than derive a new result, you can use &=, |= and ^= to perform the update directly. For example, instead of: flag = flag | mask; you can use: flag |= mask; Using MasksWhat sorts of things do you use masking operations for? Often a low level API will require that particular bits in a status word are set or unset to make it operate in a particular way. However, this is unusual in JavaScript because it generally doesn't access lower level APIs. However, new developments like Canvas, WebGL and so on are changing this. One of the best known uses of bit manipulation predates HTML5 - extracting the color codes from an RGB color value. For example: var RGBcolor=0x010203; var B=RGBcolor & 0x0000FF; var G=RGBcolor & 0x00FF00; var R=RGBcolor & 0xFF0000; This takes an RGB value and splits it up into its components using appropriate masks. The result is that you end up with 0x010000 stored in R, 0x000200 in G and 0x000003 in B. Notice that while the value of B is correct, R and G are incorrect and the bits need shifting to the right. This brings us to the use of the shift operators. In Chapter but not in this extract
Summary
Now available as a paperback or ebook from Amazon.JavaScript Bitmap Graphics
|
|||
Last Updated ( Monday, 09 August 2021 ) |