143 lines
3.5 KiB
TypeScript

import { Renderer, Camera, Transform, Texture, Raycast, 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);
const raycast = new Raycast();
let activeTool = "pan";
let shouldBeRendering = false;
function update() {
if (!shouldBeRendering) return;
requestAnimationFrame(update);
controls.update();
renderer.render({ scene, camera });
}
function click() {
const res = raycast.intersectSphere(skybox);
console.log(res);
}
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() {
//@ts-ignore
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) {
//@ts-ignore
overlayProgram.uniforms.opacity.value = o / 100;
}
return {
start, stop, setTool, updateOverlay, setOpacity, click
}
}