binarybit-manipulationbitwise-operatorsbitbit-masks

32-bit int struct bits don't seem to match up (nodejs)


I have a file that defines a set of tiles (used in an online game). The format for each tile is as follows:

   x: 12 bits
   y: 12 bits
tile: 8 bits

32 bits in total, so each tile can be expressed as a 32 bit integer.

More info about the file format can be found here:

http://wiki.minegoboom.com/index.php/LVL_Format

http://www.rarefied.org/subspace/lvlformat.html

The 4 byte structures are not broken along byte boundaries. As you can see x: and y: are both defined as 12 bits. ie. x is stored in 1.5 bytes, y is stored in 1.5 bytes and tile is stored in 1 byte.

Even though x and y use 12 bits their max value is 1023, so they could be expressed in 10 bits. This was down to the creator of the format. I guess they were just padding things out so they could use a 32-bit integer for each tile? Either way, for x and y we can ignore the final 2 bits.

I'm using a nodejs Buffer to read the file and I'm using the following code to read the values.

var n = tileBuffer.readUInt32LE(0);
var x = n & 0x03FF;
var y = (n >> 12) & 0x03FF;
var tile = (n >> 24) & 0x00ff; 

This code works fine but when I read the bits themselves, in an attempt to understand binary better, I see something that confuses me.

Take, for example a int that expresses the following:

   x: 1023
   y: 1023
tile: 1

Creating the tiles in a map editor and reading the resulting file into a buffer returns <Buffer ff f3 3f 01>

When I convert each byte into a string of bits I get the following:

ff = 11111111
f3 = 11110011
3f = 00111111
01 = 00000001

11111111 11110011 00111111 00000001

I assume I should just take the first 12 bits as x but chop off the last 2 bits. Use the next 12 bits as y, chopping off 2 bits again, and the remaining 8 bits would be the tile.

   x: 1111111111
   y: 0011001111
tile: 00000001

The x is correct (1111111111 = 1023), the y is wrong (0011001111 = 207, not 1023), and tile is correct (00000001 = 1)

I'm confused and obviously missing something.


Solution

  • It makes more sense to look at it in this order: (this would be the binary representation of n)

    00000001 00111111 11110011 11111111
    

    On that order, you can easily do the masking and shifting visually.

    The problem with what you did is that for example in 11111111 11110011, the bits of the second byte that belong to the first field are at the right (the lowest part of that byte), which in that order is discontinuous.

    Also, masking with 0x03FF makes those first two fields have 10 bits, with two bits just disappearing. You can make them 12 bits by masking with 0x0FFF. As it is now, you effectively have two padding bits.