1 /**
2  * Mandelbulber v2, a 3D fractal generator       ,=#MKNmMMKmmßMNWy,
3  *                                             ,B" ]L,,p%%%,,,§;, "K
4  * Copyright (C) 2016-21 Mandelbulber Team     §R-==%w["'~5]m%=L.=~5N
5  *                                        ,=mm=§M ]=4 yJKA"/-Nsaj  "Bw,==,,
6  * This file is part of Mandelbulber.    §R.r= jw",M  Km .mM  FW ",§=ß., ,TN
7  *                                     ,4R =%["w[N=7]J '"5=],""]]M,w,-; T=]M
8  * Mandelbulber is free software:     §R.ß~-Q/M=,=5"v"]=Qf,'§"M= =,M.§ Rz]M"Kw
9  * you can redistribute it and/or     §w "xDY.J ' -"m=====WeC=\ ""%""y=%"]"" §
10  * modify it under the terms of the    "§M=M =D=4"N #"%==A%p M§ M6  R' #"=~.4M
11  * GNU General Public License as        §W =, ][T"]C  §  § '§ e===~ U  !§[Z ]N
12  * published by the                    4M",,Jm=,"=e~  §  §  j]]""N  BmM"py=ßM
13  * Free Software Foundation,          ]§ T,M=& 'YmMMpM9MMM%=w=,,=MT]M m§;'§,
14  * either version 3 of the License,    TWw [.j"5=~N[=§%=%W,T ]R,"=="Y[LFT ]N
15  * or (at your option)                   TW=,-#"%=;[  =Q:["V""  ],,M.m == ]N
16  * any later version.                      J§"mr"] ,=,," =="""J]= M"M"]==ß"
17  *                                          §= "=C=4 §"eM "=B:m|4"]#F,§~
18  * Mandelbulber is distributed in            "9w=,,]w em%wJ '"~" ,=,,ß"
19  * the hope that it will be useful,                 . "K=  ,=RMMMßM"""
20  * but WITHOUT ANY WARRANTY;                            .'''
21  * without even the implied warranty
22  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  * See the GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with Mandelbulber. If not, see <http://www.gnu.org/licenses/>.
27  *
28  * ###########################################################################
29  *
30  * Authors: pmneila, Sebastian Jennen (jenzebas@gmail.com)
31  *
32  * Re-licensed with the written authorization of P. M. Neila
33  * for use with Mandelbulber. See here for original code:
34  * https://github.com/pmneila/PyMCubes/
35  */
36 
37 #include "marchingcubes.h"
38 
39 #include <QMap>
40 
41 #include "calculate_distance.hpp"
42 #include "common_math.h"
43 #include "compute_fractal.hpp"
44 #include "fractal_container.hpp"
45 #include "fractparams.hpp"
46 #include "initparameters.hpp"
47 #include "nine_fractals.hpp"
48 #include "opencl_engine.h"
49 #include "opencl_engine_render_fractal.h"
50 #include "opencl_global.h"
51 #include "render_data.hpp"
52 #include "system_data.hpp"
53 #include "write_log.hpp"
54 
55 // custom includes
56 #ifdef USE_OPENCL
57 #include "opencl/mesh_export_data_cl.h"
58 #endif
59 
MarchingCubes(std::shared_ptr<const cParameterContainer> paramsContainer,std::shared_ptr<const cFractalContainer> fractalContainer,std::shared_ptr<sParamRender> params,std::shared_ptr<cNineFractals> fractals,std::shared_ptr<sRenderData> renderData,int numx,int numy,int numz,const CVector3 & lower,const CVector3 & upper,double dist_thresh,bool * stop,std::vector<double> & vertices,std::vector<long long> & polygons,std::vector<double> & colorIndices)60 MarchingCubes::MarchingCubes(std::shared_ptr<const cParameterContainer> paramsContainer,
61 	std::shared_ptr<const cFractalContainer> fractalContainer, std::shared_ptr<sParamRender> params,
62 	std::shared_ptr<cNineFractals> fractals, std::shared_ptr<sRenderData> renderData, int numx,
63 	int numy, int numz, const CVector3 &lower, const CVector3 &upper, double dist_thresh, bool *stop,
64 	std::vector<double> &vertices, std::vector<long long> &polygons,
65 	std::vector<double> &colorIndices)
66 		: vertices{vertices}, polygons{polygons}, colorIndices{colorIndices}
67 {
68 	this->numx = numx;
69 	this->numy = numy;
70 	this->numz = numz;
71 
72 	this->lower = lower;
73 	this->upper = upper;
74 
75 	this->params = params;
76 	this->fractals = fractals;
77 	this->dist_thresh = dist_thresh;
78 	this->renderData = renderData;
79 
80 	this->paramsContainer = paramsContainer;
81 	this->fractalContainer = fractalContainer;
82 
83 	dx = (upper.x - lower.x) / numx;
84 	dy = (upper.y - lower.y) / numy;
85 	dz = (upper.z - lower.z) / numz;
86 
87 	numyb = numy + 1;
88 	numzb = numz + 1;
89 	numyzb = numyb * numzb;
90 	z3 = numz * 3;
91 	yz3 = numy * z3;
92 
93 	this->stop = stop;
94 
95 	coloredMesh = paramsContainer->Get<bool>("mesh_color");
96 
97 	try
98 	{
99 		shared_indices.resize(2LL * numy * numz * 3);
100 		voxelBuffer.resize(2LL * numyzb);
101 		colorBuffer.resize(2LL * numyzb);
102 	}
103 	catch (std::bad_alloc &ba)
104 	{
105 		FreeBuffers();
106 		throw ba;
107 	}
108 }
109 
FreeBuffers()110 void MarchingCubes::FreeBuffers()
111 {
112 	shared_indices.clear();
113 	voxelBuffer.clear();
114 	colorBuffer.clear();
115 }
116 
RunMarchingCube()117 void MarchingCubes::RunMarchingCube()
118 {
119 	bool openClEnabled = false;
120 #ifdef USE_OPENCL
121 
122 	openClEnabled =
123 		paramsContainer->Get<bool>("opencl_enabled")
124 		&& cOpenClEngineRenderFractal::enumClRenderEngineMode(paramsContainer->Get<int>("opencl_mode"))
125 				 != cOpenClEngineRenderFractal::clRenderEngineTypeNone;
126 
127 	sClMeshExport clMeshParams;
128 	clMeshParams.distThresh = dist_thresh;
129 	clMeshParams.limitMax = toClFloat3(upper);
130 	clMeshParams.limitMin = toClFloat3(lower);
131 	clMeshParams.maxiter = params->N;
132 	clMeshParams.size = toClInt3(numx, numy, numz);
133 	clMeshParams.sliceHeight = numy + 1;
134 	clMeshParams.sliceWidth = numz + 1;
135 	clMeshParams.coloredMesh = coloredMesh;
136 
137 	if (openClEnabled)
138 	{
139 		gOpenCl->openClEngineRenderFractal->Lock();
140 		gOpenCl->openClEngineRenderFractal->SetParameters(
141 			paramsContainer, fractalContainer, params, fractals, renderData, true);
142 		gOpenCl->openClEngineRenderFractal->SetMeshExportParameters(&clMeshParams);
143 		if (gOpenCl->openClEngineRenderFractal->LoadSourcesAndCompile(paramsContainer))
144 		{
145 			gOpenCl->openClEngineRenderFractal->CreateKernel4Program(paramsContainer);
146 			WriteLogDouble("OpenCl render fractal - needed mem:",
147 				gOpenCl->openClEngineRenderFractal->CalcNeededMemory() / 1048576.0, 2);
148 			gOpenCl->openClEngineRenderFractal->PreAllocateBuffers(paramsContainer);
149 			gOpenCl->openClEngineRenderFractal->CreateCommandQueue();
150 		}
151 		else
152 		{
153 			emit finished();
154 			gOpenCl->openClEngineRenderFractal->ReleaseMemory();
155 			gOpenCl->openClEngineRenderFractal->Unlock();
156 			return;
157 		}
158 	}
159 
160 #endif // USE_OPENCL
161 
162 	// numx, numy and numz are the numbers of evaluations in each direction
163 	for (long long i = 0; i < numx; ++i)
164 	{
165 		emit signalUpdateProgressAndStatus(i, polygons.size() / 3);
166 
167 		// shift voxel planes
168 		if (i > 0)
169 		{
170 			for (long long jk = 0; jk < numyzb; ++jk)
171 			{
172 				long long ptr = jk;
173 				long long ptr2 = ptr + numyzb;
174 				voxelBuffer[ptr] = voxelBuffer[ptr2];
175 				colorBuffer[ptr] = colorBuffer[ptr2];
176 			}
177 		}
178 
179 #ifdef USE_OPENCL
180 		if (openClEnabled)
181 		{
182 			size_t dataOffset = clMeshParams.sliceHeight * clMeshParams.sliceWidth;
183 			bool result = gOpenCl->openClEngineRenderFractal->Render(&voxelBuffer, &colorBuffer, nullptr,
184 				i, renderData->stopRequest, renderData.get(), dataOffset);
185 
186 			if (!result)
187 			{
188 				gOpenCl->openClEngineRenderFractal->ReleaseMemory();
189 				gOpenCl->openClEngineRenderFractal->Unlock();
190 				return;
191 			}
192 		}
193 #endif // USE_OPENCL
194 
195 		if (!openClEnabled)
196 		{
197 			calculateVoxelPlane(i);
198 		}
199 		if (i > 0)
200 		{
201 			calculateEdges(i);
202 		}
203 		if (*stop || systemData.globalStopRequest) break;
204 	}
205 
206 #ifdef USE_OPENCL
207 	if (openClEnabled)
208 	{
209 		gOpenCl->openClEngineRenderFractal->ReleaseMemory();
210 		gOpenCl->openClEngineRenderFractal->Unlock();
211 	}
212 #endif // USE_OPENCL
213 
214 	emit finished();
215 }
216 
calculateVoxelPlane(int i)217 void MarchingCubes::calculateVoxelPlane(int i)
218 {
219 	// calculate voxel plane
220 	long long start = (i == 0) ? 0 : 1;
221 	for (long long ii = start; ii < 2; ++ii)
222 	{
223 		double xx = lower.x + dx * (ii + i);
224 
225 		for (long long jj = 0; jj < numyb; ++jj)
226 		{
227 			if (*stop)
228 			{
229 				return;
230 			}
231 
232 			double yy = lower.y + dy * jj;
233 
234 #ifdef USE_OFFLOAD
235 #pragma offload target(mic) inout(voxelBuffer) inout(colorBuffer) nocopy(f)
236 #endif // USE_OFFLOAD
237 
238 #pragma omp parallel for schedule(dynamic, 1)
239 			for (long long kk = 0; kk < numzb;
240 					 ++kk) // long long is used because size_t doesn't work with msvc and OpenMP
241 			{
242 				long long ptr = ii * numyzb + jj * numzb + kk;
243 
244 				double zz = lower.z + dz * kk;
245 				voxelBuffer[ptr] = getDistance(xx, yy, zz, &colorBuffer[ptr]);
246 			}
247 		}
248 	}
249 }
250 
calculateEdges(int i)251 void MarchingCubes::calculateEdges(int i)
252 {
253 	double x = lower.x + dx * i;
254 	double x_dx = lower.x + dx * (i + 1);
255 	const int i_mod_2 = i % 2;
256 	const int i_mod_2_inv = (i_mod_2 ? 0 : 1);
257 
258 	for (long long j = 0; j < numy; ++j)
259 	{
260 		if (*stop)
261 		{
262 			return;
263 		}
264 
265 		double y = lower.y + dy * j;
266 		double y_dy = lower.y + dy * (j + 1);
267 
268 		for (long long k = 0; k < numz; ++k)
269 		{
270 			double z = lower.z + dz * k;
271 			double z_dz = lower.z + dz * (k + 1);
272 
273 			double v[8];
274 			double colorIndex[8];
275 			v[0] = voxelBuffer[j * numzb + k];
276 			v[1] = voxelBuffer[numyzb + j * numzb + k];
277 			v[2] = voxelBuffer[numyzb + (j + 1) * numzb + k];
278 			v[3] = voxelBuffer[(j + 1) * numzb + k];
279 			v[4] = voxelBuffer[j * numzb + k + 1];
280 			v[5] = voxelBuffer[numyzb + j * numzb + k + 1];
281 			v[6] = voxelBuffer[numyzb + (j + 1) * numzb + k + 1];
282 			v[7] = voxelBuffer[(j + 1) * numzb + k + 1];
283 
284 			colorIndex[0] = colorBuffer[j * numzb + k];
285 			colorIndex[1] = colorBuffer[numyzb + j * numzb + k];
286 			colorIndex[2] = colorBuffer[numyzb + (j + 1) * numzb + k];
287 			colorIndex[3] = colorBuffer[(j + 1) * numzb + k];
288 			colorIndex[4] = colorBuffer[j * numzb + k + 1];
289 			colorIndex[5] = colorBuffer[numyzb + j * numzb + k + 1];
290 			colorIndex[6] = colorBuffer[numyzb + (j + 1) * numzb + k + 1];
291 			colorIndex[7] = colorBuffer[(j + 1) * numzb + k + 1];
292 
293 			unsigned int cubeindex = 0;
294 
295 			for (int m = 0; m < 8; ++m)
296 				if (v[m] < dist_thresh) cubeindex |= 1 << m;
297 
298 			// Generate vertices AVOIDING DUPLICATES.
299 
300 			int edges = edge_table[cubeindex];
301 			std::vector<long long> indices(12, -1);
302 			if (edges & 0x040)
303 			{
304 				indices[6] = vertices.size() / 3;
305 				shared_indices[i_mod_2 * yz3 + j * z3 + k * 3 + 0] = indices[6];
306 				mc_add_vertex(x_dx, y_dy, z_dz, x, 0, v[6], v[7], dist_thresh, &vertices, colorIndex[6],
307 					colorIndex[7], &colorIndices);
308 			}
309 			if (edges & 0x020)
310 			{
311 				indices[5] = vertices.size() / 3;
312 				shared_indices[i_mod_2 * yz3 + j * z3 + k * 3 + 1] = indices[5];
313 				mc_add_vertex(x_dx, y, z_dz, y_dy, 1, v[5], v[6], dist_thresh, &vertices, colorIndex[5],
314 					colorIndex[6], &colorIndices);
315 			}
316 			if (edges & 0x400)
317 			{
318 				indices[10] = vertices.size() / 3;
319 				shared_indices[i_mod_2 * yz3 + j * z3 + k * 3 + 2] = indices[10];
320 				mc_add_vertex(x_dx, y + dx, z, z_dz, 2, v[2], v[6], dist_thresh, &vertices, colorIndex[2],
321 					colorIndex[6], &colorIndices);
322 			}
323 
324 			if (edges & 0x001)
325 			{
326 				if (j == 0 || k == 0)
327 				{
328 					indices[0] = vertices.size() / 3;
329 					mc_add_vertex(x, y, z, x_dx, 0, v[0], v[1], dist_thresh, &vertices, colorIndex[0],
330 						colorIndex[1], &colorIndices);
331 				}
332 				else
333 					indices[0] = shared_indices[i_mod_2 * yz3 + (j - 1) * z3 + (k - 1) * 3 + 0];
334 			}
335 			if (edges & 0x002)
336 			{
337 				if (k == 0)
338 				{
339 					indices[1] = vertices.size() / 3;
340 					mc_add_vertex(x_dx, y, z, y_dy, 1, v[1], v[2], dist_thresh, &vertices, colorIndex[1],
341 						colorIndex[2], &colorIndices);
342 				}
343 				else
344 					indices[1] = shared_indices[i_mod_2 * yz3 + j * z3 + (k - 1) * 3 + 1];
345 			}
346 			if (edges & 0x004)
347 			{
348 				if (k == 0)
349 				{
350 					indices[2] = vertices.size() / 3;
351 					mc_add_vertex(x_dx, y_dy, z, x, 0, v[2], v[3], dist_thresh, &vertices, colorIndex[2],
352 						colorIndex[3], &colorIndices);
353 				}
354 				else
355 					indices[2] = shared_indices[i_mod_2 * yz3 + j * z3 + (k - 1) * 3 + 0];
356 			}
357 			if (edges & 0x008)
358 			{
359 				if (i == 0 || k == 0)
360 				{
361 					indices[3] = vertices.size() / 3;
362 					mc_add_vertex(x, y_dy, z, y, 1, v[3], v[0], dist_thresh, &vertices, colorIndex[3],
363 						colorIndex[0], &colorIndices);
364 				}
365 				else
366 					indices[3] = shared_indices[i_mod_2_inv * yz3 + j * z3 + (k - 1) * 3 + 1];
367 			}
368 			if (edges & 0x010)
369 			{
370 				if (j == 0)
371 				{
372 					indices[4] = vertices.size() / 3;
373 					mc_add_vertex(x, y, z_dz, x_dx, 0, v[4], v[5], dist_thresh, &vertices, colorIndex[4],
374 						colorIndex[5], &colorIndices);
375 				}
376 				else
377 					indices[4] = shared_indices[i_mod_2 * yz3 + (j - 1) * z3 + k * 3 + 0];
378 			}
379 			if (edges & 0x080)
380 			{
381 				if (i == 0)
382 				{
383 					indices[7] = vertices.size() / 3;
384 					mc_add_vertex(x, y_dy, z_dz, y, 1, v[7], v[4], dist_thresh, &vertices, colorIndex[7],
385 						colorIndex[4], &colorIndices);
386 				}
387 				else
388 					indices[7] = shared_indices[i_mod_2_inv * yz3 + j * z3 + k * 3 + 1];
389 			}
390 			if (edges & 0x100)
391 			{
392 				if (i == 0 || j == 0)
393 				{
394 					indices[8] = vertices.size() / 3;
395 					mc_add_vertex(x, y, z, z_dz, 2, v[0], v[4], dist_thresh, &vertices, colorIndex[0],
396 						colorIndex[4], &colorIndices);
397 				}
398 				else
399 					indices[8] = shared_indices[i_mod_2_inv * yz3 + (j - 1) * z3 + k * 3 + 2];
400 			}
401 			if (edges & 0x200)
402 			{
403 				if (j == 0)
404 				{
405 					indices[9] = vertices.size() / 3;
406 					mc_add_vertex(x_dx, y, z, z_dz, 2, v[1], v[5], dist_thresh, &vertices, colorIndex[1],
407 						colorIndex[3], &colorIndices);
408 				}
409 				else
410 					indices[9] = shared_indices[i_mod_2 * yz3 + (j - 1) * z3 + k * 3 + 2];
411 			}
412 			if (edges & 0x800)
413 			{
414 				if (i == 0)
415 				{
416 					indices[11] = vertices.size() / 3;
417 					mc_add_vertex(x, y_dy, z, z_dz, 2, v[3], v[7], dist_thresh, &vertices, colorIndex[3],
418 						colorIndex[7], &colorIndices);
419 				}
420 				else
421 					indices[11] = shared_indices[i_mod_2_inv * yz3 + j * z3 + k * 3 + 2];
422 			}
423 
424 			int tri;
425 			int *triangle_table_ptr = triangle_table[cubeindex];
426 			for (int m = 0; tri = triangle_table_ptr[m], tri != -1; ++m)
427 				polygons.push_back(indices[tri]);
428 		}
429 	}
430 }
431 
432 #ifdef USE_OFFLOAD
target(mic)433 __declspec(target(mic))
434 #endif // USE_OFFLOAD
435 	double MarchingCubes::getDistance(double x, double y, double z, double *colorIndex) const
436 {
437 	CVector3 point;
438 	point.x = x;
439 	point.y = y;
440 	point.z = z;
441 
442 	sDistanceOut distanceOut;
443 	sDistanceIn distanceIn(point, dist_thresh, false);
444 
445 	double dist =
446 		CalculateDistance(*params.get(), *fractals.get(), distanceIn, &distanceOut, renderData.get());
447 
448 	cObjectData objectData = renderData->objectData[distanceOut.objectId];
449 	cMaterial *material = &renderData->materials[objectData.materialId];
450 
451 	sFractalIn fractIn(point, params->minN, params->N, &params->common, -1, false, material);
452 	sFractalOut fractOut;
453 
454 	Compute<fractal::calcModeColouring>(*fractals, fractIn, &fractOut);
455 
456 	*colorIndex = fractOut.colorIndex;
457 
458 	return dist;
459 }
460 
461 int MarchingCubes::edge_table[256] = {0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c,
462 	0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795,
463 	0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x033, 0x13a, 0x636,
464 	0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3,
465 	0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460,
466 	0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69,
467 	0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa,
468 	0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f,
469 	0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc,
470 	0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5,
471 	0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56,
472 	0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3,
473 	0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60,
474 	0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569,
475 	0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa,
476 	0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f,
477 	0x636, 0x13a, 0x033, 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c,
478 	0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905,
479 	0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000};
480 
481 int MarchingCubes::triangle_table[256][16] = {
482 	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
483 	{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
484 	{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
485 	{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
486 	{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
487 	{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
488 	{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
489 	{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
490 	{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
491 	{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
492 	{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
493 	{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
494 	{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
495 	{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
496 	{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
497 	{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
498 	{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
499 	{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
500 	{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
501 	{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
502 	{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
503 	{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
504 	{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
505 	{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
506 	{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
507 	{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
508 	{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
509 	{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
510 	{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
511 	{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
512 	{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
513 	{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
514 	{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
515 	{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
516 	{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
517 	{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
518 	{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
519 	{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
520 	{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
521 	{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
522 	{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
523 	{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
524 	{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
525 	{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
526 	{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
527 	{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
528 	{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
529 	{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
530 	{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
531 	{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
532 	{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
533 	{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
534 	{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
535 	{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
536 	{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
537 	{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
538 	{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
539 	{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
540 	{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
541 	{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
542 	{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
543 	{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
544 	{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
545 	{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
546 	{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
547 	{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
548 	{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
549 	{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
550 	{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
551 	{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
552 	{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
553 	{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
554 	{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
555 	{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
556 	{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
557 	{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
558 	{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
559 	{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
560 	{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
561 	{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
562 	{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
563 	{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
564 	{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
565 	{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
566 	{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
567 	{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
568 	{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
569 	{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
570 	{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
571 	{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
572 	{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
573 	{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
574 	{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
575 	{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
576 	{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
577 	{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
578 	{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
579 	{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
580 	{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
581 	{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
582 	{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
583 	{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
584 	{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
585 	{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
586 	{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
587 	{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
588 	{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
589 	{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
590 	{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
591 	{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
592 	{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
593 	{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
594 	{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
595 	{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
596 	{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
597 	{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
598 	{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
599 	{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
600 	{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
601 	{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
602 	{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
603 	{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
604 	{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
605 	{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
606 	{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
607 	{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
608 	{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
609 	{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
610 	{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
611 	{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
612 	{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
613 	{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
614 	{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
615 	{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
616 	{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
617 	{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
618 	{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
619 	{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
620 	{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
621 	{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
622 	{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
623 	{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
624 	{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
625 	{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
626 	{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
627 	{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
628 	{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
629 	{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
630 	{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
631 	{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
632 	{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
633 	{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
634 	{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
635 	{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
636 	{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
637 	{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
638 	{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
639 	{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
640 	{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
641 	{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
642 	{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
643 	{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
644 	{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
645 	{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
646 	{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
647 	{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
648 	{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
649 	{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
650 	{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
651 	{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
652 	{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
653 	{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
654 	{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
655 	{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
656 	{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
657 	{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
658 	{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
659 	{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
660 	{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
661 	{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
662 	{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
663 	{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
664 	{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
665 	{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
666 	{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
667 	{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
668 	{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
669 	{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
670 	{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
671 	{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
672 	{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
673 	{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
674 	{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
675 	{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
676 	{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
677 	{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
678 	{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
679 	{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
680 	{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
681 	{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
682 	{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
683 	{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
684 	{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
685 	{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
686 	{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
687 	{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
688 	{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
689 	{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
690 	{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
691 	{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
692 	{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
693 	{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
694 	{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
695 	{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
696 	{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
697 	{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
698 	{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
699 	{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
700 	{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
701 	{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
702 	{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
703 	{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
704 	{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
705 	{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
706 	{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
707 	{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
708 	{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
709 	{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
710 	{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
711 	{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
712 	{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
713 	{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
714 	{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
715 	{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
716 	{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
717 	{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
718 	{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
719 	{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
720 	{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
721 	{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
722 	{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
723 	{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
724 	{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
725 	{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
726 	{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
727 	{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
728 	{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
729 	{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
730 	{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
731 	{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
732 	{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
733 	{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
734 	{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
735 	{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
736 	{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
737 	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
738