Skip to content

Commit 99ff737

Browse files
authored
Merge pull request #105 from vidartf/renderer
Auto-gen continuation
2 parents 1a5248b + e7ed1e4 commit 99ff737

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2896
-1783
lines changed

README.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pythreejs
22
=========
33

4-
This is a _significant_ re-work of the pythreejs extension that introduces an "autogen" script that generates the majority of the ipython-widget code to wrap each of three.js's types. It also takes a different view towards the pythreejs API. Whereas pythreejs adds custom functionality to the classes, sometimes renaming, etc., this approach attempts to mimic the low-level three.js API as closely as possible, opening up the possibility for others to build utility libraries on top of this.
4+
This is a _significant_ re-work of the pythreejs extension that introduces an "autogen" script that generates the majority of the ipython-widget code to wrap each of three.js's types. It also takes a different view towards the pythreejs API. Whereas pythreejs adds custom functionality to the classes, sometimes renaming, etc., this approach attempts to mimic the low-level three.js API as closely as possible, opening up the possibility for others to build utility libraries on top of this.
55

66
This branch does not support all the functionality of the current pythreejs, but it is a significant step forward in terms of the potential to support the majority of three.js's features. Currently supported features:
77
- Basic building blocks of a scene:
@@ -15,7 +15,7 @@ This branch does not support all the functionality of the current pythreejs, but
1515

1616
The autogen script, `generate-wrappers.js`, takes advantage of a config file `three-class-config.js` to auto-generate both javascript and python files to define the ipywidget wrappers for each three.js class. The generated javascript files will have `.autogen.js` as the extension. The generated python files have `_autogen.py` as their extension. The script uses the handlebars template system to generate the various code files.
1717

18-
The autogen solution allows for overriding the default behavior of the generated classes. E.g., if `Object3D.js` is present, then it will be loaded into the namespace as opposed to loading `Object3D.autogen.js`. It is up to the author of the override classe to decide whether to inherit behavior from the autogen class or not. Same goes for the python modules. This allows for writing custom methods on both the python and javascript side when needed.
18+
The autogen solution allows for overriding the default behavior of the generated classes. E.g., if `Object3D.js` is present, then it will be loaded into the namespace as opposed to loading `Object3D.autogen.js`. It is up to the author of the override classe to decide whether to inherit behavior from the autogen class or not. Same goes for the python modules. This allows for writing custom methods on both the python and javascript side when needed.
1919

2020
The autogen script relies on a json-like config file (`three-class-config.js`) to describe the classes. Reasonable defaults should take care of most, but it allows specifying the base class, constructor args, etc. for each of the wrappers. A base version of this file can be generated by `generate-class-config.js`, but beware, it overwrites any customization to the config file that has already been done.
2121

