import { Renderer, Camera, Transform, Texture, Sphere, Program, Mesh } from "ogl" import { Orbit } from "./CustomOrbit" import { bufToImageUrl } from "../../helpers"; import VertexShader from "./Orb.vert"; import FragmentShader from "./Orb.frag"; import Toast from "../Toast"; let hasConfirmed = false; export default (image: Image, canvas2D: CanvasRenderingContext2D, canvas3D: HTMLCanvasElement) => { const renderer = new Renderer({ dpr: 2, canvas: canvas3D }); const gl = renderer.gl; gl.clearColor(1, 1, 1, 1); const camera = new Camera(gl, { fov: 45 }); camera.position.set(0, 0, 8); const controls = new Orbit(camera, { enablePan: false, enableZoom: false, rotateSpeed: -0.1 }); function resize() { renderer.setSize(window.innerWidth, window.innerHeight); camera.perspective({ aspect: gl.canvas.width / gl.canvas.height }); } window.addEventListener('resize', resize, false); resize(); const scene = new Transform(); // Texture is equirectangular const texture = new Texture(gl); const img = new Image(); img.onload = () => (texture.image = img); img.src = bufToImageUrl(image.data, image.type); // Use Sphere geometry to render equirectangular textures const geometry = new Sphere(gl, { radius: 1, widthSegments: 64 }); const program = new Program(gl, { vertex: VertexShader, fragment: FragmentShader, uniforms: { tMap: { value: texture }, opacity: { value: 1 } }, // Need inside of sphere to be visible cullFace: null, }); // Camera will dwell inside skybox const skybox = new Mesh(gl, { geometry, program }); skybox.scale.set(10); skybox.scale.x = -10; skybox.setParent(scene); const overlayTexture = new Texture(gl, { image: new Uint8Array(image.data), width: image.width, height: image.height, }); // Use Sphere geometry to render equirectangular textures const overlayGeometry = new Sphere(gl, { radius: 1, widthSegments: 64 }); const overlayProgram = new Program(gl, { vertex: VertexShader, fragment: FragmentShader, uniforms: { tMap: { value: overlayTexture }, opacity: { value: 0.5 } }, transparent: true, // Need inside of sphere to be visible cullFace: null, }); // Camera will dwell inside skybox const overlay = new Mesh(gl, { geometry: overlayGeometry, program: overlayProgram }); overlay.scale.set(9.995); overlay.scale.x = -9.995; overlay.setParent(scene); let activeTool = "pan"; let shouldBeRendering = false; function update() { if (!shouldBeRendering) return; requestAnimationFrame(update); controls.update(); renderer.render({ scene, camera }); } function start() { !hasConfirmed && Toast.confirm("Drawing does not work correctly in 3D at the moment").then(c => { hasConfirmed = c; }) if (shouldBeRendering) return; updateOverlay(); shouldBeRendering = true; update(); } function updateOverlay() { overlayProgram.uniforms.tMap.value.image = canvas2D.getImageData(0, 0, image.width, image.height).data; } function stop() { shouldBeRendering = false; } function setTool(t) { activeTool = t; controls.enabled = t === "pan"; } function setOpacity(o) { overlayProgram.uniforms.opacity.value = o / 100; } return { start, stop, setTool, updateOverlay, setOpacity } }