diff --git a/crates/gaiku_baker_marching_cubes/src/baker.rs b/crates/gaiku_baker_marching_cubes/src/baker.rs index 93aa1b6..cea0b02 100644 --- a/crates/gaiku_baker_marching_cubes/src/baker.rs +++ b/crates/gaiku_baker_marching_cubes/src/baker.rs @@ -106,14 +106,18 @@ impl MarchingCubesBaker { let uvs = texture.get_uv(atlas); let atlas_origin = uvs.0; - let atlas_dimensions = [uvs.2[0] - uvs.0[0], uvs.2[1] - uvs.0[1]]; + let atlas_min = uvs.0; + let atlas_max = uvs.2; + let atlas_dimensions = [atlas_max[0] - atlas_min[0], atlas_max[1] - atlas_min[1]]; // Put face uvs into atlas uv space let final_uvs: [[f32; 2]; 3] = face_uvs .iter() .map(|uv| { [ - atlas_origin[0] + uv[0] * atlas_dimensions[0], - atlas_origin[1] + uv[1] * atlas_dimensions[1], + (atlas_origin[0] + uv[0] * atlas_dimensions[0]) + .clamp(atlas_min[0], atlas_max[0]), + (atlas_origin[1] + uv[1] * atlas_dimensions[1]) + .clamp(atlas_min[1], atlas_max[1]), ] }) .collect::>() diff --git a/crates/gaiku_baker_modified_marching_cubes/src/baker.rs b/crates/gaiku_baker_modified_marching_cubes/src/baker.rs index 663f069..996c317 100644 --- a/crates/gaiku_baker_modified_marching_cubes/src/baker.rs +++ b/crates/gaiku_baker_modified_marching_cubes/src/baker.rs @@ -106,14 +106,18 @@ impl ModMarchingCubesBaker { let uvs = texture.get_uv(atlas); let atlas_origin = uvs.0; - let atlas_dimensions = [uvs.2[0] - uvs.0[0], uvs.2[1] - uvs.0[1]]; + let atlas_min = uvs.0; + let atlas_max = uvs.2; + let atlas_dimensions = [atlas_max[0] - atlas_min[0], atlas_max[1] - atlas_min[1]]; // Put face uvs into atlas uv space let final_uvs: [[f32; 2]; 3] = face_uvs .iter() .map(|uv| { [ - atlas_origin[0] + uv[0] * atlas_dimensions[0], - atlas_origin[1] + uv[1] * atlas_dimensions[1], + (atlas_origin[0] + uv[0] * atlas_dimensions[0]) + .clamp(atlas_min[0], atlas_max[0]), + (atlas_origin[1] + uv[1] * atlas_dimensions[1]) + .clamp(atlas_min[1], atlas_max[1]), ] }) .collect::>() diff --git a/crates/gaiku_baker_voxel/src/baker.rs b/crates/gaiku_baker_voxel/src/baker.rs index 2fd0835..6069d97 100644 --- a/crates/gaiku_baker_voxel/src/baker.rs +++ b/crates/gaiku_baker_voxel/src/baker.rs @@ -109,14 +109,18 @@ impl VoxelBaker { let uvs = texture.get_uv(atlas); let atlas_origin = uvs.0; - let atlas_dimensions = [uvs.2[0] - uvs.0[0], uvs.2[1] - uvs.0[1]]; + let atlas_min = uvs.0; + let atlas_max = uvs.2; + let atlas_dimensions = [atlas_max[0] - atlas_min[0], atlas_max[1] - atlas_min[1]]; // Put face uvs into atlas uv space let final_uvs: [[f32; 2]; 3] = face_uvs .iter() .map(|uv| { [ - atlas_origin[0] + uv[0] * atlas_dimensions[0], - atlas_origin[1] + uv[1] * atlas_dimensions[1], + (atlas_origin[0] + uv[0] * atlas_dimensions[0]) + .clamp(atlas_min[0], atlas_max[0]), + (atlas_origin[1] + uv[1] * atlas_dimensions[1]) + .clamp(atlas_min[1], atlas_max[1]), ] }) .collect::>() diff --git a/crates/gaiku_baker_voxel/src/table_gen.rs b/crates/gaiku_baker_voxel/src/table_gen.rs index c245df2..14335c3 100644 --- a/crates/gaiku_baker_voxel/src/table_gen.rs +++ b/crates/gaiku_baker_voxel/src/table_gen.rs @@ -123,7 +123,7 @@ fn vec_dot(a: &[f32; 3], b: &[f32; 3]) -> f32 { a[0] * b[0] + a[1] * b[1] + a[2] * b[2] } -fn get_verts(a_coord: [i8; 3], b_coord: [i8; 3]) -> Option<([i8; 4], [[f32; 2]; 4], u8)> { +fn get_verts(a_coord: [i8; 3], b_coord: [i8; 3]) -> Option<([i8; 4], [[f32; 2]; 4])> { // All a_coord or b_coors are corner points so their values all always [0/2, 0/2, 0/2] never 1 let mid_coord = [ (b_coord[0] + a_coord[0]) / 2, @@ -179,14 +179,11 @@ fn get_verts(a_coord: [i8; 3], b_coord: [i8; 3]) -> Option<([i8; 4], [[f32; 2]; let cross = vec_cross(c_delta, d_delta); let mid_cross = vec_add(mid_coord, cross); let result; - let corner; if vec_eq(mid_cross, a_coord) { // Cross of c,d + mid == a result = [mid_coord, d, c, [1, 1, 1]]; - corner = 0; } else { result = [mid_coord, c, d, [1, 1, 1]]; - corner = 1; } let normal = [-cross[0] as f32, -cross[1] as f32, -cross[2] as f32]; @@ -247,7 +244,6 @@ fn get_verts(a_coord: [i8; 3], b_coord: [i8; 3]) -> Option<([i8; 4], [[f32; 2]; *VERT_MAP.get(&result[3]).unwrap(), ], uvs.try_into().unwrap(), - corner, )) } @@ -272,21 +268,22 @@ fn main() { for j in (i + 1)..8 { let m = values[i]; let n = values[j]; - if let Some((verts, uvs, corner_idx)) = + if let Some((verts, uvs)) = get_verts(CORNER_MAP[&(i as i8)], CORNER_MAP[&(j as i8)]) { - let corner = match corner_idx { - 0 => i, - 1 => j, - _ => unreachable!(), + let corner: i8 = if m { + i.try_into().unwrap() + } else { + j.try_into().unwrap() }; + add_to_tables( m, n, cube_index, verts, uvs, - corner.try_into().unwrap(), + corner, &mut edge_table, &mut triangle_table, &mut uv_table, diff --git a/crates/gaiku_baker_voxel/src/tables.rs b/crates/gaiku_baker_voxel/src/tables.rs index eff7d9a..7d88be5 100644 --- a/crates/gaiku_baker_voxel/src/tables.rs +++ b/crates/gaiku_baker_voxel/src/tables.rs @@ -20578,1272 +20578,1272 @@ pub const CORNER_TABLE: [[i8; 73]; 256] = [ -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, + 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, + 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, - 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, - 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, + 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, + 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, + 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, - 5, 5, 6, 6, 6, 6, 6, 6, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 5, 5, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, + 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, + 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, + 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, - 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, + 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, - 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 4, 4, + 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 4, 4, + 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, + 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, + 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 4, 4, + 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, + 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, - 5, 5, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, + 5, 5, 7, 7, 7, 7, 7, 7, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, + 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, - 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 5, 5, - 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, - 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, - 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, + 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, - 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, + 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 4, 4, + 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, - 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 6, 6, + 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, + 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, + 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, + 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, + 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, - 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 5, 5, + 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 7, 7, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 7, 7, + 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], [ - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ], diff --git a/crates/gaiku_common/Cargo.toml b/crates/gaiku_common/Cargo.toml index 3f9839a..901dab5 100644 --- a/crates/gaiku_common/Cargo.toml +++ b/crates/gaiku_common/Cargo.toml @@ -22,3 +22,9 @@ png = { version = "^0.16.7", optional = true } serde = { version = "1.0", optional = true, features = ["derive"] } rstar = "0.8.3" glam = { version = "^0.12.0 ", features = ["mint"] } +thiserror = "1.0.26" + +[dev-dependencies] +rand = "0.8.4" +gaiku = { path = "../../", version = "0.1.0" } +assert_matches = "1.5.0" diff --git a/crates/gaiku_common/src/chunker/common.rs b/crates/gaiku_common/src/chunker/common.rs new file mode 100644 index 0000000..111a925 --- /dev/null +++ b/crates/gaiku_common/src/chunker/common.rs @@ -0,0 +1,163 @@ +use crate::{ + atlas::{Atlasify, AtlasifyMut}, + boxify::{Boxify, Sizable}, + chunk::{Chunkify, ChunkifyMut}, +}; +use std::convert::TryInto; + +/// +/// Chunk holds the result from a chunking operation +/// +/// This includes aspects like location and scale +/// because some chunking operations such as the LOD +/// chunkers will scale the chunks to adjust the resolution +/// +pub struct Chunked { + /// The location of the chunk relative to the first sample datas location + pub location: [f32; 3], + /// The scale of the chunk relative to the original datas scale + pub scale: [f32; 3], + /// The resulting chunk + pub chunk: C, +} + +/// +/// Generic interface for Chunkers +/// +pub trait Chunker +where + C: Chunkify + ChunkifyMut + AtlasifyMut + Boxify, +{ + /// + /// Create chunks using this chunk for input + /// + /// The values and atlas values from the source + /// chunk are copied + /// + /// # Parameters + /// + /// * `chunk` - chunk + /// + /// # Returns + /// + /// returns description + /// + fn from_chunk(chunk: &D) -> Self + where + D: Chunkify + Atlasify + Sizable, + Self: Sized, + { + let width = chunk.width(); + let height = chunk.height(); + let depth = chunk.depth(); + let mut data = vec![]; + let mut atlas_data = vec![]; + for x in 0..width { + for y in 0..height { + for z in 0..depth { + data.push(chunk.get(x.into(), y.into(), z.into())); + atlas_data.push(chunk.get_atlas(x.into(), y.into(), z.into())); + } + } + } + + Self::from_array_with_atlas( + data.as_slice(), + atlas_data.as_slice(), + width.try_into().unwrap(), + height.try_into().unwrap(), + depth.try_into().unwrap(), + ) + } + + /// + /// Chunks the input array + /// + /// The length of data samples should match those provided by + /// width * height * depth + /// + /// # Parameters + /// + /// * `data` - The input data samples + /// + /// * `width` - width of samples + /// + /// * `height` - height of samples + /// + /// * `depth` - depth of samples + /// + /// # Returns + /// + /// returns description + /// + fn from_array(data: &[T], width: usize, height: usize, depth: usize) -> Self + where + Self: Sized, + { + Self::from_array_with_atlas(data, &[], width, height, depth) + } + + /// + /// Chunks the data with atlas values + /// + /// The data needs to have the length equal to the + /// width * height * depth. But the atlas data does + /// not any missing values will likely be replaced with + /// defaults + /// + /// # Parameters + /// + /// * `data` - The source data for the values + /// + /// * `atlas_data` - The source data for the atlas values + /// + /// * `width` - width of the data + /// + /// * `height` - height of the data + /// + /// * `depth` - depth of the data + /// + /// # Returns + /// + /// returns description + /// + fn from_array_with_atlas( + data: &[T], + atlas_data: &[U], + width: usize, + height: usize, + depth: usize, + ) -> Self + where + Self: Sized; + + /// + /// Generates the chunks + /// + /// The source data needs to be already setup + /// and ready before making this call + /// + fn generate_chunks(&mut self); + + /// + /// Gets the resulting chunks + /// + /// This should be called after `generate_chunks` + /// + /// # Returns + /// + /// returns a `Vec<& Chunked>` + /// + fn get_chunks(&self) -> Vec<&Chunked>; + + /// + /// Gets the resulting chunks mutably + /// + /// This should be called after `generate_chunks` + /// + /// # Returns + /// + /// returns a `Vec<&mut Chunked>` + /// + fn get_chunks_mut(&mut self) -> Vec<&mut Chunked>; +} diff --git a/crates/gaiku_common/src/chunker/flat.rs b/crates/gaiku_common/src/chunker/flat.rs new file mode 100644 index 0000000..402c16a --- /dev/null +++ b/crates/gaiku_common/src/chunker/flat.rs @@ -0,0 +1,278 @@ +// Takes input data and generates a +// series of chunks at specified size +use super::common::*; +use crate::{ + atlas::AtlasifyMut, + boxify::Boxify, + chunk::{Chunkify, ChunkifyMut}, +}; +use std::convert::TryInto; + +/// +/// FlatChunker will simply seperate the data into chunks of a +/// specified size. +/// +/// If the size of the data does not equally +/// divide into the specified size then the last chunks +/// in each dimension will be smaller. +/// +pub struct FlatChunker { + data: Vec, + atlas_data: Vec, + data_width: usize, + data_height: usize, + data_depth: usize, + chunk_sizes: [u16; 3], + results: Vec>, +} + +impl Chunker for FlatChunker +where + C: Chunkify + ChunkifyMut + AtlasifyMut + Boxify, +{ + fn from_array_with_atlas( + data: &[f32], + atlas_data: &[u8], + width: usize, + height: usize, + depth: usize, + ) -> Self { + Self { + data: data.to_vec(), + atlas_data: atlas_data.to_vec(), + data_width: width, + data_height: height, + data_depth: depth, + chunk_sizes: [16, 16, 16], + results: vec![], + } + } + + /// + /// Generates the chunks from the source data + /// + /// The source data needs to be already setup + /// and ready before making this call + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// use gaiku::common::prelude::*; + /// use gaiku::common::chunk::Chunk; + /// + /// let dimensions = [48, 48, 48]; + /// let data = vec![1.; dimensions[0] * dimensions[1] * dimensions[2]]; + /// + /// let mut chunker: FlatChunker = FlatChunker::from_array( + /// &data, + /// dimensions[0], + /// dimensions[1], + /// dimensions[2], + /// ); + /// + /// chunker.generate_chunks(); + /// let results = chunker.get_chunks(); + /// + /// assert_eq!(results.len(), 27); + /// ``` + /// + fn generate_chunks(&mut self) { + let mut results = vec![]; + let chunk_sizes = [ + self.chunk_sizes[0] as usize, + self.chunk_sizes[1] as usize, + self.chunk_sizes[2] as usize, + ]; + for x in 0..(self.data_width / chunk_sizes[0] + 1) { + for y in 0..(self.data_height / chunk_sizes[1] + 1) { + for z in 0..(self.data_depth / chunk_sizes[2] + 1) { + let x_min = x * chunk_sizes[0]; + let x_max = std::cmp::min(x_min + chunk_sizes[0] + 1, self.data_width); + let x_size = x_max - x_min; + if x_size == 0 { + continue; + } + + let y_min = y * chunk_sizes[1]; + let y_max = std::cmp::min(y_min + chunk_sizes[1] + 1, self.data_height); + let y_size = y_max - y_min; + if y_size == 0 { + continue; + } + + let z_min = z * chunk_sizes[2]; + let z_max = std::cmp::min(z_min + chunk_sizes[2] + 1, self.data_depth); + let z_size = z_max - z_min; + if z_size == 0 { + continue; + } + let location = [x_min as f32, y_min as f32, z_min as f32]; + let mut chunk = C::new( + location, + x_size.try_into().unwrap(), + y_size.try_into().unwrap(), + z_size.try_into().unwrap(), + ); + + for i in x_min..x_max { + let c_i = i - x_min; + for j in y_min..y_max { + let c_j = j - y_min; + for k in z_min..z_max { + let c_k = k - z_min; + let idx = i + j * self.data_width + k * self.data_width * self.data_height; + chunk.set(c_i, c_j, c_k, self.data[idx]); + if let Some(&atlas) = self.atlas_data.get(idx) { + chunk.set_atlas(c_i, c_j, c_k, atlas); + } + } + } + } + + results.push(Chunked { + location, + scale: [1., 1., 1.], + chunk, + }) + } + } + } + self.results = results; + } + + /// + /// Gets the resulting chunks + /// + /// This should be called after `generate_chunks` + /// + /// # Returns + /// + /// returns a `Vec<& Chunked>` + /// + fn get_chunks(&self) -> Vec<&Chunked> { + self.results.iter().collect() + } + + /// + /// Gets the resulting chunks mutably + /// + /// This should be called after `generate_chunks` + /// + /// # Returns + /// + /// returns a `Vec<&mut Chunked>` + /// + fn get_chunks_mut(&mut self) -> Vec<&mut Chunked> { + self.results.iter_mut().collect() + } +} + +impl FlatChunker +where + C: Chunkify + ChunkifyMut + AtlasifyMut + Boxify, +{ + /// + /// Sets the size to use for this chunker + /// chuked size + /// + /// long description + /// + /// # Parameters + /// + /// * `size` - maximum size of generated chunks in `[u16; 3]` + /// + /// # Returns + /// + /// returns Self + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// use gaiku::common::prelude::*; + /// use gaiku::common::chunk::Chunk; + /// + /// let dimensions = [48, 48, 48]; + /// let data = vec![1.; dimensions[0] * dimensions[1] * dimensions[2]]; + /// + /// let mut chunker: FlatChunker = FlatChunker::from_array( + /// &data, + /// dimensions[0], + /// dimensions[1], + /// dimensions[2], + /// ); + /// chunker.set_chunk_size([16, 16, 16]); + /// + /// chunker.generate_chunks(); + /// let results = chunker.get_chunks(); + /// assert_eq!(results.len(), 27); + /// ``` + /// + pub fn set_chunk_size(&mut self, size: [u16; 3]) { + self.chunk_sizes = size; + } + + /// Chunk data into a fraction of its current size + /// + /// # Parameters + /// + /// * `fraction` - Should be a float between 0. and 1. + /// + /// # Returns + /// + /// returns Self + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// use gaiku::common::prelude::*; + /// use gaiku::common::chunk::Chunk; + /// + /// let dimensions = [48, 48, 48]; + /// let data = vec![1.; dimensions[0] * dimensions[1] * dimensions[2]]; + /// + /// let mut chunker: FlatChunker = FlatChunker::from_array( + /// &data, + /// dimensions[0], + /// dimensions[1], + /// dimensions[2], + /// ); + /// chunker.set_chunk_fraction([0.5, 0.5, 0.5]); + /// + /// chunker.generate_chunks(); + /// let results = chunker.get_chunks(); + /// assert_eq!(results.len(), 8); + /// ``` + /// + pub fn set_chunk_fraction(&mut self, fraction: [f32; 3]) { + let size: [u16; 3] = [ + (self.data_width as f32 * fraction[0]) as u16, + (self.data_height as f32 * fraction[1]) as u16, + (self.data_depth as f32 * fraction[2]) as u16, + ]; + self.set_chunk_size(size); + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::chunk::Chunk; + + #[test] + fn test_flat_chunker() { + let dimensions = [48, 48, 48]; + let data = vec![1.; dimensions[0] * dimensions[1] * dimensions[2]]; + + let mut chunker: FlatChunker = + FlatChunker::from_array(&data, dimensions[0], dimensions[1], dimensions[2]); + chunker.set_chunk_size([16, 16, 16]); + + chunker.generate_chunks(); + let results = chunker.get_chunks(); + + assert_eq!(results.len(), 27); + } +} diff --git a/crates/gaiku_common/src/chunker/lod.rs b/crates/gaiku_common/src/chunker/lod.rs new file mode 100644 index 0000000..2bcb0cf --- /dev/null +++ b/crates/gaiku_common/src/chunker/lod.rs @@ -0,0 +1,682 @@ +use super::common::*; +use crate::{ + atlas::AtlasifyMut, + boundary::Boundary, + boxify::Boxify, + chunk::{Chunkify, ChunkifyMut}, + interpolators::*, +}; +use glam::Vec3; + +/// +/// This chunker will create a LOD tree +/// +/// This is done using an octree +/// with greater detail at the deeper +/// leaves. +/// +/// In order to calculate the sample values +/// at arbitary resolution trilinear interpolation +/// is used. +/// +pub struct LodChunker { + /// The interpolator used to calculate the arbitary points + interpolator: TriLinear, + /// The tree that holds the data + tree: OctTree>, + /// The point we calculate the lod distances from + observation_point: Vec3, + /// The size in voxels of every generated chunk + chunk_sizes: [u16; 3], + /// The lod distance. + /// The hightest detail lod is distance from center of the leaf + /// is less than this distance + /// The second highest lod is twice this distance + /// The third highest lod is 4x this distance + /// The forth highest lod is 8x this distance etc + lod_distance: f32, +} + +impl Chunker for LodChunker +where + C: Chunkify + ChunkifyMut + AtlasifyMut + Boxify, +{ + /// + /// Chunks the data with atlas values + /// + /// The data needs to have the length equal to the + /// width * height * depth. But the atlas data does + /// not any missing values will likely be replaced with + /// defaults (usually zero) + /// + /// # Parameters + /// + /// * `data` - The source data for the values + /// + /// * `atlas_data` - The source data for the atlas values + /// + /// * `width` - width of the data + /// + /// * `height` - height of the data + /// + /// * `depth` - depth of the data + /// + /// # Returns + /// + /// returns description + /// + fn from_array_with_atlas( + data: &[f32], + atlas_data: &[u8], + width: usize, + height: usize, + depth: usize, + ) -> Self { + Self { + interpolator: TriLinear::from_array_with_atlas(data, atlas_data, width, height, depth), + observation_point: [0., 0., 0.].into(), + tree: OctTree::new( + Boundary::new( + &[0., 0., 0.].into(), + &[width as f32, height as f32, depth as f32].into(), + ), + 0, + ), + chunk_sizes: [16, 16, 16], + lod_distance: 16., + } + } + + /// + /// Generates the chunks from the source data + /// + /// The source data needs to be already setup + /// and ready before making this call + /// + /// This method is lazy and will only generate chunks + /// visible from the `observation_point` + /// + /// It will also not update chunks that have already been + /// generated. To force a reupdate of all chunks + /// call `reset_chunks` + /// + fn generate_chunks(&mut self) { + let root_size = self.tree.get_size(); + for leaf in + OctTreeVisibleIterMut::new(&mut self.tree, self.observation_point, self.lod_distance) + { + if leaf.get_data().is_none() { + // Need to update this leaf + let location = leaf.get_origin(); + let mut chunk = C::new( + location.into(), + self.chunk_sizes[0], + self.chunk_sizes[1], + self.chunk_sizes[2], + ); + let chunk_sizes_f32: Vec3 = [ + self.chunk_sizes[0] as f32, + self.chunk_sizes[1] as f32, + self.chunk_sizes[2] as f32, + ] + .into(); + let scale = leaf.get_size() / root_size; + + let delta = leaf.get_size() / (chunk_sizes_f32 - Vec3::one()); + for i in 0..self.chunk_sizes[0] as usize { + for j in 0..self.chunk_sizes[1] as usize { + for k in 0..self.chunk_sizes[2] as usize { + let ijk: Vec3 = [i as f32, j as f32, k as f32].into(); + let d_pos: Vec3 = delta * ijk; + let p_pos: Vec3 = location + d_pos; + if let Ok(value) = self.interpolator.get_value(p_pos.into()) { + chunk.set(i, j, k, value); + } + if let Ok(Some(atlas_value)) = self.interpolator.get_atlas_value(p_pos.into()) { + chunk.set_atlas(i, j, k, atlas_value); + } + } + } + } + + let data = Chunked { + location: location.into(), + scale: scale.into(), + chunk, + }; + leaf.set_data(data); + } + } + } + + /// + /// Gets the resulting chunks + /// + /// This should be called after `generate_chunks` + /// and only returns the visible chunks that have + /// been generated + /// + /// # Returns + /// + /// returns a `Vec<& Chunked>` + /// + fn get_chunks(&self) -> Vec<&Chunked> { + self + .visible_iter() + .map(|leaf| leaf.get_data()) + .flatten() + .collect() + } + + /// + /// Gets the resulting chunks mutably + /// + /// This should be called after `generate_chunks` + /// and only returns the visible chunks that have + /// been generated + /// + /// # Returns + /// + /// returns a `Vec<&mut Chunked>` + /// + fn get_chunks_mut(&mut self) -> Vec<&mut Chunked> { + self + .visible_iter_mut() + .map(|leaf| leaf.get_data_mut()) + .flatten() + .collect::>>() + } +} + +impl LodChunker +where + C: Chunkify + ChunkifyMut + AtlasifyMut + Boxify, +{ + /// + /// Sets the number of LODs + /// + /// A LOD tree starts with zero lods. If this is not called + /// then only the lowest resolution will be avaliable + /// + /// # Parameters + /// + /// * `levels` - The number of LOD levels to use + /// + pub fn set_lod_levels(&mut self, levels: usize) { + self.tree.resize_tree(levels); + } + + /// + /// Sets the distance that governs when the LOD will change + /// + /// The chosen LOD level (n) is calcaulted from + /// the distance (d) of the `observation_point` and `lod_distance` (l) + /// n = ⎣ln(d/l)/ln(2)⎦ + /// + /// This should equate to this: + /// The hightest detail lod less than `lod_distance` from center of the leaf + /// The second highest lod is twice this distance + /// The third highest lod is 4x this distance + /// The forth highest lod is 8x this distance etc + /// + /// # Parameters + /// + /// * `lod_distance` - The distance to use when increasing the LOD + /// + pub fn set_lod_distance(&mut self, lod_distance: f32) { + self.lod_distance = lod_distance; + } + + /// + /// This will change the chunk size that each LOD level has + /// + /// This will only change new chunks made after this point. + /// If you want to regenerate all chunks first call `reset_chunks` + /// + /// # Parameters + /// + /// * `size` - size + /// + pub fn set_chunk_size(&mut self, size: [u16; 3]) { + self.chunk_sizes = size; + } + + /// + /// This will clear all chunk data on all LODs + /// + pub fn reset_chunks(&mut self) { + self.tree.clear_data(); + } + + /// + /// Set the point to consider as the observation point + /// when computing the LODs + /// + /// # Parameters + /// + /// * `point` - The location to observe from + /// + pub fn set_observation_point(&mut self, point: [f32; 3]) { + self.observation_point = point.into(); + } + + /// Iter over all leafs in the tree + #[allow(dead_code)] + fn iter(&self) -> OctTreeIter<'_, Chunked> { + OctTreeIter::new(&self.tree) + } + + /// Iter over all leafs in the tree mutably + #[allow(dead_code)] + fn iter_mut(&mut self) -> OctTreeIterMut<'_, Chunked> { + OctTreeIterMut::new(&mut self.tree) + } + + /// Iter over all leafs in the tree that are visible + #[allow(dead_code)] + fn visible_iter(&self) -> OctTreeVisibleIter<'_, Chunked> { + OctTreeVisibleIter::new(&self.tree, self.observation_point, self.lod_distance) + } + + /// Iter over all leafs in the tree mutably that are visible + #[allow(dead_code)] + fn visible_iter_mut(&mut self) -> OctTreeVisibleIterMut<'_, Chunked> { + OctTreeVisibleIterMut::new(&mut self.tree, self.observation_point, self.lod_distance) + } +} + +/// +/// OctTree is the internal structure used to manage the +/// chunks. +/// +/// Each leaf and node holds data which will be the chunk. +/// +/// +struct OctTree { + value: OctTreeLeaf, + /// Octtree children with order + /// bottom_front_left + /// bottom_front_right + /// bottom_back_right + /// bottom_back_left + /// top_front_left + /// top_front_right + /// top_back_right + /// top_back_left + children: Vec>, +} + +impl OctTree { + /// Get the bounds (min, max) that this leaf encloses + fn get_bounds(&self) -> &Boundary { + self.value.get_bounds() + } + + /// Set the arbitary data for this leaf + #[allow(dead_code)] + fn set_data(&mut self, data: Data) { + self.value.set_data(data) + } + + /// Get the arbitary data for this leaf + #[allow(dead_code)] + fn get_data(&self) -> Option<&Data> { + self.value.get_data() + } + + /// Get the mutable arbitary data for this leaf + #[allow(dead_code)] + fn get_data_mut(&mut self) -> Option<&mut Data> { + self.value.get_data_mut() + } + + /// Get the center of this leaf + fn get_center(&self) -> Vec3 { + self.value.get_center() + } + + /// Get the size of this leaf + fn get_size(&self) -> Vec3 { + self.value.get_size() + } + + /// Get the origin (min) of the leaf + #[allow(dead_code)] + fn get_origin(&self) -> Vec3 { + self.value.get_origin() + } + + /// Get the lod level of this leaf. 0 is the highest detail + fn get_level(&self) -> usize { + self.value.get_level() + } + + /// Used to make the new children recursively + fn make_children(parent_bounds: Boundary, parent_level: usize) -> Vec> { + if parent_level > 0 { + let new_levels = parent_level - 1; + let (min, max) = (parent_bounds.min, parent_bounds.max); + let minx = min[0]; + let maxx = max[0]; + let half_x = (min[0] + max[0]) / 2.; + let miny = min[1]; + let maxy = max[1]; + let half_y = (min[1] + max[1]) / 2.; + let minz = min[2]; + let maxz = max[2]; + let half_z = (min[2] + max[2]) / 2.; + vec![ + OctTree::new( + Boundary::new(&[minx, miny, half_z].into(), &[half_x, half_y, maxz].into()), + new_levels, + ), + OctTree::new( + Boundary::new(&[half_x, miny, half_z].into(), &[maxx, half_y, maxz].into()), + new_levels, + ), + OctTree::new( + Boundary::new(&[half_x, miny, minz].into(), &[maxx, half_y, half_z].into()), + new_levels, + ), + OctTree::new( + Boundary::new(&[minx, miny, minz].into(), &[half_x, half_y, half_z].into()), + new_levels, + ), + OctTree::new( + Boundary::new(&[minx, half_y, half_z].into(), &[half_x, maxy, maxz].into()), + new_levels, + ), + OctTree::new( + Boundary::new(&[half_x, half_y, half_z].into(), &[maxx, maxy, maxz].into()), + new_levels, + ), + OctTree::new( + Boundary::new(&[half_x, half_y, minz].into(), &[maxx, maxy, half_z].into()), + new_levels, + ), + OctTree::new( + Boundary::new(&[minx, half_y, minz].into(), &[half_x, maxy, half_z].into()), + new_levels, + ), + ] + } else { + vec![] + } + } + + /// Create a new level of the tree. If levels > 0 then also create its children + /// bounds is the space this tree encloses + fn new(bounds: Boundary, levels: usize) -> OctTree { + let new_children = OctTree::make_children(bounds.clone(), levels); + let value = OctTreeLeaf::new(bounds, levels); + OctTree { + value, + children: new_children, + } + } + + /// This will change the tree such that it includes + /// the specified number of levels + fn resize_tree(&mut self, levels: usize) { + if self.get_level() == levels { + return; // No change + } else if self.children.is_empty() && levels > 0 { + // growing the tree from here + let bounds = Boundary::new(&self.get_bounds().min, &self.get_bounds().max); + let new_children = OctTree::make_children(bounds, levels); + self.children = new_children; + } else if levels == 0 { + // trim the tree here + self.children = vec![]; + } else { + for child in self.children.iter_mut() { + child.resize_tree(levels - 1); + } + } + self.value.level = levels; + } + + /// This will clear all data on all leafs + fn clear_data(&mut self) { + for child in self.children.iter_mut() { + child.clear_data(); + } + self.value.clear_data(); + } +} + +/// +/// This is the leaf data for an OctTree +/// +struct OctTreeLeaf { + /// Bounds represents the desired size of the domain in (min, max) + bounds: Boundary, + + /// Arbitary data for this LOD level + data: Option, + + /// LOD Level 0 is highest detail + level: usize, +} + +impl OctTreeLeaf { + /// Get the bounds this leaf encloses + fn get_bounds(&self) -> &Boundary { + &self.bounds + } + + /// Set the arbitary data of this leaf + fn set_data(&mut self, data: Data) { + self.data = Some(data); + } + + /// Set the arbitary data of this leaf + fn clear_data(&mut self) { + self.data = None; + } + + /// Get the arbitary data of this leaf + fn get_data(&self) -> Option<&Data> { + self.data.as_ref() + } + + /// Get the mutable arbitary data of this leaf + fn get_data_mut(&mut self) -> Option<&mut Data> { + self.data.as_mut() + } + + /// Get the center of the leaf + fn get_center(&self) -> Vec3 { + (self.bounds.min + self.bounds.max) / 2. + } + + /// Get the size of the leaf + fn get_size(&self) -> Vec3 { + self.bounds.max - self.bounds.min + } + + /// Gets the origin (min) of the leaf + fn get_origin(&self) -> Vec3 { + self.bounds.min + } + + /// Get the lod level of the leaf. 0 represents the highest detail + fn get_level(&self) -> usize { + self.level + } + + /// Create a new leaf without any arbitary data + fn new(bounds: Boundary, levels: usize) -> OctTreeLeaf { + let data: Option = None; + + OctTreeLeaf { + bounds, + data, + level: levels, + } + } +} + +/// This is the iter of a tree. +/// It visits every leaf +struct OctTreeIter<'a, Data> { + stack: Vec<&'a OctTree>, +} + +impl<'a, Data> OctTreeIter<'a, Data> { + fn new(tree: &'a OctTree) -> OctTreeIter<'a, Data> { + OctTreeIter { stack: vec![tree] } + } +} + +impl<'a, Data> Iterator for OctTreeIter<'a, Data> { + type Item = &'a OctTreeLeaf; + + fn next(&mut self) -> Option { + let node = self.stack.pop()?; + for child in node.children.iter() { + self.stack.push(child); + } + Some(&node.value) + } +} + +/// This is the mutable iter of a tree. +/// It visits every leaf +struct OctTreeIterMut<'a, Data> { + stack: Vec<&'a mut OctTree>, +} + +impl<'a, Data> OctTreeIterMut<'a, Data> { + fn new(tree: &'a mut OctTree) -> OctTreeIterMut<'a, Data> { + OctTreeIterMut { stack: vec![tree] } + } +} + +impl<'a, Data> Iterator for OctTreeIterMut<'a, Data> { + type Item = &'a mut OctTreeLeaf; + + fn next(&mut self) -> Option { + let node = self.stack.pop()?; + for child in node.children.iter_mut() { + self.stack.push(child); + } + Some(&mut node.value) + } +} + +/// This is the visible iter of a tree. +/// It visits only leafs that are visible +struct OctTreeVisibleIter<'a, Data> { + stack: Vec<&'a OctTree>, + camera_position: Vec3, + lod_distance: f32, +} + +impl<'a, Data> OctTreeVisibleIter<'a, Data> { + fn new( + tree: &'a OctTree, + camera_position: Vec3, + lod_distance: f32, + ) -> OctTreeVisibleIter<'a, Data> { + OctTreeVisibleIter { + stack: vec![tree], + camera_position, + lod_distance, + } + } +} + +impl<'a, Data> Iterator for OctTreeVisibleIter<'a, Data> { + type Item = &'a OctTreeLeaf; + + fn next(&mut self) -> Option { + loop { + let node = self.stack.pop()?; + if !node.children.is_empty() { + let center = node.get_center(); + let d = center.distance(self.camera_position); + let lod: usize = ((d / self.lod_distance).ln() / 2_f32.ln()).floor() as usize; + if node.get_level() <= lod { + return Some(&node.value); + } else { + for child in node.children.iter() { + self.stack.push(child); + } + } + } else { + return Some(&node.value); + } + } + } +} + +/// This is the mutable visible iter of a tree. +/// It visits only leafs that are visible +struct OctTreeVisibleIterMut<'a, Data> { + stack: Vec<&'a mut OctTree>, + camera_position: Vec3, + lod_distance: f32, +} + +impl<'a, Data> OctTreeVisibleIterMut<'a, Data> { + fn new( + tree: &'a mut OctTree, + camera_position: Vec3, + lod_distance: f32, + ) -> OctTreeVisibleIterMut<'a, Data> { + OctTreeVisibleIterMut { + stack: vec![tree], + camera_position, + lod_distance, + } + } +} + +impl<'a, Data> Iterator for OctTreeVisibleIterMut<'a, Data> { + type Item = &'a mut OctTreeLeaf; + + fn next(&mut self) -> Option { + loop { + let node = self.stack.pop()?; + if !node.children.is_empty() { + let center = node.get_center(); + let d = center.distance(self.camera_position); + let lod: usize = ((d / self.lod_distance).ln() / 2_f32.ln()).floor() as usize; + if node.get_level() <= lod { + return Some(&mut node.value); + } else { + for child in node.children.iter_mut() { + self.stack.push(child); + } + } + } else { + return Some(&mut node.value); + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::chunk::Chunk; + + #[test] + fn test_lod_chunker() { + let dimensions = [48, 48, 48]; + let data = vec![1.; dimensions[0] * dimensions[1] * dimensions[2]]; + + let mut chunker: LodChunker = + LodChunker::from_array(&data, dimensions[0], dimensions[1], dimensions[2]); + chunker.set_chunk_size([16, 16, 16]); + chunker.set_lod_distance(32.); + chunker.set_observation_point([10., 1., -1.]); + chunker.set_lod_levels(2); + + chunker.generate_chunks(); + let results = chunker.get_chunks(); + + assert_eq!(results.len(), 64); + } +} diff --git a/crates/gaiku_common/src/chunker/mod.rs b/crates/gaiku_common/src/chunker/mod.rs new file mode 100644 index 0000000..63a15e8 --- /dev/null +++ b/crates/gaiku_common/src/chunker/mod.rs @@ -0,0 +1,9 @@ +//! The `chunker` module contains structures +//! that will seperate data input into +//! multiple chunks. +//! +mod common; +mod flat; +mod lod; + +pub use self::{common::*, flat::FlatChunker, lod::LodChunker}; diff --git a/crates/gaiku_common/src/interpolators/common.rs b/crates/gaiku_common/src/interpolators/common.rs new file mode 100644 index 0000000..bfacdd6 --- /dev/null +++ b/crates/gaiku_common/src/interpolators/common.rs @@ -0,0 +1,195 @@ +use crate::{atlas::Atlasify, boundary::Boundary, boxify::Sizable, chunk::Chunkify}; +use std::convert::TryInto; +use thiserror::Error; + +/// Errors that the interpolator can raise +#[derive(Error, Debug)] +pub enum InterpolaterError { + /// Interpolators can only approximate values inside its bounds + #[error("the requested point {point:?} is out of bounds {bounds:?}")] + OutOfBounds { point: [f32; 3], bounds: Boundary }, + /// Used for any other error a trait might need to raise + #[error("the following error occured: {0}")] + Other(String), +} + +/// Interpolater trait describes the generic +/// interface for the interpolating methods +pub trait Interpolater { + /// Creates an interpolator from a chunk + /// + /// # Arguments + /// + /// * `chunk` - The chunk to load the sample data from. Data is copied + /// + fn from_chunk(chunk: &D) -> Self + where + D: Chunkify + Atlasify + Sizable, + Self: Sized, + { + let width = chunk.width(); + let height = chunk.height(); + let depth = chunk.depth(); + let mut data = vec![]; + let mut atlas_data = vec![]; + for x in 0..width { + for y in 0..height { + for z in 0..depth { + data.push(chunk.get(x.into(), y.into(), z.into())); + atlas_data.push(chunk.get_atlas(x.into(), y.into(), z.into())); + } + } + } + + Self::from_array_with_atlas( + data.as_slice(), + atlas_data.as_slice(), + width.try_into().unwrap(), + height.try_into().unwrap(), + depth.try_into().unwrap(), + ) + } + + /// + /// Create an interpolator from an array of Data + /// + /// The length of the array should match the width*height*depth + /// + /// # Parameters + /// + /// * `data` - The input data samples. These should be on a flattened grid of width x height x depth + /// + /// * `width` - width of data samples + /// + /// * `height` - height of data samples + /// + /// * `depth` - depth of data samples + /// + /// # Returns + /// + /// returns an Interpolator + /// + fn from_array(data: &[T], width: usize, height: usize, depth: usize) -> Self + where + Self: Sized, + { + Self::from_array_with_atlas(data, &[], width, height, depth) + } + + /// + /// Creates an interpolator with both interpolated values and atlases + /// + /// The length of values should equate to width*height*depth + /// The length of atlas_data should also be the same as the values + /// but in the event it is not the atlas will return None at that point + /// + /// # Parameters + /// + /// * `data` - The input value samples arranged on a flattened grid of width x height x depth + /// + /// * `atlas_data` - The input atlas values samples also arranged on a flattened grid. + /// + /// * `width` - width of sample data + /// + /// * `height` - height of sample data + /// + /// * `depth` - depth of sample data + /// + /// # Returns + /// + /// returns an Interpolater + /// + fn from_array_with_atlas( + data: &[T], + atlas_data: &[U], + width: usize, + height: usize, + depth: usize, + ) -> Self + where + Self: Sized; + + /// + /// The boundary for which the interpolation is valid + /// + /// Interpolation is not the same as extrapolation + /// The data must be contained within the samples + /// OutOfBounds + /// + /// # Returns + /// + /// A `Boundary` which extends over the samples domain + an `EPSILON` + /// + fn get_boundary(&self) -> Boundary; + + /// + /// Get the raw data sample + /// + /// This returns the value at a grid point uninterpolated. + /// + /// # Parameters + /// + /// * `point` - The position as a `[usize; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK sample value at grid point + /// - Err An `InterpolaterError` + /// + fn get_sample(&self, point: [usize; 3]) -> Result; + + /// + /// Get the interpolated value + /// + /// This gets the interpolated value the `point` must be in bounds. + /// + /// # Parameters + /// + /// * `point` - The point to get the interpolated value as `[f32; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK interpolated value at point + /// - Err An `InterpolaterError` + /// + fn get_value(&self, point: [f32; 3]) -> Result; + + /// + /// Get the raw atlas sample + /// + /// This returns the atlas value at a grid point uninterpolated. + /// + /// # Parameters + /// + /// * `point` - The position as a `[usize; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK atlas sample value at grid point + /// - Err An `InterpolaterError` + /// + fn get_atlas_sample(&self, point: [usize; 3]) -> Result, InterpolaterError>; + + /// + /// Get the interpolated atlas value + /// + /// This gets the interpolated atlas value the `point` must be in bounds. + /// + /// In most cases this will simply be nearest neighbour as atlas values + /// cannot typically be interpolated + /// + /// # Parameters + /// + /// * `point` - The point to get the interpolated atlas value as `[f32; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK interpolated atlas value at point + /// - Err An `InterpolaterError` + /// + fn get_atlas_value(&self, point: [f32; 3]) -> Result, InterpolaterError>; +} diff --git a/crates/gaiku_common/src/interpolators/mod.rs b/crates/gaiku_common/src/interpolators/mod.rs new file mode 100644 index 0000000..8ebd1ba --- /dev/null +++ b/crates/gaiku_common/src/interpolators/mod.rs @@ -0,0 +1,13 @@ +//! The interpolation methods +//! +//! Interpolaters are structures designed to +//! calculated values off of the usual grid +//! points. They can include smoothing and +//! are typically used to calculate LODs +//! at higher reolutions then the input data +//! +mod common; +mod nearestneighbour; +mod trilinear; + +pub use self::{common::*, nearestneighbour::NearestNeighbour, trilinear::TriLinear}; diff --git a/crates/gaiku_common/src/interpolators/nearestneighbour.rs b/crates/gaiku_common/src/interpolators/nearestneighbour.rs new file mode 100644 index 0000000..4a36a4c --- /dev/null +++ b/crates/gaiku_common/src/interpolators/nearestneighbour.rs @@ -0,0 +1,270 @@ +use super::{Interpolater, InterpolaterError}; +use crate::boundary::Boundary; + +const EPSILON: f32 = 1e-4; + +/// +/// This interpolator simply returns the sample nearest +/// the requested point. +/// +pub struct NearestNeighbour { + data: Vec, + atlas_data: Vec, + dimensions: [usize; 3], +} + +impl Interpolater for NearestNeighbour { + /// + /// Creates a NearestNeighbour with both interpolated values and atlases + /// + /// This interpolator simple returns the sample data nearest the specified + /// point. + /// + /// The length of values should equate to width*height*depth + /// The length of atlas_data should also be the same as the values + /// but in the event it is not the atlas will return None at that point + /// + /// # Parameters + /// + /// * `data` - The input value samples arranged on a flattened grid of width x height x depth + /// + /// * `atlas_data` - The input atlas values samples also arranged on a flattened grid. + /// + /// * `width` - width of sample data + /// + /// * `height` - height of sample data + /// + /// * `depth` - depth of sample data + /// + /// # Returns + /// + /// returns a NearestNeighbour + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// # extern crate rand; + /// use gaiku::common::prelude::*; + /// use rand::Rng; + /// let mut rng = rand::thread_rng(); + /// + /// let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// let interpolator = NearestNeighbour::from_array_with_atlas( + /// &samples, + /// &atlas_samples, + /// 3, + /// 3, + /// 3, + /// ); + /// ``` + /// + fn from_array_with_atlas( + data: &[f32], + atlas_data: &[u8], + width: usize, + height: usize, + depth: usize, + ) -> Self { + Self { + data: data.to_vec(), + atlas_data: atlas_data.to_vec(), + dimensions: [width, height, depth], + } + } + + /// + /// Get's the boundary of the interpolation + /// + /// Interpolation cannot return values outside + /// of its sample range. This method will + /// inform you what those boundaries are. + /// + /// # Returns + /// + /// returns a Boundary bouding the sample data + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// # extern crate rand; + /// # use gaiku::common::prelude::*; + /// # use rand::Rng; + /// # let mut rng = rand::thread_rng(); + /// # let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// # let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// # let interpolator = NearestNeighbour::from_array_with_atlas( + /// # &samples, + /// # &atlas_samples, + /// # 3, + /// # 3, + /// # 3, + /// # ); + /// let boundary = interpolator.get_boundary(); + /// assert!(boundary.contains(&[1., 1., 2.].into())); + /// ``` + /// + fn get_boundary(&self) -> Boundary { + Boundary::new( + &[-EPSILON, -EPSILON, -EPSILON].into(), + &[ + self.dimensions[0] as f32 + EPSILON, + self.dimensions[1] as f32 + EPSILON, + self.dimensions[2] as f32 + EPSILON, + ] + .into(), + ) + } + + /// + /// Get the raw data sample + /// + /// This returns the value at a grid point uninterpolated. + /// + /// # Parameters + /// + /// * `point` - The position as a `[usize; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK sample value at grid point + /// - Err An `InterpolaterError` + /// + fn get_sample(&self, point: [usize; 3]) -> Result { + let idx = + point[0] + point[1] * self.dimensions[0] + point[2] * self.dimensions[0] * self.dimensions[1]; + Ok(self.data[idx]) + } + + /// + /// Get the interpolated value + /// + /// This gets the interpolated value the `point` must be in bounds. + /// + /// # Parameters + /// + /// * `point` - The point to get the interpolated value as `[f32; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK interpolated value at point + /// - Err An `InterpolaterError` + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// # extern crate rand; + /// # use gaiku::common::prelude::*; + /// # use rand::Rng; + /// # let mut rng = rand::thread_rng(); + /// # let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// # let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// # let interpolator = NearestNeighbour::from_array_with_atlas( + /// # &samples, + /// # &atlas_samples, + /// # 3, + /// # 3, + /// # 3, + /// # ); + /// let value = interpolator.get_value([0.25, 0.5, 1.]); + /// ``` + /// + fn get_value(&self, point: [f32; 3]) -> Result { + let boundary = self.get_boundary(); + if !boundary.contains(&point.into()) { + return Err(InterpolaterError::OutOfBounds { + bounds: boundary, + point, + }); + } + + // Nearest point can be found by shifting the coordinates + let i = (point[0] + 0.5) as usize; + let j = (point[1] + 0.5) as usize; + let k = (point[2] + 0.5) as usize; + + self.get_sample([i, j, k]) + } + + /// + /// Get the raw atlas sample + /// + /// This returns the atlas value at a grid point uninterpolated. + /// + /// # Parameters + /// + /// * `point` - The position as a `[usize; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK atlas sample value at grid point + /// - Err An `InterpolaterError` + /// + fn get_atlas_sample(&self, point: [usize; 3]) -> Result, InterpolaterError> { + let idx = + point[0] + point[1] * self.dimensions[0] + point[2] * self.dimensions[0] * self.dimensions[1]; + Ok(self.atlas_data.get(idx).copied()) + } + + /// + /// Get the interpolated atlas value + /// + /// This gets the interpolated atlas value the `point` must be in bounds. + /// + /// In most cases this will simply be nearest neighbour as atlas values + /// cannot typically be interpolated + /// + /// # Parameters + /// + /// * `point` - The point to get the interpolated atlas value as `[f32; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK interpolated atlas value at point + /// - Err An `InterpolaterError` + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate assert_matches; + /// # extern crate gaiku; + /// # extern crate rand; + /// # use gaiku::common::prelude::*; + /// # use rand::Rng; + /// # let mut rng = rand::thread_rng(); + /// # let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// # let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// # let interpolator = NearestNeighbour::from_array_with_atlas( + /// # &samples, + /// # &atlas_samples, + /// # 3, + /// # 3, + /// # 3, + /// # ); + /// let atlas_value = interpolator.get_atlas_value([0.25, 0.5, 1.]); + /// assert_matches!(atlas_value, Ok(Some(_))); + /// ``` + fn get_atlas_value(&self, point: [f32; 3]) -> Result, InterpolaterError> { + let boundary = self.get_boundary(); + if !boundary.contains(&point.into()) { + return Err(InterpolaterError::OutOfBounds { + bounds: boundary, + point, + }); + } + + // Nearest point can be found by shifting the coordinates + let i = (point[0] + 0.5) as usize; + let j = (point[1] + 0.5) as usize; + let k = (point[2] + 0.5) as usize; + + self.get_atlas_sample([i, j, k]) + } +} diff --git a/crates/gaiku_common/src/interpolators/trilinear.rs b/crates/gaiku_common/src/interpolators/trilinear.rs new file mode 100644 index 0000000..ce76e0c --- /dev/null +++ b/crates/gaiku_common/src/interpolators/trilinear.rs @@ -0,0 +1,415 @@ +use super::{Interpolater, InterpolaterError}; +use crate::boundary::Boundary; +use glam::Vec3; + +const EPSILON: f32 = 1e-4; + +/// +/// This interpolator simply returns the sample nearest +/// the requested point. +/// +pub struct TriLinear { + data: Vec, + atlas_data: Vec, + dimensions: [usize; 3], +} + +/// +/// This interpolator uses linear interpolation for the samples +/// and nearest neighbour for the atlas values. +/// +impl Interpolater for TriLinear { + /// + /// Creates a TriLinear with both interpolated values and atlases + /// + /// This interpolator will use linear interpolation on 3d + /// for the samples. + /// + /// It will use nearestneighbour for the atlas samples. + /// + /// The length of values should equate to width*height*depth + /// The length of atlas_data should also be the same as the values + /// but in the event it is not the atlas will return None at that point + /// + /// # Parameters + /// + /// * `data` - The input value samples arranged on a flattened grid of width x height x depth + /// + /// * `atlas_data` - The input atlas values samples also arranged on a flattened grid. + /// + /// * `width` - width of sample data + /// + /// * `height` - height of sample data + /// + /// * `depth` - depth of sample data + /// + /// # Returns + /// + /// returns a TriLinear + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// # extern crate rand; + /// use gaiku::common::prelude::*; + /// use rand::Rng; + /// let mut rng = rand::thread_rng(); + /// + /// let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// let interpolator = TriLinear::from_array_with_atlas( + /// &samples, + /// &atlas_samples, + /// 3, + /// 3, + /// 3, + /// ); + /// ``` + /// + fn from_array_with_atlas( + data: &[f32], + atlas_data: &[u8], + width: usize, + height: usize, + depth: usize, + ) -> Self { + Self { + data: data.to_vec(), + atlas_data: atlas_data.to_vec(), + dimensions: [width, height, depth], + } + } + + /// + /// Get's the boundary of the interpolation + /// + /// Interpolation cannot return values outside + /// of its sample range. This method will + /// inform you what those boundaries are. + /// + /// # Returns + /// + /// returns a Boundary bouding the sample data + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// # extern crate rand; + /// # use gaiku::common::prelude::*; + /// # use rand::Rng; + /// # let mut rng = rand::thread_rng(); + /// # let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// # let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// # let interpolator = TriLinear::from_array_with_atlas( + /// # &samples, + /// # &atlas_samples, + /// # 3, + /// # 3, + /// # 3, + /// # ); + /// let boundary = interpolator.get_boundary(); + /// assert!(boundary.contains(&[1., 1., 2.].into())); + /// ``` + /// + fn get_boundary(&self) -> Boundary { + Boundary::new( + &[-EPSILON, -EPSILON, -EPSILON].into(), + &[ + self.dimensions[0] as f32 + EPSILON, + self.dimensions[1] as f32 + EPSILON, + self.dimensions[2] as f32 + EPSILON, + ] + .into(), + ) + } + + /// + /// Get the raw data sample + /// + /// This returns the value at a grid point uninterpolated. + /// + /// # Parameters + /// + /// * `point` - The position as a `[usize; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK sample value at grid point + /// - Err An `InterpolaterError` + /// + fn get_sample(&self, point: [usize; 3]) -> Result { + let idx = + point[0] + point[1] * self.dimensions[0] + point[2] * self.dimensions[0] * self.dimensions[1]; + Ok(self.data[idx]) + } + + /// + /// Get the interpolated value + /// + /// This gets the interpolated value the `point` must be in bounds. + /// + /// # Parameters + /// + /// * `point` - The point to get the interpolated value as `[f32; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK interpolated value at point + /// - Err An `InterpolaterError` + /// + /// # Examples + /// + /// ``` + /// # extern crate gaiku; + /// # extern crate rand; + /// # use gaiku::common::prelude::*; + /// # use rand::Rng; + /// # let mut rng = rand::thread_rng(); + /// # let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// # let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// # let interpolator = TriLinear::from_array_with_atlas( + /// # &samples, + /// # &atlas_samples, + /// # 3, + /// # 3, + /// # 3, + /// # ); + /// let value = interpolator.get_value([0.25, 0.5, 1.]); + /// ``` + /// + fn get_value(&self, point: [f32; 3]) -> Result { + let point: Vec3 = point.into(); + + // Boundary check + let boundary = self.get_boundary(); + if !boundary.contains(&point) { + return Err(InterpolaterError::OutOfBounds { + bounds: boundary, + point: point.into(), + }); + } + + // Ensure we are in range! + // this should change any rounding error -0.0002 into 0. + // that the above bounary check dosen't reject + let point: Vec3 = [ + point[0].clamp(0., (self.dimensions[0] - 1) as f32), + point[1].clamp(0., (self.dimensions[1] - 1) as f32), + point[2].clamp(0., (self.dimensions[2] - 1) as f32), + ] + .into(); + + // Grid cell can be found by flooring + let grid_origin: Vec3 = point.floor(); + + // Nearest neighbour can be found by a shift and a floor + let nearest_neighbour = (point + Vec3::from([0.5, 0.5, 0.5])).floor(); + + // Are we close enough to a nearest neighbour? + if nearest_neighbour.distance(point) < EPSILON { + return self.get_sample([ + nearest_neighbour[0] as usize, + nearest_neighbour[1] as usize, + nearest_neighbour[2] as usize, + ]); + } + + // Get the sample coords of the grid + let i = grid_origin[0] as usize; + let j = grid_origin[1] as usize; + let k = grid_origin[2] as usize; + + let cell_coord = point - grid_origin; + + // There a few edge cases here + // + // we want a cell of 8 points at + // 000 + // 100 + // 110 + // 010 + // 001 + // 101 + // 111 + // 011 + // + // However some of those points will be out of bounds + // at the edges + // + // In these cases we just want to do the 2d/1d Interpolation + // rather than the 3d + // + + let i_limit = self.dimensions[0] - 1; + let j_limit = self.dimensions[1] - 1; + let k_limit = self.dimensions[2] - 1; + + let result = if i == i_limit && j == j_limit && k == k_limit { + // xyz maxima case (this should be caught by the above check anyways) + self.get_sample([i, j, k])? + } else if i == i_limit && j == j_limit { + // xy maxima case + let f000 = self.get_sample([i, j, k])?; + let f001 = self.get_sample([i, j, k + 1])?; + let z_sample = cell_coord[2]; + f000 * (1. - z_sample) + f001 * z_sample + } else if i == i_limit && k == k_limit { + // xz maxima case + let f000 = self.get_sample([i, j, k])?; + let f010 = self.get_sample([i, j + 1, k])?; + let y_sample = cell_coord[1]; + f000 * (1. - y_sample) + f010 * (y_sample) + } else if j == j_limit && k == k_limit { + // yz maxima case + let f000 = self.get_sample([i, j, k])?; + let f100 = self.get_sample([i + 1, j, k])?; + let x_sample = cell_coord[0]; + f000 * (1. - x_sample) + f100 * (x_sample) + } else if i == i_limit { + // x maxima case + let f000 = self.get_sample([i, j, k])?; + let f001 = self.get_sample([i, j, k + 1])?; + let f010 = self.get_sample([i, j + 1, k])?; + let f011 = self.get_sample([i, j + 1, k + 1])?; + let y_sample = cell_coord[1]; + let z_sample = cell_coord[2]; + f000 * (1. - y_sample) * (1. - z_sample) + + f001 * (1. - y_sample) * z_sample + + f010 * (y_sample) * (1. - z_sample) + + f011 * (y_sample) * (z_sample) + } else if j == j_limit { + // y maxima case + let f000 = self.get_sample([i, j, k])?; + let f001 = self.get_sample([i, j, k + 1])?; + let f100 = self.get_sample([i + 1, j, k])?; + let f101 = self.get_sample([i + 1, j, k + 1])?; + let x_sample = cell_coord[0]; + let z_sample = cell_coord[2]; + f000 * (1. - x_sample) * (1. - z_sample) + + f001 * (1. - x_sample) * z_sample + + f100 * (x_sample) * (1. - z_sample) + + f101 * (x_sample) * (z_sample) + } else if k == k_limit { + // z maxima case + let f000 = self.get_sample([i, j, k])?; + let f010 = self.get_sample([i, j + 1, k])?; + let f100 = self.get_sample([i + 1, j, k])?; + let f110 = self.get_sample([i + 1, j + 1, k])?; + let x_sample = cell_coord[0]; + let y_sample = cell_coord[1]; + f000 * (1. - x_sample) * (1. - y_sample) + + f010 * (1. - x_sample) * (y_sample) + + f100 * (x_sample) * (1. - y_sample) + + f110 * (x_sample) * (y_sample) + } else if i < i_limit && j < j_limit && k < k_limit { + // normal case 3d case + let f000 = self.get_sample([i, j, k])?; + let f001 = self.get_sample([i, j, k + 1])?; + let f010 = self.get_sample([i, j + 1, k])?; + let f100 = self.get_sample([i + 1, j, k])?; + let f011 = self.get_sample([i, j + 1, k + 1])?; + let f101 = self.get_sample([i + 1, j, k + 1])?; + let f110 = self.get_sample([i + 1, j + 1, k])?; + let f111 = self.get_sample([i + 1, j + 1, k + 1])?; + let x_sample = cell_coord[0]; + let y_sample = cell_coord[1]; + let z_sample = cell_coord[2]; + f000 * (1. - x_sample) * (1. - y_sample) * (1. - z_sample) + + f001 * (1. - x_sample) * (1. - y_sample) * z_sample + + f010 * (1. - x_sample) * (y_sample) * (1. - z_sample) + + f100 * (x_sample) * (1. - y_sample) * (1. - z_sample) + + f011 * (1. - x_sample) * (y_sample) * (z_sample) + + f101 * (x_sample) * (1. - y_sample) * (z_sample) + + f110 * (x_sample) * (y_sample) * (1. - z_sample) + + f111 * (x_sample) * (y_sample) * (z_sample) + } else { + return Err(InterpolaterError::OutOfBounds { + point: point.into(), + bounds: self.get_boundary(), + }); + }; + + Ok(result) + } + + /// + /// Get the raw atlas sample + /// + /// This returns the atlas value at a grid point uninterpolated. + /// + /// # Parameters + /// + /// * `point` - The position as a `[usize; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK atlas sample value at grid point + /// - Err An `InterpolaterError` + /// + fn get_atlas_sample(&self, point: [usize; 3]) -> Result, InterpolaterError> { + let idx = + point[0] + point[1] * self.dimensions[0] + point[2] * self.dimensions[0] * self.dimensions[1]; + Ok(self.atlas_data.get(idx).copied()) + } + + /// + /// Get the interpolated atlas value + /// + /// This gets the interpolated atlas value the `point` must be in bounds. + /// + /// In most cases this will simply be nearest neighbour as atlas values + /// cannot typically be interpolated + /// + /// # Parameters + /// + /// * `point` - The point to get the interpolated atlas value as `[f32; 3]` + /// + /// # Returns + /// + /// A `Result` that is either + /// - OK interpolated atlas value at point + /// - Err An `InterpolaterError` + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate assert_matches; + /// # extern crate gaiku; + /// # extern crate rand; + /// # use gaiku::common::prelude::*; + /// # use rand::Rng; + /// # let mut rng = rand::thread_rng(); + /// # let samples: Vec = (0..27).map(|_| rng.gen_range((-10.)..(10.))).collect(); + /// # let atlas_samples: Vec = (0..27).map(|_| rng.gen_range(0..10)).collect(); + /// # let interpolator = TriLinear::from_array_with_atlas( + /// # &samples, + /// # &atlas_samples, + /// # 3, + /// # 3, + /// # 3, + /// # ); + /// let atlas_value = interpolator.get_atlas_value([0.25, 0.5, 1.]); + /// assert_matches!(atlas_value, Ok(Some(_))); + /// ``` + fn get_atlas_value(&self, point: [f32; 3]) -> Result, InterpolaterError> { + let boundary = self.get_boundary(); + if !boundary.contains(&point.into()) { + return Err(InterpolaterError::OutOfBounds { + bounds: boundary, + point, + }); + } + + // Nearest point can be found by shifting the coordinates + let i = (point[0] + 0.5) as usize; + let j = (point[1] + 0.5) as usize; + let k = (point[2] + 0.5) as usize; + + self.get_atlas_sample([i, j, k]) + } +} diff --git a/crates/gaiku_common/src/lib.rs b/crates/gaiku_common/src/lib.rs index 5b9baa6..a2ab633 100644 --- a/crates/gaiku_common/src/lib.rs +++ b/crates/gaiku_common/src/lib.rs @@ -23,12 +23,16 @@ mod boundary; pub mod boxify; /// Chunk implementation, also offers all traits used internally to build the chunk object. pub mod chunk; +/// Chunker holds structures for breaking up data into chunks +pub mod chunker; +/// Interpolates data for off grid values and gradients +pub mod interpolators; /// Mesh related traits/implementation, also offers some utils like MeshBuilder. pub mod mesh; +/// For the mesh builders that help convert faces into a mesh +pub mod meshbuilder; /// Texture related traits/implementation. pub mod texture; -// For the mesh builders that help convert faces into a mesh -pub mod meshbuilder; /// `use gaiku_common::prelude::*;` to import common traits and utils. pub mod prelude { @@ -36,6 +40,8 @@ pub mod prelude { atlas::{Atlasify, AtlasifyMut}, boxify::*, chunk::{Chunkify, ChunkifyMut}, + chunker::*, + interpolators::*, mesh::Meshify, meshbuilder::*, texture::{TextureAtlas2d, Texturify2d}, diff --git a/crates/gaiku_format_gox/src/lib.rs b/crates/gaiku_format_gox/src/lib.rs index b87c26d..b3d9b69 100644 --- a/crates/gaiku_format_gox/src/lib.rs +++ b/crates/gaiku_format_gox/src/lib.rs @@ -16,10 +16,8 @@ impl FileFormat for GoxReader { C: Chunkify + ChunkifyMut + AtlasifyMut + Boxify, T: Texturify2d, { - type Coord = usize; let gox = Gox::from_bytes(bytes, vec![Only::Layers, Only::Blocks]); let mut colors: Vec<[u8; 4]> = Vec::with_capacity(255); - let mut result = vec![]; let mut block_data: Vec<&Block> = vec![]; for data in gox.data.iter() { @@ -40,55 +38,28 @@ impl FileFormat for GoxReader { } } } - let init_coord = starts[0]; + let gox_chunk_size = [16, 16, 16]; let min = [ - starts - .iter() - .fold(init_coord[0], |acc, c| if c[0] < acc { c[0] } else { acc }), - starts - .iter() - .fold(init_coord[1], |acc, c| if c[1] < acc { c[1] } else { acc }), - starts - .iter() - .fold(init_coord[2], |acc, c| if c[2] < acc { c[2] } else { acc }), + starts.iter().map(|v| v[0]).min().unwrap(), + starts.iter().map(|v| v[1]).min().unwrap(), + starts.iter().map(|v| v[2]).min().unwrap(), ]; let max = [ - starts.iter().fold(init_coord[0] + 16, |acc, c| { - if c[0] + 16 > acc { - c[0] + 16 - } else { - acc - } - }), - starts.iter().fold(init_coord[1] + 16, |acc, c| { - if c[1] + 16 > acc { - c[1] + 16 - } else { - acc - } - }), - starts.iter().fold(init_coord[2] + 16, |acc, c| { - if c[2] + 16 > acc { - c[2] + 16 - } else { - acc - } - }), + starts.iter().map(|v| v[0]).max().unwrap() + gox_chunk_size[0], + starts.iter().map(|v| v[1]).max().unwrap() + gox_chunk_size[1], + starts.iter().map(|v| v[2]).max().unwrap() + gox_chunk_size[2], ]; - let chunk_size: [Coord; 3] = [ + let data_dim: [usize; 3] = [ (max[0] - min[0] + 1).try_into().unwrap(), (max[1] - min[1] + 1).try_into().unwrap(), (max[2] - min[2] + 1).try_into().unwrap(), ]; + let data_size = data_dim[0] * data_dim[1] * data_dim[2]; - let mut chunk = C::new( - [(min[0]) as f32, (min[2]) as f32, (min[1]) as f32], - chunk_size[0].try_into().unwrap(), - chunk_size[2].try_into().unwrap(), // goxel is in y up gaiku in z up - chunk_size[1].try_into().unwrap(), - ); + let mut values = vec![-1.; data_size]; + let mut atlas_values = vec![0; data_size]; for data in gox.data.iter() { if let Data::Layers(layers, _bounds) = &data { @@ -96,18 +67,21 @@ impl FileFormat for GoxReader { if !layer.blocks.is_empty() { for data in layer.blocks.iter() { let block_colors = block_data[data.block_index]; - let origin: [Coord; 3] = [ + let origin: [usize; 3] = [ (data.x - min[0]).try_into().unwrap(), (data.y - min[1]).try_into().unwrap(), (data.z - min[2]).try_into().unwrap(), ]; + // println!("===="); + // println!("Origin: {:?}", origin); + for x in 0..16 { - let x_c = x as Coord + origin[0]; + let x_c = x + origin[0]; for y in 0..16 { - let y_c = y as Coord + origin[1]; + let y_c = y + origin[1]; for z in 0..16 { - let z_c = z as Coord + origin[2]; + let z_c = z + origin[2]; if !block_colors.is_empty(x, y, z) { let color = block_colors.get_pixel(x, y, z); let index = if let Some((index, _)) = @@ -125,8 +99,12 @@ impl FileFormat for GoxReader { }; if index <= std::u8::MAX as usize { - chunk.set(x_c, z_c, y_c, 1.); // goxel is in y up gaiku in zup - chunk.set_atlas(x_c, z_c, y_c, index as Self::AtlasValue); + // Swap y and z axis + // Gox is in z up + // Gaiku in y up + let idx = x_c + z_c * data_dim[0] + y_c * data_dim[2] * data_dim[0]; + values[idx] = 1.; + atlas_values[idx] = index as Self::AtlasValue } } } @@ -138,7 +116,24 @@ impl FileFormat for GoxReader { } } - result.push(chunk); + let mut chunker: FlatChunker = FlatChunker::from_array_with_atlas( + values.as_slice(), + atlas_values.as_slice(), + data_dim[0], + data_dim[2], // Swap y and z axis + data_dim[1], // Gox is in z up + // Gaiku in y up + ); + chunker.set_chunk_size([16, 16, 16]); + chunker.generate_chunks(); + let mut chunked = chunker.get_chunks_mut(); + + // Because we don't assume clone we take ownership by swapping with some default + // we can do this because we don't want to use chunker of chunked again + let result: Vec = chunked + .iter_mut() + .map(|c| std::mem::replace(&mut c.chunk, C::new([0., 0., 0.], 0, 0, 0))) + .collect(); if !colors.is_empty() { let mut atlas = TextureAtlas2d::new(1); diff --git a/integrations/gaiku_amethyst/Cargo.toml b/integrations/gaiku_amethyst/Cargo.toml index 8037bc9..da363ee 100644 --- a/integrations/gaiku_amethyst/Cargo.toml +++ b/integrations/gaiku_amethyst/Cargo.toml @@ -28,9 +28,16 @@ features = ["metal"] name = "terrain" path = "examples/terrain.rs" +[[example]] +name = "lod" +path = "examples/lod.rs" + [dev-dependencies] amethyst = "0.15.3" gaiku_baker_voxel = { path = "../../crates/gaiku_baker_voxel", version = "0.1.0" } gaiku_baker_marching_cubes = { path = "../../crates/gaiku_baker_marching_cubes", version = "0.1.0" } gaiku_baker_modified_marching_cubes = { path = "../../crates/gaiku_baker_modified_marching_cubes", version = "0.1.0" } gaiku_format_gox = { path = "../../crates/gaiku_format_gox", version = "0.1.0" } +glam = { version = "^0.12.0 ", features = ["mint"] } +noise = "0.7.0" +rand = "0.8.4" diff --git a/integrations/gaiku_amethyst/examples/lod.rs b/integrations/gaiku_amethyst/examples/lod.rs new file mode 100644 index 0000000..d917b0d --- /dev/null +++ b/integrations/gaiku_amethyst/examples/lod.rs @@ -0,0 +1,540 @@ +//! Gaiku Amethyst LOD +//! +//! A small demo of gaiku-amethust +//! This uses the LOD chunker to make a large terrain + +const RANGE: f32 = 2000.; // meters in all dimensions +const RESOLUTION: f32 = 0.01; // noise sample per meter + +// const RANGE: f32 = 20.; // meters in all dimensions +// const RESOLUTION: f32 = 1.; // noise sample per meter + +const CHUNK_DIM: u16 = 16; // The size of the individual chunks in voxels + +use amethyst::{ + assets::{AssetStorage, Handle, Loader}, + controls::{FlyControlBundle, FlyControlTag}, + core::{ + math::{Vector3, Vector4}, + transform::{Transform, TransformBundle}, + Hidden, + }, + ecs::prelude::*, + input::{InputBundle, StringBindings}, + prelude::*, + renderer::{ + light::{DirectionalLight, Light}, + palette::{rgb::Rgb, Srgb}, + plugins::{RenderShaded3D, RenderSkybox, RenderToWindow}, + types::{DefaultBackend, MeshData, TextureData}, + visibility::BoundingSphere, + ActiveCamera, Camera, Material, MaterialDefaults, Mesh, RenderingBundle, Texture, + }, + ui::{RenderUi, UiBundle}, + utils::application_root_dir, +}; + +use gaiku_amethyst::prelude::*; +use gaiku_baker_marching_cubes::MarchingCubesBaker as TheBaker; +// use gaiku_baker_voxel::VoxelBaker as TheBaker; +use gaiku_common::{chunk::Chunk, Baker}; + +use glam::{Mat4, Vec3}; +use noise::{Fbm as SourceNoise, NoiseFn, Seedable}; +use rand::Rng; + +fn main() -> amethyst::Result<()> { + amethyst::start_logger(Default::default()); + + let app_root = application_root_dir()?; + let assets_dir = app_root.join("examples").join("assets"); + + let display_config_path = assets_dir.join("display.ron"); + + let binding_path = assets_dir.join("bindings.ron"); + let input_bundle = InputBundle::::new().with_bindings_from_file(binding_path)?; + + let render_bund = RenderingBundle::::new() + // The RenderToWindow plugin provides all the scaffolding for opening a window and drawing on it + .with_plugin( + RenderToWindow::from_config_path(display_config_path)?.with_clear([0.0, 0.0, 0.0, 1.0]), + ) + .with_plugin(RenderShaded3D::default()) + .with_plugin(RenderUi::default()) + .with_plugin(RenderSkybox::with_colors( + Srgb::new(0.82, 0.51, 0.50), + Srgb::new(0.18, 0.11, 0.85), + )); + + let game_data = GameDataBuilder::default() + .with_bundle(render_bund)? + // With transform systems for position tracking + .with_bundle(TransformBundle::new())? + .with_bundle( + FlyControlBundle::::new( + Some(String::from("right")), + Some(String::from("up")), + Some(String::from("forward")), + ) + .with_speed(100.), + )? + .with_bundle(input_bundle)? + .with_bundle(UiBundle::::new())?; + + let mut game = Application::new(assets_dir, GameLoad::new(), game_data)?; + + game.run(); + Ok(()) +} + +pub struct GameLoad { + noise_source: SourceNoise, + visible_entities: Vec, + terrain_transform: Mat4, +} + +impl SimpleState for GameLoad { + fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) { + let world = data.world; + + self.initialise_camera(world); + self.add_light(world); + self.build_terrain(world); + } + + fn fixed_update(&mut self, data: StateData<'_, GameData<'_, '_>>) -> SimpleTrans { + let world = data.world; + self.update_visible_chunks(world); + SimpleTrans::None + } + + // Uncomment this to print the camera position. + // Useful to find where you might want to save the camera position + // + // fn fixed_update(&mut self, data: StateData<'_, GameData<'_, '_>>) -> SimpleTrans { + // let world = data.world; + // type SystemData<'s> = (Read<'s, ActiveCamera>, ReadStorage<'s, Transform>); + // world.exec(|(act_cam, transforms): SystemData| { + // if let Some(act_cam_ent) = act_cam.entity { + // if let Some(cam_trans) = transforms.get(act_cam_ent) { + // println!("Cam Location: {:?}", cam_trans.translation()); + // } + // } + // }); + // SimpleTrans::None + // } +} + +impl Default for GameLoad { + fn default() -> Self { + Self::new() + } +} + +impl GameLoad { + pub fn new() -> Self { + Self { + noise_source: SourceNoise::new().set_seed(0), + visible_entities: vec![], + terrain_transform: Mat4::from_scale_rotation_translation( + // Assuming + // RANGE = 2000. + // RESOLUTION = 0.01 + // + // The size of the noise is 40x40x40 + // The size of the real domain in 4000x4000x4000 + // centered at 2000x2000x2000 + // This transform is to enforce that + // 0.,0.,0. => 20.,20.,20. + // 2000.,2000.,2000. => 40.,40.,40. + // -2000.,-2000.,-2000. => 0.,0.,0. + [RESOLUTION, RESOLUTION, RESOLUTION].into(), + Default::default(), + [RANGE * RESOLUTION, RANGE * RESOLUTION, RANGE * RESOLUTION].into(), + ), + } + } + + fn initialise_camera(&self, world: &mut World) { + let mut transform = Transform::default(); + transform.set_translation_xyz(0., 10., 22.0); + transform.face_towards(Vector3::new(0., 5., 0.), Vector3::new(0., 1., 0.)); + + let cam_ent = world + .create_entity() + .with(Camera::standard_3d(600., 400.)) + .with(transform) + .with(FlyControlTag) + .build(); + let act_cam: &mut ActiveCamera = world.get_mut().expect("There shoud be an active camera"); + act_cam.entity = Some(cam_ent); + } + + fn add_light(&self, world: &mut World) { + world + .create_entity() + .with(Light::from(DirectionalLight { + color: Rgb::new(1.0, 1.0, 1.0), + direction: [-1.0, -1.0, -1.0].into(), + intensity: 1.0, + })) + .build(); + } + + fn noise(&self, x: f32, y: f32, z: f32) -> f32 { + const GROUND_HEIGHT: f32 = 0.0; // Could replace with 2D noise + const HEIGHT_DROPOFF: f32 = 1.0 / 1000.; + + // The fbm noise + let coords = [x as f64, y as f64, z as f64]; + let noise = self.noise_source.get(coords); + + // Less dense as we go above ground height + // Just using a linear dropoff but could try exp or power + let solid_below = -(y - GROUND_HEIGHT) * HEIGHT_DROPOFF; + + noise as f32 + solid_below + } + + fn build_terrain(&self, world: &mut World) { + // First we build the noise as an array at lowest LOD + let density_dimensions = [(RANGE * 2. * RESOLUTION) as usize; 3]; + + let origin = [-RANGE, -RANGE, -RANGE]; + let delta = [1. / RESOLUTION, 1. / RESOLUTION, 1. / RESOLUTION]; + + let noise_data = (0..density_dimensions[0]) + .into_iter() + .map(|i| { + (0..density_dimensions[1]) + .into_iter() + .map(|j| { + (0..density_dimensions[2]) + .into_iter() + .map(|k| { + self.noise( + origin[0] + delta[0] * (i as f32), + origin[1] + delta[1] * (j as f32), + origin[2] + delta[2] * (k as f32), + ) + }) + .collect::>() + }) + .collect::>>() + }) + .collect::>>>() + .iter() + .flatten() + .flatten() + .copied() + .collect::>(); + + println!("Noise source dimensions: {:?}", density_dimensions); + let mut chunker: LodChunker = LodChunker::from_array( + &noise_data, + density_dimensions[0], + density_dimensions[1], + density_dimensions[2], + ); + + chunker.set_chunk_size([CHUNK_DIM, CHUNK_DIM, CHUNK_DIM]); + let (scale, _, _) = self.terrain_transform.to_scale_rotation_translation(); + chunker.set_lod_distance((scale * 50.).length()); + chunker.set_observation_point( + self + .terrain_transform + .transform_point3([0., 0., 0.].into()) + .into(), + ); + + // Some math to make the resolution the same + // regardless of RANGE/RESOLUTION. + const MAX_DESIRED_RESOLUTION: f32 = 1.; + let lods = (((RANGE * 2. / (CHUNK_DIM as f32) / MAX_DESIRED_RESOLUTION).ln() / 2_f32.ln()) + .floor() as usize) + .max(1); + println!("Generating: {} lods", lods); + chunker.set_lod_levels(lods); + + world.insert(chunker); + } + + fn update_visible_chunks(&mut self, world: &mut World) { + // First hide all those that are currently shown + { + let mut hiddens = world.write_storage::(); + for ent in self.visible_entities.drain(..) { + if hiddens.insert(ent, Hidden).is_err() { + println!("Failed to hide old chunk"); + } + } + } + + // Now either create or unhide + type SystemData<'s> = ( + Entities<'s>, + WriteExpect<'s, LodChunker>, + ReadExpect<'s, Loader>, + ReadExpect<'s, MaterialDefaults>, + Read<'s, ActiveCamera>, + Read<'s, AssetStorage>, + Read<'s, AssetStorage>, + Read<'s, AssetStorage>, + WriteStorage<'s, Transform>, + WriteStorage<'s, Handle>, + WriteStorage<'s, Handle>, + WriteStorage<'s, BoundingSphere>, + WriteStorage<'s, Hidden>, + ); + world.exec( + |( + entities, + mut chunk_tree, + loader, + material_default, + act_cam, + meshes, + textures, + materials, + mut transforms, + mut mesh_storage, + mut material_storage, + mut bound_storage, + mut hidden_storage, + ): SystemData| { + let inverse_transform = self.terrain_transform.inverse(); + + if let Some(cam_ent) = act_cam.entity { + // Get the cameras global position + let global_cam_pos = { + let cam_trans = transforms + .get(cam_ent) + .expect("Camera should have a transform"); + cam_trans.global_matrix() * Vector4::new(0., 0., 0., 1.0) + }; + + // Update observation_point + chunk_tree.set_observation_point( + self + .terrain_transform + .transform_point3([global_cam_pos[0], global_cam_pos[1], global_cam_pos[2]].into()) + .into(), + ); + + // Generate the chunks from this observation_point + chunk_tree.generate_chunks(); + + // Make chunks if visible + for chunked in chunk_tree.get_chunks_mut() { + // let scale: [f32; 3] = chunked.scale; + let chunk = &mut chunked.chunk; + + if let Some(ent) = chunk.get_entity() { + // Chunk already has an entity just use that + hidden_storage.remove(ent); + self.visible_entities.push(ent); + } else { + // This chunk is made up of this many voxel + let chunk_size: Vec3 = [ + (chunk.width() - 1) as f32, + (chunk.height() - 1) as f32, + (chunk.depth() - 1) as f32, + ] + .into(); + // Total area the chunk tree covers is this: + let area_size: Vec3 = [RANGE * 2., RANGE * 2., RANGE * 2.].into(); + + let origin: [f32; 3] = inverse_transform + .transform_point3(chunked.location.into()) + .into(); + let scale: [f32; 3] = (Vec3::from(chunked.scale) * area_size / chunk_size).into(); + + // Create new entitiy for this chunk + // let color = [10, 200, 10, 255]; + let color = [ + rand::thread_rng().gen_range(0..255), + rand::thread_rng().gen_range(0..255), + rand::thread_rng().gen_range(0..255), + 255, + ]; + + let bake_result = self.make_mesh_from_chunk(chunk, color); + + // Make an entity we can assign to the metachunk + let entity = if let Some((mesh_data, tex_data)) = bake_result { + // if the bake was successful this entity will use the baked mesh + let (mesh, mat) = { + let tex = loader.load_from_data(tex_data, (), &textures); + let mesh = loader.load_from_data(mesh_data, (), &meshes); + let mat: Handle = loader.load_from_data( + Material { + albedo: tex, + ..material_default.0.clone() + }, + (), + &materials, + ); + (mesh, mat) + }; + + // Get transform from the tree data + let mut transform = Transform::default(); + transform.set_translation_xyz(origin[0], origin[1], origin[2]); + + transform.set_scale(scale.into()); + let current_size: Vec3 = [ + chunk.width() as f32, + chunk.height() as f32, + chunk.depth() as f32, + ] + .into(); + + // The bounding box should also be set so that amethyst dosen't clip it + // These are in mesh coordinates before scaling + let radius = current_size.length() * 1.5; + let center: [f32; 3] = (current_size / 2.).into(); + let bounding = BoundingSphere { + center: center.into(), + radius, + }; + + entities + .build_entity() + .with(mesh, &mut mesh_storage) + .with(mat, &mut material_storage) + .with(transform, &mut transforms) + .with(bounding, &mut bound_storage) + .build() + } else { + // Otherwise we just assign an empty entity + entities.build_entity().build() + }; + chunk.set_entity(entity); + self.visible_entities.push(entity); + } + } + } + }, + ); + } + + fn make_mesh_from_chunk( + &self, + chunk: &MetaChunk, + color: [u8; 4], + ) -> Option<(MeshData, TextureData)> { + // Make a texture that just has a green tile in it + let mut texture = TextureAtlas2d::new(4); + texture.set_at_index(0, [color; 4 * 4].to_vec()); + + // Create the baker options to include this texture + let options = BakerOptions { + texture: Some(texture), + ..Default::default() + }; + + // Bake the mesh + let meshgox = TheBaker::bake::(chunk, &options); + + if let Ok(Some(mesh)) = meshgox { + let tex = options.texture.unwrap().get_texture(); + + // Put all data into amethyst format + let tex_data: TextureData = tex.into(); + let mesh_data: MeshData = mesh.into(); + Some((mesh_data, tex_data)) + } else { + // Nothing too bake probably an empty chunk + None + } + } +} + +/// We use this structure for the LOD tree +/// chunks so that we can hold extra meta data +/// with it related to amethyst and the mesh +pub struct MetaChunk { + chunk: Chunk, + entity: Option, +} + +impl MetaChunk { + pub fn get_entity(&self) -> Option { + self.entity + } + + pub fn set_entity(&mut self, ent: Entity) { + self.entity = Some(ent); + } +} + +impl Boxify for MetaChunk { + fn new(position: [f32; 3], width: u16, height: u16, depth: u16) -> Self { + Self { + chunk: Chunk::new(position, width, height, depth), + entity: None, + } + } +} + +impl Chunkify for MetaChunk { + fn is_air(&self, x: usize, y: usize, z: usize, isovalue: f32) -> bool { + self.chunk.is_air(x, y, z, isovalue) + } + + fn get(&self, x: usize, y: usize, z: usize) -> f32 { + self.chunk.get(x, y, z) + } +} + +impl ChunkifyMut for MetaChunk { + fn set(&mut self, x: usize, y: usize, z: usize, value: f32) { + self.chunk.set(x, y, z, value) + } +} + +impl Atlasify for MetaChunk { + fn get_atlas(&self, x: usize, y: usize, z: usize) -> u8 { + self.chunk.get_atlas(x, y, z) + } +} + +impl AtlasifyMut for MetaChunk { + fn set_atlas(&mut self, x: usize, y: usize, z: usize, value: u8) { + self.chunk.set_atlas(x, y, z, value) + } +} + +impl Positionable for MetaChunk { + fn with_position(position: [f32; 3]) -> Self { + Self { + chunk: Chunk::new(position, 16, 16, 16), + entity: None, + } + } + + fn position(&self) -> [f32; 3] { + self.chunk.position() + } +} + +impl Sizable for MetaChunk { + fn with_size(width: u16, height: u16, depth: u16) -> Self { + Self { + chunk: Chunk::new([0.0, 0.0, 0.0], width, height, depth), + entity: None, + } + } + + fn depth(&self) -> u16 { + self.chunk.depth() + } + + fn height(&self) -> u16 { + self.chunk.height() + } + + fn width(&self) -> u16 { + self.chunk.width() + } +}