UNPKG

@codyjasonbennett/react-ogl

Version:

A barebones react renderer for OGL.

296 lines (295 loc) 9.15 kB
var _a; import Reconciler from "react-reconciler"; import { DefaultEventPriority } from "react-reconciler/constants"; import * as OGL from "ogl"; import * as React from "react"; import { toPascalCase, detach, classExtends, attach, applyProps } from "./utils.mjs"; import { RESERVED_PROPS } from "./constants.mjs"; const catalogue = { ...OGL }; const catalogueGL = [ OGL.Camera, OGL.Geometry, OGL.Mesh, OGL.Program, OGL.RenderTarget, OGL.Texture, OGL.Flowmap, OGL.GPGPU, OGL.NormalProgram, OGL.Polyline, OGL.Post, OGL.Shadow, OGL.AxesHelper, OGL.GridHelper, OGL.WireMesh ]; function extend(objects, gl = false) { for (const key in objects) { const value = objects[key]; catalogue[key] = value; if (gl) catalogueGL.push(value); } } function createInstance(type, { object = null, args = [], ...props }, root) { const name = toPascalCase(type); const target = catalogue[name]; if (type !== "primitive" && !target) throw `${type} is not a part of the OGL catalogue! Did you forget to extend?`; if (type === "primitive" && !object) throw `"object" must be set when using primitives.`; const instance = { root, parent: null, children: [], type, props: { ...props, args }, object }; return instance; } const appendChild = (parent, child) => { child.parent = parent; parent.children.push(child); }; function removeChild(parent, child) { var _a2, _b; child.parent = null; const childIndex = parent.children.indexOf(child); if (childIndex !== -1) parent.children.splice(childIndex, 1); if (child.props.attach) detach(parent, child); else if (child.object instanceof OGL.Transform) parent.object.removeChild(child.object); if (child.props.dispose !== null) (_b = (_a2 = child.object).dispose) == null ? void 0 : _b.call(_a2); child.object = null; } function commitInstance(instance) { var _a2; if (!instance.parent) return; if (instance.type !== "primitive" && !instance.object) { const name = toPascalCase(instance.type); const target = catalogue[name]; const { args = [], ...props } = instance.props; const isGLInstance = Object.values(catalogueGL).some((elem) => classExtends(elem, target)); if (isGLInstance) { const { gl } = instance.root.getState(); const filtered = args.filter((arg) => arg !== gl); if (instance.type === "program" || instance.type === "geometry") { const attrs = Object.entries(props).reduce((acc, [key, value]) => { if (instance.type === "geometry" && !(value == null ? void 0 : value.data)) return acc; if (!key.includes("-")) acc[key] = value; return acc; }, (_a2 = filtered[0]) != null ? _a2 : {}); instance.object = new target(gl, attrs); } else { instance.object = new target(gl, ...filtered); } } else { instance.object = new target(...args); } } if (!instance.props.attach) { if (instance.object instanceof OGL.Geometry) instance.props.attach = "geometry"; else if (instance.object instanceof OGL.Program) instance.props.attach = "program"; } for (const child of instance.children) { if (child.props.attach) attach(instance, child); else if (child.object instanceof OGL.Transform) child.object.setParent(instance.object); } if (!instance.parent.parent) { if (instance.props.attach) attach(instance.parent, instance); else if (instance.object instanceof OGL.Transform) instance.object.setParent(instance.parent.object); } applyProps(instance.object, instance.props); } function switchInstance(instance, type, props, root) { const newInstance = createInstance(type, props, instance.root); const parent = instance.parent; removeChild(parent, instance); appendChild(parent, newInstance); commitInstance(newInstance); if (parent.parent) { if (newInstance.props.attach) attach(parent, newInstance); else if (newInstance.object instanceof OGL.Transform) newInstance.object.setParent(parent.object); } for (const child of instance.children) { appendChild(newInstance, child); if (child.props.attach) { detach(instance, child); attach(newInstance, child); } } instance.children = []; [root, root.alternate].forEach((fiber) => { if (fiber !== null) { fiber.stateNode = newInstance; if (fiber.ref) { if (typeof fiber.ref === "function") fiber.ref(newInstance.object); else fiber.ref.current = newInstance.object; } } }); return newInstance; } function checkShallow(a, b) { if (Array.isArray(a)) { if (!Array.isArray(b)) return false; if (a == b) return true; if (a.every((v, i) => v === b[i])) return true; } if (a === b) return true; return false; } function diffProps(instance, newProps, oldProps) { const changedProps = {}; for (const key in newProps) { if (RESERVED_PROPS.includes(key)) continue; if (instance.type === "primitive" && key === "object") continue; if (checkShallow(newProps[key], oldProps[key])) continue; changedProps[key] = newProps[key]; } return changedProps; } function insertBefore(parent, child, beforeChild) { if (!child) return; child.parent = parent; parent.children.splice(parent.children.indexOf(beforeChild), 0, child); } const reconciler = Reconciler({ isPrimaryRenderer: false, supportsMutation: true, supportsHydration: false, supportsPersistence: false, scheduleTimeout: () => typeof setTimeout !== "undefined" ? setTimeout : void 0, cancelTimeout: () => typeof clearTimeout !== "undefined" ? clearTimeout : void 0, noTimeout: -1, shouldSetTextContent: () => false, resetTextContent: () => { }, createTextInstance() { throw new Error("Text is not allowed in the OGL scene-graph!"); }, hideTextInstance() { throw new Error("Text is not allowed in the OGL scene-graph!"); }, unhideTextInstance: () => { }, getPublicInstance: (instance) => instance.object, getRootHostContext: () => null, getChildHostContext: (parentHostContext) => parentHostContext, preparePortalMount: (container) => container, prepareForCommit: () => null, resetAfterCommit: () => { }, clearContainer: () => false, createInstance, appendChild, appendInitialChild: appendChild, appendChildToContainer: () => { }, removeChild, removeChildFromContainer: () => { }, insertBefore, insertInContainerBefore: () => { }, prepareUpdate(instance, type, oldProps, newProps) { var _a2, _b, _c; if (instance.type === "primitive" && oldProps.object !== newProps.object) return [true]; if (type === "program") { if (oldProps.vertex !== newProps.vertex) return [true]; if (oldProps.fragment !== newProps.fragment) return [true]; } if (type === "geometry") { for (const key in oldProps) { const isAttribute = ((_a2 = oldProps[key]) == null ? void 0 : _a2.data) || ((_b = newProps[key]) == null ? void 0 : _b.data); if (isAttribute && oldProps[key] !== newProps[key]) return [true]; } } if ((_c = newProps.args) == null ? void 0 : _c.some((value, index) => { var _a3; return value !== ((_a3 = oldProps.args) == null ? void 0 : _a3[index]); })) return [true]; const changedProps = diffProps(instance, newProps, oldProps); if (Object.keys(changedProps).length) return [false, changedProps]; return null; }, commitUpdate(instance, payload, type, oldProps, newProps, root) { const [reconstruct, changedProps] = payload; if (reconstruct) return switchInstance(instance, type, newProps, root); if (changedProps == null ? void 0 : changedProps.attach) { if (oldProps.attach) detach(instance.parent, instance); instance.props.attach = newProps.attach; if (newProps.attach) attach(instance.parent, instance); } Object.assign(instance.props, newProps); applyProps(instance.object, newProps); }, hideInstance(instance) { if (instance.object instanceof OGL.Transform) { instance.object.visible = false; } }, unhideInstance(instance) { var _a2; if (instance.object instanceof OGL.Transform) { instance.object.visible = (_a2 = instance.props.visible) != null ? _a2 : true; } }, finalizeInitialChildren: () => true, commitMount: commitInstance, getCurrentEventPriority: () => DefaultEventPriority, beforeActiveInstanceBlur: () => { }, afterActiveInstanceBlur: () => { }, detachDeletedInstance: () => { } }); const act = React.unstable_act; const isProd = typeof process === "undefined" || ((_a = process.env) == null ? void 0 : _a["NODE_ENV"]) === "production"; reconciler.injectIntoDevTools({ findFiberByHostInstance: (instance) => instance.root, bundleType: isProd ? 0 : 1, version: React.version, rendererPackageName: "react-ogl" }); export { act, extend, reconciler }; //# sourceMappingURL=reconciler.mjs.map