import * as React from 'react' import * as THREE from 'three' import { ForwardRefComponent } from '../helpers/ts-utils' export type Args = T extends new (...args: any) => any ? ConstructorParameters : T export type ShapeProps = Omit & { args?: Args } function create(type: string, effect?: (mesh: THREE.Mesh) => void): ForwardRefComponent, THREE.Mesh> { const El: any = type + 'Geometry' return React.forwardRef(({ args, children, ...props }: ShapeProps, fref: React.ForwardedRef) => { const ref = React.useRef(null!) React.useImperativeHandle(fref, () => ref.current) React.useLayoutEffect(() => void effect?.(ref.current)) return ( {children} ) }) } export const Box = /* @__PURE__ */ create('box') export const Circle = /* @__PURE__ */ create('circle') export const Cone = /* @__PURE__ */ create('cone') export const Cylinder = /* @__PURE__ */ create('cylinder') export const Sphere = /* @__PURE__ */ create('sphere') export const Plane = /* @__PURE__ */ create('plane') export const Tube = /* @__PURE__ */ create('tube') export const Torus = /* @__PURE__ */ create('torus') export const TorusKnot = /* @__PURE__ */ create('torusKnot') export const Tetrahedron = /* @__PURE__ */ create('tetrahedron') export const Ring = /* @__PURE__ */ create('ring') export const Polyhedron = /* @__PURE__ */ create('polyhedron') export const Icosahedron = /* @__PURE__ */ create('icosahedron') export const Octahedron = /* @__PURE__ */ create('octahedron') export const Dodecahedron = /* @__PURE__ */ create('dodecahedron') export const Extrude = /* @__PURE__ */ create('extrude') export const Lathe = /* @__PURE__ */ create('lathe') export const Capsule = /* @__PURE__ */ create('capsule') export const Shape = /* @__PURE__ */ create('shape', ({ geometry }) => { // Calculate UVs (by https://discourse.threejs.org/u/prisoner849) // https://discourse.threejs.org/t/custom-shape-in-image-not-working/49348/10 const pos = geometry.attributes.position as THREE.BufferAttribute const b3 = new THREE.Box3().setFromBufferAttribute(pos) const b3size = new THREE.Vector3() b3.getSize(b3size) const uv: number[] = [] let x = 0, y = 0, u = 0, v = 0 for (let i = 0; i < pos.count; i++) { x = pos.getX(i) y = pos.getY(i) u = (x - b3.min.x) / b3size.x v = (y - b3.min.y) / b3size.y uv.push(u, v) } geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2)) })