Skip to content

Commit

Permalink
fix react-babylonjs-spring #156 (#158)
Browse files Browse the repository at this point in the history
turn off stories not working to test storybook github action
  • Loading branch information
brianzinn authored Sep 30, 2021
1 parent 39cc92a commit bbaa0a1
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 51 deletions.
2 changes: 1 addition & 1 deletion src/Engine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export type EngineProps = {
canvasId?: string,
debug?: boolean,
// onCreated?: (engine: Engine) => void
}
} // TODO: put this in the next major version and remove canvasStyle and canvasId props (breaking changes). & React.CanvasHTMLAttributes<HTMLCanvasElement>

export type EngineState = {
canRender: boolean
Expand Down
6 changes: 6 additions & 0 deletions src/ReactBabylonJSHostConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,12 @@ const ReactBabylonJSHostConfig: HostConfig<
enumerable: true
});
}
if (createdReference.hostInstance && !('__rb_propsHandlers' in createdReference.hostInstance)) {
Object.defineProperty(createdReference.hostInstance, '__rb_propsHandlers', {
get() { return createdReference.propsHandlers; },
enumerable: true
});
}
if (babylonObject) {
babylonObject.inspectableCustomProperties = [
{
Expand Down
38 changes: 0 additions & 38 deletions src/UpdateInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,41 +118,3 @@ export const applyInitialPropsToCreatedInstance = (createdInstance: CreatedInsta
})
}
}

/**
* @deprecated Please use @see applyPropsToRef instead
* (same functionality different parameters better name, but doesn't work with "public" ref provided by reconciler)
* @param hostInstance a babylonjs hosted instance (available with useRef)
* @param props
*/
export const applyInitialPropsToInstance = (hostInstance: any, props: any): void => {
// this is a bad cast. it is here for backwards compatibility with a react-spring dependency that only uses vector/color prop changes.
applyPropsToRef({ hostInstance } as CreatedInstance<any>, props);
}

/**
* Will apply props to a ref and is useful to apply outside of the regular prop updates. This is used by react-spring for fast animations.
* Can be used outside of react render loop.
*
* @param hostInstance babylonjs hosted instance (available with useRef)
* @param props props to apply
*/
export const applyPropsToRef = (createdInstance: CreatedInstance<any>, props: Record<string, any>): void => {
const initPayload: PropertyUpdate[] = []
createdInstance.propsHandlers?.getPropsHandlers().forEach((propHandler: PropsHandler<any>) => {
const handlerUpdates: PropertyUpdate[] | null = propHandler.getPropertyUpdates(
{}, // We will reapply any props passed in (will not "clear" props, if we pass in an undefined prop)
props
);
if (handlerUpdates !== null) {
initPayload.push(...handlerUpdates);
}
})

if (initPayload.length > 0) {
initPayload.forEach(update => {
// this is not entirely true.
applyUpdateToInstance(createdInstance, update);
})
}
}
110 changes: 110 additions & 0 deletions src/plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { Quaternion, Vector3 } from "@babylonjs/core/Maths/math.vector.js";
import { CreatedInstance } from "./CreatedInstance";
import { HasPropsHandlers, PropChangeType, PropertyUpdate, PropsHandler } from "./PropsHandler";

/**
* @deprecated Please use @see applyPropsToRef instead
* (same functionality different parameters better name, but doesn't work with "public" ref provided by reconciler)
* @param hostInstance a babylonjs public ref (available with useRef)
* @param props
*/
export const applyInitialPropsToInstance = (target: any, props: Record<string, any>): void => {
// this is a bad cast. it is here for backwards compatibility with a react-spring dependency that only uses vector/color prop changes.
const initPayload: PropertyUpdate[] = []
if ('__rb_propsHandlers' in target) {
(target.__rb_propsHandlers as HasPropsHandlers<unknown>).getPropsHandlers().forEach((propHandler: PropsHandler<any>) => {
const handlerUpdates: PropertyUpdate[] | null = propHandler.getPropertyUpdates(
{}, // We will reapply any props passed in (will not "clear" props, if we pass in an undefined prop)
props
);
if (handlerUpdates !== null) {
initPayload.push(...handlerUpdates);
}
})
}

if (initPayload.length > 0) {
// this is all copied code from `applyUpdateToInstance(...)`
initPayload.forEach(update => {
switch (update.changeType) {
case PropChangeType.Primitive:
case PropChangeType.FresnelParameters:
case PropChangeType.LambdaExpression:
case PropChangeType.Texture:
// console.log(` > ${type}: updating ${update.changeType} on ${update.propertyName} to ${update.value}`)
if (update.propertyName.indexOf('.') !== -1) {
const dotProps: string[] = update.propertyName.split('.');
const lastProp = dotProps.pop()!;
const newTarget = dotProps.reduce((target, prop) => target[prop], target);
newTarget[lastProp] = update.value;
} else {
target[update.propertyName] = update.value;
}
break;
case PropChangeType.Vector3:
if (target[update.propertyName]) {
(target[update.propertyName] as Vector3).copyFrom(update.value);
} else if (update.value) {
target[update.propertyName] = update.value.clone();
} else {
target[update.propertyName] = update.value; // ie: undefined/null?
}
break;
case PropChangeType.Color3:
case PropChangeType.Color4:
if (update.value) {
target[update.propertyName] = update.value.clone();
} else {
target[update.propertyName] = update.value;
}
break;
case PropChangeType.Control:
target[update.propertyName] = update.value;
break;
case PropChangeType.NumericArray:
target[update.propertyName] = update.value;
break;
case PropChangeType.Observable:
console.warn('observable not supported for plugins (create a request if needed)')
break;
case PropChangeType.Method:
if (typeof target[update.propertyName] === "function") {
if (Array.isArray(update.value)) {
target[update.propertyName](...update.value);
} else if (Object(update.value) !== update.value) {
// primitive, undefined & null. Comparison is 7x slower than instanceof check,
// TODO: should be: update.value === undefined || typeof(update.value) === 'number' || ...
target[update.propertyName](update.value);
} else {
// TODO: there is a bug here in that setTarget={new Vector3(0, 1, 0)} will throw an exception...
console.error('need to make sure this isn\'t something like a Vector3 before destructuring')
target[update.propertyName](...Object.values(update.value));
}
} else {
console.error(`Cannot call [not a function] ${update.propertyName}(...) on:`, target);
}
break;
case PropChangeType.Quaternion:
// console.warn(`quaternion update detected ${update.propertyName} to:`, update.value)
if (target[update.propertyName]) {
(target[update.propertyName] as Quaternion).copyFrom(update.value);
} else if (update.value) {
target[update.propertyName] = (update.value as Quaternion).clone();
} else {
target[update.propertyName] = update.value; // ie: undefined/null?
}
break;
default:
console.error(`Unhandled property update of type '${update.changeType}'`);
break;
}
})
}
}

/**
* @deprecated I don't believe this is used currently, but it can be added back.
*/
export const applyPropsToRef = (createdInstance: CreatedInstance<any>, props: Record<string, any>): void => {
throw new Error('if you need this method please create an issue.')
}
2 changes: 1 addition & 1 deletion src/react-babylonjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export * from './customComponents';
export * from './PropsHandler';
export * from './HostRegistrationStore';
// applyInitialPropsToInstance is marked deprecated
export { applyInitialPropsToInstance, applyPropsToRef } from './UpdateInstance'; // Imported by react-babylonjs-spring
export { applyInitialPropsToInstance } from './plugins'; // Imported by react-babylonjs-spring

export { default as Engine } from './Engine';
export { default as Scene, SceneEventArgs } from './Scene';
Expand Down
5 changes: 3 additions & 2 deletions storybook/stories/babylonjs/Basic/gizmo.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Color3 } from '@babylonjs/core/Maths/math.color';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
import '../../style.css'

