var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var faces_exports = {};
__export(faces_exports, {
  FACE_ORDER: () => FACE_ORDER,
  generateVoxelFaceSurfaces: () => generateVoxelFaceSurfaces
});
module.exports = __toCommonJS(faces_exports);
const FACE_ORDER = ["east", "west", "top", "bottom", "north", "south"];
const FACE_CONFIGS = {
  east: { axis: 0, direction: 1, uAxis: 2, vAxis: 1 },
  west: { axis: 0, direction: -1, uAxis: 2, vAxis: 1 },
  top: { axis: 1, direction: 1, uAxis: 0, vAxis: 2 },
  bottom: { axis: 1, direction: -1, uAxis: 0, vAxis: 2 },
  north: { axis: 2, direction: 1, uAxis: 0, vAxis: 1 },
  south: { axis: 2, direction: -1, uAxis: 0, vAxis: 1 }
};
function clamp(value, min, max) {
  return Math.min(max, Math.max(min, value));
}
function getVoxelAt(voxels, dims, x, y, z) {
  if (x < 0 || y < 0 || z < 0)
    return 0;
  if (x >= dims[0] || y >= dims[1] || z >= dims[2])
    return 0;
  const index = x + dims[0] * (y + dims[1] * z);
  return voxels[index] ?? 0;
}
function buildFaceGeometry(face, config, size) {
  const positions = new Float32Array(12);
  const normals = new Float32Array(12);
  const uvs = new Float32Array(8);
  const vertexOrder = (() => {
    switch (face) {
      case "east":
        return [
          [-1, -1],
          [-1, 1],
          [1, 1],
          [1, -1]
        ];
      case "west":
        return [
          [1, -1],
          [1, 1],
          [-1, 1],
          [-1, -1]
        ];
      case "top":
        return [
          [-1, -1],
          [-1, 1],
          [1, 1],
          [1, -1]
        ];
      case "bottom":
        return [
          [-1, -1],
          [1, -1],
          [1, 1],
          [-1, 1]
        ];
      case "north":
        return [
          [-1, -1],
          [1, -1],
          [1, 1],
          [-1, 1]
        ];
      case "south":
      default:
        return [
          [1, -1],
          [-1, -1],
          [-1, 1],
          [1, 1]
        ];
    }
  })();
  const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
  const halfSize = [size[0] / 2, size[1] / 2, size[2] / 2];
  const centerCoordinate = config.direction > 0 ? halfSize[config.axis] : -halfSize[config.axis];
  const uHalf = size[config.uAxis] / 2;
  const vHalf = size[config.vAxis] / 2;
  const normalVector = [0, 0, 0];
  normalVector[config.axis] = config.direction;
  vertexOrder.forEach(([uSign, vSign], index) => {
    const offset = index * 3;
    const position = [0, 0, 0];
    position[config.axis] = centerCoordinate;
    position[config.uAxis] = uSign * uHalf;
    position[config.vAxis] = vSign * vHalf;
    positions[offset] = position[0];
    positions[offset + 1] = position[1];
    positions[offset + 2] = position[2];
    normals[offset] = normalVector[0];
    normals[offset + 1] = normalVector[1];
    normals[offset + 2] = normalVector[2];
  });
  const baseUvs = (() => {
    switch (face) {
      case "east":
        return [
          [0, 1],
          [0, 0],
          [1, 0],
          [1, 1]
        ];
      case "west":
        return [
          [1, 1],
          [1, 0],
          [0, 0],
          [0, 1]
        ];
      case "top":
        return [
          [0, 1],
          [0, 0],
          [1, 0],
          [1, 1]
        ];
      case "bottom":
        return [
          [0, 0],
          [1, 0],
          [1, 1],
          [0, 1]
        ];
      case "north":
        return [
          [0, 1],
          [1, 1],
          [1, 0],
          [0, 0]
        ];
      case "south":
      default:
        return [
          [1, 1],
          [0, 1],
          [0, 0],
          [1, 0]
        ];
    }
  })();
  baseUvs.forEach(([u, v], index) => {
    uvs[index * 2] = u;
    uvs[index * 2 + 1] = v;
  });
  return { positions, normals, uvs, indices };
}
function generateVoxelFaceSurfaces(options) {
  const { primitive, materialsById, defaultColor } = options;
  if (!Array.isArray(primitive.voxels) || primitive.voxels.length === 0) {
    return [];
  }
  const size = primitive.size ?? [1, 1, 1];
  const dims = [
    Math.max(1, Math.round(size[0])),
    Math.max(1, Math.round(size[1])),
    Math.max(1, Math.round(size[2]))
  ];
  if (primitive.voxels.length !== dims[0] * dims[1] * dims[2]) {
    return [];
  }
  const voxelSize = [1, 1, 1];
  const primitiveSize = [
    dims[0] * voxelSize[0],
    dims[1] * voxelSize[1],
    dims[2] * voxelSize[2]
  ];
  const palette = primitive.palette ?? [];
  const patches = [];
  const createEmptyCell = () => ({
    color: [0, 0, 0, 0],
    emissive: [0, 0, 0, 0],
    occupied: false
  });
  const ensurePlane = (planes, planeIndex, surfaceCoord, width, height) => {
    let plane = planes.get(planeIndex);
    if (!plane) {
      const cells = Array.from({ length: height }, () => Array.from({ length: width }, () => createEmptyCell()));
      plane = { surfaceCoord, cells };
      planes.set(planeIndex, plane);
    }
    return plane;
  };
  const halfSize = [primitiveSize[0] / 2, primitiveSize[1] / 2, primitiveSize[2] / 2];
  FACE_ORDER.forEach((face) => {
    const config = FACE_CONFIGS[face];
    const width = dims[config.uAxis];
    const height = dims[config.vAxis];
    const planes = /* @__PURE__ */ new Map();
    for (let x = 0; x < dims[0]; x += 1) {
      for (let y = 0; y < dims[1]; y += 1) {
        for (let z = 0; z < dims[2]; z += 1) {
          const paletteIndex = getVoxelAt(primitive.voxels, dims, x, y, z);
          if (paletteIndex === 0) {
            continue;
          }
          const neighborCoord = [x, y, z];
          neighborCoord[config.axis] += config.direction;
          const neighbor = getVoxelAt(primitive.voxels, dims, neighborCoord[0], neighborCoord[1], neighborCoord[2]);
          if (neighbor !== 0) {
            continue;
          }
          const uCoord = [x, y, z][config.uAxis];
          const vCoord = [x, y, z][config.vAxis];
          const voxelAxis = [x, y, z][config.axis];
          const surfaceCoord = config.direction > 0 ? voxelAxis + 1 : voxelAxis;
          const plane = ensurePlane(planes, surfaceCoord, surfaceCoord, width, height);
          const cell = plane.cells[vCoord][uCoord];
          const materialId = palette[paletteIndex - 1];
          const material = materialId ? materialsById.get(materialId) : void 0;
          const baseColor = material?.baseColor ?? defaultColor;
          const opacity = material?.opacity !== void 0 ? clamp(material.opacity, 0, 1) : 1;
          const alpha = Math.round(opacity * 255);
          cell.color = [baseColor[0], baseColor[1], baseColor[2], alpha];
          cell.occupied = alpha > 0;
          if (material?.emissiveColor) {
            cell.emissive = [material.emissiveColor[0], material.emissiveColor[1], material.emissiveColor[2], 255];
          } else {
            cell.emissive = [0, 0, 0, 0];
          }
        }
      }
    }
    const cellSizeU = voxelSize[config.uAxis];
    const cellSizeV = voxelSize[config.vAxis];
    planes.forEach((plane) => {
      const visited = Array.from({ length: height }, () => new Array(width).fill(false));
      for (let v = 0; v < height; v += 1) {
        for (let u = 0; u < width; u += 1) {
          if (visited[v][u])
            continue;
          const cell = plane.cells[v][u];
          if (!cell.occupied) {
            visited[v][u] = true;
            continue;
          }
          let patchWidth = 1;
          while (u + patchWidth < width) {
            const nextCell = plane.cells[v][u + patchWidth];
            if (!nextCell.occupied || visited[v][u + patchWidth])
              break;
            patchWidth += 1;
          }
          let patchHeight = 1;
          outer: while (v + patchHeight < height) {
            for (let offset = 0; offset < patchWidth; offset += 1) {
              const nextCell = plane.cells[v + patchHeight][u + offset];
              if (!nextCell.occupied || visited[v + patchHeight][u + offset]) {
                break outer;
              }
            }
            patchHeight += 1;
          }
          for (let dv = 0; dv < patchHeight; dv += 1) {
            for (let du = 0; du < patchWidth; du += 1) {
              visited[v + dv][u + du] = true;
            }
          }
          const textureWidth = patchWidth;
          const textureHeight = patchHeight;
          const colorBuffer = new Uint8Array(textureWidth * textureHeight * 4);
          const emissiveBuffer = new Uint8Array(textureWidth * textureHeight * 4);
          let patchHasEmissive = false;
          let patchHasTransparency = false;
          for (let pv = 0; pv < patchHeight; pv += 1) {
            for (let pu = 0; pu < patchWidth; pu += 1) {
              const sourceCell = plane.cells[v + pv][u + pu];
              const targetY = textureHeight - 1 - pv;
              const targetIndex = (targetY * textureWidth + pu) * 4;
              colorBuffer[targetIndex] = sourceCell.color[0];
              colorBuffer[targetIndex + 1] = sourceCell.color[1];
              colorBuffer[targetIndex + 2] = sourceCell.color[2];
              colorBuffer[targetIndex + 3] = sourceCell.color[3];
              if (sourceCell.color[3] < 255) {
                patchHasTransparency = true;
              }
              emissiveBuffer[targetIndex] = sourceCell.emissive[0];
              emissiveBuffer[targetIndex + 1] = sourceCell.emissive[1];
              emissiveBuffer[targetIndex + 2] = sourceCell.emissive[2];
              emissiveBuffer[targetIndex + 3] = sourceCell.emissive[3];
              if (sourceCell.emissive[3] > 0) {
                patchHasEmissive = true;
              }
            }
          }
          const geometry = buildPatchGeometry({
            face,
            config,
            primitiveSize,
            voxelSize,
            halfSize,
            uStart: u,
            vStart: v,
            patchWidth,
            patchHeight,
            surfaceCoord: plane.surfaceCoord
          });
          patches.push({
            face,
            width: patchWidth * cellSizeU,
            height: patchHeight * cellSizeV,
            textureWidth,
            textureHeight,
            color: colorBuffer,
            emissive: patchHasEmissive ? emissiveBuffer : void 0,
            hasEmissive: patchHasEmissive,
            hasTransparency: patchHasTransparency,
            geometry
          });
        }
      }
    });
  });
  return patches;
}
function buildPatchGeometry(options) {
  const { face, config, primitiveSize, voxelSize, halfSize, uStart, vStart, patchWidth, patchHeight, surfaceCoord } = options;
  const positions = new Float32Array(12);
  const normals = new Float32Array(12);
  const uvs = new Float32Array(8);
  const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
  const cellSizeAxis = voxelSize[config.axis];
  const axisCoord = -halfSize[config.axis] + surfaceCoord * cellSizeAxis;
  const cellSizeU = voxelSize[config.uAxis];
  const cellSizeV = voxelSize[config.vAxis];
  const uMin = -halfSize[config.uAxis] + uStart * cellSizeU;
  const uMax = uMin + patchWidth * cellSizeU;
  const vMin = -halfSize[config.vAxis] + vStart * cellSizeV;
  const vMax = vMin + patchHeight * cellSizeV;
  const pick = (sign, minValue, maxValue) => sign < 0 ? minValue : maxValue;
  const vertexOrder = (() => {
    switch (face) {
      case "east":
        return [
          [-1, -1],
          [-1, 1],
          [1, 1],
          [1, -1]
        ];
      case "west":
        return [
          [1, -1],
          [1, 1],
          [-1, 1],
          [-1, -1]
        ];
      case "top":
        return [
          [-1, -1],
          [-1, 1],
          [1, 1],
          [1, -1]
        ];
      case "bottom":
        return [
          [-1, -1],
          [1, -1],
          [1, 1],
          [-1, 1]
        ];
      case "north":
        return [
          [-1, -1],
          [1, -1],
          [1, 1],
          [-1, 1]
        ];
      case "south":
      default:
        return [
          [1, -1],
          [-1, -1],
          [-1, 1],
          [1, 1]
        ];
    }
  })();
  const uvOrder = (() => {
    switch (face) {
      case "east":
        return [
          [0, 1],
          [0, 0],
          [1, 0],
          [1, 1]
        ];
      case "west":
        return [
          [1, 1],
          [1, 0],
          [0, 0],
          [0, 1]
        ];
      case "top":
        return [
          [0, 1],
          [0, 0],
          [1, 0],
          [1, 1]
        ];
      case "bottom":
        return [
          [0, 0],
          [1, 0],
          [1, 1],
          [0, 1]
        ];
      case "north":
        return [
          [0, 1],
          [1, 1],
          [1, 0],
          [0, 0]
        ];
      case "south":
      default:
        return [
          [1, 1],
          [0, 1],
          [0, 0],
          [1, 0]
        ];
    }
  })();
  for (let i = 0; i < vertexOrder.length; i += 1) {
    const [uSign, vSign] = vertexOrder[i];
    const pos = [0, 0, 0];
    pos[config.axis] = axisCoord;
    pos[config.uAxis] = pick(uSign, uMin, uMax);
    pos[config.vAxis] = pick(vSign, vMin, vMax);
    positions[i * 3] = pos[0];
    positions[i * 3 + 1] = pos[1];
    positions[i * 3 + 2] = pos[2];
    const normal = [0, 0, 0];
    normal[config.axis] = config.direction;
    normals[i * 3] = normal[0];
    normals[i * 3 + 1] = normal[1];
    normals[i * 3 + 2] = normal[2];
    uvs[i * 2] = uvOrder[i][0];
    uvs[i * 2 + 1] = uvOrder[i][1];
  }
  return { positions, normals, uvs, indices };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  FACE_ORDER,
  generateVoxelFaceSurfaces
});
