/**
* Bitmasking utils
* @module Bitmasking
*/
const map = [
[0],
[1, 4, 16, 64],
[5, 20, 80, 65],
[7, 28, 112, 193],
[17, 68],
[21, 84, 81, 69],
[23, 92, 113, 197],
[29, 116, 209, 71],
[31, 124, 241, 199],
[85],
[87, 93, 117, 213],
[95, 125, 245, 215],
[119, 221],
[127, 253, 247, 223],
[255]
];
const front_map = [0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 3, 4, 5, 5];
const oriented_mask = { 2: 1, 8: 2, 10: 3, 11: 4, 16: 5, 18: 6, 22: 7, 24: 8, 26: 9, 27: 10, 30: 11, 31: 12, 64: 13, 66: 14, 72: 15, 74: 16, 75: 17, 80: 18, 82: 19, 86: 20, 88: 21, 90: 22, 91: 23, 94: 24, 95: 25, 104: 26, 106: 27, 107: 28, 120: 29, 122: 30, 123: 31, 126: 32, 127: 33, 208: 34, 210: 35, 214: 36, 216: 37, 218: 38, 219: 39, 222: 40, 223: 41, 248: 42, 250: 43, 251: 44, 254: 45, 255: 46, 0: 47 };
const noncorner_map = [
[0],
[1, 4, 8, 2],
[3, 5, 12, 10],
[6, 9],
[7, 13, 14, 11],
[15]
];
function getTileposAndRotation(map, m) {
let rotation = 0;
let tilepos = 0;
for (const b in map) {
let rots = map[b];
let ri = rots.indexOf(m);
if (ri !== -1) {
tilepos = b * 1;
rotation = ri * Math.PI * 0.5;
break;
}
}
return { m: tilepos, rot: rotation };
}
/**
* Get a bitmask texture offset for tiles without corners (tiles with 6 textures that can be rotated)
*
* 
* @param {Grid} grid
* @param {number} x
* @param {number} y
* @param {Array} connects_to
* @param {string} [prop_path="type"] the property path if its an object, otherwise pass null
* @return {number}
*/
function get4MaskRotated(grid, x, y, connects_to, prop_path = "type") {
let n = grid.neighbours(x, y, prop_path);
let m = 0;
let dirs = ["n", "w", "e", "s"];
connects_to.forEach(tag => {
for (let i = 0; i < dirs.length; i++) {
if (n[dirs[i]].tags) {
if (n[dirs[i]].hasTag(tag)) {
m += Math.pow(2, i);
}
} else {
if (n[dirs[i]] == tag) {
m += Math.pow(2, i);
}
}
}
});
return getTileposAndRotation(noncorner_map, m);
}
/**
* Get a bitmask texture offset for always front-facing tiles, like walls
*
* **Example texture:**
* 
* @param {Grid} grid
* @param {number} x
* @param {number} y
* @param {Array} connects_to
* @param {string} [prop_path="type"] the property path if its an object, otherwise pass null
* @return {number}
*/
function get4MaskFront(grid, x, y, connects_to, prop_path = "type") {
let n = grid.neighbours(x, y, prop_path);
let m = 0;
connects_to.forEach(tag => {
if (n.e == tag) {
m += 1;
}
if (n.se == tag) {
m += 2;
}
if (n.sw == tag) {
m += 4;
}
if (n.w == tag) {
m += 8;
}
});
return front_map[m];
}
/**
* Get a bitmask texture offset for oriented tiles with corners (tiles with 48 textures that can't be rotated)
*
* **Example texture:**
* 
* @param {Grid} grid
* @param {number} x
* @param {number} y
* @param {Array} connects_to
* @param {string} [prop_path="type"] the property path if its an object, otherwise pass null
* @return {number}
*/
function get8Mask(grid, x, y, connects_to, prop_path = "type") {
let m = 0;
let n = grid.neighbours(x, y, prop_path);
for (const key in n) {
if (n[key] === null) continue;
if (n[key].tags) {
n[key] = n[key].hasAnyTag(connects_to);
} else {
n[key] = connects_to.includes(n[key]);
}
}
if (n.n) {
m += 2;
if (n.ne && n.e) m += 4;
}
if (n.e) {
m += 16;
if (n.se && n.s) m += 128;
}
if (n.s) {
m += 64;
if (n.sw && n.w) m += 32;
}
if (n.w) {
m += 8;
if (n.nw && n.n) m += 1;
}
return oriented_mask[m] || m;
}
/**
* Get a bitmask texture offset for tiles with corners (tiles with 15 textures that can be rotated)
*
* **Example texture:**
* 
* @param {Grid} grid
* @param {number} x
* @param {number} y
* @param {Array} connects_to
* @param {string} [prop_path="type"] the property path if its an object, otherwise pass null
* @return {number}
*/
function get8MaskRotated(grid, x, y, connects_to, prop_path = "type") {
let m = grid.bitmask(x, y, connects_to, prop_path);
return getTileposAndRotation(map, m);
}
export {
get4MaskFront,
get4MaskRotated,
get8Mask,
get8MaskRotated
};