export default { title: 'Babylon Basic' };
// export default { title: 'Babylon Basic' };

const GizmoBox = ({position, color} = props) => (
<box size={2} position={position}>
Expand All @@ -13,7 +13,8 @@ const GizmoBox = ({position, color} = props) => (
</box>
)

export const Gizmo = () => (
// broken in 4.2 - works in 5.0
const Gizmo = () => (
<div style={{ flex: 1, display: 'flex' }}>
<Engine antialias adaptToDeviceRatio canvasId='babylonJS' >
<Scene>
Expand Down
5 changes: 3 additions & 2 deletions storybook/stories/babylonjs/Basic/gizmoManager.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import { Color3 } from '@babylonjs/core/Maths/math.color';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
import '../../style.css'

export default { title: 'Babylon Basic' };
// export default { title: 'Babylon Basic' };

const Inspector = () => {
const scene = useScene();
scene.debugLayer.show();
return null;
}

export const GizmoManager = () => {
// broken in 4.2 - works in 5.0
const GizmoManager = () => {
const [lightRef, setLightRef] = useState(undefined);

useEffect(() => {
Expand Down
5 changes: 3 additions & 2 deletions storybook/stories/babylonjs/Basic/snippetMaterial.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { Engine, Scene, useScene } from 'react-babylonjs'

import '../../style.css';

export default { title: 'Babylon Basic' };
// disabled due to errors
// export default { title: 'Babylon Basic' };


const setBlockValue = (
Expand Down Expand Up @@ -66,7 +67,7 @@ const SnippetMaterialById = ({snippetId, name, blockValues, freeze}) => {

const colors = ["Red", "Green", "Yellow"]

export const SnippetMaterial = () => {
const SnippetMaterial = () => {
const [selectedColor, setSelectedColor] = useState("Green");
const onChange = (e) => {
setSelectedColor(e.target.value);
Expand Down
16 changes: 11 additions & 5 deletions storybook/stories/babylonjs/Integrations/reactSpring.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class CustomColor3ArrayHandler {
return Array.isArray(newProp);
}

process(oldProp, ) {
process(oldProp, newProp) {
if (oldProp === undefined || oldProp.length !== newProp.length) {
console.log(`found diff length (${oldProp?.length}/${newProp?.length}) Color3Array new? ${oldProp === undefined}`)
return {
Expand Down Expand Up @@ -157,10 +157,13 @@ class CustomVector3ArrayHandler {
* This is the end of code that needed to be copied, since it is not exported.
*/

CustomPropsHandler.RegisterPropsHandler(new CustomColor3StringHandler());
CustomPropsHandler.RegisterPropsHandler(new CustomColor3ArrayHandler());
CustomPropsHandler.RegisterPropsHandler(new CustomColor4StringHandler());
CustomPropsHandler.RegisterPropsHandler(new CustomVector3ArrayHandler());
// we need to keep registering these as our fiber instance is being recreated when reloaded - the registrations imported as side-effects are
const registerPropsHandlers = () => {
CustomPropsHandler.RegisterPropsHandler(new CustomColor3StringHandler());
CustomPropsHandler.RegisterPropsHandler(new CustomColor3ArrayHandler());
CustomPropsHandler.RegisterPropsHandler(new CustomColor4StringHandler());
CustomPropsHandler.RegisterPropsHandler(new CustomVector3ArrayHandler());
}

const getRandomColor = (function () {
// const Colors = ['#4F86EC', '#D9503F', '#F2BD42', '#58A55C'];
Expand All @@ -183,6 +186,9 @@ function getCyclePosition(i, blankRadius) {
}

const WithSpring = () => {
// this only needs to be done once, so not on every render.
registerPropsHandlers();

const [props, set] = useSprings(100, i => {
const [x, z] = getCyclePosition(i, 30);

Expand Down

0 comments on commit bbaa0a1

Please sign in to comment.