@@ -43,37 +43,37 @@ js/package.json
4343
js/webpack.config.js
4444
4545
# Files for auto-generation
46-
js/scripts/clean-generated-files.js
47-
js/scripts/generate-class-config.js
48-
js/scripts/generate-wrappers.js
49-
js/scripts/prop-types.js
50-
js/scripts/templates/js_index.mustache
51-
js/scripts/templates/js_param_obj.mustache
52-
js/scripts/templates/js_wrapper.mustache
53-
js/scripts/templates/py_top_level_init.mustache
54-
js/scripts/templates/py_wrapper.mustache
55-
js/scripts/three-class-config-defaults.js
56-
js/scripts/three-class-config.js
57-
js/scripts/three-class-config.js.backup
46+
js/scripts/*
5847
5948
# New bases classes for supporting wrapper classes
60-
js/src/_base/RendererPool.js
61-
js/src/_base/Three.js
62-
js/src/_base/enums.js
49+
js/src/_base/*
6350
pythreejs/_base/Three.py
6451
pythreejs/enums.py
6552
pythreejs/traits.py
6653
6754
# Overridden classes
6855
js/src/core/Object3D.js
56+
js/src/cameras/OrthographicCamera.js
57+
js/src/cameras/PerspectiveCamera.js
58+
js/src/controls/OrbitControls.js
59+
js/src/controls/TrackballControls.js
60+
js/src/controls/FlyControls.js
61+
js/src/controls/Picker.js
6962
js/src/textures/DataTexture.js
63+
js/src/textures/DepthTexture.js
7064
js/src/renderers/WebGLRenderer.js
65+
7166
pythreejs/core/Object3D.py
7267
pythreejs/renderers/WebGLRenderer.py
7368
7469
# Custom classes
70+
js/src/core/Renderer.js
71+
js/src/textures/ImageTexture.js # created to ease image texture loading
7572
js/src/textures/ImageTexture.js # created to ease image texture loading
7673
js/src/textures/TextTexture.js # created to ease creation of textures of rasterized text
74+
js/src/geometry/PlainGeometry.js # created to not auto-sync geometry data of generated geometry
75+
pythreejs/core/Renderer.py
76+
7777
7878
# Updated examples notesbooks
7979
examples/Examples.ipynb
@@ -89,13 +89,12 @@ js/src/examples/Detector.js
8989
js/src/examples/controls/MomentumCameraControls.js
9090
js/src/examples/controls/OrbitControls.js
9191
js/src/examples/controls/TrackballControls.js
92-
js/src/examples/js/controls/OrbitControls.js
9392
js/src/examples/renderers/CanvasRenderer.js
9493
js/src/examples/renderers/Projector.js
9594
```
9695

9796

98-
TODO: Everything below here is probably outdated.
97+
TODO: Everything below here is probably outdated.
9998

10099
Getting Started
101100
---------------

examples/Examples.ipynb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"outputs": [],
3030
"source": [
3131
"ball = Mesh(geometry=SphereGeometry(radius=1), \n",
32-
" material=LambertMaterial(color='red'),\n",
32+
" material=MeshLambertMaterial(color='red'),\n",
3333
" position=[2, 1, 0])\n",
3434
"\n",
3535
"scene = Scene(children=[ball, AmbientLight(color='#777777')])\n",
@@ -100,9 +100,9 @@
100100
" width_segments=nx - 1,\n",
101101
" height_segments=ny - 1)\n",
102102
"\n",
103-
"surf = Mesh(geometry=surf_g, material=LambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n",
103+
"surf = Mesh(geometry=surf_g, material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n",
104104
"surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'))\n",
105-
"hover_point = Mesh(geometry=SphereGeometry(radius=0.05), material=LambertMaterial(color='hotpink'))\n",
105+
"hover_point = Mesh(geometry=SphereGeometry(radius=0.05), material=MeshLambertMaterial(color='hotpink'))\n",
106106
"scene = Scene(children=[surf, surfgrid, hover_point, AmbientLight(color='#777777')])\n",
107107
"c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], \n",
108108
" children=[DirectionalLight(color='white', position=[3, 5, 1], intensity=0.6)])\n",
@@ -114,7 +114,7 @@
114114
" value = change['new']\n",
115115
" print('Clicked on %s' % value)\n",
116116
" point = Mesh(geometry=SphereGeometry(radius=0.05), \n",
117-
" material=LambertMaterial(color='red'),\n",
117+
" material=MeshLambertMaterial(color='red'),\n",
118118
" position=value)\n",
119119
" scene.children = list(scene.children) + [point]\n",
120120
"\n",
@@ -179,7 +179,7 @@
179179
"t = DataTexture(data=rgba_list, format='RGBAFormat', width=size, height=size)\n",
180180
"\n",
181181
"geometry = SphereGeometry()#TorusKnotGeometry(radius=2, radialSegments=200)\n",
182-
"material = LambertMaterial(map=t)\n",
182+
"material = MeshLambertMaterial(map=t)\n",
183183
"\n",
184184
"myobject = Mesh(geometry=geometry, material=material)\n",
185185
"c = PerspectiveCamera(position=[0, 3, 3], fov=40,\n",
@@ -254,8 +254,8 @@
254254
"\"\"\"\n",
255255
"surf_g = ParametricGeometry(func=f);\n",
256256
"\n",
257-
"surf = Mesh(geometry=surf_g, material=LambertMaterial(color='green', side='FrontSide'))\n",
258-
"surf2 = Mesh(geometry=surf_g, material=LambertMaterial(color='yellow', side='BackSide'))\n",
257+
"surf = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='green', side='FrontSide'))\n",
258+
"surf2 = Mesh(geometry=surf_g, material=MeshLambertMaterial(color='yellow', side='BackSide'))\n",
259259
"scene = Scene(children=[surf, surf2, AmbientLight(color='#777777')])\n",
260260
"c = PerspectiveCamera(position=[5, 5, 3], up=[0, 0, 1],\n",
261261
" children=[DirectionalLight(color='white',\n",
@@ -314,7 +314,7 @@
314314
"facecolors = [[vertexcolors[i] for i in f] for f in faces]\n",
315315
"cubeGeometry = PlainGeometry(vertices=vertices, faces=faces, faceColors = facecolors)\n",
316316
"\n",
317-
"myobjectCube = Mesh(geometry=cubeGeometry, material = LambertMaterial(vertexColors = 'VertexColors'))\n",
317+
"myobjectCube = Mesh(geometry=cubeGeometry, material = MeshLambertMaterial(vertexColors = 'VertexColors'))\n",
318318
"cCube = PerspectiveCamera(position=[3, 3, 3], fov=20,\n",
319319
" children=[DirectionalLight(color='#ffffff', position=[-3, 5, 1], intensity=0.5)])\n",
320320
"sceneCube = Scene(children=[myobjectCube, AmbientLight(color='#dddddd')])\n",
@@ -374,7 +374,7 @@
374374
"\n",
375375
"cubeGeometry = PlainBufferGeometry(vertices=vertices, faces=faces, colors = vertexcolors)\n",
376376
"\n",
377-
"myobjectCube = Mesh(geometry=cubeGeometry, material = LambertMaterial(vertexColors = 'VertexColors'))\n",
377+
"myobjectCube = Mesh(geometry=cubeGeometry, material = MeshLambertMaterial(vertexColors = 'VertexColors'))\n",
378378
"cCube = PerspectiveCamera(position=[3, 3, 3], fov=20,\n",
379379
" children=[DirectionalLight(color='#ffffff', position=[-3, 5, 1], intensity=0.5)])\n",
380380
"sceneCube = Scene(children=[myobjectCube, AmbientLight(color='#dddddd')])\n",

examples/threejs/voxel_painter.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155
" depth = csize\n",
156156
")\n",
157157
"\n",
158-
"cube_mat = LambertMaterial(\n",
158+
"cube_mat = MeshLambertMaterial(\n",
159159
" color = 0xfeb74c,\n",
160160
" shading = 'FlatShading',\n",
161161
" map = cube_tex\n",

js/package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jupyter-threejs",
3-
"version": "0.2.0",
3+
"version": "0.3.0-alpha.0",
44
"description": "jupyter - threejs bridge",
55
"author": "Jupyter-Threejs development team",
66
"license": "BSD-3-Clause",
@@ -11,7 +11,9 @@
1111
},
1212
"scripts": {
1313
"clean": "node ./scripts/clean-generated-files.js",
14-
"autogen": "node ./scripts/generate-wrappers.js",
14+
"autogen-enums": "node ./scripts/generate-enums.js",
15+
"autogen-wrappers": "node ./scripts/generate-wrappers.js",
16+
"autogen": "npm run autogen-enums && npm run autogen-wrappers",
1517
"build": "webpack",
1618
"test": "echo \"Error: no test specified\" && exit 1"
1719
},
@@ -25,9 +27,9 @@
2527
"webpack": "^1.12.14"
2628
},
2729
"dependencies": {
28-
"jupyter-js-widgets": "^2.1.4",
30+
"@jupyter-widgets/base": "^0.2.0",
2931
"ndarray": "^1.0.18",
30-
"three": "^0.75.0",
32+
"three": "^0.85.2",
3133
"underscore": "^1.8.3"
3234
}
3335
}

js/scripts/generate-enums.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
var _ = require('underscore');
2+
var path = require('path');
3+
var fs = require('fs');
4+
var fse = require('fs-extra');
5+
var Promise = require('bluebird');
6+
var Handlebars = require('handlebars');
7+
8+
Promise.promisifyAll(fs);
9+
Promise.promisifyAll(fse);
10+
11+
const enumConfigs = require('./three-enum-config');
12+
13+
const scriptDir = __dirname;
14+
const baseDir = path.resolve(scriptDir, '..');
15+
16+
const jsSrcDir = path.resolve(baseDir, 'src/');
17+
const pySrcDir = path.resolve(baseDir, '..', 'pythreejs');
18+
const templateDir = path.resolve(scriptDir, 'templates');
19+
20+
const threeSrcDir = path.resolve(baseDir, 'node_modules', 'three', 'src');
21+
22+
const jsEnumDst = path.resolve(jsSrcDir, '_base', 'enums.js');
23+
const pyEnumDst = path.resolve(pySrcDir, 'enums.py');
24+
25+
//
26+
// Actual THREE constants:
27+
//
28+
29+
function parseThreeConstants() {
30+
var content = fs.readFileSync(path.resolve(threeSrcDir, 'constants.js'), 'utf-8');
31+
eval('var result = new function() {\n' + content.replace(/export var (.*?);/g, 'var $1;\nthis.$1;') + '}()');
32+
return result;
33+
}
34+
35+
const threeEnums = parseThreeConstants();
36+
37+
38+
//
39+
// Templates
40+
//
41+
42+
function compileTemplate(templateName) {
43+
var templateName = path.basename(templateName, '.mustache');
44+
var templatePath = path.resolve(templateDir, templateName + '.mustache');
45+
return Handlebars.compile(fs.readFileSync(templatePath, {
46+
encoding: 'utf-8'
47+
}));
48+
}
49+
50+
var jsEnumTemplate = compileTemplate('js_enums');
51+
var pyEnumTemplate = compileTemplate('py_enums');
52+
53+
54+
//
55+
// Helper functions
56+
//
57+
58+
function checkUnused() {
59+
return new Promise(function(resolve, reject) {
60+
var unusedThreeEnums = _.keys(threeEnums);
61+
62+
_.keys(enumConfigs).map(function(category) {
63+
values = enumConfigs[category];
64+
values.forEach(function(enumKey) {
65+
if (Array.isArray(enumKey)) {
66+
// Several keys share the same value, remove all.
67+
enumKey.forEach(function(subKey) {
68+
unusedThreeEnums.splice(unusedThreeEnums.indexOf(subKey), 1);
69+
});
70+
} else {
71+
unusedThreeEnums.splice(unusedThreeEnums.indexOf(enumKey), 1);
72+
}
73+
}, this);
74+
}, this);
75+
76+
if (unusedThreeEnums.length > 0) {
77+
console.error('Unreferenced constants: ', unusedThreeEnums);
78+
}
79+
});
80+
}
81+
82+
83+
//
84+
// Generator functions
85+
//
86+
87+
function writeJavascriptFile() {
88+
// Here we generate a code to enum string LUT
89+
90+
var categories = [];
91+
92+
_.keys(enumConfigs).map(function(category) {
93+
var categoryObj = {key: category, enums: []};
94+
categories.push(categoryObj);
95+
enumConfigs[category].forEach(function(enumKey) {
96+
if (Array.isArray(enumKey)) {
97+
// Several keys share the same value, use the first one.
98+
enumKey = enumKey[0];
99+
}
100+
categoryObj.enums.push({ key: enumKey, value: threeEnums[enumKey] });
101+
}, this);
102+
}, this);
103+
104+
var content = jsEnumTemplate({
105+
now: new Date(),
106+
generatorScriptName: path.basename(__filename),
107+
108+
categories: categories
109+
});
110+
111+
return fse.outputFileAsync(jsEnumDst, content);
112+
}
113+
114+
function createJavascriptFiles() {
115+
return new Promise(function(resolve, reject) {
116+
resolve(writeJavascriptFile());
117+
});
118+
}
119+
120+
function writePythonFile() {
121+
// Here we generate lists of enum keys
122+
123+
var categories = [];
124+
125+
_.keys(enumConfigs).map(function(category) {
126+
var enums = [];
127+
enumConfigs[category].forEach(function(enumKey) {
128+
if (Array.isArray(enumKey)) {
129+
// Several keys share the same value, include all.
130+
enums = enums.concat(enumKey);
131+
} else {
132+
enums.push(enumKey);
133+
}
134+
});
135+
var categoryObj = {key: category, enums: enums};
136+
categories.push(categoryObj);
137+
});
138+
139+
var content = pyEnumTemplate({
140+
now: new Date(),
141+
generatorScriptName: path.basename(__filename),
142+
143+
categories: categories,
144+
});
145+
146+
return fse.outputFileAsync(pyEnumDst, content);
147+
}
148+
149+
function createPythonFiles() {
150+
return new Promise(function(resolve, reject) {
151+
resolve(writePythonFile());
152+
});
153+
}
154+
155+
function generateFiles() {
156+
157+
return Promise.all([
158+
createJavascriptFiles(),
159+
createPythonFiles(),
160+
checkUnused(),
161+
]);
162+
163+
}
164+
165+
if (require.main === module) {
166+
generateFiles().then(function() {
167+
console.log('DONE');
168+
});
169+
}

0 commit comments

Comments
 (0)