Skip to content

Instantly share code, notes, and snippets.

@Matt54
Created August 13, 2025 03:45
Show Gist options
  • Save Matt54/aec7da63e5af60d93b91e5d962bc5617 to your computer and use it in GitHub Desktop.
Save Matt54/aec7da63e5af60d93b91e5d962bc5617 to your computer and use it in GitHub Desktop.
LowLevelMesh shape shifting with Marching Cubes and SDF interpolation
#ifndef edgeTable_h
#define edgeTable_h
constant int edgeTable[256]={
0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
#endif /* edgeTable_h */
#include <metal_stdlib>
using namespace metal;
#define SDFShapeTypeSphere 0u
#define SDFShapeTypeBox 1u
#define SDFShapeTypeTorus 2u
#define SDFShapeTypeRoundedBox 3u
#define SDFShapeTypeBoxFrame 4u
#define SDFShapeTypeLink 5u
#define SDFShapeTypeOctahedron 6u
inline float sdf_sphere(float3 p, float3 c, float r) {
return length(p - c) - r;
}
inline float sdf_box(float3 p, float3 c, float3 b) {
float3 d = abs(p - c) - b;
return length(max(d, float3(0.0))) + min(max(d.x, max(d.y, d.z)), 0.0);
}
inline float sdf_torus(float3 p, float3 c, float R, float r) {
float3 q = p - c;
float2 k = float2(length(q.xz) - R, q.y);
return length(k) - r;
}
inline float sdf_rounded_box(float3 p, float3 c, float3 b, float cr) {
float3 q = abs(p - c) - (b - cr);
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - cr;
}
inline float sdf_box_frame(float3 p, float3 c, float3 b, float e) {
float3 pp = abs(p - c) - b;
float3 q = abs(pp + e) - e;
float3 v1 = float3(pp.x, q.y, q.z);
float3 v2 = float3(q.x, pp.y, q.z);
float3 v3 = float3(q.x, q.y, pp.z);
float d1 = length(max(v1, 0.0)) + min(max(pp.x, max(q.y, q.z)), 0.0);
float d2 = length(max(v2, 0.0)) + min(max(q.x, max(pp.y, q.z)), 0.0);
float d3 = length(max(v3, 0.0)) + min(max(q.x, max(q.y, pp.z)), 0.0);
return min(min(d1, d2), d3);
}
inline float sdf_link(float3 p, float3 c, float le, float r1, float r2) {
float3 q = float3(p.x - c.x, max(abs(p.y - c.y) - le, 0.0), p.z - c.z);
return length(float2(length(q.xy) - r1, q.z)) - r2;
}
inline float sdf_octahedron(float3 p, float3 c, float s) {
float3 pp = abs(p - c);
return (pp.x + pp.y + pp.z - s) * 0.57735027; // 1/sqrt(3)
}
// Single-radius presets sized from a common bounding radius
inline float sdf_for_shape(uint shapeType, float3 p, float3 center, float radius) {
switch (shapeType) {
default:
case SDFShapeTypeSphere:
return sdf_sphere(p, center, radius);
case SDFShapeTypeBox: {
float s = radius / sqrt(3.0f);
return sdf_box(p, center, float3(s));
}
case SDFShapeTypeTorus: {
float R = radius * 0.65f;
float r = radius * 0.28f;
return sdf_torus(p, center, R, r);
}
case SDFShapeTypeRoundedBox: {
float s = radius / sqrt(3.0f);
float cr = s * 0.3f;
return sdf_rounded_box(p, center, float3(s), cr);
}
case SDFShapeTypeBoxFrame: {
float s = radius / sqrt(3.0f);
float e = s * 0.20f;
return sdf_box_frame(p, center, float3(s), e);
}
case SDFShapeTypeLink: {
float le = radius * 0.25f;
float r1 = radius * 0.6f;
float r2 = radius * 0.15f;
return sdf_link(p, center, le, r1, r2);
}
case SDFShapeTypeOctahedron: {
float s = radius * 1.0f;
return sdf_octahedron(p, center, s);
}
}
}
// Domain repetition
inline float3 opRepetition(float3 p, uint count, float radius) {
if (count <= 1) return p;
// Reduce the effective radius
float effectiveRadius = radius * 0.6;
// Calculate spacing
float spacing = 2.0 * effectiveRadius / float(count);
// Limit the repetition
float3 q = p;
q.x = p.x - spacing * clamp(round(p.x / spacing), -float(count-1)/2.0, float(count-1)/2.0);
q.y = p.y - spacing * clamp(round(p.y / spacing), -float(count-1)/2.0, float(count-1)/2.0);
q.z = p.z - spacing * clamp(round(p.z / spacing), -float(count-1)/2.0, float(count-1)/2.0);
return q;
}
// Apply repetition to SDF shapes with radius scaling
inline float sdf_with_repetition(uint shapeType, float3 p, float3 center, float radius,
uint repetition) {
if (repetition <= 1) {
// No repetition, use original SDF
return sdf_for_shape(shapeType, p, center, radius);
}
// Scale radius down more aggressively to prevent overlap
float scaledRadius = radius / (float(repetition) * 2.0);
// Apply repetition transformation using radius for spacing
float3 q = opRepetition(p, repetition, radius);
return sdf_for_shape(shapeType, q, center, scaledRadius);
}
import Foundation
enum SDFShape: UInt32, CaseIterable {
case sphere = 0
case box = 1
case torus = 2
case roundedBox = 3
case boxFrame = 4
case link = 5
case octahedron = 6
}
#include <metal_stdlib>
using namespace metal;
#include "VertexPositionNormal.h"
#include "ShapeShiftingSDFMarchingCubesParams.h"
#include "edgeTable.h"
#include "triTable.h"
#include "SDFPrimitives.metal"
inline float3 interpolateIsoSurfacePosition(float3 pA, float valueA,
float3 pB, float valueB,
float isoLevel) {
float denom = (valueB - valueA);
float t = (isoLevel - valueA) / (denom + 1e-6f);
return mix(pA, pB, clamp(t, 0.0f, 1.0f));
}
// Blend between two SDF primitives chosen by ids (shape0, shape1)
inline float fieldValue(float3 worldPos, constant ShapeShiftingSDFMarchingCubesParams& P) {
float d0 = sdf_with_repetition(P.shape0, worldPos, P.center, P.radius, P.repetition0);
float d1 = sdf_with_repetition(P.shape1, worldPos, P.center, P.radius, P.repetition1);
return mix(d0, d1, clamp(P.blendT, 0.0f, 1.0f));
}
inline float3 estimateNormalFromField(float3 worldPos, constant ShapeShiftingSDFMarchingCubesParams& P) {
float h = 0.5f * min(P.cellSize.x, min(P.cellSize.y, P.cellSize.z));
float fx = fieldValue(worldPos + float3(h,0,0), P) - fieldValue(worldPos - float3(h,0,0), P);
float fy = fieldValue(worldPos + float3(0,h,0), P) - fieldValue(worldPos - float3(0,h,0), P);
float fz = fieldValue(worldPos + float3(0,0,h), P) - fieldValue(worldPos - float3(0,0,h), P);
return normalize(float3(fx, fy, fz) / (2.0f * h));
}
kernel void shapeShiftingSDFMarchingCubesMesh(device VertexPositionNormal* outVertices [[buffer(0)]],
device uint* outIndices [[buffer(1)]],
device atomic_uint* outVertexCounter [[buffer(2)]],
constant ShapeShiftingSDFMarchingCubesParams& P [[buffer(3)]],
uint3 cellCoord [[thread_position_in_grid]]) {
if (cellCoord.x >= P.cells.x || cellCoord.y >= P.cells.y || cellCoord.z >= P.cells.z) return;
const int3 cornerOffsets[8] = {
int3(0,0,0), int3(1,0,0), int3(1,1,0), int3(0,1,0),
int3(0,0,1), int3(1,0,1), int3(1,1,1), int3(0,1,1)
};
const int2 edgeCornerIndexPairs[12] = {
int2(0,1), int2(1,2), int2(2,3), int2(3,0),
int2(4,5), int2(5,6), int2(6,7), int2(7,4),
int2(0,4), int2(1,5), int2(2,6), int2(3,7)
};
const float3 cellOriginWS = P.origin + float3(cellCoord) * P.cellSize;
float cornerScalar[8];
float3 cornerPositionWS[8];
for (int i = 0; i < 8; ++i) {
float3 cp = cellOriginWS + float3(cornerOffsets[i]) * P.cellSize;
cornerPositionWS[i] = cp;
cornerScalar[i] = fieldValue(cp, P);
}
int cubeIndex = 0;
if (cornerScalar[0] > P.isoLevel) cubeIndex |= 1;
if (cornerScalar[1] > P.isoLevel) cubeIndex |= 2;
if (cornerScalar[2] > P.isoLevel) cubeIndex |= 4;
if (cornerScalar[3] > P.isoLevel) cubeIndex |= 8;
if (cornerScalar[4] > P.isoLevel) cubeIndex |= 16;
if (cornerScalar[5] > P.isoLevel) cubeIndex |= 32;
if (cornerScalar[6] > P.isoLevel) cubeIndex |= 64;
if (cornerScalar[7] > P.isoLevel) cubeIndex |= 128;
int edgeMask = edgeTable[cubeIndex];
if (edgeMask == 0) return;
float3 edgeIntersectionWS[12];
for (int edge = 0; edge < 12; ++edge) {
if (edgeMask & (1 << edge)) {
const int a = edgeCornerIndexPairs[edge].x;
const int b = edgeCornerIndexPairs[edge].y;
edgeIntersectionWS[edge] = interpolateIsoSurfacePosition(
cornerPositionWS[a], cornerScalar[a],
cornerPositionWS[b], cornerScalar[b],
P.isoLevel
);
}
}
constant int* triangleEdgesRow = &triTable[cubeIndex][0];
for (int triIdx = 0; triIdx < 16 && triangleEdgesRow[triIdx] != -1; triIdx += 3) {
const int e0 = triangleEdgesRow[triIdx + 0];
const int e1 = triangleEdgesRow[triIdx + 1];
const int e2 = triangleEdgesRow[triIdx + 2];
const float3 p0 = edgeIntersectionWS[e0];
const float3 p1 = edgeIntersectionWS[e1];
const float3 p2 = edgeIntersectionWS[e2];
const float3 n0 = estimateNormalFromField(p0, P);
const float3 n1 = estimateNormalFromField(p1, P);
const float3 n2 = estimateNormalFromField(p2, P);
const uint baseVertexIndex = atomic_fetch_add_explicit(outVertexCounter, (uint)3, memory_order_relaxed);
outVertices[baseVertexIndex + 0].position = p0;
outVertices[baseVertexIndex + 0].normal = n0;
outVertices[baseVertexIndex + 1].position = p1;
outVertices[baseVertexIndex + 1].normal = n1;
outVertices[baseVertexIndex + 2].position = p2;
outVertices[baseVertexIndex + 2].normal = n2;
outIndices[baseVertexIndex + 0] = baseVertexIndex + 0;
outIndices[baseVertexIndex + 1] = baseVertexIndex + 1;
outIndices[baseVertexIndex + 2] = baseVertexIndex + 2;
}
}
#ifndef SingleSDFMarchingCubesParams_h
#define SingleSDFMarchingCubesParams_h
#include <simd/simd.h>
struct ShapeShiftingSDFMarchingCubesParams {
simd_uint3 cells;
simd_float3 origin;
simd_float3 cellSize;
float isoLevel;
simd_float3 center;
float radius;
float blendT;
uint32_t shape0;
uint32_t shape1;
uint32_t repetition0;
uint32_t repetition1;
};
#endif /* SingleSDFMarchingCubesParams_h */
import SwiftUI
import RealityKit
import Metal
struct ShapeShiftingSDFMarchingCubesView: View {
@State private var entity: Entity?
@State private var mesh: LowLevelMesh?
@State private var timer: Timer?
@State private var interpolationAmount: Float = 0
@State private var directionForward: Bool = true
@State private var animationRate: Float = 1.5
@State private var dwellTime: Float = 0
@State private var maxDwellTime: Float = 1.0
@State private var shape0: SDFShape = .sphere
@State private var repetition0: UInt32 = 1
@State private var shape1: SDFShape = .box
@State private var repetition1: UInt32 = 1
@State private var lastSwapEnd: Int = 0
@State private var rotationAngles: SIMD3<Float> = [0, 0, 0]
@State private var lastRotationUpdateTime = CACurrentMediaTime()
let device: MTLDevice
let commandQueue: MTLCommandQueue
let computePipelineState: MTLComputePipelineState
let vertexCountBuffer: MTLBuffer
let radius: Float = 0.175
var cellsPerAxis: UInt32 = 80
var cells: SIMD3<UInt32> {
return SIMD3<UInt32>(cellsPerAxis, cellsPerAxis, cellsPerAxis)
}
var cellSize: SIMD3<Float> {
let ratio = radius / Float(cellsPerAxis) * 2
return SIMD3<Float>(ratio, ratio, ratio)
}
var material: PhysicallyBasedMaterial {
var m = PhysicallyBasedMaterial()
m.roughness = .init(floatLiteral: 0.0)
m.metallic = .init(floatLiteral: 1.0)
return m
}
init() {
let device = MTLCreateSystemDefaultDevice()!
self.device = device
self.commandQueue = device.makeCommandQueue()!
let library = device.makeDefaultLibrary()!
let function = library.makeFunction(name: "shapeShiftingSDFMarchingCubesMesh")!
self.computePipelineState = try! device.makeComputePipelineState(function: function)
self.vertexCountBuffer = device.makeBuffer(length: MemoryLayout<UInt32>.stride, options: .storageModeShared)!
}
var body: some View {
VStack(spacing: 160) {
RealityView { content in
let maxCellCount = Int(cells.x * cells.y * cells.z)
let vertexCapacity = 15 * maxCellCount
let indexCapacity = vertexCapacity
let lowLevelMesh = try! VertexPositionNormal.initializeMesh(vertexCapacity: vertexCapacity,
indexCapacity: indexCapacity)
let meshResource = try! await MeshResource(from: lowLevelMesh)
let entity = ModelEntity(mesh: meshResource, materials: [material])
content.add(entity)
self.mesh = lowLevelMesh
self.entity = entity
startTimer()
}
.onDisappear { stopTimer() }
VStack {
HStack {
Text("Animation Rate: \(animationRate, specifier: "%.2fx")")
Spacer()
Slider(value: $animationRate, in: 0.5...2)
.frame(width: 300)
}
HStack {
Text("Dwell Time: \(maxDwellTime, specifier: "%.2f")s")
Spacer()
Slider(value: $maxDwellTime, in: 0.0...2.0)
.frame(width: 300)
}
}
.frame(width: 500)
.padding()
.glassBackgroundEffect()
}
}
func startTimer() {
stopTimer()
timer = Timer.scheduledTimer(withTimeInterval: 1.0 / 60.0, repeats: true) { _ in
let currentTime = CACurrentMediaTime()
let frameDuration = currentTime - lastRotationUpdateTime
let deltaInterpolation = Float(frameDuration) * animationRate
interpolationAmount += directionForward ? deltaInterpolation : -deltaInterpolation
// Handle dwell time at the ends
if interpolationAmount >= 1.0 {
if dwellTime < maxDwellTime {
dwellTime += Float(frameDuration)
interpolationAmount = 1.0
} else {
// Dwell time complete, start transitioning
if lastSwapEnd != 1 {
shape0 = randomShape(excluding: shape1)
repetition0 = randomizeRepetition()
lastSwapEnd = 1
}
interpolationAmount = 1.0
directionForward = false
dwellTime = 0 // Reset dwell counter
}
} else if interpolationAmount <= 0 {
if dwellTime < maxDwellTime {
dwellTime += Float(frameDuration)
interpolationAmount = 0
} else {
// Dwell time complete, start transitioning
if lastSwapEnd != 0 {
shape1 = randomShape(excluding: shape0)
repetition1 = randomizeRepetition()
lastSwapEnd = 0
}
interpolationAmount = 0
directionForward = true
dwellTime = 0 // Reset dwell counter
}
}
updateMesh()
// Rotate along all axis at different rates for a wonky roll effect
let rotationMultiplier: Float = 1.25
rotationAngles.x += Float(frameDuration * 0.25) * rotationMultiplier
rotationAngles.y += Float(frameDuration * 0.125) * rotationMultiplier
rotationAngles.z += Float(frameDuration * 0.0675) * rotationMultiplier
let rotationX = simd_quatf(angle: rotationAngles.x, axis: [1, 0, 0])
let rotationY = simd_quatf(angle: rotationAngles.y, axis: [0, 1, 0])
let rotationZ = simd_quatf(angle: rotationAngles.z, axis: [0, 0, 1])
entity?.transform.rotation = rotationX * rotationY * rotationZ
lastRotationUpdateTime = currentTime
}
}
func stopTimer() {
timer?.invalidate()
timer = nil
}
func updateMesh() {
guard let mesh = mesh,
let commandBuffer = commandQueue.makeCommandBuffer(),
let computeEncoder = commandBuffer.makeComputeCommandEncoder()
else { return }
let gridSizeWorldSpace = SIMD3<Float>(Float(cells.x), Float(cells.y), Float(cells.z)) * cellSize
let gridMinCornerWorldSpace = -0.5 * gridSizeWorldSpace
let gridMaxCornerWorldSpace = gridMinCornerWorldSpace + gridSizeWorldSpace
var params = ShapeShiftingSDFMarchingCubesParams(
cells: cells,
origin: gridMinCornerWorldSpace,
cellSize: cellSize,
isoLevel: 0.0,
center: SIMD3<Float>(0, 0, 0),
radius: radius,
blendT: interpolationAmount,
shape0: shape0.rawValue,
shape1: shape1.rawValue,
repetition0: repetition0,
repetition1: repetition1
)
vertexCountBuffer.contents().bindMemory(to: UInt32.self, capacity: 1).pointee = 0
let vertexBuffer = mesh.replace(bufferIndex: 0, using: commandBuffer)
let indexBuffer = mesh.replaceIndices(using: commandBuffer)
computeEncoder.setComputePipelineState(computePipelineState)
computeEncoder.setBuffer(vertexBuffer, offset: 0, index: 0)
computeEncoder.setBuffer(indexBuffer, offset: 0, index: 1)
computeEncoder.setBuffer(vertexCountBuffer, offset: 0, index: 2)
computeEncoder.setBytes(&params, length: MemoryLayout<ShapeShiftingSDFMarchingCubesParams>.stride, index: 3)
let threadsPerThreadgroup = MTLSize(width: 8, height: 8, depth: 4)
let threadgroups = MTLSize(
width: (Int(cells.x) + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width,
height: (Int(cells.y) + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height,
depth: (Int(cells.z) + threadsPerThreadgroup.depth - 1) / threadsPerThreadgroup.depth
)
computeEncoder.dispatchThreadgroups(threadgroups, threadsPerThreadgroup: threadsPerThreadgroup)
computeEncoder.endEncoding()
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
let vertexCount = Int(vertexCountBuffer.contents().bindMemory(to: UInt32.self, capacity: 1).pointee)
mesh.parts.replaceAll([
LowLevelMesh.Part(indexCount: vertexCount,
topology: .triangle,
bounds: BoundingBox(min: gridMinCornerWorldSpace, max: gridMaxCornerWorldSpace))
])
}
func randomShape(excluding: SDFShape) -> SDFShape {
let choices = SDFShape.allCases.filter { $0 != excluding }
return choices.randomElement()!
}
func randomizeRepetition() -> UInt32 {
let random = Float.random(in: 0...1)
let chance: Float = 0.25
return random > chance ? 1 : 3
}
}
#Preview { ShapeShiftingSDFMarchingCubesView() }
#ifndef triTable_h
#define triTable_h
constant int triTable[256][16] =
{{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
#endif /* triTable_h */
import Foundation
import RealityKit
extension VertexPositionNormal {
static var vertexAttributes: [LowLevelMesh.Attribute] = [
.init(semantic: .position, format: .float3, offset: MemoryLayout<Self>.offset(of: \.position)!),
.init(semantic: .normal, format: .float3, offset: MemoryLayout<Self>.offset(of: \.normal)!)
]
static var vertexLayouts: [LowLevelMesh.Layout] = [
.init(bufferIndex: 0, bufferStride: MemoryLayout<Self>.stride)
]
static var descriptor: LowLevelMesh.Descriptor {
var desc = LowLevelMesh.Descriptor()
desc.vertexAttributes = VertexPositionNormal.vertexAttributes
desc.vertexLayouts = VertexPositionNormal.vertexLayouts
desc.indexType = .uint32
return desc
}
@MainActor static func initializeMesh(vertexCapacity: Int,
indexCapacity: Int) throws -> LowLevelMesh {
var desc = VertexPositionNormal.descriptor
desc.vertexCapacity = vertexCapacity
desc.indexCapacity = indexCapacity
return try LowLevelMesh(descriptor: desc)
}
}
#include <simd/simd.h>
#ifndef VertexPositionNormal_h
#define VertexPositionNormal_h
struct VertexPositionNormal {
simd_float3 position;
simd_float3 normal;
};
#endif /* VertexPositionNormal_h */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment