import * as se3 from './se3'; function memoize(f) { const memo = {}; function g(...args) { if (!(args in memo)) { memo[args] = f(...args); } return memo[args]; } return g; } function _makeTextureFace(texture) { const textMul = 0.0625; const textOff = texture.map(x => x * textMul); const textuv = [ [0.99, 0.99], [0.01, 0.99], [0.01, 0.01], [0.99, 0.99], [0.01, 0.01], [0.99, 0.01], ]; const textures = textuv.map(uv => uv.map((x, j) => textMul * x + textOff[j])); return textures; } const makeTextureFace = memoize(_makeTextureFace); function makePZFace(texture) { return { vertices: [[0.5, 0.5, 0], [-0.5, 0.5, 0], [-0.5, -0.5, 0], [0.5, 0.5, 0], [-0.5, -0.5, 0], [0.5, -0.5, 0]], normals: Array(6).fill([0.0, 0.0, 1.0]), textures: makeTextureFace(texture), }; } function makeNZFace(texture) { return { vertices: [[-0.5, 0.5, 0.0], [0.5, 0.5, 0.0], [0.5, -0.5, 0.0], [-0.5, 0.5, 0.0], [0.5, -0.5, 0.0], [-0.5, -0.5, 0.0]], normals: Array(6).fill([0.0, 0.0, -1.0]), textures: makeTextureFace(texture), }; } function makePXFace(texture) { return { vertices: [[0, 0.5, -0.5], [0, 0.5, 0.5], [0, -0.5, 0.5], [0, 0.5, -0.5], [0, -0.5, 0.5], [0, -0.5, -0.5]], normals: Array(6).fill([1.0, 0.0, 0.0]), textures: makeTextureFace(texture), }; } function makeNXFace(texture) { return { vertices: [[0, 0.5, 0.5], [0, 0.5, -0.5], [0, -0.5, -0.5], [0, 0.5, 0.5], [0, -0.5, -0.5], [0, -0.5, 0.5]], normals: Array(6).fill([-1.0, 0.0, 0.0]), textures: makeTextureFace(texture), }; } function makePYFace(texture) { return { vertices: [[0.5, 0, -0.5], [-0.5, 0, -0.5], [-0.5, 0, 0.5], [0.5, 0, -0.5], [-0.5, 0, 0.5], [0.5, 0, 0.5]], normals: Array(6).fill([0.0, 1.0, 0.0]), textures: makeTextureFace(texture), }; } function makeNYFace(texture) { return { vertices: [[0.5, 0, 0.5], [-0.5, 0, 0.5], [-0.5, 0, -0.5], [0.5, 0, 0.5], [-0.5, 0, -0.5], [0.5, 0, -0.5]], normals: Array(6).fill([0.0, -1.0, 0.0]), textures: makeTextureFace(texture), }; } function translateFace(face, x, y, z) { return { normals: face.normals, textures: face.textures, vertices: face.vertices.map(([vx, vy, vz]) => [vx + x, vy + y, vz + z]), }; } export function makeFace(which, texture, centerPos) { switch(which) { case '-x': return translateFace(makeNXFace(texture), ...centerPos); case '+x': return translateFace(makePXFace(texture), ...centerPos); case '-y': return translateFace(makeNYFace(texture), ...centerPos); case '+y': return translateFace(makePYFace(texture), ...centerPos); case '-z': return translateFace(makeNZFace(texture), ...centerPos); case '+z': return translateFace(makePZFace(texture), ...centerPos); } throw Error('unknown face'); } /** Packs all those faces into one big buffer. */ export function makeBufferFromFaces(gl, faces) { const numVertices = faces.map(f => f.vertices).reduce((count, vertices) => count + vertices.length, 0); // 3 * float32 + 3 * byte (padded to 4) + 2 * short // see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer#examples const vertexSize = 3 * 4 + 4 + 4; const glBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, glBuffer); const buffer = new Uint8Array(numVertices * vertexSize); const dv = new DataView(buffer.buffer); let offset = 0; faces.forEach(face => { for (let i = 0; i < face.vertices.length; i++) { const position = face.vertices[i]; dv.setFloat32(offset + 0, position[0], true); dv.setFloat32(offset + 4, position[1], true); dv.setFloat32(offset + 8, position[2], true); offset += 12; const normal = face.normals[i]; dv.setInt8(offset + 0, normal[0] * 0x7f); dv.setInt8(offset + 1, normal[1] * 0x7f); dv.setInt8(offset + 2, normal[2] * 0x7f); offset += 4; const texture = face.textures[i]; dv.setUint16(offset + 0, texture[0] * 0xffff, true); dv.setUint16(offset + 2, texture[1] * 0xffff, true); offset += 4; } }); gl.bufferData(gl.ARRAY_BUFFER, buffer, gl.STATIC_DRAW); return { glBuffer, numVertices, delete: () => gl.deleteBuffer(glBuffer), }; }