Skip to content

Commit

Permalink
add 'fromInstance' support. #81
Browse files Browse the repository at this point in the history
  • Loading branch information
brianzinn committed Sep 11, 2020
1 parent 17aa569 commit 2432f51
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 53 deletions.
113 changes: 63 additions & 50 deletions src/ReactBabylonJSHostConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,62 +299,75 @@ const ReactBabylonJSHostConfig: HostConfig<

// console.log(`creating: ${createInfoArgs.namespace}.${type}`)
let generatedParameters: GeneratedParameter[] = createInfoArgs.parameters
let babylonObject: any | undefined = undefined

// console.log("generated params:", generatedParameters)

let args = generatedParameters.map(generatedParameter => {
if (Array.isArray(generatedParameter.type)) {
// TODO: if all props are missing, warn if main prop (ie: options) is required.
let newParameter = {} as any
generatedParameter.type.forEach(subParameter => {
let subPropValue = props[subParameter.name]
if (subPropValue === undefined && subParameter.optional === false && generatedParameter.optional === false) {
console.warn("Missing a required secondary property:", subParameter.name)
} else {
newParameter[subParameter.name] = subPropValue
}
})
return newParameter
} else {
let value = props[generatedParameter.name]
if (value === undefined) {
// NOTE: we removed the hosted Scene component, which needs (generatedParameter.type == "BabylonjsCoreEngine")
// SceneOrEngine type is Scene
if (generatedParameter.type.includes("BabylonjsCoreScene") || (generatedParameter.type === "any" && generatedParameter.name === "scene")) {
// MeshBuild.createSphere(name: string, options: {...}, scene: any)
// console.log('Assigning scene to:', type, generatedParameter)
value = scene
} else if (generatedParameter.optional === false) {
console.warn(`required parameter for ${type} unassigned -> ${generatedParameter.name}:${generatedParameter.type}`);
}
}

if (value === undefined && generatedParameter.optional === false) {
console.warn(`On ${type} you are missing a non-optional parameter '${generatedParameter.name}' of type '${generatedParameter.type}'`)
if (props.fromInstance !== undefined) {
if(createInfoArgs.namespace.startsWith('@babylonjs/')) {
const clazz: any = GENERATED.babylonClassFactory(type);
// instanceof will check prototype and derived classes (ie: can assign Mesh instance to a Node)
if (props.fromInstance instanceof clazz) {
babylonObject = props.fromInstance;
} else {
// prevent assigning incorrect type.
console.error('fromInstance wrong type.', props.fromInstance, clazz);
}

return value
} else {
console.error('cannot generate non babylonjs using fromInstance');
}
})

let babylonObject: any | undefined = undefined

if (createInfoArgs.creationType === CreationType.FactoryMethod) {
// console.warn(`creating from Factory: ${createInfoArgs.libraryLocation}.${createInfoArgs.factoryMethod}(...args). args:`, args)
babylonObject = GENERATED.babylonClassFactory(createInfoArgs.libraryLocation)[createInfoArgs.factoryMethod!](...args)
} else {
if (metadata.delayCreation !== true) {
if(createInfoArgs.namespace.startsWith('@babylonjs/')) {
const clazz: any = GENERATED.babylonClassFactory(type);
if (clazz === undefined) {
throw new Error(`Cannot generate '${type}' (react-babylonjs):`);
// console.log("generated params:", generatedParameters)
let args = generatedParameters.map(generatedParameter => {
if (Array.isArray(generatedParameter.type)) {
// TODO: if all props are missing, warn if main prop (ie: options) is required.
let newParameter = {} as any
generatedParameter.type.forEach(subParameter => {
let subPropValue = props[subParameter.name]
if (subPropValue === undefined && subParameter.optional === false && generatedParameter.optional === false) {
console.warn("Missing a required secondary property:", subParameter.name)
} else {
newParameter[subParameter.name] = subPropValue
}
babylonObject = new clazz(...args)
} else if (createInfoArgs.namespace.startsWith('./extensions/')) {
const extClassName = (GENERATED.intrinsicClassMap as any)[type] || type;
babylonObject = new (BABYLONEXT as any)[extClassName](...args)
})
return newParameter
} else {
console.error("metadata defines (or does not) a namespace that is known", createInfoArgs.namespace)
let value = props[generatedParameter.name]
if (value === undefined) {
// NOTE: we removed the hosted Scene component, which needs (generatedParameter.type == "BabylonjsCoreEngine")
// SceneOrEngine type is Scene
if (generatedParameter.type.includes("BabylonjsCoreScene") || (generatedParameter.type === "any" && generatedParameter.name === "scene")) {
// MeshBuild.createSphere(name: string, options: {...}, scene: any)
// console.log('Assigning scene to:', type, generatedParameter)
value = scene
} else if (generatedParameter.optional === false) {
console.warn(`required parameter for ${type} unassigned -> ${generatedParameter.name}:${generatedParameter.type}`);
}
}

if (value === undefined && generatedParameter.optional === false) {
console.warn(`On ${type} you are missing a non-optional parameter '${generatedParameter.name}' of type '${generatedParameter.type}'`)
}

return value
}
})

if (createInfoArgs.creationType === CreationType.FactoryMethod) {
// console.warn(`creating from Factory: ${createInfoArgs.libraryLocation}.${createInfoArgs.factoryMethod}(...args). args:`, args)
babylonObject = GENERATED.babylonClassFactory(createInfoArgs.libraryLocation)[createInfoArgs.factoryMethod!](...args)
} else {
if (metadata.delayCreation !== true) {
if(createInfoArgs.namespace.startsWith('@babylonjs/')) {
const clazz: any = GENERATED.babylonClassFactory(type);
if (clazz === undefined) {
throw new Error(`Cannot generate '${type}' (react-babylonjs):`);
}
babylonObject = new clazz(...args)
} else if (createInfoArgs.namespace.startsWith('./extensions/')) {
const extClassName = (GENERATED.intrinsicClassMap as any)[type] || type;
babylonObject = new (BABYLONEXT as any)[extClassName](...args)
} else {
console.error("metadata defines (or does not) a namespace that is known", createInfoArgs.namespace)
}
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/generatedCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,8 @@ export class FiberAbstractMesh implements HasPropsHandlers<FiberAbstractMeshProp
};
public static readonly Metadata: CreatedInstanceMetadata = {
"isNode": true,
"acceptsMaterials": true,
"isMesh": true,
"className": "FiberAbstractMesh"
};
}
Expand Down Expand Up @@ -540,6 +542,8 @@ export class FiberInstancedMesh implements HasPropsHandlers<FiberAbstractMeshPro
};
public static readonly Metadata: CreatedInstanceMetadata = {
"isNode": true,
"acceptsMaterials": true,
"isMesh": true,
"className": "FiberInstancedMesh"
};
}
Expand Down Expand Up @@ -597,6 +601,8 @@ export class FiberInstancedLinesMesh implements HasPropsHandlers<FiberAbstractMe
};
public static readonly Metadata: CreatedInstanceMetadata = {
"isNode": true,
"acceptsMaterials": true,
"isMesh": true,
"className": "FiberInstancedLinesMesh"
};
}
Expand Down Expand Up @@ -690,6 +696,8 @@ export class FiberMesh implements HasPropsHandlers<FiberAbstractMeshProps> {
};
public static readonly Metadata: CreatedInstanceMetadata = {
"isNode": true,
"acceptsMaterials": true,
"isMesh": true,
"className": "FiberMesh"
};
}
Expand Down Expand Up @@ -776,6 +784,8 @@ export class FiberLinesMesh implements HasPropsHandlers<FiberAbstractMeshProps>
};
public static readonly Metadata: CreatedInstanceMetadata = {
"isNode": true,
"acceptsMaterials": true,
"isMesh": true,
"className": "FiberLinesMesh"
};
}
Expand Down Expand Up @@ -833,6 +843,8 @@ export class FiberGroundMesh implements HasPropsHandlers<FiberAbstractMeshProps>
};
public static readonly Metadata: CreatedInstanceMetadata = {
"isNode": true,
"acceptsMaterials": true,
"isMesh": true,
"className": "FiberGroundMesh"
};
}
Expand Down Expand Up @@ -908,6 +920,8 @@ export class FiberTrailMesh implements HasPropsHandlers<FiberAbstractMeshProps>
};
public static readonly Metadata: CreatedInstanceMetadata = {
"isNode": true,
"acceptsMaterials": true,
"isMesh": true,
"className": "FiberTrailMesh"
};
}
Expand Down
58 changes: 58 additions & 0 deletions stories/babylonjs/Basic/fromInstance.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useState, useMemo } from 'react'
import { Engine, Scene, useBabylonScene } from '../../../dist/react-babylonjs'
import { Vector3, Color3, Color4, MeshBuilder } from '@babylonjs/core'
import '../../style.css'

