It's a very simple thing to do, you need to encode 3 bytes in a 32bit integer which allows 4. So what you need is
int32_t coordinates;
coordinates = x | (y << 8) | (z << 16);
and then you can access the coordinates with masks of bit flags.
Test program:
#include <stdint.h>
#include <stdio.h>
int
main(void)
{
int x = 16;
int y = 2;
int z = 4;
int32_t coordinates = x | (y << 8) | (z << 16);
fprintf(stdout, "x = %d\n", (coordinates & 0xFF));
fprintf(stdout, "y = %d\n", ((coordinates >> 8) & 0xFF));
fprintf(stdout, "z = %d\n", ((coordinates >> 16) & 0xFF));
return 0;
}
But then you can't encode 256 because it requires one more bit, remember that you start at 20 so you can only represent 255 with 8 bits, so here is an idea
#include <stdint.h>
#include <stdio.h>
#define XSHIFT 0
#define YSHIFT 9
#define ZSHIFT 18
#define GET_X(x) (((x) >> XSHIFT) & 0x1FF)
#define GET_Y(y) (((y) >> YSHIFT) & 0x1FF)
#define GET_Z(z) (((z) >> ZSHIFT) & 0x1FF)
#define ENCODE(x, y, z) (((x) << XSHIFT) | ((y) << YSHIFT) | ((z) << ZSHIFT))
int
main(void)
{
int32_t coordinates = ENCODE(256, 0, 1);
fprintf(stdout, "x = %d\n", GET_X(coordinates));
fprintf(stdout, "y = %d\n", GET_Y(coordinates));
fprintf(stdout, "z = %d\n", GET_Z(coordinates));
return 0;
}
Use one extra bit from the remaining 8 bits that you have in a 32 bit integer.
NOTE: perhaps you (and others) think that defining XSHIFT
is superflous but I think that the expressions then make more sense and are easier to read. It's something I believe I learned from studying physics and it's hard for me to see things like x + 7
in code as it is in mathematical expressions derived from physical laws.