Skip to content

Commit 68bcd3b

Browse files
committed
Finish initialized three types
A more workable implementation of models that gets generated from three.js objects. Has special handing during model initialization to avoid race conditions where a model reference is sent before the actual model comm is opened.
1 parent 294b5c7 commit 68bcd3b

File tree

4 files changed

+73
-38
lines changed

4 files changed

+73
-38
lines changed

js/scripts/prop-types.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,28 @@ function InitializedThreeType(typeName, options={}) {
101101
ThreeType.call(this, typeName, options);
102102
}
103103
_.extend(InitializedThreeType.prototype, ThreeType.prototype, {
104-
getPropertyConverterFn: function() {
105-
return 'convertInitializedThreeType';
104+
getJSPropertyValue: function() {
105+
return '"uninitialized"';
106+
},
107+
getPythonDefaultValue: function() {
108+
return 'UninitializedSentinel';
109+
},
110+
getTraitlet: function() {
111+
var typeName = this.typeName;
112+
var nullableStr = this.nullable ? 'True' : 'False';
113+
var inst = `Instance(${typeName}`;
114+
if (this.args !== undefined) {
115+
inst += `, args=${this.args}`;
116+
}
117+
if (this.kwargs !== undefined) {
118+
inst += `, kw=${this.kwargs}`;
119+
}
120+
inst += `)`;
121+
var uninit = 'Instance(Uninitialized)';
122+
var ret = `Union([\n ${uninit},\n ${inst}\n ]`
123+
ret += `, default_value=${this.getPythonDefaultValue()}, allow_none=${nullableStr})`;
124+
ret += `.tag(sync=True, **unitialized_serialization)`;
125+
return ret;
106126
},
107127
});
108128

js/scripts/three-class-config.js

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -470,19 +470,15 @@ module.exports = {
470470
relativePath: './lights/DirectionalLight',
471471
superClass: 'Light',
472472
properties: {
473-
target: new Types.InitializedThreeType('Object3D', null, {args: '()', nullable: false}),
474-
shadow: new Types.InitializedThreeType('DirectionalLightShadow', 'LightShadow', {args: '()', nullable: false}),
473+
target: new Types.InitializedThreeType('Object3D', {nullable: false}),
474+
shadow: new Types.InitializedThreeType('LightShadow', {nullable: false}),
475475
},
476476
constructorArgs: [ 'color', 'intensity' ],
477477
propsDefinedByThree: [ 'target', 'shadow' ]
478478
},
479479
DirectionalLightShadow: {
480480
relativePath: './lights/DirectionalLightShadow',
481481
superClass: 'LightShadow',
482-
properties: {
483-
// TODO: Fix this
484-
camera: new Types.InitializedThreeType('OrthographicCamera', 'Camera', {args: '()'}),
485-
},
486482
},
487483
HemisphereLight: {
488484
relativePath: './lights/HemisphereLight',
@@ -504,8 +500,7 @@ module.exports = {
504500
LightShadow: {
505501
relativePath: './lights/LightShadow',
506502
properties: {
507-
// TODO: Fix this
508-
camera: new Types.ThreeType('Camera', {args: '()'}),
503+
camera: new Types.InitializedThreeType('Camera', {nullable: false}),
509504
bias: new Types.Float(0),
510505
mapSize: new Types.Vector2(512, 512),
511506
radius: new Types.Float(1)
@@ -520,7 +515,7 @@ module.exports = {
520515
power: new Types.Float(4.0 * Math.PI),
521516
distance: new Types.Float(0.0),
522517
decay: new Types.Float(1.0),
523-
shadow: new Types.InitializedThreeType('LightShadow', null, {args: '()'}),
518+
shadow: new Types.InitializedThreeType('LightShadow', {nullable: false}),
524519
},
525520
constructorArgs: [ 'color', 'intensity', 'distance', 'decay' ],
526521
propsDefinedByThree: [ 'shadow' ],
@@ -533,23 +528,19 @@ module.exports = {
533528
relativePath: './lights/SpotLight',
534529
superClass: 'Light',
535530
properties: {
536-
target: new Types.InitializedThreeType('Object3D', null, {args: '()', nullable: false}),
531+
target: new Types.InitializedThreeType('Object3D', {nullable: false}),
537532
distance: new Types.Float(0.0),
538533
angle: new Types.Float(Math.PI / 3.0),
539534
penumbra: new Types.Float(0.0),
540535
decay: new Types.Float(1.0),
541-
shadow: new Types.InitializedThreeType('SpotLightShadow', 'LightShadow', {args: '()'}),
536+
shadow: new Types.InitializedThreeType('LightShadow', {nullable: false}),
542537
},
543538
constructorArgs: [ 'color', 'intensity', 'distance', 'angle', 'penumbra', 'decay' ],
544539
propsDefinedByThree: [ 'target', 'shadow' ]
545540
},
546541
SpotLightShadow: {
547542
relativePath: './lights/SpotLightShadow',
548543
superClass: 'LightShadow',
549-
properties: {
550-
// TODO: Fix this
551-
camera: new Types.InitializedThreeType('PerspectiveCamera', 'Camera', {args: '()'}),
552-
},
553544
},
554545
AnimationLoader: {
555546
relativePath: './loaders/AnimationLoader',

js/src/_base/Three.js

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ var ThreeModel = widgets.WidgetModel.extend({
7474
var obj = options.three_obj;
7575
delete options.three_obj;
7676

77-
this.initPromise = Promise.resolve(obj).bind(this).then(this.processNewObj
78-
).then(function (obj) {
77+
this.processNewObj(obj);
78+
79+
this.initPromise = this.createUninitializedChildren().bind(this).then(function() {
7980

8081
// sync in all the properties from the THREE object
8182
this.syncToModel(true);
@@ -89,6 +90,8 @@ var ThreeModel = widgets.WidgetModel.extend({
8990

9091
// Instantiate Three.js object
9192
this.initPromise = this.createThreeObjectAsync().bind(this).then(function() {
93+
return this.createUninitializedChildren();
94+
}).then(function() {
9295

9396
// pull in props created by three
9497
this.syncToModel();
@@ -164,6 +167,26 @@ var ThreeModel = widgets.WidgetModel.extend({
164167

165168
},
166169

170+
createUninitializedChildren: function() {
171+
172+
// Get any properties to create from this side
173+
var uninit = _.filter(this.three_properties, function(propName) {
174+
return this.get(propName) === 'uninitialized';
175+
}, this);
176+
177+
// Return promise for their creation
178+
return Promise.all(_.map(uninit, function(propName) {
179+
var obj = this.obj[propName]
180+
// First, we need to figure out which model constructor to use
181+
var ctorName = `${obj.constructor.name}Model`;
182+
var index = require('../');
183+
var ctor = index[ctorName];
184+
// Create the model
185+
var modelPromise = utils.createModel(ctor, this.widget_manager, obj);
186+
return modelPromise;
187+
}, this));
188+
},
189+
167190
createThreeObjectAsync: function() {
168191

169192
var objPromise;
@@ -618,25 +641,6 @@ var ThreeModel = widgets.WidgetModel.extend({
618641
return threeType.ipymodel;
619642
},
620643

621-
// InitializedThreeType
622-
convertInitializedThreeTypeModelToThree: function(model, propName) {
623-
if (model) {
624-
return model.obj;
625-
}
626-
return null;
627-
},
628-
629-
convertInitializedThreeTypeThreeToModel: function(threeType, propName) {
630-
if (threeType.ipymodelId === undefined) {
631-
var placeholder = this.get(propName);
632-
threeType.ipymodelId = placeholder.obj.ipymodelId;
633-
threeType.ipymodel = placeholder;
634-
placeholder.obj = threeType;
635-
placeholder.syncToModel();
636-
}
637-
return threeType.ipymodel;
638-
},
639-
640644
// ThreeTypeArray
641645
convertThreeTypeArrayModelToThree: function(modelArr, propName) {
642646
return modelArr.map(function(model) {

pythreejs/traits.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
Bool, Tuple, Undefined, TraitError, Union,
77
)
88

9+
from ipywidgets import widget_serialization
10+
911
from ipydatawidgets import DataUnion, NDArrayWidget
1012

1113
def Vector2(trait_type=CFloat, default=None, **kwargs):
@@ -74,3 +76,21 @@ def validate(self, obj, value):
7476
# 64-bit not supported, coerce to 32-bit
7577
value = value.astype('float32')
7678
return value
79+
80+
81+
class Uninitialized:
82+
pass
83+
84+
_widget_to_json = widget_serialization['to_json']
85+
86+
def _serialize_uninitialized(value, owner):
87+
if isinstance(value, Uninitialized):
88+
return 'uninitialized'
89+
return _widget_to_json(value, owner)
90+
91+
unitialized_serialization = {
92+
'to_json': _serialize_uninitialized,
93+
'from_json': widget_serialization['from_json'],
94+
}
95+
96+
UninitializedSentinel = Uninitialized()

0 commit comments

Comments
 (0)