export default { title: 'Babylon Basic' };

const MyMesh = (props) => {
const [mesh, setMesh] = useState(null);
const scene = useBabylonScene();
useMemo(() => {
console.log('creating a box with scene', scene);
setMesh(MeshBuilder.CreateBox('test', { size: 1}, scene));
}, []);

return (
<>
{mesh &&
<mesh fromInstance={mesh} rotation={props.rotation}>
<standardMaterial name='boxmat' diffuseColor={Color3.Blue()} specularColor={Color3.Black()} />
</mesh>
}
</>
)
}

export const FromInstance = () => {
const [rotation, setRotation] = useState(new Vector3(0, 0, 0));
const addRotation = () => {
setRotation((state) => new Vector3(0, rotation.y + Math.PI / 4, 0));
};



return (
<div className="App">
<button onClick={addRotation}>Rotate</button>
<Engine antialias adaptToDeviceRatio canvasId="babylonJS">
<Scene>
<arcRotateCamera
name="arc"
target={Vector3.Zero()}
minZ={0.001}
alpha={-Math.PI / 2}
beta={Math.PI / 1.2}
radius={4}
/>
<hemisphericLight
name="light1"
intensity={0.9}
direction={Vector3.Down()}
/>
<MyMesh rotation={rotation} />
</Scene>
</Engine>
</div>
);
}
6 changes: 3 additions & 3 deletions tools/generate-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1493,9 +1493,9 @@ const generateCode = async () => {
name: "IntrinsicElements",

})
// This includes Node, which is base class for ie: Camera, Mesh, etc.
createClassesDerivedFrom(generatedCodeSourceFile, generatedPropsSourceFile, classesOfInterest.get("TransformNode")!, {}, undefined);
createClassesInheritedFrom(generatedCodeSourceFile, generatedPropsSourceFile, classesOfInterest.get("AbstractMesh")!, () => ({isNode: true}));
// This includes Node, which is base class for ie: Camera, Mesh, etc. (inheriting from Node would add new things like TextureDome)
createClassesDerivedFrom(generatedCodeSourceFile, generatedPropsSourceFile, classesOfInterest.get("TransformNode")!, { isNode: true }, undefined);
createClassesInheritedFrom(generatedCodeSourceFile, generatedPropsSourceFile, classesOfInterest.get("AbstractMesh")!, () => ({isNode: true, acceptsMaterials: true, isMesh: true}));

const extra = (newClassDeclaration: ClassDeclaration, originalClassDeclaration: ClassDeclaration) => {
// consider having targetable as metadata.
Expand Down

0 comments on commit 2432f51

Please sign in to comment.