├── test ├── testset │ ├── colorpool │ │ └── .gitkeep │ ├── primitives │ │ ├── box.es.txt │ │ ├── grid.es.txt │ │ ├── line.es.txt │ │ ├── sphere.es.txt │ │ ├── cylinder.es.txt │ │ ├── triangle.racket-notation.es.txt │ │ └── triangle.es.txt │ ├── geometric │ │ ├── fz.es.txt │ │ ├── m.es.txt │ │ ├── matrix.es.txt │ │ ├── m.def.es.txt │ │ ├── matrix.def.es.txt │ │ ├── x.es.txt │ │ ├── y.es.txt │ │ ├── z.es.txt │ │ ├── fx.es.txt │ │ ├── s.3.es.txt │ │ ├── x.def.es.txt │ │ ├── y.def.es.txt │ │ ├── z.def.es.txt │ │ ├── rx.es.txt │ │ ├── ry.es.txt │ │ ├── rz.es.txt │ │ ├── s.1.es.txt │ │ ├── rx.def.es.txt │ │ ├── ry.def.es.txt │ │ ├── rz.def.es.txt │ │ ├── s.1.def.es.txt │ │ └── fy.es.txt │ ├── colorspace │ │ ├── color.default_color.es.txt │ │ ├── color.hex3.es.txt │ │ ├── blend.hex3.es.txt │ │ ├── blend.hex6.es.txt │ │ ├── color.colorname.es.txt │ │ ├── color.hex6.es.txt │ │ ├── blend.colorname.es.txt │ │ ├── color.random.es.txt │ │ ├── blend.random.es.txt │ │ ├── a.define.varname.es.txt │ │ ├── color.hex3.define.es.txt │ │ ├── hue.define.varname.es.txt │ │ ├── b.define.varname.es.txt │ │ ├── color.hex6.define.es.txt │ │ ├── b.es.txt │ │ ├── h.es.txt │ │ ├── sat.es.txt │ │ ├── hue.es.txt │ │ ├── brightness.es.txt │ │ ├── saturation.es.txt │ │ ├── a.es.txt │ │ ├── alpha.es.txt │ │ ├── blend.hex.and.hsv.es.txt │ │ └── sat.define.varname.es.txt │ ├── comments │ │ ├── single_line.es.txt │ │ └── multiline.es.txt │ ├── actions │ │ ├── background │ │ │ ├── background.hex3.es.txt │ │ │ ├── background.colorname.es.txt │ │ │ └── background.hex6.es.txt │ │ ├── seed │ │ │ └── seed.es.txt │ │ ├── maxdepth │ │ │ └── maxdepth.strange.es.txt │ │ └── maxobjects │ │ │ └── maxobjects.es.txt │ └── modifiers │ │ ├── maxdepth │ │ ├── md.es.txt │ │ ├── maxdepth.es.txt │ │ ├── maxdepth.define.varname.es.txt │ │ ├── maxdepth.nested_recursive_rule.es.txt │ │ ├── maxdepth.parallel_traverse.es.txt │ │ ├── maxdepth.alternate_rule.es.txt │ │ ├── maxdepth.alternate_rule.define.varname.es.txt │ │ └── maxdepth.nested_transform.es.txt │ │ └── weight │ │ └── w.es.txt ├── helpers │ └── prettify.js ├── behavior │ └── should_be_good_interpreter.js └── interpreter_test.js ├── examples ├── js │ ├── eisenscript.js │ ├── render.js │ └── loaders │ │ └── OBJLoader.js ├── obj │ └── box.obj ├── export.html ├── index.html ├── import.html └── css │ └── main.css ├── sample ├── sample1.png ├── sample2.png ├── sample3.png ├── sample4.png ├── sample5.png ├── sample6.png └── sample7.png ├── src ├── math.js ├── index.js ├── exporter │ ├── STLExporter.js │ └── OBJExporter.js ├── Primitive.js ├── sprintf.js ├── Compiler.js ├── Symbol.js ├── csscolor.js ├── utils.js ├── Matrix4.js ├── mt.js ├── parser.jison └── Interpreter.js ├── .editorconfig ├── .circleci └── config.yml ├── .gitignore ├── webpack.config.js ├── LICENSE ├── README.md ├── package.json └── gulpfile.js /test/testset/colorpool/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/js/eisenscript.js: -------------------------------------------------------------------------------- 1 | ../../build/eisenscript.js -------------------------------------------------------------------------------- /sample/sample1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/after12am/eisenscript/HEAD/sample/sample1.png -------------------------------------------------------------------------------- /sample/sample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/after12am/eisenscript/HEAD/sample/sample2.png -------------------------------------------------------------------------------- /sample/sample3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/after12am/eisenscript/HEAD/sample/sample3.png -------------------------------------------------------------------------------- /sample/sample4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/after12am/eisenscript/HEAD/sample/sample4.png -------------------------------------------------------------------------------- /sample/sample5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/after12am/eisenscript/HEAD/sample/sample5.png -------------------------------------------------------------------------------- /sample/sample6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/after12am/eisenscript/HEAD/sample/sample6.png -------------------------------------------------------------------------------- /sample/sample7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/after12am/eisenscript/HEAD/sample/sample7.png -------------------------------------------------------------------------------- /src/math.js: -------------------------------------------------------------------------------- 1 | module.exports.clamp = (x, a, b) => (x < a) ? a : ((x > b) ? b : x); 2 | 3 | module.exports.degToRad = (degrees) => degrees * Math.PI / 180; 4 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Compiler from './Compiler'; 2 | import OBJExporter from './exporter/OBJExporter'; 3 | 4 | module.exports.Compiler = Compiler; 5 | module.exports.OBJExporter = OBJExporter; 6 | -------------------------------------------------------------------------------- /src/exporter/STLExporter.js: -------------------------------------------------------------------------------- 1 | export default class STLExporter { 2 | constructor() { 3 | this.buff = ''; 4 | } 5 | 6 | exports(meshes) { 7 | console.warn("not implemented"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/helpers/prettify.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // prettify json and dump 4 | module.exports = function(object, replacer, space) { 5 | replacer = replacer || null; 6 | space = space || 2; 7 | return JSON.stringify(object, replacer, space); 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | block_comment_start = /** 11 | block_comment = * 12 | block_comment_end = */ 13 | 14 | [*.md] 15 | indent_size = 4 16 | -------------------------------------------------------------------------------- /test/testset/primitives/box.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/primitives/grid.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | grid 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"grid","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/primitives/line.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | line 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"line","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/fz.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { fz x 1 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":-1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} -------------------------------------------------------------------------------- /test/testset/primitives/sphere.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | sphere 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"sphere","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/color.default_color.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/color.hex3.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { color #fff } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FFFFFF","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/m.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { m 3 0 0 0 2 0 0 0 1 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":3,"1":0,"2":0,"3":0,"4":0,"5":2,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/blend.hex3.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { blend #fff 1 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF8080","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/blend.hex6.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { blend #ffffff 1 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF8080","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/color.colorname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { color red } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/color.hex6.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { color #ffffff } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FFFFFF","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/blend.colorname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { blend white 1 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF8080","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/color.random.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set seed 1 3 | { color random } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":1,"objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#6AC1F3","opacity":1,"depth":1}],"num":1} 6 | -------------------------------------------------------------------------------- /test/testset/comments/single_line.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | // have a nice day 3 | box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":1} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/matrix.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { matrix 3 0 0 0 2 0 0 0 1 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":3,"1":0,"2":0,"3":0,"4":0,"5":2,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/blend.random.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set seed 1 3 | { blend random 1 } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":1,"objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#B5617A","opacity":1,"depth":1}],"num":1} 6 | -------------------------------------------------------------------------------- /test/testset/comments/multiline.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | /* 3 | have a nice day 4 | */ 5 | box 6 | +/ 7 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":1} 8 | -------------------------------------------------------------------------------- /test/testset/colorspace/a.define.varname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define aa .1 3 | 4 | { a aa } box 5 | +/ 6 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.1,"depth":1}],"num":1} 7 | -------------------------------------------------------------------------------- /test/testset/colorspace/color.hex3.define.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define aa #f00 3 | 4 | { color aa } box 5 | +/ 6 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} 7 | -------------------------------------------------------------------------------- /test/testset/colorspace/hue.define.varname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define aa 36 3 | 4 | { hue aa } grid 5 | +/ 6 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"grid","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF9900","opacity":1,"depth":1}],"num":1} 7 | -------------------------------------------------------------------------------- /test/testset/colorspace/b.define.varname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define aa 100 3 | 4 | { color #fff b aa } box 5 | +/ 6 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FFFFFF","opacity":1,"depth":1}],"num":1} 7 | -------------------------------------------------------------------------------- /test/testset/colorspace/color.hex6.define.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define aa #ff0000 3 | 4 | { color aa } box 5 | +/ 6 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} 7 | -------------------------------------------------------------------------------- /test/testset/actions/background/background.hex3.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set background #fff 3 | box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"background","color":"#fff"},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":2} 6 | -------------------------------------------------------------------------------- /examples/obj/box.obj: -------------------------------------------------------------------------------- 1 | # box example 2 | g cube 3 | v 0 0 0 4 | v 10 0 0 5 | v 0 10 0 6 | v 10 10 0 7 | v 0 0 10 8 | v 10 0 10 9 | v 0 10 10 10 | v 10 10 10 11 | vn 0 0 -1 12 | vn -1 0 0 13 | vn 1 0 0 14 | vn 0 -1 0 15 | vn 0 1 0 16 | vn 0 0 1 17 | f 1//1 3//1 4//1 2//1 18 | f 1//2 5//2 7//2 3//2 19 | f 2//3 4//3 8//3 6//3 20 | f 1//4 2//4 6//4 5//4 21 | f 3//5 7//5 8//5 4//5 22 | f 5//6 6//6 8//6 7//6 -------------------------------------------------------------------------------- /test/testset/actions/background/background.colorname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set background white 3 | box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"background","color":"white"},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/actions/background/background.hex6.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set background #ffffff 3 | box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"background","color":"#ffffff"},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/m.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define zero 0 3 | #define one 1 4 | #define two 2 5 | #define three 3 6 | { m three zero zero zero two zero zero zero one } box 7 | +/ 8 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":3,"1":0,"2":0,"3":0,"4":0,"5":2,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} 9 | -------------------------------------------------------------------------------- /test/testset/geometric/matrix.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define zero 0 3 | #define one 1 4 | #define two 2 5 | #define three 3 6 | { matrix three zero zero zero two zero zero zero one } box 7 | +/ 8 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":3,"1":0,"2":0,"3":0,"4":0,"5":2,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":1} 9 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | orbs: 3 | node: circleci/node@1.1.6 4 | jobs: 5 | build-and-test: 6 | executor: 7 | name: node/default 8 | steps: 9 | - checkout 10 | - node/with-cache: 11 | steps: 12 | - run: npm install 13 | - run: npm test 14 | - store_artifacts: 15 | path: coverage 16 | workflows: 17 | build-and-test: 18 | jobs: 19 | - build-and-test 20 | -------------------------------------------------------------------------------- /src/Primitive.js: -------------------------------------------------------------------------------- 1 | module.exports = class Primitive { 2 | static get Box() { return 'box'; } 3 | static get Grid() { return 'grid'; } 4 | static get Sphere() { return 'sphere'; } 5 | static get Line() { return 'line'; } 6 | static get Point() { return 'point'; } 7 | static get Triangle() { return 'triangle'; } 8 | static get Mesh() { return 'mesh'; } 9 | static get Cylinder() { return 'cylinder'; } 10 | static get Tube() { return 'tube'; } 11 | static get Squash() { return 'squash'; } 12 | } 13 | -------------------------------------------------------------------------------- /test/testset/geometric/x.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { x 2 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/y.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { y 2 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":2,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":4,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/z.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { z 2 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":2,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":4,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/fx.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { fx } 1 * { x 5 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":-1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-5,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":2}],"num":2} -------------------------------------------------------------------------------- /test/testset/geometric/s.3.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { s 2 3 0.5 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":2,"1":0,"2":0,"3":0,"4":0,"5":3,"6":0,"7":0,"8":0,"9":0,"10":0.5,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":4,"1":0,"2":0,"3":0,"4":0,"5":9,"6":0,"7":0,"8":0,"9":0,"10":0.25,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/primitives/cylinder.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | box 3 | { x 1 } cylinder 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"cylinder","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/x.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define dist 2 3 | 2 * { x dist } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/y.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define dist 2 3 | 2 * { y dist } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":2,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":4,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/z.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define dist 2 3 | 2 * { z dist } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":2,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":4,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /src/sprintf.js: -------------------------------------------------------------------------------- 1 | const makeArray = (array) => { 2 | const ret = []; 3 | if(array != null){ 4 | let i = array.length; 5 | if ( i == null || array.split || array.setInterval || array.call ) { 6 | ret[0] = array; 7 | } else { 8 | while( i ) ret[--i] = array[i]; 9 | } 10 | } 11 | return ret; 12 | }; 13 | 14 | export default function sprintf() { 15 | let _arg = makeArray(arguments), template = _arg.shift(), i; 16 | for(i in _arg){ 17 | template = template.replace('%s', _arg[i]); 18 | } 19 | return template; 20 | }; 21 | -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/md.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | rule R1 md 2 { 3 | box 4 | { x 1 } R1 5 | } 6 | 7 | R1 8 | +/ 9 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 10 | -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/maxdepth.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | rule R1 maxdepth 2 { 3 | box 4 | { x 1 } R1 5 | } 6 | 7 | R1 8 | +/ 9 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 10 | -------------------------------------------------------------------------------- /test/testset/geometric/rx.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { rx 45 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.7071067690849304,"6":0.7071067690849304,"7":0,"8":0,"9":-0.7071067690849304,"10":0.7071067690849304,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":5.551115123125783e-17,"6":1,"7":0,"8":0,"9":-1,"10":5.551115123125783e-17,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/ry.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { ry 45 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":0.7071067690849304,"1":0,"2":-0.7071067690849304,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.7071067690849304,"9":0,"10":0.7071067690849304,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":5.551115123125783e-17,"1":0,"2":-1,"3":0,"4":0,"5":1,"6":0,"7":0,"8":1,"9":0,"10":5.551115123125783e-17,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/rz.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { rz 45 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":0.7071067690849304,"1":0.7071067690849304,"2":0,"3":0,"4":-0.7071067690849304,"5":0.7071067690849304,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":5.551115123125783e-17,"1":1,"2":0,"3":0,"4":-1,"5":5.551115123125783e-17,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/maxdepth.define.varname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define num 2 3 | 4 | rule R1 maxdepth num { 5 | box 6 | { x 1 } R1 7 | } 8 | 9 | R1 10 | +/ 11 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 12 | -------------------------------------------------------------------------------- /test/testset/geometric/s.1.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { x -1 s 1.2 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1.2000000476837158,"1":0,"2":0,"3":0,"4":0,"5":1.2000000476837158,"6":0,"7":0,"8":0,"9":0,"10":1.2000000476837158,"11":0,"12":-1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1.440000057220459,"1":0,"2":0,"3":0,"4":0,"5":1.440000057220459,"6":0,"7":0,"8":0,"9":0,"10":1.440000057220459,"11":0,"12":-2.200000047683716,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 5 | -------------------------------------------------------------------------------- /test/testset/geometric/rx.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define angle 45 3 | 2 * { rx angle } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.7071067690849304,"6":0.7071067690849304,"7":0,"8":0,"9":-0.7071067690849304,"10":0.7071067690849304,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":5.551115123125783e-17,"6":1,"7":0,"8":0,"9":-1,"10":5.551115123125783e-17,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/ry.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define angle 45 3 | 2 * { ry angle } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":0.7071067690849304,"1":0,"2":-0.7071067690849304,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.7071067690849304,"9":0,"10":0.7071067690849304,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":5.551115123125783e-17,"1":0,"2":-1,"3":0,"4":0,"5":1,"6":0,"7":0,"8":1,"9":0,"10":5.551115123125783e-17,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/rz.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define angle 45 3 | 2 * { rz angle } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":0.7071067690849304,"1":0.7071067690849304,"2":0,"3":0,"4":-0.7071067690849304,"5":0.7071067690849304,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":5.551115123125783e-17,"1":1,"2":0,"3":0,"4":-1,"5":5.551115123125783e-17,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/geometric/s.1.def.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define scale 1.2 3 | 2 * { x -1 s scale } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1.2000000476837158,"1":0,"2":0,"3":0,"4":0,"5":1.2000000476837158,"6":0,"7":0,"8":0,"9":0,"10":1.2000000476837158,"11":0,"12":-1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1.440000057220459,"1":0,"2":0,"3":0,"4":0,"5":1.440000057220459,"6":0,"7":0,"8":0,"9":0,"10":1.440000057220459,"11":0,"12":-2.200000047683716,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/primitives/triangle.racket-notation.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | triangle [0,0,0;1,0,0;0.5,0.5,0.5] 3 | triangle[-1,0,1;0,1,0;1,0,1] 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"triangle","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0,"coords":[[0,0,0],[1,0,0],[0.5,0.5,0.5]]},{"type":"primitive","name":"triangle","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0,"coords":[[-1,0,1],[0,1,0],[1,0,1]]}],"num":2} 6 | -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/maxdepth.nested_recursive_rule.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | corner 3 | rule corner md 2 { 4 | ARC 5 | {ry 36}corner 6 | } 7 | rule ARC md 1 { 8 | ARC 9 | box 10 | } 11 | +/ 12 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.80901700258255,"1":0,"2":-0.5877852439880371,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.5877852439880371,"9":0,"10":0.80901700258255,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":2} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | *.pid.lock 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # nyc test coverage 19 | .nyc_output 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 29 | 30 | # Dependency directories 31 | node_modules 32 | jspm_packages 33 | 34 | # Optional npm cache directory 35 | .npm 36 | 37 | # Optional eslint cache 38 | .eslintcache 39 | 40 | # Optional REPL history 41 | .node_repl_history 42 | 43 | # Output of 'npm pack' 44 | *.tgz 45 | 46 | 47 | .DS_Store 48 | coverage 49 | _docpress 50 | -------------------------------------------------------------------------------- /test/testset/geometric/fy.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { fy } 2 * { fx } 1 * { x 1 y 3 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":-1,"1":0,"2":0,"3":0,"4":0,"5":-1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-1,"13":-3,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":-1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":-3,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":-1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-1,"13":3,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":3}],"num":4} -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/maxdepth.parallel_traverse.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | crate 3 | rule crate md 2 { 4 | box 5 | { s 0.5 x 0.9 z 0.9 y -0.9 } crate //1 6 | { s 0.5 x -0.9 z 0.9 y -0.9 } crate //2 7 | } 8 | +/ 9 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":0,"2":0,"3":0,"4":0,"5":0.5,"6":0,"7":0,"8":0,"9":0,"10":0.5,"11":0,"12":0.44999998807907104,"13":-0.44999998807907104,"14":0.44999998807907104,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":0,"2":0,"3":0,"4":0,"5":0.5,"6":0,"7":0,"8":0,"9":0,"10":0.5,"11":0,"12":-0.44999998807907104,"13":-0.44999998807907104,"14":0.44999998807907104,"15":1}},"color":"#FF0000","opacity":1,"depth":1}],"num":3} 10 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | const version = require('./package.json').version; 5 | 6 | const copyright = `eisenscript 7 | https://github.com/after12am/eisenscript 8 | (c)2013-2020 Satoshi Okami 9 | Released under the MIT license`; 10 | 11 | module.exports = { 12 | 13 | entry: { 14 | eisenscript: __dirname + '/src/index.js', 15 | }, 16 | 17 | output: { 18 | path: __dirname + '/build', 19 | filename: '[name].js', 20 | library: 'eisen = EISEN', 21 | libraryTarget: 'var' 22 | }, 23 | 24 | module: { 25 | loaders: [ 26 | { 27 | loader: 'babel-loader', 28 | query: { 29 | presets: ['es2015'] 30 | } 31 | }, 32 | { 33 | test: /\.json$/, 34 | loader: 'json-loader', 35 | } 36 | ] 37 | }, 38 | 39 | node: { 40 | fs: "empty" 41 | }, 42 | 43 | resolve: { 44 | extensions: ['', '.js', '.jsx', '.json'] 45 | }, 46 | 47 | plugins: [ 48 | new webpack.BannerPlugin(copyright) 49 | ] 50 | }; 51 | -------------------------------------------------------------------------------- /src/Compiler.js: -------------------------------------------------------------------------------- 1 | import parser from './parser'; 2 | import Interpreter from './Interpreter'; 3 | 4 | export default class Compiler { 5 | /** 6 | * convert eisenscript code to intermediate object that is possible to load 3d renderer. 7 | * 8 | * @description parse eisenscript code and interpret the result while scanning the ast. 9 | * @param {String} source eisenscript 10 | * @return {Object} execution result 11 | *
12 |    * new Compiler().compile('2 * { x 1 } box');
13 |    * 
14 | */ 15 | compile(source) { 16 | const interpreter = new Interpreter(); 17 | return interpreter.generate(this.parse(source)); 18 | } 19 | 20 | /** 21 | * parse eisenscript code 22 | * 23 | * @description parse eisenscript code and get [ast](https://en.wikipedia.org/wiki/Abstract_syntax_tree). 24 | * @param {String} source eisenscript 25 | * @return {Object} ast 26 | *
27 |    * new Compiler().parse('2 * { x 1 } box');
28 |    * 
29 | */ 30 | parse(source) { 31 | return parser.parse(source); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (C) 2013-2020 Satoshi Okami 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | eisenscript 2 | =========== 3 | 4 | [![CircleCI](https://circleci.com/gh/after12am/eisenscript.svg?style=svg)](https://circleci.com/gh/after12am/eisenscript) 5 | 6 | [Demo](https://after12am.github.io/eisenscript-editor/?show=0) 7 | 8 | [Doc](https://after12am.github.io/eisenscript-docs/build/docs/getting-started-introduction) 9 | 10 | EisenScript is a programming language designed by Mikael Hvidtfeldt for generating 3d structures. 11 | This language shows you that even a simple system has a big possibility to generate surprising 12 | and complex structures, and then brings a big amazing to you. A set of those structures, you would 13 | get, has often been called ”generative art” for having both organic and mechanical in itself. 14 | If you want to create ”generative art” intuitively, this powerful language will be your best friend. 15 | 16 | 17 | 18 | ## Notes 19 | 20 | This is a javascript implementation for generating in real time in your browser. 21 | Original implementation is included in Structure Synth authored by Mikael Hvidtfeldt. 22 | 23 | ## License 24 | 25 | Copyright (c) 2013-2020 Satoshi Okami. See the LICENSE file for license rights and limitations (MIT). 26 | -------------------------------------------------------------------------------- /test/behavior/should_be_good_interpreter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { assert } = require('chai'); 4 | const fs = require('fs'); 5 | const parser = require('../../src/parser'); 6 | const Interpreter = require('../../src/Interpreter'); 7 | 8 | // read testset from testset directory 9 | function read(testset, encoding = 'utf8') { 10 | return Promise.resolve() 11 | .then(() => { 12 | return fs.readFileSync(testset, encoding); 13 | }) 14 | .then((data) => { 15 | const m = data.trim().match(/^\/\+\n([\s\S.]*)\n\+\/\n([\s\S.]*)/); 16 | if (m) { 17 | return { 18 | source: m[1], 19 | expected: m[2] 20 | }; 21 | } 22 | return Promise.reject(new Error(`testset format is not correct: ${testset}`)); 23 | }); 24 | } 25 | 26 | // compile eisenscript code and return intermediate object 27 | function compile(source) { 28 | const ast = parser.parse(source); 29 | const interpreter = new Interpreter(); 30 | const object = interpreter.generate(ast); 31 | // console.log(JSON.stringify(object)); 32 | return object; 33 | } 34 | 35 | module.exports = function(testset) { 36 | it(testset, function() { 37 | return read(testset) 38 | .then(({ source, expected }) => { 39 | const output = compile(source); 40 | assert.deepEqual(JSON.stringify(output), expected); 41 | }); 42 | }); 43 | } 44 | 45 | module.exports.compile = compile; 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eisenscript", 3 | "version": "2.2.2", 4 | "scripts": { 5 | "start": "$(npm bin)/gulp serve", 6 | "test": "$(npm bin)/istanbul cover $(npm bin)/_mocha test -- --recursive", 7 | "jison": "$(npm bin)/jison src/parser.jison -o src/parser.js", 8 | "build": "$(npm bin)/webpack --config webpack.config.js -p", 9 | "release": "npm login && $(npm bin)/release-it", 10 | "serve-doc": "$(npm bin)/docpress serve", 11 | "build-doc": "$(npm bin)/docpress build" 12 | }, 13 | "devDependencies": { 14 | "babel-core": "^6.17.0", 15 | "babel-loader": "^6.2.5", 16 | "babel-preset-es2015": "^6.16.0", 17 | "babel-register": "^6.16.3", 18 | "browser-sync": "^2.29.1", 19 | "chai": "^4.2.0", 20 | "color-js": "^1.0.3", 21 | "docpress": "^0.8.2", 22 | "gulp": "^4.0.2", 23 | "gulp-load-plugins": "^2.0.3", 24 | "gulp-plumber": "^1.0.1", 25 | "gulp-spawn-mocha": "^6.0.0", 26 | "istanbul": "^0.4.5", 27 | "jison": "^0.4.17", 28 | "mocha": "^7.1.1", 29 | "release-it": "^15.10.1", 30 | "webpack": "^1.13.2", 31 | "webpack-stream": "^3.2.0" 32 | }, 33 | "dependencies": {}, 34 | "eslintConfig": { 35 | "env": { 36 | "es6": true, 37 | "node": true, 38 | "browser": true 39 | }, 40 | "rules": { 41 | "quotes": [ 42 | 2, 43 | "single" 44 | ] 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const gulpLoadPlugins = require('gulp-load-plugins'); 5 | const webpack = require('webpack-stream'); 6 | const browserSync = require('browser-sync'); 7 | const $ = gulpLoadPlugins(); 8 | const reload = browserSync.reload; 9 | 10 | /** 11 | * regression test 12 | */ 13 | gulp.task('watch:test', () => { 14 | gulp.watch([ 15 | 'src/**/*', 16 | 'test/**/*' 17 | ], gulp.series('test')); 18 | }); 19 | 20 | /** 21 | * unit test 22 | */ 23 | gulp.task('test', () => { 24 | return gulp.src('test/**/inter*.js') 25 | .pipe($.plumber()) 26 | .pipe($.spawnMocha()); 27 | }); 28 | 29 | /** 30 | * build source code as eisenscript library 31 | */ 32 | gulp.task('webpack', () => { 33 | const config = require('./webpack.config'); 34 | const entry = Object.values(config.entry); 35 | return gulp.src(entry) 36 | .pipe(webpack(config)) 37 | .pipe(gulp.dest('build/')); 38 | }); 39 | 40 | /** 41 | * start web app 42 | */ 43 | gulp.task('serve', () => { 44 | browserSync({ 45 | notify: false, 46 | port: 9000, 47 | startPath: '/examples', 48 | open: 'external', 49 | server: { 50 | baseDir: ['.'] 51 | } 52 | }); 53 | 54 | gulp.watch([ 55 | 'src/**/*' 56 | ], gulp.series('webpack')); 57 | 58 | gulp.watch([ 59 | 'src/**/*', 60 | 'examples/**/*', 61 | ]).on('change', reload); 62 | }); 63 | 64 | gulp.task('serve:dist', () => { 65 | browserSync({ 66 | notify: false, 67 | port: 9000, 68 | server: { 69 | baseDir: ['dist'] 70 | } 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /src/Symbol.js: -------------------------------------------------------------------------------- 1 | module.exports = class Symbol { 2 | static get Define() { return 'define'; } 3 | static get Set() { return 'set'; } 4 | static get Statement() { return 'statement'; } 5 | static get Primitive() { return 'primitive'; } 6 | static get Rule() { return 'rule'; } 7 | static get Modifier() { return 'modifier'; } 8 | static get Maxdepth() { return 'maxdepth'; } 9 | static get Maxobjects() { return 'maxobjects'; } 10 | static get Minsize() { return 'minsize'; } 11 | static get Maxsize() { return 'maxsize'; } 12 | static get Seed() { return 'seed'; } 13 | static get Weight() { return 'weight'; } 14 | static get Background() { return 'background'; } 15 | static get XShift() { return 'xshift'; } 16 | static get YShift() { return 'yshift'; } 17 | static get ZShift() { return 'zshift'; } 18 | static get RotateX() { return 'rotatex'; } 19 | static get RotateY() { return 'rotatey'; } 20 | static get RotateZ() { return 'rotatez'; } 21 | static get FX() { return 'fx'; } 22 | static get FY() { return 'fy'; } 23 | static get FZ() { return 'fz'; } 24 | static get Size() { return 'size'; } 25 | static get Matrix() { return 'matrix'; } 26 | static get Color() { return 'color'; } 27 | static get ColorPool() { return 'colorpool'; } 28 | static get Hue() { return 'hue'; } 29 | static get Saturation() { return 'saturation'; } 30 | static get Brightness() { return 'brightness'; } 31 | static get Blend() { return 'blend'; } 32 | static get Alpha() { return 'alpha'; } 33 | static get ColorList() { return 'list'; } 34 | static get ColorRandomhue() { return 'randomhue'; } 35 | static get ColorRandomrgb() { return 'randomrgb'; } 36 | static get ColorGreyscale() { return 'greyscale'; } 37 | } 38 | -------------------------------------------------------------------------------- /test/testset/colorspace/b.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 1 b 0.9 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#E60000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#CF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#BA0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#A70000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#970000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#880000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#7A0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#6E0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#630000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#590000","opacity":1,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/h.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 2 h 10 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF2A00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF5500","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#FF8000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#FFAA00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#FFD500","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":12,"13":0,"14":0,"15":1}},"color":"#FFFF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":14,"13":0,"14":0,"15":1}},"color":"#D4FF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":16,"13":0,"14":0,"15":1}},"color":"#AAFF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":18,"13":0,"14":0,"15":1}},"color":"#80FF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":20,"13":0,"14":0,"15":1}},"color":"#55FF00","opacity":1,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/sat.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 1 sat 0.9 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF1919","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF3030","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#FF4545","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF5858","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#FF6868","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#FF7777","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#FF8585","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#FF9191","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#FF9C9C","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#FFA6A6","opacity":1,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/hue.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 2 hue 10 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF2A00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF5500","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#FF8000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#FFAA00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#FFD500","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":12,"13":0,"14":0,"15":1}},"color":"#FFFF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":14,"13":0,"14":0,"15":1}},"color":"#D4FF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":16,"13":0,"14":0,"15":1}},"color":"#AAFF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":18,"13":0,"14":0,"15":1}},"color":"#80FF00","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":20,"13":0,"14":0,"15":1}},"color":"#55FF00","opacity":1,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/brightness.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 1 brightness 0.9 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#E60000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#CF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#BA0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#A70000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#970000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#880000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#7A0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#6E0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#630000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#590000","opacity":1,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/saturation.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 1 saturation 0.9 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF1919","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF3030","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#FF4545","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF5858","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#FF6868","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#FF7777","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#FF8585","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#FF9191","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#FF9C9C","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#FFA6A6","opacity":1,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/actions/seed/seed.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set seed 1 3 | 4 | 10 * { x 1 color random } box 5 | +/ 6 | {"minsize":0.2,"maxsize":1,"seed":1,"objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#6AC1F3","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#B8672E","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#7777EE","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#4D65AA","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#2591CB","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#17A380","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#2FAEBF","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#5876AA","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#65928D","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#89EFE4","opacity":1,"depth":1}],"num":10} 7 | -------------------------------------------------------------------------------- /test/testset/colorspace/a.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 1 a 0.5 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.5,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.25,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0625,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.03125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.015625,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0078125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.00390625,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.001953125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0009765625,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/alpha.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 10 * { x 1 alpha 0.5 } box 3 | +/ 4 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.5,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.25,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0625,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.03125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.015625,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0078125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.00390625,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.001953125,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0009765625,"depth":1}],"num":10} 5 | -------------------------------------------------------------------------------- /test/testset/colorspace/blend.hex.and.hsv.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | rule R1 md 10 { 3 | { x 2 color blue hue 36 } R1 4 | box 5 | } 6 | 7 | R1 8 | +/ 9 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":18,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":9},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":16,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":8},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":14,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":7},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":12,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":6},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":5},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#9900FF","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0}],"num":10} 10 | -------------------------------------------------------------------------------- /examples/export.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Export Test 5 | 6 | 16 | 17 | 18 | obj file 19 | 20 | 21 | 22 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /test/testset/actions/maxdepth/maxdepth.strange.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set maxdepth 10 3 | 4 | rule R1 { 5 | box { x 1 hue 36 rx 10 } R1 6 | } 7 | 8 | R1 9 | +/ 10 | {"maxdepth":10,"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.9848077297210693,"6":0.1736481785774231,"7":0,"8":0,"9":-0.1736481785774231,"10":0.9848077297210693,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF9900","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.9396926164627075,"6":0.3420201539993286,"7":0,"8":0,"9":-0.3420201539993286,"10":0.9396926164627075,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#CCFF00","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.8660253882408142,"6":0.5,"7":0,"8":0,"9":-0.5,"10":0.8660253882408142,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#33FF00","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.7660444378852844,"6":0.6427876353263855,"7":0,"8":0,"9":-0.6427876353263855,"10":0.7660444378852844,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#00FF66","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.6427875757217407,"6":0.7660444378852844,"7":0,"8":0,"9":-0.7660444378852844,"10":0.6427875757217407,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#00FFFF","opacity":1,"depth":5},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.4999999701976776,"6":0.8660253882408142,"7":0,"8":0,"9":-0.8660253882408142,"10":0.4999999701976776,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#0066FF","opacity":1,"depth":6},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.3420201241970062,"6":0.9396926164627075,"7":0,"8":0,"9":-0.9396926164627075,"10":0.3420201241970062,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#3300FF","opacity":1,"depth":7}],"num":8} 11 | -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/maxdepth.alternate_rule.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | 2 * { ry 60 } r 3 | rule r md 2 > k { 4 | sphere 5 | {x 2}r 6 | } 7 | rule k md 2 { 8 | box 9 | {y 2}k 10 | } 11 | +/ 12 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"sphere","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"sphere","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":1,"13":0,"14":-1.7320507764816284,"15":1}},"color":"#FF0000","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":2,"13":0,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":2,"13":2,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"sphere","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"sphere","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":-1,"13":0,"14":-1.7320507764816284,"15":1}},"color":"#FF0000","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":-2,"13":0,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":-2,"13":2,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":4}],"num":8} 13 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 56 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/maxdepth.alternate_rule.define.varname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define num 2 3 | 4 | 2 * { ry 60 } r 5 | rule r md num > k { 6 | sphere 7 | {x 2}r 8 | } 9 | rule k md 2 { 10 | box 11 | {y 2}k 12 | } 13 | +/ 14 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"sphere","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"sphere","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":1,"13":0,"14":-1.7320507764816284,"15":1}},"color":"#FF0000","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":2,"13":0,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":0.5,"11":0,"12":2,"13":2,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"sphere","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"sphere","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":-1,"13":0,"14":-1.7320507764816284,"15":1}},"color":"#FF0000","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":-2,"13":0,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.5,"1":0,"2":-0.8660253882408142,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0.8660253882408142,"9":0,"10":-0.5,"11":0,"12":-2,"13":2,"14":-3.464101552963257,"15":1}},"color":"#FF0000","opacity":1,"depth":4}],"num":8} 15 | -------------------------------------------------------------------------------- /test/testset/primitives/triangle.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | { x 2 } triangle 3 | 10 * { x 1 a 0.2 } box 4 | +/ 5 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"triangle","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.2,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.04000000000000001,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.008000000000000002,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0016000000000000005,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.00032000000000000013,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.00006400000000000002,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.000012800000000000006,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":0.0000025600000000000013,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":5.120000000000002e-7,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":10,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1.0240000000000006e-7,"depth":1}],"num":11} 6 | -------------------------------------------------------------------------------- /src/exporter/OBJExporter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import sprintf from '../sprintf'; 4 | 5 | /** 6 | * @see http://paulbourke.net/dataformats/obj/ 7 | */ 8 | export default class OBJExporter { 9 | constructor() { 10 | this.header = "#\n# generated by eisenscript\n# https://github.com/after12am/eisenscript/\n#\n"; 11 | this.buff = ''; 12 | } 13 | 14 | // If function name change to 'export', google clousure complains about that. 15 | exports(meshes) { 16 | this.buff = sprintf(this.header); 17 | for (let i = 0; i < meshes.length; i++) this.exportMesh(meshes[i], i); 18 | return this.buff; 19 | } 20 | 21 | exportMesh(mesh, i) { 22 | const that = this; 23 | const m = mesh.matrix.elements; 24 | 25 | // group 26 | const group = mesh.name ? mesh.name : mesh.material.name + i; 27 | this.buff += sprintf("g %s\n", group); 28 | 29 | // material 30 | if (mesh.material.name) { 31 | this.buff += sprintf("usemtl %s\n", mesh.material.name); 32 | } 33 | 34 | // vetices 35 | mesh.geometry.vertices.forEach(function(v) { 36 | // test: v 1.0 2.0 3.0 37 | that.buff += sprintf( 38 | "v %s %s %s\n", 39 | m[0] * v.x + m[1] * v.y + m[2] * v.z + m[3] * 1, 40 | m[4] * v.x + m[5] * v.y + m[6] * v.z + m[7] * 1, 41 | m[8] * v.x + m[9] * v.y + m[10] * v.z + m[11] * 1 42 | ); 43 | }); 44 | 45 | // normals 46 | mesh.geometry.faces.forEach(function(face) { 47 | // test: vn 1.0 2.0 3.0 48 | that.buff += sprintf( 49 | "vn %s %s %s\n", 50 | face.normal.x, 51 | face.normal.y, 52 | face.normal.z 53 | ); 54 | }); 55 | 56 | // uvs 57 | mesh.geometry.faceVertexUvs.forEach(function(uvs) { 58 | // test: vt 0.1 0.2 59 | for (let i = 0; i < uvs.length; i++) { 60 | for (let j = 0; j < uvs[i].length; j++) { 61 | that.buff += sprintf( 62 | "vt %s %s\n", 63 | uvs[i][j].x, 64 | uvs[i][j].y 65 | ); 66 | } 67 | } 68 | }); 69 | 70 | // faces 71 | mesh.geometry.faces.forEach(function(face) { 72 | // test: f 1 2 3 73 | that.buff += sprintf( 74 | "f %s %s %s %s\n", 75 | face.a + 1, 76 | face.b + 1, 77 | face.c + 1, 78 | face.d !== undefined ? face.d + 1 : '' 79 | ); 80 | }); 81 | }; 82 | 83 | exportObject(object, i) { 84 | // no need to implement because eisenscript.js does not support object loading 85 | console.warn("not implemented"); 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /test/testset/actions/maxobjects/maxobjects.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set maxobjects 10 3 | 4 | rule R1 { 5 | box { x 1 hue 36 rx 10 } R1 6 | } 7 | 8 | R1 9 | +/ 10 | {"maxobjects":10,"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":0},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.9848077297210693,"6":0.1736481785774231,"7":0,"8":0,"9":-0.1736481785774231,"10":0.9848077297210693,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF9900","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.9396926164627075,"6":0.3420201539993286,"7":0,"8":0,"9":-0.3420201539993286,"10":0.9396926164627075,"11":0,"12":2,"13":0,"14":0,"15":1}},"color":"#CCFF00","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.8660253882408142,"6":0.5,"7":0,"8":0,"9":-0.5,"10":0.8660253882408142,"11":0,"12":3,"13":0,"14":0,"15":1}},"color":"#33FF00","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.7660444378852844,"6":0.6427876353263855,"7":0,"8":0,"9":-0.6427876353263855,"10":0.7660444378852844,"11":0,"12":4,"13":0,"14":0,"15":1}},"color":"#00FF66","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.6427875757217407,"6":0.7660444378852844,"7":0,"8":0,"9":-0.7660444378852844,"10":0.6427875757217407,"11":0,"12":5,"13":0,"14":0,"15":1}},"color":"#00FFFF","opacity":1,"depth":5},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.4999999701976776,"6":0.8660253882408142,"7":0,"8":0,"9":-0.8660253882408142,"10":0.4999999701976776,"11":0,"12":6,"13":0,"14":0,"15":1}},"color":"#0066FF","opacity":1,"depth":6},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.3420201241970062,"6":0.9396926164627075,"7":0,"8":0,"9":-0.9396926164627075,"10":0.3420201241970062,"11":0,"12":7,"13":0,"14":0,"15":1}},"color":"#3300FF","opacity":1,"depth":7},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":0.1736481636762619,"6":0.9848077297210693,"7":0,"8":0,"9":-0.9848077297210693,"10":0.1736481636762619,"11":0,"12":8,"13":0,"14":0,"15":1}},"color":"#CC00FF","opacity":1,"depth":8},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":-9.733654771082456e-9,"6":1,"7":0,"8":0,"9":-1,"10":-9.733654771082456e-9,"11":0,"12":9,"13":0,"14":0,"15":1}},"color":"#FF0099","opacity":1,"depth":9}],"num":10} 11 | -------------------------------------------------------------------------------- /examples/import.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Import Test 6 | 12 | 13 | 14 | 15 | 16 | 17 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /test/testset/colorspace/sat.define.varname.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | #define aa 0.9 3 | 4 | 12 * { x 1 rz 30 sat aa } box 5 | +/ 6 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":0.8660253882408142,"1":0.5,"2":0,"3":0,"4":-0.5,"5":0.8660253882408142,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":0,"14":0,"15":1}},"color":"#FF1919","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":0.8660253882408142,"2":0,"3":0,"4":-0.8660253882408142,"5":0.5,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1.866025447845459,"13":0.5,"14":0,"15":1}},"color":"#FF3030","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":7.771812526868871e-9,"1":1,"2":0,"3":0,"4":-1,"5":7.771812526868871e-9,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2.366025447845459,"13":1.366025447845459,"14":0,"15":1}},"color":"#FF4545","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.5,"1":0.8660253882408142,"2":0,"3":0,"4":-0.8660253882408142,"5":-0.5,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":2.366025447845459,"13":2.366025447845459,"14":0,"15":1}},"color":"#FF5858","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.8660253882408142,"1":0.5,"2":0,"3":0,"4":-0.5,"5":-0.8660253882408142,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1.866025447845459,"13":3.232050895690918,"14":0,"15":1}},"color":"#FF6868","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":-1,"1":7.771812526868871e-9,"2":0,"3":0,"4":-7.771812526868871e-9,"5":-1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3.732050895690918,"14":0,"15":1}},"color":"#FF7777","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.8660253882408142,"1":-0.5,"2":0,"3":0,"4":0.5,"5":-0.8660253882408142,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":0,"13":3.732050895690918,"14":0,"15":1}},"color":"#FF8585","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.5,"1":-0.8660253882408142,"2":0,"3":0,"4":0.8660253882408142,"5":-0.5,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-0.8660253882408142,"13":3.232050895690918,"14":0,"15":1}},"color":"#FF9191","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":-7.771812526868871e-9,"1":-1,"2":0,"3":0,"4":1,"5":-7.771812526868871e-9,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-1.366025447845459,"13":2.366025447845459,"14":0,"15":1}},"color":"#FF9C9C","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.5,"1":-0.8660253882408142,"2":0,"3":0,"4":0.8660253882408142,"5":0.5,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-1.366025447845459,"13":1.366025447845459,"14":0,"15":1}},"color":"#FFA6A6","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.8660253882408142,"1":-0.5,"2":0,"3":0,"4":0.5,"5":0.8660253882408142,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-0.866025447845459,"13":0.5000000596046448,"14":0,"15":1}},"color":"#FFAFAF","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":-7.771812526868871e-9,"2":0,"3":0,"4":7.771812526868871e-9,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":-5.960464477539063e-8,"13":5.960464477539063e-8,"14":0,"15":1}},"color":"#FFB7B7","opacity":1,"depth":1}],"num":12} 7 | -------------------------------------------------------------------------------- /test/testset/modifiers/maxdepth/maxdepth.nested_transform.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | // bug around three.js? 3 | corner 4 | rule corner md 4 { 5 | { s 1 2 1.2 }ARC 6 | {ry 36}corner 7 | } 8 | rule ARC md 3 { 9 | { z 0.85 rx 4.5 s 0.95 } ARC 10 | box 11 | } 12 | +/ 13 | {"minsize":0.2,"maxsize":1,"seed":"initial","objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":0.9024999737739563,"1":0,"2":0,"3":0,"4":0,"5":1.7827774286270142,"6":0.16941852867603302,"7":0,"8":0,"9":-0.2823641896247864,"10":1.0696665048599243,"11":0,"12":0,"13":-0.12671144306659698,"14":1.9860129356384277,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.949999988079071,"1":0,"2":0,"3":0,"4":0,"5":1.8941428661346436,"6":0.08944337069988251,"7":0,"8":0,"9":-0.1490722894668579,"10":1.1364858150482178,"11":0,"12":0,"13":0,"14":1.0199999809265137,"15":1}},"color":"#FF0000","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":2,"6":0,"7":0,"8":0,"9":0,"10":1.2000000476837158,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":1},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.730137825012207,"1":0,"2":-0.5304762125015259,"3":0,"4":0.09958171099424362,"5":1.7827774286270142,"6":0.13706247508525848,"7":0,"8":0.6287342309951782,"9":-0.2823641896247864,"10":0.8653783798217773,"11":0,"12":1.167349100112915,"13":-0.12671144306659698,"14":1.6067181825637817,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.7685661315917969,"1":0,"2":-0.5583959817886353,"3":0,"4":0.052573490887880325,"5":1.8941428661346436,"6":0.07236120849847794,"7":0,"8":0.6680095791816711,"9":-0.1490722894668579,"10":0.9194363355636597,"11":0,"12":0.5995409488677979,"13":0,"14":0.8251973390579224,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.80901700258255,"1":0,"2":-0.5877852439880371,"3":0,"4":0,"5":2,"6":0,"7":0,"8":0.7053422927856445,"9":0,"10":0.970820426940918,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":2},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.27888786792755127,"1":0,"2":-0.8583285212516785,"3":0,"4":0.16112661361694336,"5":1.7827774286270142,"6":0.05235320329666138,"7":0,"8":1.0173133611679077,"9":-0.2823641896247864,"10":0.3305450975894928,"11":0,"12":1.888810634613037,"13":-0.12671144306659698,"14":0.6137117147445679,"15":1}},"color":"#FF0000","opacity":1,"depth":5},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.29356616735458374,"1":0,"2":-0.9035037159919739,"3":0,"4":0.08506570011377335,"5":1.8941428661346436,"6":0.027639523148536682,"7":0,"8":1.080862283706665,"9":-0.1490722894668579,"10":0.3511933982372284,"11":0,"12":0.9700776934623718,"13":0,"14":0.3151973485946655,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":0.30901700258255005,"1":0,"2":-0.9510565400123596,"3":0,"4":0,"5":2,"6":0,"7":0,"8":1.1412678956985474,"9":0,"10":0.37082040309906006,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":3},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.27888786792755127,"1":0,"2":-0.8583285212516785,"3":0,"4":0.16112661361694336,"5":1.7827774286270142,"6":-0.05235320329666138,"7":0,"8":1.0173133611679077,"9":-0.2823641896247864,"10":-0.3305450975894928,"11":0,"12":1.888810634613037,"13":-0.12671144306659698,"14":-0.6137117147445679,"15":1}},"color":"#FF0000","opacity":1,"depth":6},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.29356616735458374,"1":0,"2":-0.9035037159919739,"3":0,"4":0.08506570011377335,"5":1.8941428661346436,"6":-0.027639523148536682,"7":0,"8":1.080862283706665,"9":-0.1490722894668579,"10":-0.3511933982372284,"11":0,"12":0.9700776934623718,"13":0,"14":-0.3151973485946655,"15":1}},"color":"#FF0000","opacity":1,"depth":5},{"type":"primitive","name":"box","matrix":{"elements":{"0":-0.30901700258255005,"1":0,"2":-0.9510565400123596,"3":0,"4":0,"5":2,"6":0,"7":0,"8":1.1412678956985474,"9":0,"10":-0.37082040309906006,"11":0,"12":0,"13":0,"14":0,"15":1}},"color":"#FF0000","opacity":1,"depth":4}],"num":12} 14 | -------------------------------------------------------------------------------- /src/csscolor.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | aliceblue:'#F0F8FF', 3 | antiquewhite:'#FAEBD7', 4 | aqua:'#00FFFF', 5 | aquamarine:'#7FFFD4', 6 | azure:'#F0FFFF', 7 | beige:'#F5F5DC', 8 | bisque:'#FFE4C4', 9 | black:'#000000', 10 | blanchedalmond:'#FFEBCD', 11 | blue:'#0000FF', 12 | blueviolet:'#8A2BE2', 13 | brown:'#A52A2A', 14 | burlywood:'#DEB887', 15 | cadetblue:'#5F9EA0', 16 | chartreuse:'#7FFF00', 17 | chocolate:'#D2691E', 18 | coral:'#FF7F50', 19 | cornflowerblue:'#6495ED', 20 | cornsilk:'#FFF8DC', 21 | crimson:'#DC143C', 22 | cyan:'#00FFFF', 23 | darkblue:'#00008B', 24 | darkcyan:'#008B8B', 25 | darkgoldenrod:'#B8860B', 26 | darkgray:'#A9A9A9', 27 | darkgrey:'#A9A9A9', 28 | darkgreen:'#006400', 29 | darkkhaki:'#BDB76B', 30 | darkmagenta:'#8B008B', 31 | darkolivegreen:'#556B2F', 32 | darkorange:'#FF8C00', 33 | darkorchid:'#9932CC', 34 | darkred:'#8B0000', 35 | darksalmon:'#E9967A', 36 | darkseagreen:'#8FBC8F', 37 | darkslateblue:'#483D8B', 38 | darkslategray:'#2F4F4F', 39 | darkslategrey:'#2F4F4F', 40 | darkturquoise:'#00CED1', 41 | darkviolet:'#9400D3', 42 | deeppink:'#FF1493', 43 | deepskyblue:'#00BFFF', 44 | dimgray:'#696969', 45 | dimgrey:'#696969', 46 | dodgerblue:'#1E90FF', 47 | firebrick:'#B22222', 48 | floralwhite:'#FFFAF0', 49 | forestgreen:'#228B22', 50 | fuchsia:'#FF00FF', 51 | gainsboro:'#DCDCDC', 52 | ghostwhite:'#F8F8FF', 53 | gold:'#FFD700', 54 | goldenrod:'#DAA520', 55 | gray:'#808080', 56 | grey:'#808080', 57 | green:'#008000', 58 | greenyellow:'#ADFF2F', 59 | honeydew:'#F0FFF0', 60 | hotpink:'#FF69B4', 61 | indianred:'#CD5C5C', 62 | indigo:'#4B0082', 63 | ivory:'#FFFFF0', 64 | khaki:'#F0E68C', 65 | lavender:'#E6E6FA', 66 | lavenderblush:'#FFF0F5', 67 | lawngreen:'#7CFC00', 68 | lemonchiffon:'#FFFACD', 69 | lightblue:'#ADD8E6', 70 | lightcoral:'#F08080', 71 | lightcyan:'#E0FFFF', 72 | lightgoldenrodyellow:'#FAFAD2', 73 | lightgray:'#D3D3D3', 74 | lightgrey:'#D3D3D3', 75 | lightgreen:'#90EE90', 76 | lightpink:'#FFB6C1', 77 | lightsalmon:'#FFA07A', 78 | lightseagreen:'#20B2AA', 79 | lightskyblue:'#87CEFA', 80 | lightslategray:'#778899', 81 | lightslategrey:'#778899', 82 | lightsteelblue:'#B0C4DE', 83 | lightyellow:'#FFFFE0', 84 | lime:'#00FF00', 85 | limegreen:'#32CD32', 86 | linen:'#FAF0E6', 87 | magenta:'#FF00FF', 88 | maroon:'#800000', 89 | mediumaquamarine:'#66CDAA', 90 | mediumblue:'#0000CD', 91 | mediumorchid:'#BA55D3', 92 | mediumpurple:'#9370D8', 93 | mediumseagreen:'#3CB371', 94 | mediumslateblue:'#7B68EE', 95 | mediumspringgreen:'#00FA9A', 96 | mediumturquoise:'#48D1CC', 97 | mediumvioletred:'#C71585', 98 | midnightblue:'#191970', 99 | mintcream:'#F5FFFA', 100 | mistyrose:'#FFE4E1', 101 | moccasin:'#FFE4B5', 102 | navajowhite:'#FFDEAD', 103 | navy:'#000080', 104 | oldlace:'#FDF5E6', 105 | olive:'#808000', 106 | olivedrab:'#6B8E23', 107 | orange:'#FFA500', 108 | orangered:'#FF4500', 109 | orchid:'#DA70D6', 110 | palegoldenrod:'#EEE8AA', 111 | palegreen:'#98FB98', 112 | paleturquoise:'#AFEEEE', 113 | palevioletred:'#D87093', 114 | papayawhip:'#FFEFD5', 115 | peachpuff:'#FFDAB9', 116 | peru:'#CD853F', 117 | pink:'#FFC0CB', 118 | plum:'#DDA0DD', 119 | powderblue:'#B0E0E6', 120 | purple:'#800080', 121 | rebeccapurple:'#663399', 122 | red:'#FF0000', 123 | rosybrown:'#BC8F8F', 124 | royalblue:'#4169E1', 125 | saddlebrown:'#8B4513', 126 | salmon:'#FA8072', 127 | sandybrown:'#F4A460', 128 | seagreen:'#2E8B57', 129 | seashell:'#FFF5EE', 130 | sienna:'#A0522D', 131 | silver:'#C0C0C0', 132 | skyblue:'#87CEEB', 133 | slateblue:'#6A5ACD', 134 | slategray:'#708090', 135 | slategrey:'#708090', 136 | snow:'#FFFAFA', 137 | springgreen:'#00FF7F', 138 | steelblue:'#4682B4', 139 | tan:'#D2B48C', 140 | teal:'#008080', 141 | thistle:'#D8BFD8', 142 | tomato:'#FF6347', 143 | turquoise:'#40E0D0', 144 | violet:'#EE82EE', 145 | wheat:'#F5DEB3', 146 | white:'#FFFFFF', 147 | whitesmoke:'#F5F5F5', 148 | yellow:'#FFFF00', 149 | yellowgreen:'#9ACD32' 150 | }; 151 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const HCHARS = "0123456789ABCDEF" 2 | 3 | module.exports = { 4 | extend: function(destination, source) { 5 | for(let k in source) destination[k] = source[k]; 6 | return destination; 7 | }, 8 | 9 | /** 10 | * Converts 0-1 to 0-255 11 | * @method real2dec 12 | * @param n {float} the number to convert 13 | * @return {int} a number 0-255 14 | */ 15 | real2dec: function(n) { 16 | return Math.min(255, Math.round(n*256)); 17 | }, 18 | 19 | /** 20 | * Converts HSV (h[0-360], s[0-1]), v[0-1] to RGB [255,255,255] 21 | * @method hsv2rgb 22 | * @param h {int|[int, float, float]} the hue, or an 23 | * array containing all three parameters 24 | * @param s {float} the saturation 25 | * @param v {float} the value/brightness 26 | * @return {[int, int, int]} the red, green, blue values in 27 | * decimal. 28 | */ 29 | hsv2rgb: function(h, s, v) { 30 | 31 | var r, g, b, i, f, p, q, t; 32 | i = Math.floor((h/60)%6); 33 | f = (h/60)-i; 34 | p = v*(1-s); 35 | q = v*(1-f*s); 36 | t = v*(1-(1-f)*s); 37 | switch(i) { 38 | case 0: r=v; g=t; b=p; break; 39 | case 1: r=q; g=v; b=p; break; 40 | case 2: r=p; g=v; b=t; break; 41 | case 3: r=p; g=q; b=v; break; 42 | case 4: r=t; g=p; b=v; break; 43 | case 5: r=v; g=p; b=q; break; 44 | } 45 | 46 | var fn=this.real2dec; 47 | 48 | return [fn(r), fn(g), fn(b)]; 49 | }, 50 | 51 | /** 52 | * Converts to RGB [255,255,255] to HSV (h[0-360], s[0-1]), v[0-1] 53 | * @method rgb2hsv 54 | * @param r {int|[int, int, int]} the red value, or an 55 | * array containing all three parameters 56 | * @param g {int} the green value 57 | * @param b {int} the blue value 58 | * @return {[int, float, float]} the value converted to hsv 59 | */ 60 | rgb2hsv: function(r, g, b) { 61 | 62 | r=r/255; 63 | g=g/255; 64 | b=b/255; 65 | 66 | var min,max,delta,h,s,v; 67 | min = Math.min(Math.min(r,g),b); 68 | max = Math.max(Math.max(r,g),b); 69 | delta = max-min; 70 | 71 | switch (max) { 72 | case min: h=0; break; 73 | case r: h=60*(g-b)/delta; 74 | if (g FFFFFF 92 | * @method rgb2hex 93 | * @param r {int|[int, int, int]} the red value, or an 94 | * array containing all three parameters 95 | * @param g {int} the green value 96 | * @param b {int} the blue value 97 | * @return {string} the hex string 98 | */ 99 | rgb2hex: function(r, g, b) { 100 | var f=this.dec2hex; 101 | return f(r) + f(g) + f(b); 102 | }, 103 | 104 | /** 105 | * Converts an int 0...255 to hex pair 00...FF 106 | * @method dec2hex 107 | * @param n {int} the number to convert 108 | * @return {string} the hex equivalent 109 | */ 110 | dec2hex: function(n) { 111 | n = parseInt(n, 10); 112 | n = (typeof n === 'number') ? n : 0; 113 | n = (n > 255 || n < 0) ? 0 : n; 114 | 115 | return HCHARS.charAt((n - n % 16) / 16) + HCHARS.charAt(n % 16); 116 | }, 117 | 118 | /** 119 | * Converts a hex pair 00...FF to an int 0...255 120 | * @method hex2dec 121 | * @param str {string} the hex pair to convert 122 | * @return {int} the decimal 123 | */ 124 | hex2dec: function(str) { 125 | var f = function(c) { 126 | return HCHARS.indexOf(c.toUpperCase()); 127 | }; 128 | 129 | var s=str.split(''); 130 | 131 | return ((f(s[0]) * 16) + f(s[1])); 132 | }, 133 | 134 | /** 135 | * Converts a hex string to rgb 136 | * @method hex2rgb 137 | * @param str {string} the hex string 138 | * @return {[int, int, int]} an array containing the rgb values 139 | */ 140 | hex2rgb: function(s) { 141 | var f = this.hex2dec; 142 | return [f(s.substr(0, 2)), f(s.substr(2, 2)), f(s.substr(4, 2))]; 143 | } 144 | }; 145 | -------------------------------------------------------------------------------- /src/Matrix4.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | * @author supereggbert / http://www.paulbrunt.co.uk/ 4 | * @author philogb / http://blog.thejit.org/ 5 | * @author jordi_ros / http://plattsoft.com 6 | * @author D1plo1d / http://github.com/D1plo1d 7 | * @author alteredq / http://alteredqualia.com/ 8 | * @author mikael emtinger / http://gomo.se/ 9 | * @author timknip / http://www.floorplanner.com/ 10 | * @author bhouston / http://exocortex.com 11 | */ 12 | 13 | module.exports = class Matrix4 { 14 | 15 | constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 16 | const te = this.elements = new Float32Array( 16 ); 17 | 18 | // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix 19 | // we should not support semi specification of Matrix4, it is just weird. 20 | 21 | te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; 22 | te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; 23 | te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; 24 | te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; 25 | } 26 | 27 | set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 28 | 29 | const te = this.elements; 30 | 31 | te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; 32 | te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; 33 | te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; 34 | te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; 35 | 36 | return this; 37 | 38 | } 39 | 40 | identity() { 41 | 42 | this.set( 43 | 44 | 1, 0, 0, 0, 45 | 0, 1, 0, 0, 46 | 0, 0, 1, 0, 47 | 0, 0, 0, 1 48 | 49 | ); 50 | 51 | return this; 52 | 53 | } 54 | 55 | multiplyMatrices( a, b ) { 56 | var ae = a.elements; 57 | var be = b.elements; 58 | var te = this.elements; 59 | 60 | var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; 61 | var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; 62 | var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; 63 | var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; 64 | 65 | var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; 66 | var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; 67 | var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; 68 | var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; 69 | 70 | te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; 71 | te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; 72 | te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; 73 | te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; 74 | 75 | te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; 76 | te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; 77 | te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; 78 | te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; 79 | 80 | te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; 81 | te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; 82 | te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; 83 | te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; 84 | 85 | te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; 86 | te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; 87 | te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; 88 | te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; 89 | 90 | return this; 91 | 92 | } 93 | 94 | translate( v ) { 95 | 96 | const te = this.elements; 97 | const x = v.x, y = v.y, z = v.z; 98 | 99 | te[12] = te[0] * x + te[4] * y + te[8] * z + te[12]; 100 | te[13] = te[1] * x + te[5] * y + te[9] * z + te[13]; 101 | te[14] = te[2] * x + te[6] * y + te[10] * z + te[14]; 102 | te[15] = te[3] * x + te[7] * y + te[11] * z + te[15]; 103 | 104 | return this; 105 | 106 | } 107 | 108 | rotateX( angle ) { 109 | 110 | const te = this.elements; 111 | const m12 = te[4]; 112 | const m22 = te[5]; 113 | const m32 = te[6]; 114 | const m42 = te[7]; 115 | const m13 = te[8]; 116 | const m23 = te[9]; 117 | const m33 = te[10]; 118 | const m43 = te[11]; 119 | const c = Math.cos( angle ); 120 | const s = Math.sin( angle ); 121 | 122 | te[4] = c * m12 + s * m13; 123 | te[5] = c * m22 + s * m23; 124 | te[6] = c * m32 + s * m33; 125 | te[7] = c * m42 + s * m43; 126 | 127 | te[8] = c * m13 - s * m12; 128 | te[9] = c * m23 - s * m22; 129 | te[10] = c * m33 - s * m32; 130 | te[11] = c * m43 - s * m42; 131 | 132 | return this; 133 | 134 | } 135 | 136 | rotateY( angle ) { 137 | 138 | const te = this.elements; 139 | const m11 = te[0]; 140 | const m21 = te[1]; 141 | const m31 = te[2]; 142 | const m41 = te[3]; 143 | const m13 = te[8]; 144 | const m23 = te[9]; 145 | const m33 = te[10]; 146 | const m43 = te[11]; 147 | const c = Math.cos( angle ); 148 | const s = Math.sin( angle ); 149 | 150 | te[0] = c * m11 - s * m13; 151 | te[1] = c * m21 - s * m23; 152 | te[2] = c * m31 - s * m33; 153 | te[3] = c * m41 - s * m43; 154 | 155 | te[8] = c * m13 + s * m11; 156 | te[9] = c * m23 + s * m21; 157 | te[10] = c * m33 + s * m31; 158 | te[11] = c * m43 + s * m41; 159 | 160 | return this; 161 | 162 | } 163 | 164 | rotateZ( angle ) { 165 | 166 | const te = this.elements; 167 | const m11 = te[0]; 168 | const m21 = te[1]; 169 | const m31 = te[2]; 170 | const m41 = te[3]; 171 | const m12 = te[4]; 172 | const m22 = te[5]; 173 | const m32 = te[6]; 174 | const m42 = te[7]; 175 | const c = Math.cos( angle ); 176 | const s = Math.sin( angle ); 177 | 178 | te[0] = c * m11 + s * m12; 179 | te[1] = c * m21 + s * m22; 180 | te[2] = c * m31 + s * m32; 181 | te[3] = c * m41 + s * m42; 182 | 183 | te[4] = c * m12 - s * m11; 184 | te[5] = c * m22 - s * m21; 185 | te[6] = c * m32 - s * m31; 186 | te[7] = c * m42 - s * m41; 187 | 188 | return this; 189 | 190 | } 191 | 192 | scale( v ) { 193 | 194 | const te = this.elements; 195 | const x = v.x, y = v.y, z = v.z; 196 | 197 | te[0] *= x; te[4] *= y; te[8] *= z; 198 | te[1] *= x; te[5] *= y; te[9] *= z; 199 | te[2] *= x; te[6] *= y; te[10] *= z; 200 | te[3] *= x; te[7] *= y; te[11] *= z; 201 | 202 | return this; 203 | 204 | } 205 | 206 | clone() { 207 | 208 | const te = this.elements; 209 | 210 | return new Matrix4( 211 | 212 | te[0], te[4], te[8], te[12], 213 | te[1], te[5], te[9], te[13], 214 | te[2], te[6], te[10], te[14], 215 | te[3], te[7], te[11], te[15] 216 | 217 | ); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /test/interpreter_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const shouldBeGoodInterpreter = require('./behavior/should_be_good_interpreter'); 6 | const { assert } = require('chai'); 7 | const parser = require('../src/parser'); 8 | const Interpreter = require('../src/Interpreter'); 9 | const utils = require('../src/utils'); 10 | 11 | function readdir(dir) { 12 | return fs.readdirSync(dir).map(filename => path.join(dir, filename)); 13 | } 14 | 15 | /** 16 | * TODO: more matrix tests 17 | * TODO: more color translation tests. blend 18 | */ 19 | describe('Interpreter', function() { 20 | describe.skip('default', function() { 21 | const tests = [ 22 | 23 | ]; 24 | tests.forEach(shouldBeGoodInterpreter); 25 | }); 26 | 27 | describe('comments', function() { 28 | const tests = readdir('test/testset/comments'); 29 | tests.forEach(shouldBeGoodInterpreter); 30 | }); 31 | 32 | describe('primitives', function() { 33 | const tests = readdir('test/testset/primitives'); 34 | tests.forEach(shouldBeGoodInterpreter); 35 | }); 36 | 37 | describe('modifiers', function() { 38 | describe('md / maxdepth [integer]', function() { 39 | const tests = readdir('test/testset/modifiers/maxdepth'); 40 | tests.forEach(shouldBeGoodInterpreter); 41 | }); 42 | 43 | describe('weight', function() { 44 | const tests = readdir('test/testset/modifiers/weight'); 45 | tests.forEach(shouldBeGoodInterpreter); 46 | }); 47 | }); 48 | 49 | describe('actions', function() { 50 | describe('set background [color]', function() { 51 | const tests = readdir('test/testset/actions/background'); 52 | tests.forEach(shouldBeGoodInterpreter); 53 | 54 | // disable to use random as background color 55 | const source = 'set background random'; 56 | const ast = parser.parse(source); 57 | const interpreter = new Interpreter(); 58 | assert.throws(() => interpreter.generate(ast)); 59 | }); 60 | 61 | describe('set seed [integer] / initial', function() { 62 | const tests = readdir('test/testset/actions/seed'); 63 | tests.forEach(shouldBeGoodInterpreter); 64 | 65 | // The color is different every time if initial is set. 66 | const source = 'set seed initial\n10 * { x 1 color random } box'; 67 | const ast = parser.parse(source); 68 | const interpreter = new Interpreter(); 69 | const object = interpreter.generate(ast); 70 | assert.isFalse(JSON.stringify(interpreter.generate(ast)) === JSON.stringify(interpreter.generate(ast))); 71 | }); 72 | 73 | describe('set maxobjects [integer]', function() { 74 | const tests = readdir('test/testset/actions/maxobjects'); 75 | tests.forEach(shouldBeGoodInterpreter); 76 | }); 77 | 78 | describe('set maxdepth [integer]', function() { 79 | const tests = readdir('test/testset/actions/maxdepth'); 80 | tests.forEach(shouldBeGoodInterpreter); 81 | }); 82 | 83 | // TODO: not implemented yet 84 | describe('set minsize [float]', function() { 85 | // it('set minsize 10.1', function() { 86 | // const source = 'set minsize 10.1'; 87 | // }); 88 | }); 89 | 90 | // TODO: not implemented yet 91 | describe('set maxsize [float]', function() { 92 | // it('set maxsize 10.1', function() { 93 | // const source = 'set maxsize 10.1'; 94 | // }); 95 | }); 96 | }); 97 | 98 | // NOTE: If you want to express same color transformation in three.js, use basic material type. 99 | describe('colorspace', function() { 100 | const tests = readdir('test/testset/colorspace'); 101 | tests.forEach(shouldBeGoodInterpreter); 102 | }); 103 | 104 | describe('geometrical transformations', function() { 105 | const tests = readdir('test/testset/geometric'); 106 | tests.forEach(shouldBeGoodInterpreter); 107 | }); 108 | 109 | describe('preprocessor commands', function() { 110 | describe('define', function() { 111 | it('#define varname 10', function() { 112 | const source = '#define varname 10\n{ x varname } box'; 113 | const ast = parser.parse(source); 114 | const interpreter = new Interpreter(); 115 | const object = interpreter.generate(ast); 116 | const expected = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 0, 0, 1]; 117 | assert.deepEqual(expected, Array.from(object.objects[0].matrix.elements)) 118 | }); 119 | }); 120 | }); 121 | 122 | // NOTE: not implement yet 123 | describe('colorpool', function() { 124 | it('{ set colorpool randomhue', function() { 125 | const source = 'set colorpool randomhue\n100 * { color random } box'; 126 | const ast = parser.parse(source); 127 | const interpreter = new Interpreter(); 128 | const object = interpreter.generate(ast); 129 | for (let i = 0; i < 100; i++) { 130 | const color = object.objects[i].color; 131 | const hex = color.substring(1, 7); 132 | const rgb = utils.hex2rgb(hex); 133 | const hsv = utils.rgb2hsv(rgb[0], rgb[1], rgb[2]); 134 | assert.ok(hsv[0] >= 0 && hsv[0] <= 360); 135 | assert.equal(hsv[1], 1); 136 | assert.equal(hsv[2], 1); 137 | } 138 | }); 139 | 140 | it('{ set colorpool randomrgb', function() { 141 | const source = 'set colorpool randomrgb\n100 * { color random } box'; 142 | const ast = parser.parse(source); 143 | const interpreter = new Interpreter(); 144 | const object = interpreter.generate(ast); 145 | for (let i = 0; i < 100; i++) { 146 | const color = object.objects[i].color; 147 | const hex = color.substring(1, 7); 148 | const rgb = utils.hex2rgb(hex); 149 | assert.ok(rgb[0] >= 0 && rgb[0] <= 360); 150 | assert.ok(rgb[1] >= 0 && rgb[1] <= 360); 151 | assert.ok(rgb[2] >= 0 && rgb[2] <= 360); 152 | } 153 | }); 154 | 155 | it('{ set colorpool greyscale', function() { 156 | const source = 'set colorpool greyscale\n100 * { color random } box'; 157 | const ast = parser.parse(source); 158 | const interpreter = new Interpreter(); 159 | const object = interpreter.generate(ast); 160 | for (let i = 0; i < 100; i++) { 161 | const color = object.objects[i].color; 162 | const r = color.substring(1, 3); 163 | assert.equal(color, `#${r}${r}${r}`); 164 | } 165 | }); 166 | // 167 | // it('{ set colorpool image:filename.png', function() { 168 | // const source = 'set colorpool image:filename.png'; 169 | // }); 170 | // 171 | it('{ set colorpool list:orange,white,grey', function() { 172 | const source = 'set colorpool list:orange,white,grey\n100 * { color random } box'; 173 | const ast = parser.parse(source); 174 | const interpreter = new Interpreter(); 175 | const object = interpreter.generate(ast); 176 | for (let i = 0; i < 100; i++) { 177 | assert.ok(['#808080', '#FFFFFF', '#FFA500'].includes(object.objects[i].color)); 178 | } 179 | }); 180 | }); 181 | }); 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/mt.js: -------------------------------------------------------------------------------- 1 | // mt.js 0.2.4 (2005-12-23) 2 | 3 | /* 4 | 5 | Mersenne Twister in JavaScript based on "mt19937ar.c" 6 | 7 | * JavaScript version by Magicant: Copyright (C) 2005 Magicant 8 | 9 | 10 | * Original C version by Makoto Matsumoto and Takuji Nishimura 11 | http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html 12 | 13 | Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions 18 | are met: 19 | 20 | 1. Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | 23 | 2. Redistributions in binary form must reproduce the above copyright 24 | notice, this list of conditions and the following disclaimer in the 25 | documentation and/or other materials provided with the distribution. 26 | 27 | 3. The names of its contributors may not be used to endorse or promote 28 | products derived from this software without specific prior written 29 | permission. 30 | 31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 35 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 36 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 37 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 38 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | 43 | */ 44 | 45 | 46 | // Methods whose name starts with "_" are private methods. 47 | // Don't call them externally! 48 | 49 | 50 | /** 51 | * Constructor: MersenneTwister([integer/Array seed]) 52 | * initializes the object with the given seed. 53 | * The seed may be an integer or an array of integers. 54 | * If the seed is not given, the object will be initialized with the current 55 | * time: new Date().getTime(). 56 | * See also: setSeed(seed). 57 | */ 58 | function MersenneTwister(seed) { 59 | if (arguments.length == 0) 60 | seed = new Date().getTime(); 61 | 62 | this._mt = new Array(624); 63 | this.setSeed(seed); 64 | } 65 | 66 | /** multiplies two uint32 values and returns a uint32 result. */ 67 | MersenneTwister._mulUint32 = function(a, b) { 68 | var a1 = a >>> 16, a2 = a & 0xffff; 69 | var b1 = b >>> 16, b2 = b & 0xffff; 70 | return (((a1 * b2 + a2 * b1) << 16) + a2 * b2) >>> 0; 71 | }; 72 | 73 | /** returns ceil(value) if value is finite number, otherwise 0. */ 74 | MersenneTwister._toNumber = function(x) { 75 | return (typeof x == "number" && !isNaN(x)) ? Math.ceil(x) : 0; 76 | }; 77 | 78 | /** 79 | * Method: setSeed(integer/Array seed) 80 | * resets the seed. The seed may be an integer or an array of integers. 81 | * Elements in the seed array that are not numbers will be treated as 0. 82 | * Numbers that are not integers will be rounded down. 83 | * The integer(s) should be greater than or equal to 0 and less than 2^32. 84 | * This method is compatible with init_genrand and init_by_array function of 85 | * the original C version. 86 | */ 87 | MersenneTwister.prototype.setSeed = function(seed) { 88 | var mt = this._mt; 89 | if (typeof seed == "number") { 90 | mt[0] = seed >>> 0; 91 | for (var i = 1; i < mt.length; i++) { 92 | var x = mt[i-1] ^ (mt[i-1] >>> 30); 93 | mt[i] = MersenneTwister._mulUint32(1812433253, x) + i; 94 | } 95 | this._index = mt.length; 96 | } else if (seed instanceof Array) { 97 | var i = 1, j = 0; 98 | this.setSeed(19650218); 99 | for (var k = Math.max(mt.length, seed.length); k > 0; k--) { 100 | var x = mt[i-1] ^ (mt[i-1] >>> 30); 101 | x = MersenneTwister._mulUint32(x, 1664525); 102 | mt[i] = (mt[i] ^ x) + (seed[j] >>> 0) + j; 103 | if (++i >= mt.length) { 104 | mt[0] = mt[mt.length-1]; 105 | i = 1; 106 | } 107 | if (++j >= seed.length) { 108 | j = 0; 109 | } 110 | } 111 | for (var k = mt.length - 1; k > 0; k--) { 112 | var x = mt[i-1] ^ (mt[i-1] >>> 30); 113 | x = MersenneTwister._mulUint32(x, 1566083941); 114 | mt[i] = (mt[i] ^ x) - i; 115 | if (++i >= mt.length) { 116 | mt[0] = mt[mt.length-1]; 117 | i = 1; 118 | } 119 | } 120 | mt[0] = 0x80000000; 121 | } else { 122 | throw new TypeError("MersenneTwister: illegal seed."); 123 | } 124 | }; 125 | 126 | /** returns the next random Uint32 value. */ 127 | MersenneTwister.prototype._nextInt = function() { 128 | var mt = this._mt, value; 129 | 130 | if (this._index >= mt.length) { 131 | var k = 0, N = mt.length, M = 397; 132 | do { 133 | value = (mt[k] & 0x80000000) | (mt[k+1] & 0x7fffffff); 134 | mt[k] = mt[k+M] ^ (value >>> 1) ^ ((value & 1) ? 0x9908b0df : 0); 135 | } while (++k < N-M); 136 | do { 137 | value = (mt[k] & 0x80000000) | (mt[k+1] & 0x7fffffff); 138 | mt[k] = mt[k+M-N] ^ (value >>> 1) ^ ((value & 1) ? 0x9908b0df : 0); 139 | } while (++k < N-1); 140 | value = (mt[N-1] & 0x80000000) | (mt[0] & 0x7fffffff); 141 | mt[N-1] = mt[M-1] ^ (value >>> 1) ^ ((value & 1) ? 0x9908b0df : 0); 142 | this._index = 0; 143 | } 144 | 145 | value = mt[this._index++]; 146 | value ^= value >>> 11; 147 | value ^= (value << 7) & 0x9d2c5680; 148 | value ^= (value << 15) & 0xefc60000; 149 | value ^= value >>> 18; 150 | return value >>> 0; 151 | }; 152 | 153 | /** 154 | * Method: nextInt([[number min,] number max]) 155 | * returns a random integer that is greater than or equal to min and less than 156 | * max. The value of (max - min) must be positive number less or equal to 2^32. 157 | * If min is not given or not a number, this method uses 0 for min. 158 | * If neither of min and max is given or max is out of range, this method 159 | * uses 2^32 for max. 160 | * This method is compatible with genrand_int32 function of the original C 161 | * version for min=0 & max=2^32, but not with genrand_int31 function. 162 | */ 163 | MersenneTwister.prototype.nextInt = function() { 164 | var min, sup; 165 | switch (arguments.length) { 166 | case 0: 167 | return this._nextInt(); 168 | case 1: 169 | min = 0; 170 | sup = MersenneTwister._toNumber(arguments[0]); 171 | break; 172 | default: 173 | min = MersenneTwister._toNumber(arguments[0]); 174 | sup = MersenneTwister._toNumber(arguments[1]) - min; 175 | break; 176 | } 177 | 178 | if (!(0 < sup && sup < 0x100000000)) 179 | return this._nextInt() + min; 180 | if ((sup & (~sup + 1)) == sup) 181 | return ((sup - 1) & this._nextInt()) + min; 182 | 183 | var value; 184 | do { 185 | value = this._nextInt(); 186 | } while (sup > 4294967296 - (value - (value %= sup))); 187 | return value + min; 188 | }; 189 | 190 | /** 191 | * Method: next() 192 | * returns a random number that is greater than or equal to 0 and less than 1. 193 | * This method is compatible with genrand_res53 function of the original C 194 | * version. 195 | */ 196 | MersenneTwister.prototype.next = function() { 197 | var a = this._nextInt() >>> 5, b = this._nextInt() >>> 6; 198 | return (a * 0x4000000 + b) / 0x20000000000000; 199 | }; 200 | 201 | if (module) { 202 | module.exports = MersenneTwister; 203 | } 204 | -------------------------------------------------------------------------------- /examples/js/render.js: -------------------------------------------------------------------------------- 1 | var scene, camera, renderer, group; 2 | 3 | function toDataURL(format) { 4 | if (renderer) { 5 | const dom = renderer.domElement; 6 | switch (format) { 7 | case 'jpg': 8 | case 'jpeg': return dom.toDataURL("image/jpeg"); 9 | case 'gif': return dom.toDataURL("image/gif"); 10 | default: return dom.toDataURL("image/png"); 11 | } 12 | } 13 | } 14 | 15 | function save(format) { 16 | window.open(toDataURL(format)); 17 | } 18 | 19 | function render() { 20 | requestAnimationFrame( render ); 21 | 22 | group.rotation.x += 0.005; 23 | group.rotation.y += 0.005; 24 | 25 | renderer.render( scene, camera ); 26 | }; 27 | 28 | function createGeometry(type) { 29 | switch (type) { 30 | case 'box': return new THREE.BoxBufferGeometry(1, 1, 1); 31 | // TODO https://threejs.org/docs/#api/en/geometries/WireframeGeometry 32 | case 'grid': return new THREE.BoxBufferGeometry(1, 1, 1); 33 | case 'sphere': return new THREE.SphereBufferGeometry(.5, 32, 32); 34 | case 'line': 35 | var points = []; 36 | points.push( new THREE.Vector3(-.5, 0, 0 )); 37 | points.push( new THREE.Vector3( .5, 0, 0 )); 38 | return new THREE.BufferGeometry().setFromPoints(points); 39 | case 'point': 40 | console.warn("point is not implemented yet"); return; 41 | case 'mesh': console.warn("mesh is not implemented yet"); return; 42 | case 'cylinder': return new THREE.CylinderBufferGeometry(.5, .5, 1, 32); 43 | case 'tube': console.warn("tube is not implemented yet"); return; 44 | case 'triangle': 45 | var geometry = new THREE.BufferGeometry(); 46 | // default position if not specified 47 | var vertices = new Float32Array( [ 48 | 0.0, .5, 0.0, 49 | -.5, -.5, 0.0, 50 | .5, -.5, 0.0 51 | ] ); 52 | geometry.setAttribute( 'position', new THREE.BufferAttribute(vertices, 3)); 53 | return geometry; 54 | case 'squash': 55 | var geometry = new THREE.SphereBufferGeometry(.5, 32, 32); 56 | geometry.scale(1, .5, 1); 57 | return geometry; 58 | } 59 | } 60 | 61 | function applyVertexColors(geometry, color) { 62 | var position = geometry.attributes.position; 63 | var colors = []; 64 | 65 | for ( var i = 0; i < position.count; i ++ ) { 66 | colors.push(color.r, color.g, color.b, -100); 67 | } 68 | 69 | geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 4)); 70 | } 71 | 72 | function init(objectCode) { 73 | 74 | /////////////////////////////// 75 | // SCENE 76 | /////////////////////////////// 77 | scene = new THREE.Scene(); 78 | scene.background = new THREE.Color(0x444444); 79 | 80 | 81 | /////////////////////////////// 82 | // CAMERA 83 | /////////////////////////////// 84 | camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 100000); 85 | camera.position.z = 10; 86 | 87 | 88 | /////////////////////////////// 89 | // RENDERER 90 | /////////////////////////////// 91 | renderer = new THREE.WebGLRenderer({ antialias: true }); 92 | renderer.setPixelRatio(window.devicePixelRatio); 93 | renderer.setSize(window.innerWidth, window.innerHeight); 94 | document.body.appendChild(renderer.domElement); 95 | 96 | 97 | /////////////////////////////// 98 | // CONTROLLER 99 | /////////////////////////////// 100 | var orbit = new THREE.OrbitControls(camera, renderer.domElement); 101 | 102 | 103 | /////////////////////////////// 104 | // LIGHT 105 | /////////////////////////////// 106 | var lights = []; 107 | lights[0] = new THREE.PointLight(0xffffff, 1, 0); 108 | lights[1] = new THREE.PointLight(0xffffff, 1, 0); 109 | lights[2] = new THREE.PointLight(0xffffff, 1, 0); 110 | 111 | lights[0].position.set(0, 200, 0); 112 | lights[1].position.set(100, 200, 100); 113 | lights[2].position.set(- 100, - 200, - 100); 114 | 115 | scene.add(lights[0]); 116 | scene.add(lights[1]); 117 | scene.add(lights[2]); 118 | 119 | var light = new THREE.SpotLight( 0xffffff, .5 ); 120 | light.position.set(0, 500, 2000); 121 | // scene.add( light ); 122 | 123 | /////////////////////////////// 124 | // PRIMITIVE 125 | /////////////////////////////// 126 | group = new THREE.Group(); 127 | scene.add(group); 128 | 129 | let transparent = false; 130 | for (let i = 0; i < objectCode.objects.length; i++) { 131 | let object = objectCode.objects[i] 132 | if (object.type === 'primitive') { 133 | if (object.opacity !== 1) { 134 | console.warn(`If you don't use transparency (alpha parameter), performance will be improved extremely.`); 135 | transparent = true; 136 | break; 137 | } 138 | } 139 | } 140 | 141 | var geometries = []; 142 | var count = 0; 143 | objectCode.objects.reverse().forEach(function(object) { 144 | switch (object.type) { 145 | case 'background': 146 | scene.background = new THREE.Color(object.color); 147 | break; 148 | case 'primitive': 149 | const geometry = createGeometry(object.name); 150 | 151 | // Used in the case of triangle primitive for now 152 | if (object.coords) { 153 | var c = object.coords; 154 | var vertices = new Float32Array([ 155 | c[0][0], c[0][1], c[0][2], 156 | c[1][0], c[1][1], c[1][2], 157 | c[2][0], c[2][1], c[2][2], 158 | ]); 159 | geometry.setAttribute( 'position', new THREE.BufferAttribute(vertices, 3)); 160 | } 161 | 162 | const matrix = new THREE.Matrix4(); 163 | matrix.fromArray(object.matrix.elements) 164 | geometry.applyMatrix(matrix); 165 | 166 | if (transparent) { 167 | var meshMaterial = new THREE.MeshPhongMaterial({ 168 | color: parseInt(object.color.replace(/^#/, '0x'), 16), 169 | specular: 0x999999, 170 | shininess: 30, 171 | flatShading: true, 172 | shininess: 0, 173 | opacity: object.opacity, 174 | transparent: true 175 | }); 176 | 177 | if (object.name === 'grid') { 178 | meshMaterial.wireframe = true; 179 | } 180 | 181 | if (object.name === 'triangle') { 182 | meshMaterial.side = THREE.DoubleSide; 183 | } 184 | 185 | if (object.name === 'line') { 186 | group.add(new THREE.Line( geometry, meshMaterial )); 187 | } else { 188 | group.add(new THREE.Mesh(geometry, meshMaterial)); 189 | } 190 | 191 | } else { 192 | // if not transparency, use this for performance 193 | // change hex color format to 0xFF7733 from #FF7733 194 | const color = new THREE.Color(); 195 | applyVertexColors(geometry, color.setHex(object.color.replace(/^#/, '0x'))); 196 | geometries.push(geometry); 197 | } 198 | 199 | count++; 200 | break; 201 | } 202 | }); 203 | 204 | // if not transparency, use this for performance 205 | if (!transparent) { 206 | var defaultMaterial = new THREE.MeshPhongMaterial({ 207 | color: 0xffffff, 208 | flatShading: true, 209 | vertexColors: true, 210 | emissive: 0x072534, 211 | transparent: true, 212 | opacity: 1, 213 | wireframe: true, 214 | side: THREE.DoubleSide 215 | }); 216 | group.add(new THREE.Mesh(THREE.BufferGeometryUtils.mergeBufferGeometries(geometries), defaultMaterial)); 217 | } 218 | 219 | console.log(`Build done. Created ${count} objects.`); 220 | } 221 | 222 | 223 | 224 | window.addEventListener('resize', function() { 225 | 226 | camera.aspect = window.innerWidth / window.innerHeight; 227 | camera.updateProjectionMatrix(); 228 | renderer.setSize(window.innerWidth, window.innerHeight); 229 | 230 | }, false); 231 | -------------------------------------------------------------------------------- /examples/css/main.css: -------------------------------------------------------------------------------- 1 | :root { 2 | color-scheme: light dark; 3 | 4 | --background-color: #fff; 5 | 6 | --color-blue: #049EF4; 7 | --text-color: #444; 8 | --secondary-text-color: #9e9e9e; 9 | 10 | --font-size: 16px; 11 | --line-height: 26px; 12 | 13 | --border-style: 1px solid #E8E8E8; 14 | --header-height: 48px; 15 | --panel-width: 300px; 16 | --panel-padding: 16px; 17 | --icon-size: 20px; 18 | } 19 | 20 | @media (prefers-color-scheme: dark) { 21 | 22 | :root { 23 | --background-color: #222; 24 | 25 | --text-color: #bbb; 26 | --secondary-text-color: #666; 27 | 28 | --border-style: 1px solid #444; 29 | } 30 | 31 | } 32 | 33 | @font-face { 34 | font-family: 'Roboto Mono'; 35 | src: local('Roboto Mono'), local('RobotoMono-Regular'), url('../files/RobotoMono-Regular.woff2') format('woff2'); 36 | font-style: normal; 37 | font-weight: 400; 38 | } 39 | 40 | @font-face { 41 | font-family: 'Roboto Mono'; 42 | src: local('Roboto Mono Medium'), local('RobotoMono-Medium'), url('../files/RobotoMono-Medium.woff2') format('woff2'); 43 | font-style: normal; 44 | font-weight: 500; 45 | } 46 | 47 | * { 48 | box-sizing: border-box; 49 | -webkit-font-smoothing: antialiased; 50 | -moz-osx-font-smoothing: grayscale; 51 | } 52 | 53 | html, body { 54 | height: 100%; 55 | } 56 | 57 | html { 58 | font-size: calc(var(--font-size) - 1px); 59 | line-height: calc(var(--line-height) - 1px); 60 | } 61 | 62 | body { 63 | font-family: 'Roboto Mono', monospace; 64 | margin: 0px; 65 | color: var(--text-color); 66 | background-color: var(--background-color); 67 | } 68 | 69 | a { 70 | text-decoration: none; 71 | } 72 | 73 | h1 { 74 | font-size: 18px; 75 | line-height: 24px; 76 | font-weight: 500; 77 | } 78 | 79 | h2 { 80 | padding: 0; 81 | margin: 16px 0; 82 | font-size: calc(var(--font-size) - 1px); 83 | line-height: var(--line-height); 84 | font-weight: 500; 85 | color: var(--color-blue); 86 | } 87 | 88 | h3 { 89 | margin: 0; 90 | font-weight: 500; 91 | font-size: calc(var(--font-size) - 1px); 92 | line-height: var(--line-height); 93 | color: var(--secondary-text-color); 94 | } 95 | 96 | h1 a { 97 | color: var(--color-blue); 98 | } 99 | 100 | #header { 101 | display: flex; 102 | height: var(--header-height); 103 | border-bottom: var(--border-style); 104 | align-items: center; 105 | } 106 | #header h1 { 107 | padding-left: var(--panel-padding); 108 | flex: 1; 109 | display: flex; 110 | align-items: center; 111 | color: var(--color-blue); 112 | } 113 | #header #version { 114 | border: 1px solid var(--color-blue); 115 | color: var(--color-blue); 116 | border-radius: 4px; 117 | line-height: 16px; 118 | padding: 0px 2px; 119 | margin-left: 6px; 120 | font-size: .9rem; 121 | } 122 | 123 | #panel { 124 | position: fixed; 125 | z-index: 100; 126 | left: 0px; 127 | width: var(--panel-width); 128 | height: 100%; 129 | overflow: auto; 130 | border-right: var(--border-style); 131 | display: flex; 132 | flex-direction: column; 133 | transition: 0s 0s height; 134 | } 135 | 136 | #panel #exitSearchButton { 137 | width: 48px; 138 | height: 48px; 139 | display: none; 140 | background-color: var(--text-color); 141 | background-size: var(--icon-size); 142 | -webkit-mask-image: url(../files/ic_close_black_24dp.svg); 143 | -webkit-mask-position: 50% 50%; 144 | -webkit-mask-repeat: no-repeat; 145 | mask-image: url(../files/ic_close_black_24dp.svg); 146 | mask-position: 50% 50%; 147 | mask-repeat: no-repeat; 148 | cursor: pointer; 149 | margin-right: 0px; 150 | } 151 | 152 | #panel.searchFocused #exitSearchButton { 153 | display: block; 154 | } 155 | 156 | #panel.searchFocused #language { 157 | display: none; 158 | } 159 | 160 | #panel.searchFocused #filter { 161 | -webkit-mask-image: none; 162 | mask-image: none; 163 | background-color: inherit; 164 | padding-left: 0; 165 | } 166 | 167 | #panel #expandButton { 168 | width: 48px; 169 | height: 48px; 170 | margin-right: 4px; 171 | margin-left: 4px; 172 | display: none; 173 | cursor: pointer; 174 | background-color: var(--text-color); 175 | background-size: var(--icon-size); 176 | -webkit-mask-image: url(../files/ic_menu_black_24dp.svg); 177 | -webkit-mask-position: 50% 50%; 178 | -webkit-mask-repeat: no-repeat; 179 | mask-image: url(../files/ic_menu_black_24dp.svg); 180 | mask-position: 50% 50%; 181 | mask-repeat: no-repeat; 182 | } 183 | 184 | #panel #sections { 185 | display: flex; 186 | justify-content: center; 187 | z-index: 1000; 188 | position: relative; 189 | height: 100%; 190 | align-items: center; 191 | font-weight: 500; 192 | } 193 | 194 | #panel #sections * { 195 | padding: 0 var(--panel-padding); 196 | height: 100%; 197 | position: relative; 198 | display: flex; 199 | justify-content: center; 200 | align-items: center; 201 | } 202 | #panel #sections .selected:after { 203 | content: ""; 204 | position: absolute; 205 | left: 0; 206 | right: 0; 207 | bottom: -1px; 208 | border-bottom: 1px solid var(--text-color); 209 | } 210 | #panel #sections a { 211 | color: var(--secondary-text-color); 212 | } 213 | 214 | body.home #panel #sections { 215 | display: none; 216 | } 217 | 218 | #panel #inputWrapper { 219 | display: flex; 220 | align-items: center; 221 | height: var(--header-height); 222 | padding: 0 0 0 var(--panel-padding); 223 | position: relative; 224 | background: var(--background-color); 225 | } 226 | #panel #inputWrapper:after { 227 | position: absolute; 228 | left: 0; 229 | right: 0; 230 | bottom: 0; 231 | border-bottom: var(--border-style); 232 | content: ""; 233 | } 234 | 235 | #panel #filter { 236 | flex: 1; 237 | width: 100%; 238 | padding: 0 36px; 239 | font-size: 1rem; 240 | font-weight: 500; 241 | color: var(--text-color); 242 | outline: none; 243 | border: 0px; 244 | background-color: var(--text-color); 245 | background-size: var(--icon-size); 246 | -webkit-mask-image: url(../files/ic_search_black_24dp.svg); 247 | -webkit-mask-position: 0 50%; 248 | -webkit-mask-repeat: no-repeat; 249 | mask-image: url(../files/ic_search_black_24dp.svg); 250 | mask-position: 0 50%; 251 | mask-repeat: no-repeat; 252 | font-family: 'Roboto Mono', monospace; 253 | } 254 | 255 | #panel #language { 256 | font-family: 'Roboto Mono', monospace; 257 | font-size: 1rem; 258 | line-height: 1rem; 259 | font-weight: 500; 260 | color: var(--text-color); 261 | border: 0px; 262 | background-image: url(ic_arrow_drop_down_black_24dp.svg); 263 | background-size: var(--icon-size); 264 | background-repeat: no-repeat; 265 | background-position: right center; 266 | background-color: var(--background-color); 267 | padding: 2px 24px 4px 24px; 268 | -webkit-appearance: none; 269 | -moz-appearance: none; 270 | appearance: none; 271 | margin-right: 10px; 272 | } 273 | 274 | #panel #language:focus { 275 | outline: none; 276 | } 277 | 278 | #contentWrapper { 279 | flex: 1; 280 | overflow: hidden; 281 | display: flex; 282 | flex-direction: column; 283 | transform: translate3d(0,0,0); 284 | } 285 | #panel #content { 286 | flex: 1; 287 | overflow-y: auto; 288 | overflow-x: hidden; 289 | -webkit-overflow-scrolling: touch; 290 | padding: 0 var(--panel-padding) var(--panel-padding) var(--panel-padding); 291 | } 292 | 293 | #panel #content ul { 294 | list-style-type: none; 295 | padding: 0px; 296 | margin: 0px 0 20px 0; 297 | } 298 | #panel #content ul li { 299 | margin: 1px 0; 300 | } 301 | 302 | #panel #content h2 { 303 | margin-top: 32px; 304 | border-top: var(--border-style); 305 | padding-top: 12px; 306 | } 307 | 308 | #panel #content h2:first-child { 309 | margin-top: 16px !important; 310 | border-top: none; 311 | padding-top: 0; 312 | } 313 | 314 | #panel #content a { 315 | position: relative; 316 | color: var(--text-color); 317 | } 318 | 319 | #panel #content a:hover, 320 | #panel #content a:hover .spacer, 321 | #panel #content .selected { 322 | color: var(--color-blue); 323 | } 324 | 325 | #panel #content .selected { 326 | text-decoration: underline; 327 | } 328 | 329 | #panel #content .hidden { 330 | display: none !important; 331 | } 332 | 333 | body.home #panel #content h2 { 334 | margin-bottom: 2px; 335 | padding-bottom: 0px; 336 | margin-top: 18px; 337 | border-top: none; 338 | padding-top: 6px; 339 | } 340 | 341 | .spacer { 342 | color: var(--secondary-text-color); 343 | margin-left: 2px; 344 | padding-right: 2px; 345 | } 346 | 347 | #viewer, 348 | iframe { 349 | position: absolute; 350 | border: 0px; 351 | left: 0; 352 | right: 0; 353 | width: 100%; 354 | height: 100%; 355 | overflow: auto; 356 | } 357 | 358 | #viewer { 359 | padding-left: var(--panel-width); 360 | } 361 | 362 | #button { 363 | position: fixed; 364 | bottom: 16px; 365 | right: 16px; 366 | 367 | padding: 12px; 368 | border-radius: 50%; 369 | margin-bottom: 0px; 370 | 371 | background-color: #FFF; 372 | opacity: .9; 373 | z-index: 999; 374 | 375 | box-shadow: 0 0 4px rgba(0,0,0,.15); 376 | } 377 | #button:hover { 378 | cursor: pointer; 379 | opacity: 1; 380 | } 381 | #button img { 382 | display: block; 383 | width: var(--icon-size); 384 | } 385 | 386 | #button.text { 387 | border-radius: 25px; 388 | padding-right: 20px; 389 | padding-left: 20px; 390 | color: var(--color-blue); 391 | opacity: 1; 392 | font-weight: 500; 393 | } 394 | 395 | 396 | #projects { 397 | display: grid; 398 | grid-template-columns: repeat(6, 1fr); 399 | line-height: 0; 400 | } 401 | #projects a { 402 | overflow: hidden; 403 | } 404 | #projects a img { 405 | width: 100%; 406 | transform: scale(1.0); 407 | transition: 0.15s transform; 408 | } 409 | #projects a:hover img { 410 | transform: scale(1.08); 411 | } 412 | 413 | 414 | 415 | @media all and ( min-width: 1500px ) { 416 | #projects { 417 | grid-template-columns: repeat(7, 1fr); 418 | } 419 | } 420 | 421 | @media all and ( min-width: 1700px ) { 422 | :root { 423 | --panel-width: 360px; 424 | --font-size: 18px; 425 | --line-height: 28px; 426 | --header-height: 56px; 427 | --icon-size: 24px; 428 | } 429 | #projects { 430 | grid-template-columns: repeat(8, 1fr); 431 | } 432 | } 433 | 434 | @media all and ( min-width: 1900px ) { 435 | 436 | #projects { 437 | grid-template-columns: repeat(9, 1fr); 438 | } 439 | 440 | } 441 | 442 | @media all and ( max-width: 1300px ) { 443 | #projects { 444 | grid-template-columns: repeat(6, 1fr); 445 | } 446 | } 447 | 448 | @media all and ( max-width: 1100px ) { 449 | #projects { 450 | grid-template-columns: repeat(5, 1fr); 451 | } 452 | } 453 | 454 | @media all and ( max-width: 900px ) { 455 | #projects { 456 | grid-template-columns: repeat(4, 1fr); 457 | } 458 | } 459 | 460 | @media all and ( max-width: 700px ) { 461 | #projects { 462 | grid-template-columns: repeat(3, 1fr); 463 | } 464 | } 465 | 466 | 467 | /* mobile */ 468 | 469 | @media all and ( max-width: 640px ) { 470 | 471 | :root { 472 | --header-height: 56px; 473 | --icon-size: 24px; 474 | } 475 | 476 | #projects { 477 | grid-template-columns: repeat(2, 1fr); 478 | } 479 | 480 | #panel #expandButton { 481 | display: block; 482 | } 483 | #panel { 484 | position: absolute; 485 | left: 0; 486 | top: 0; 487 | width: 100%; 488 | right: 0; 489 | z-index: 1000; 490 | overflow-x: hidden; 491 | transition: 0s 0s height; 492 | border: none; 493 | height: var(--header-height); 494 | transition: 0s 0.2s height; 495 | } 496 | #panel.open { 497 | height: 100%; 498 | transition: 0s 0s height; 499 | } 500 | 501 | #panelScrim { 502 | pointer-events: none; 503 | background-color: rgba(0,0,0,0); 504 | position: absolute; 505 | left: 0; 506 | right: 0; 507 | top: 0; 508 | bottom: 0; 509 | z-index: 1000; 510 | pointer-events: none; 511 | transition: .2s background-color; 512 | } 513 | #panel.open #panelScrim { 514 | pointer-events: auto; 515 | background-color: rgba(0,0,0,0.4); 516 | } 517 | 518 | #contentWrapper { 519 | position: absolute; 520 | right: 0; 521 | top: 0; 522 | bottom: 0; 523 | background: var(--background-color); 524 | box-shadow: 0 0 8px rgba(0,0,0,.1); 525 | width: calc(100vw - 60px); 526 | max-width: 360px; 527 | z-index: 10000; 528 | transition: .25s transform; 529 | overflow-x: hidden; 530 | margin-right: -380px; 531 | line-height: 2rem; 532 | } 533 | #panel.open #contentWrapper { 534 | transform: translate3d(-380px, 0 ,0); 535 | } 536 | #viewer, 537 | iframe { 538 | left: 0; 539 | top: var(--header-height); 540 | width: 100%; 541 | height: calc(100% - var(--header-height)); 542 | } 543 | #viewer { 544 | padding-left: 0; 545 | } 546 | } 547 | -------------------------------------------------------------------------------- /examples/js/loaders/OBJLoader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.OBJLoader = function () { 6 | 7 | THREE.EventDispatcher.call( this ); 8 | 9 | }; 10 | 11 | THREE.OBJLoader.prototype = { 12 | 13 | constructor: THREE.OBJLoader, 14 | 15 | load: function ( url, callback ) { 16 | 17 | var scope = this; 18 | var request = new XMLHttpRequest(); 19 | 20 | request.addEventListener( 'load', function ( event ) { 21 | 22 | var hierarchy = scope.parse( event.target.responseText ); 23 | 24 | scope.dispatchEvent( { type: 'load', content: hierarchy } ); 25 | 26 | if ( callback ) callback( hierarchy ); 27 | 28 | }, false ); 29 | 30 | request.addEventListener( 'progress', function ( event ) { 31 | 32 | scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } ); 33 | 34 | }, false ); 35 | 36 | request.addEventListener( 'error', function () { 37 | 38 | scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } ); 39 | 40 | }, false ); 41 | 42 | request.open( 'GET', url, true ); 43 | request.send( null ); 44 | 45 | }, 46 | 47 | parse: function ( data ) { 48 | 49 | // fixes 50 | 51 | data = data.replace( /\ \\\r\n/g, '' ); // rhino adds ' \\r\n' some times. 52 | 53 | // 54 | 55 | function vector( x, y, z ) { 56 | 57 | return new THREE.Vector3( x, y, z ); 58 | 59 | } 60 | 61 | function uv( u, v ) { 62 | 63 | return new THREE.Vector2( u, v ); 64 | 65 | } 66 | 67 | function face3( a, b, c, normals ) { 68 | 69 | return new THREE.Face3( a, b, c, normals ); 70 | 71 | } 72 | 73 | function face4( a, b, c, d, normals ) { 74 | 75 | return new THREE.Face4( a, b, c, d, normals ); 76 | 77 | } 78 | 79 | function meshN( meshName, materialName ) { 80 | 81 | if ( geometry.vertices.length > 0 ) { 82 | 83 | geometry.mergeVertices(); 84 | geometry.computeCentroids(); 85 | geometry.computeFaceNormals(); 86 | geometry.computeBoundingSphere(); 87 | 88 | object.add( mesh ); 89 | 90 | geometry = new THREE.Geometry(); 91 | mesh = new THREE.Mesh( geometry, material ); 92 | 93 | verticesCount = 0; 94 | 95 | } 96 | 97 | if ( meshName !== undefined ) mesh.name = meshName; 98 | if ( materialName !== undefined ) { 99 | 100 | material = new THREE.MeshLambertMaterial(); 101 | material.name = materialName; 102 | 103 | mesh.material = material; 104 | 105 | } 106 | 107 | } 108 | 109 | var group = new THREE.Object3D(); 110 | var object = group; 111 | 112 | var geometry = new THREE.Geometry(); 113 | var material = new THREE.MeshLambertMaterial(); 114 | var mesh = new THREE.Mesh( geometry, material ); 115 | 116 | var vertices = []; 117 | var verticesCount = 0; 118 | var normals = []; 119 | var uvs = []; 120 | 121 | // v float float float 122 | 123 | var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/; 124 | 125 | // vn float float float 126 | 127 | var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/; 128 | 129 | // vt float float 130 | 131 | var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( [\d|\.|\+|\-|e]+)/; 132 | 133 | // f vertex vertex vertex ... 134 | 135 | var face_pattern1 = /f( +[\d]+)( [\d]+)( [\d]+)( [\d]+)?/; 136 | 137 | // f vertex/uv vertex/uv vertex/uv ... 138 | 139 | var face_pattern2 = /f( +([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))( ([\d]+)\/([\d]+))?/; 140 | 141 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ... 142 | 143 | var face_pattern3 = /f( +([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))( ([\d]+)\/([\d]+)\/([\d]+))?/; 144 | 145 | // f vertex//normal vertex//normal vertex//normal ... 146 | 147 | var face_pattern4 = /f( +([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))( ([\d]+)\/\/([\d]+))?/; 148 | 149 | // 150 | 151 | var lines = data.split( "\n" ); 152 | 153 | for ( var i = 0; i < lines.length; i ++ ) { 154 | 155 | var line = lines[ i ]; 156 | line = line.trim(); 157 | 158 | var result; 159 | 160 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) { 161 | 162 | continue; 163 | 164 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) { 165 | 166 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 167 | 168 | vertices.push( vector( 169 | parseFloat( result[ 1 ] ), 170 | parseFloat( result[ 2 ] ), 171 | parseFloat( result[ 3 ] ) 172 | ) ); 173 | 174 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) { 175 | 176 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"] 177 | 178 | normals.push( vector( 179 | parseFloat( result[ 1 ] ), 180 | parseFloat( result[ 2 ] ), 181 | parseFloat( result[ 3 ] ) 182 | ) ); 183 | 184 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) { 185 | 186 | // ["vt 0.1 0.2", "0.1", "0.2"] 187 | 188 | uvs.push( uv( 189 | parseFloat( result[ 1 ] ), 190 | parseFloat( result[ 2 ] ) 191 | ) ); 192 | 193 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) { 194 | 195 | // ["f 1 2 3", "1", "2", "3", undefined] 196 | 197 | if ( result[ 4 ] === undefined ) { 198 | 199 | geometry.vertices.push( 200 | vertices[ parseInt( result[ 1 ] ) - 1 ], 201 | vertices[ parseInt( result[ 2 ] ) - 1 ], 202 | vertices[ parseInt( result[ 3 ] ) - 1 ] 203 | ); 204 | 205 | geometry.faces.push( face3( 206 | verticesCount ++, 207 | verticesCount ++, 208 | verticesCount ++ 209 | ) ); 210 | 211 | } else { 212 | 213 | geometry.vertices.push( 214 | vertices[ parseInt( result[ 1 ] ) - 1 ], 215 | vertices[ parseInt( result[ 2 ] ) - 1 ], 216 | vertices[ parseInt( result[ 3 ] ) - 1 ], 217 | vertices[ parseInt( result[ 4 ] ) - 1 ] 218 | ); 219 | 220 | geometry.faces.push( face4( 221 | verticesCount ++, 222 | verticesCount ++, 223 | verticesCount ++, 224 | verticesCount ++ 225 | ) ); 226 | 227 | } 228 | 229 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) { 230 | 231 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined] 232 | 233 | if ( result[ 10 ] === undefined ) { 234 | 235 | geometry.vertices.push( 236 | vertices[ parseInt( result[ 2 ] ) - 1 ], 237 | vertices[ parseInt( result[ 5 ] ) - 1 ], 238 | vertices[ parseInt( result[ 8 ] ) - 1 ] 239 | ); 240 | 241 | geometry.faces.push( face3( 242 | verticesCount ++, 243 | verticesCount ++, 244 | verticesCount ++ 245 | ) ); 246 | 247 | geometry.faceVertexUvs[ 0 ].push( [ 248 | uvs[ parseInt( result[ 3 ] ) - 1 ], 249 | uvs[ parseInt( result[ 6 ] ) - 1 ], 250 | uvs[ parseInt( result[ 9 ] ) - 1 ] 251 | ] ); 252 | 253 | } else { 254 | 255 | geometry.vertices.push( 256 | vertices[ parseInt( result[ 2 ] ) - 1 ], 257 | vertices[ parseInt( result[ 5 ] ) - 1 ], 258 | vertices[ parseInt( result[ 8 ] ) - 1 ], 259 | vertices[ parseInt( result[ 11 ] ) - 1 ] 260 | ); 261 | 262 | geometry.faces.push( face4( 263 | verticesCount ++, 264 | verticesCount ++, 265 | verticesCount ++, 266 | verticesCount ++ 267 | ) ); 268 | 269 | geometry.faceVertexUvs[ 0 ].push( [ 270 | uvs[ parseInt( result[ 3 ] ) - 1 ], 271 | uvs[ parseInt( result[ 6 ] ) - 1 ], 272 | uvs[ parseInt( result[ 9 ] ) - 1 ], 273 | uvs[ parseInt( result[ 12 ] ) - 1 ] 274 | ] ); 275 | 276 | } 277 | 278 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) { 279 | 280 | // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined] 281 | 282 | if ( result[ 13 ] === undefined ) { 283 | 284 | geometry.vertices.push( 285 | vertices[ parseInt( result[ 2 ] ) - 1 ], 286 | vertices[ parseInt( result[ 6 ] ) - 1 ], 287 | vertices[ parseInt( result[ 10 ] ) - 1 ] 288 | ); 289 | 290 | geometry.faces.push( face3( 291 | verticesCount ++, 292 | verticesCount ++, 293 | verticesCount ++, 294 | [ 295 | normals[ parseInt( result[ 4 ] ) - 1 ], 296 | normals[ parseInt( result[ 8 ] ) - 1 ], 297 | normals[ parseInt( result[ 12 ] ) - 1 ] 298 | ] 299 | ) ); 300 | 301 | geometry.faceVertexUvs[ 0 ].push( [ 302 | uvs[ parseInt( result[ 3 ] ) - 1 ], 303 | uvs[ parseInt( result[ 7 ] ) - 1 ], 304 | uvs[ parseInt( result[ 11 ] ) - 1 ] 305 | ] ); 306 | 307 | } else { 308 | 309 | geometry.vertices.push( 310 | vertices[ parseInt( result[ 2 ] ) - 1 ], 311 | vertices[ parseInt( result[ 6 ] ) - 1 ], 312 | vertices[ parseInt( result[ 10 ] ) - 1 ], 313 | vertices[ parseInt( result[ 14 ] ) - 1 ] 314 | ); 315 | 316 | geometry.faces.push( face4( 317 | verticesCount ++, 318 | verticesCount ++, 319 | verticesCount ++, 320 | verticesCount ++, 321 | [ 322 | normals[ parseInt( result[ 4 ] ) - 1 ], 323 | normals[ parseInt( result[ 8 ] ) - 1 ], 324 | normals[ parseInt( result[ 12 ] ) - 1 ], 325 | normals[ parseInt( result[ 16 ] ) - 1 ] 326 | ] 327 | ) ); 328 | 329 | geometry.faceVertexUvs[ 0 ].push( [ 330 | uvs[ parseInt( result[ 3 ] ) - 1 ], 331 | uvs[ parseInt( result[ 7 ] ) - 1 ], 332 | uvs[ parseInt( result[ 11 ] ) - 1 ], 333 | uvs[ parseInt( result[ 15 ] ) - 1 ] 334 | ] ); 335 | 336 | } 337 | 338 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) { 339 | 340 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined] 341 | 342 | if ( result[ 10 ] === undefined ) { 343 | 344 | geometry.vertices.push( 345 | vertices[ parseInt( result[ 2 ] ) - 1 ], 346 | vertices[ parseInt( result[ 5 ] ) - 1 ], 347 | vertices[ parseInt( result[ 8 ] ) - 1 ] 348 | ); 349 | 350 | geometry.faces.push( face3( 351 | verticesCount ++, 352 | verticesCount ++, 353 | verticesCount ++, 354 | [ 355 | normals[ parseInt( result[ 3 ] ) - 1 ], 356 | normals[ parseInt( result[ 6 ] ) - 1 ], 357 | normals[ parseInt( result[ 9 ] ) - 1 ] 358 | ] 359 | ) ); 360 | 361 | } else { 362 | 363 | geometry.vertices.push( 364 | vertices[ parseInt( result[ 2 ] ) - 1 ], 365 | vertices[ parseInt( result[ 5 ] ) - 1 ], 366 | vertices[ parseInt( result[ 8 ] ) - 1 ], 367 | vertices[ parseInt( result[ 11 ] ) - 1 ] 368 | ); 369 | 370 | geometry.faces.push( face4( 371 | verticesCount ++, 372 | verticesCount ++, 373 | verticesCount ++, 374 | verticesCount ++, 375 | [ 376 | normals[ parseInt( result[ 3 ] ) - 1 ], 377 | normals[ parseInt( result[ 6 ] ) - 1 ], 378 | normals[ parseInt( result[ 9 ] ) - 1 ], 379 | normals[ parseInt( result[ 12 ] ) - 1 ] 380 | ] 381 | ) ); 382 | 383 | } 384 | 385 | } else if ( /^o /.test( line ) ) { 386 | 387 | // object 388 | 389 | object = new THREE.Object3D(); 390 | object.name = line.substring( 2 ).trim(); 391 | group.add( object ); 392 | 393 | } else if ( /^g /.test( line ) ) { 394 | 395 | // group 396 | 397 | meshN( line.substring( 2 ).trim(), undefined ); 398 | 399 | } else if ( /^usemtl /.test( line ) ) { 400 | 401 | // material 402 | 403 | meshN( undefined, line.substring( 7 ).trim() ); 404 | 405 | } else if ( /^mtllib /.test( line ) ) { 406 | 407 | // mtl file 408 | 409 | } else if ( /^s /.test( line ) ) { 410 | 411 | // smooth shading 412 | 413 | } else { 414 | 415 | // console.log( "THREE.OBJLoader: Unhandled line " + line ); 416 | 417 | } 418 | 419 | } 420 | 421 | // add the last group 422 | meshN( undefined, undefined ); 423 | 424 | return group; 425 | 426 | } 427 | 428 | } 429 | -------------------------------------------------------------------------------- /src/parser.jison: -------------------------------------------------------------------------------- 1 | %lex 2 | %% 3 | 4 | \s+ /* skip */ 5 | "//".* /* ignore comment */ 6 | "/*"[\w\W]*?"*/" /* ignore comment */ 7 | 8 | "set" return 'SET' 9 | "w" return 'WEIGHT'; 10 | "weight" return 'WEIGHT'; 11 | "md" return 'MAXDEPTH'; 12 | "maxdepth" return 'MAXDEPTH'; 13 | "maxobjects" return 'MAXOBJECTS'; 14 | "minsize" return 'MINSIZE'; 15 | "maxsize" return 'MAXSIZE'; 16 | "seed" return 'SEED'; 17 | "initial" return 'INITIAL'; 18 | "background" return 'BACKGROUND'; 19 | "colorpool" return 'COLORPOOL'; 20 | "rule" return 'RULE'; 21 | "Rule" return 'RULE'; 22 | ">" return '>'; 23 | "{" return '{'; 24 | "}" return '}'; 25 | "[" return '['; 26 | "]" return ']'; 27 | "^" return '^'; 28 | "*" return '*'; 29 | "/" return '/'; 30 | "+" return '+'; 31 | "-" return '-'; 32 | "(" return '('; 33 | ")" return ')'; 34 | "," return ','; 35 | "x" return 'XSHIFT'; 36 | "y" return 'YSHIFT'; 37 | "z" return 'ZSHIFT'; 38 | "rx" return 'ROTATEX'; 39 | "ry" return 'ROTATEY'; 40 | "rz" return 'ROTATEZ'; 41 | "fx" return 'FX'; 42 | "fy" return 'FY'; 43 | "fz" return 'FZ'; 44 | "s" return 'SIZE'; 45 | "m" return 'MATRIX'; 46 | "matrix" return 'MATRIX'; 47 | "hue" return 'HUE'; 48 | "h" return 'HUE'; 49 | "saturation" return 'SATURATION'; 50 | "sat" return 'SATURATION'; 51 | "brightness" return 'BRIGHTNESS'; 52 | "b" return 'BRIGHTNESS'; 53 | "alpha" return 'ALPHA'; 54 | "a" return 'ALPHA'; 55 | "color" return 'COLOR'; 56 | "random" return 'RANDOM'; 57 | "blend" return 'BLEND'; 58 | "randomhue" return 'RANDOMHUE'; 59 | "randomrgb" return 'RANDOMRGB'; 60 | "greyscale" return 'GREYSCALE'; 61 | <> return 'EOF'; 62 | [0-9]+("."[0-9]*)? return 'NUMBER'; 63 | "."[0-9]+ return 'NUMBER'; 64 | "list:"[\w,#]+ return 'COLORLIST'; 65 | "image:"[\w\.\w]+ return 'IMAGE'; 66 | "box" return 'BOX'; 67 | "grid" return 'GRID'; 68 | "sphere" return 'SPHERE'; 69 | "line" return 'LINE'; 70 | "point" return 'POINT'; 71 | "triangle" return 'TRIANGLE'; 72 | "mesh" return 'MESH'; 73 | "cylinder" return 'CYLINDER'; 74 | "tube" return 'TUBE'; 75 | "squash" return 'SQUASH'; 76 | [a-zA-Z_]+[a-zA-Z0-9_]* return 'STRING'; 77 | "#define" return 'DEFINE'; 78 | "#"[a-fA-F0-9]{6} return 'COLOR6'; 79 | "#"[a-fA-F0-9]{3} return 'COLOR3'; 80 | (aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgrey|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|grey|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgrey|lightgreen|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|rebeccapurple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen) return 'COLORNAME'; 81 | (ALICEBLUE|ANTIQUEWHITE|AQUA|AQUAMARINE|AZURE|BEIGE|BISQUE|BLACK|BLANCHEDALMOND|BLUE|BLUEVIOLET|BROWN|BURLYWOOD|CADETBLUE|CHARTREUSE|CHOCOLATE|CORAL|CORNFLOWERBLUE|CORNSILK|CRIMSON|CYAN|DARKBLUE|DARKCYAN|DARKGOLDENROD|DARKGRAY|DARKGREY|DARKGREEN|DARKKHAKI|DARKMAGENTA|DARKOLIVEGREEN|DARKORANGE|DARKORCHID|DARKRED|DARKSALMON|DARKSEAGREEN|DARKSLATEBLUE|DARKSLATEGRAY|DARKSLATEGREY|DARKTURQUOISE|DARKVIOLET|DEEPPINK|DEEPSKYBLUE|DIMGRAY|DIMGREY|DODGERBLUE|FIREBRICK|FLORALWHITE|FORESTGREEN|FUCHSIA|GAINSBORO|GHOSTWHITE|GOLD|GOLDENROD|GRAY|GREY|GREEN|GREENYELLOW|HONEYDEW|HOTPINK|INDIANRED|INDIGO|IVORY|KHAKI|LAVENDER|LAVENDERBLUSH|LAWNGREEN|LEMONCHIFFON|LIGHTBLUE|LIGHTCORAL|LIGHTCYAN|LIGHTGOLDENRODYELLOW|LIGHTGRAY|LIGHTGREY|LIGHTGREEN|LIGHTPINK|LIGHTSALMON|LIGHTSEAGREEN|LIGHTSKYBLUE|LIGHTSLATEGRAY|LIGHTSLATEGREY|LIGHTSTEELBLUE|LIGHTYELLOW|LIME|LIMEGREEN|LINEN|MAGENTA|MAROON|MEDIUMAQUAMARINE|MEDIUMBLUE|MEDIUMORCHID|MEDIUMPURPLE|MEDIUMSEAGREEN|MEDIUMSLATEBLUE|MEDIUMSPRINGGREEN|MEDIUMTURQUOISE|MEDIUMVIOLETRED|MIDNIGHTBLUE|MINTCREAM|MISTYROSE|MOCCASIN|NAVAJOWHITE|NAVY|OLDLACE|OLIVE|OLIVEDRAB|ORANGE|ORANGERED|ORCHID|PALEGOLDENROD|PALEGREEN|PALETURQUOISE|PALEVIOLETRED|PAPAYAWHIP|PEACHPUFF|PERU|PINK|PLUM|POWDERBLUE|PURPLE|REBECCAPURPLE|RED|ROSYBROWN|ROYALBLUE|SADDLEBROWN|SALMON|SANDYBROWN|SEAGREEN|SEASHELL|SIENNA|SILVER|SKYBLUE|SLATEBLUE|SLATEGRAY|SLATEGREY|SNOW|SPRINGGREEN|STEELBLUE|TAN|TEAL|THISTLE|TOMATO|TURQUOISE|VIOLET|WHEAT|WHITE|WHITESMOKE|YELLOW|YELLOWGREEN) return 'COLORNAME'; 82 | ";" return 'COORD_DELIMITER' 83 | 84 | /lex 85 | 86 | %left '+' '-' 87 | %left '*' '/' 88 | %left '^' 89 | %left NEG POS 90 | 91 | 92 | //////////////////////////////////////////////////// 93 | // EISENSCRIPT 94 | //////////////////////////////////////////////////// 95 | 96 | %start eisenscript 97 | 98 | %% /* language grammar */ 99 | 100 | eisenscript 101 | : lines EOF { $$ = $1; return $$; } 102 | ; 103 | 104 | lines 105 | : lines line { $$ = $1; $$.push($2); } 106 | | { $$ = []; } 107 | ; 108 | 109 | line 110 | : maxdepth { $$ = $1; } 111 | | maxobjects { $$ = $1; } 112 | | minsize { $$ = $1; } 113 | | maxsize { $$ = $1; } 114 | | seed { $$ = $1; } 115 | | background { $$ = $1; } 116 | | color { $$ = $1; } 117 | | colorpool { $$ = $1; } 118 | | define { $$ = $1; } 119 | | rule { $$ = $1; } 120 | | statement { $$ = $1; $1.computed = true; } 121 | ; 122 | 123 | 124 | //////////////////////////////////////////////////// 125 | // ACTION 126 | //////////////////////////////////////////////////// 127 | 128 | maxdepth 129 | : SET MAXDEPTH num { $$ = { type: 'set', key: 'maxdepth', value: $3 }; } 130 | ; 131 | 132 | maxobjects 133 | : SET MAXOBJECTS num { $$ = { type: 'set', key: 'maxobjects', value: $3 }; } 134 | ; 135 | 136 | minsize 137 | : SET MINSIZE num { $$ = { type: 'set', key: 'minsize', value: $3 }; } 138 | ; 139 | 140 | maxsize 141 | : SET MAXSIZE num { $$ = { type: 'set', key: 'maxsize', value: $3 }; } 142 | ; 143 | 144 | seed 145 | : SET SEED num { $$ = { type: 'set', key: 'seed', value: $3 }; } 146 | | SET SEED INITIAL { $$ = { type: 'set', key: 'seed', value: $3 }; } 147 | ; 148 | 149 | background 150 | : SET BACKGROUND COLOR3 { $$ = { type: 'set', key: 'background', value: $3.toLowerCase() }; } 151 | | SET BACKGROUND COLOR6 { $$ = { type: 'set', key: 'background', value: $3.toLowerCase() }; } 152 | | SET BACKGROUND COLORNAME { $$ = { type: 'set', key: 'background', value: $3.toLowerCase() }; } 153 | | SET BACKGROUND STRING { $$ = { type: 'set', key: 'background', value: $3.toLowerCase() }; } 154 | | SET BACKGROUND RANDOM { $$ = { type: 'set', key: 'background', value: $3.toLowerCase() }; } 155 | ; 156 | 157 | color 158 | : SET COLOR RANDOM { $$ = { type: 'set', key: 'color', value: $3.toLowerCase() }; } 159 | ; 160 | 161 | colorpool 162 | : SET COLORPOOL RANDOMHUE { $$ = { type: 'set', key: 'colorpool', value: $3.toLowerCase() }; } 163 | | SET COLORPOOL RANDOMRGB { $$ = { type: 'set', key: 'colorpool', value: $3.toLowerCase() }; } 164 | | SET COLORPOOL GREYSCALE { $$ = { type: 'set', key: 'colorpool', value: $3.toLowerCase() }; } 165 | | SET COLORPOOL COLORLIST { $$ = { type: 'set', key: 'colorpool', value: $3.toLowerCase() }; } 166 | | SET COLORPOOL IMAGE { $$ = { type: 'set', key: 'colorpool', value: $3.toLowerCase() }; } 167 | ; 168 | 169 | define 170 | : DEFINE STRING num { $$ = { type: 'define', varname: $2, value: $3 }; } 171 | | DEFINE STRING COLOR3 { $$ = { type: 'define', varname: $2, value: $3 }; } 172 | | DEFINE STRING COLOR6 { $$ = { type: 'define', varname: $2, value: $3 }; } 173 | | DEFINE STRING COLORNAME { $$ = { type: 'define', varname: $2, value: $3 }; } 174 | ; 175 | 176 | //////////////////////////////////////////////////// 177 | // RULE 178 | //////////////////////////////////////////////////// 179 | 180 | rule 181 | : RULE id modifiers '{' statements '}' { $$ = { type: 'rule', id: $2, params: $3, body: $5 }; } 182 | ; 183 | 184 | modifiers 185 | : modifiers modifier { $$ = $1; $$.push($2); } 186 | | { $$ = []; } 187 | ; 188 | 189 | modifier 190 | : WEIGHT num { $$ = { type: 'modifier', key: 'weight', value: $2 }; } 191 | | MAXDEPTH num { $$ = { type: 'modifier', key: 'maxdepth', value: $2 }; } 192 | | MAXDEPTH num '>' rulename { $$ = { type: 'modifier', key: 'maxdepth', value: $2, alternate: $4}; } 193 | | MAXDEPTH STRING { $$ = { type: 'modifier', key: 'maxdepth', value: $2, defined: true }; } 194 | | MAXDEPTH STRING '>' rulename { $$ = { type: 'modifier', key: 'maxdepth', value: $2, alternate: $4, defined: true}; } 195 | ; 196 | 197 | statements 198 | : statements statement { $$ = $1; $$.push($2); } 199 | | { $$ = []; } 200 | ; 201 | 202 | statement 203 | : expressions primitive { $$ = { type: 'primitive', id: $2, exprs: $1 }; } 204 | | expressions TRIANGLE '[' coords ']' { $$ = { type: 'primitive', coords: $4, id: $2, exprs: $1 }; } 205 | | expressions id { $$ = { type: 'statement', id: $2, exprs: $1 }; } 206 | ; 207 | 208 | expressions 209 | : expressions expression { $$ = $1; $$.push($2); } 210 | | { $$ = []; } 211 | ; 212 | 213 | expression 214 | : object { $$ = { type: 'expr', left: 1, right: $1 }; } 215 | | n '*' object { $$ = { type: 'expr', left: $1, right: $3 }; } 216 | | STRING '*' object { $$ = { type: 'expr', left: $1, right: $3 }; } 217 | ; 218 | 219 | object 220 | : '{' properties '}' { $$ = { type: 'object', properties: $2 }; } 221 | ; 222 | 223 | coords 224 | : coords COORD_DELIMITER coord { $$ = $1; $$.push($3); } 225 | | coords coord { $$ = $1; $$.push($2); } 226 | | { $$ = []; } 227 | ; 228 | 229 | coord 230 | : coord_point ',' coord_point ',' coord_point { $$ = [$1, $3, $5]; } 231 | ; 232 | 233 | coord_point 234 | : n 235 | | '+' n { $$ = $2; } 236 | | '-' n { $$ = -$2; } 237 | ; 238 | 239 | properties 240 | : properties property { type: 'property', $$ = $1; $$.push($2); } 241 | | { $$ = []; } 242 | ; 243 | 244 | property 245 | : geo 246 | | color 247 | ; 248 | 249 | 250 | //////////////////////////////////////////////////// 251 | // ATTRIBUTE 252 | //////////////////////////////////////////////////// 253 | 254 | geo 255 | : XSHIFT num { $$ = { type: 'property', key: 'xshift', value: $2 }; } 256 | | YSHIFT num { $$ = { type: 'property', key: 'yshift', value: $2 }; } 257 | | ZSHIFT num { $$ = { type: 'property', key: 'zshift', value: $2 }; } 258 | | ROTATEX num { $$ = { type: 'property', key: 'rotatex', value: $2 }; } 259 | | ROTATEY num { $$ = { type: 'property', key: 'rotatey', value: $2 }; } 260 | | ROTATEZ num { $$ = { type: 'property', key: 'rotatez', value: $2 }; } 261 | | SIZE num { $$ = { type: 'property', key: 'size', value: { x: $2, y: $2, z: $2 } }; } 262 | | SIZE num num num { $$ = { type: 'property', key: 'size', value: { x: $2, y: $3, z: $4 } }; } 263 | | MATRIX num num num num num num num num num { $$ = { type: 'property', key: 'matrix', value: [$2, $3, $4, $5, $6, $7, $8, $9, $10] }; } 264 | | XSHIFT STRING { $$ = { type: 'property', key: 'xshift', value: $2, defined: true }; } 265 | | YSHIFT STRING { $$ = { type: 'property', key: 'yshift', value: $2, defined: true }; } 266 | | ZSHIFT STRING { $$ = { type: 'property', key: 'zshift', value: $2, defined: true }; } 267 | | ROTATEX STRING { $$ = { type: 'property', key: 'rotatex', value: $2, defined: true }; } 268 | | ROTATEY STRING { $$ = { type: 'property', key: 'rotatey', value: $2, defined: true }; } 269 | | ROTATEZ STRING { $$ = { type: 'property', key: 'rotatez', value: $2, defined: true }; } 270 | | FX { $$ = { type: 'property', key: 'fx' }; } 271 | | FY { $$ = { type: 'property', key: 'fy' }; } 272 | | FZ { $$ = { type: 'property', key: 'fz' }; } 273 | | SIZE STRING { $$ = { type: 'property', key: 'size', value: { x: $2, y: $2, z: $2 }, defined: true }; } 274 | | SIZE STRING STRING STRING { $$ = { type: 'property', key: 'size', value: { x: $2, y: $3, z: $4 }, defined: true }; } 275 | | MATRIX STRING STRING STRING STRING STRING STRING STRING STRING STRING { $$ = { type: 'property', key: 'matrix', value: [$2, $3, $4, $5, $6, $7, $8, $9, $10], defined: true }; } 276 | ; 277 | 278 | color 279 | : HUE num { $$ = { type: 'property', key: 'hue', value: $2 }; } 280 | | HUE STRING { $$ = { type: 'property', key: 'hue', value: $2, defined: true }; } 281 | | ALPHA num { $$ = { type: 'property', key: 'alpha', value: $2 }; } 282 | | ALPHA STRING { $$ = { type: 'property', key: 'alpha', value: $2, defined: true }; } 283 | | COLOR COLOR3 { $$ = { type: 'property', key: 'color', value: $2.toLowerCase() }; } 284 | | COLOR COLOR6 { $$ = { type: 'property', key: 'color', value: $2.toLowerCase() }; } 285 | | COLOR RANDOM { $$ = { type: 'property', key: 'color', value: $2.toLowerCase() }; } 286 | | COLOR COLORNAME { $$ = { type: 'property', key: 'color', value: $2.toLowerCase() }; } 287 | | COLOR STRING { $$ = { type: 'property', key: 'color', value: $2.toLowerCase(), defined: true }; } 288 | | BLEND COLOR3 num { $$ = { type: 'property', key: 'blend', color: $2.toLowerCase(), strength: $3 }; } 289 | | BLEND COLOR6 num { $$ = { type: 'property', key: 'blend', color: $2.toLowerCase(), strength: $3 }; } 290 | | BLEND COLORNAME num { $$ = { type: 'property', key: 'blend', color: $2.toLowerCase(), strength: $3 }; } 291 | | BLEND RANDOM num { $$ = { type: 'property', key: 'blend', color: $2.toLowerCase(), strength: $3 }; } 292 | | BLEND STRING num { $$ = { type: 'property', key: 'blend', color: $2.toLowerCase(), strength: $3 }; } 293 | // TODO: make BLEND possible to use defined varname. 294 | | SATURATION num { $$ = { type: 'property', key: 'saturation', value: $2 }; } 295 | | SATURATION STRING { $$ = { type: 'property', key: 'saturation', value: $2, defined: true }; } 296 | | BRIGHTNESS num { $$ = { type: 'property', key: 'brightness', value: $2 }; } 297 | | BRIGHTNESS STRING { $$ = { type: 'property', key: 'brightness', value: $2, defined: true }; } 298 | ; 299 | 300 | 301 | //////////////////////////////////////////////////// 302 | // LITERAL 303 | //////////////////////////////////////////////////// 304 | 305 | num 306 | : n 307 | | '+' n { $$ = $2; } 308 | | '-' n { $$ = -$2; } 309 | | n '*' n { $$ = $1*$3; } 310 | | n '/' n { $$ = $1/$3; } 311 | | '-' n '*' n { $$ = -$2*$4; } 312 | | '-' n '/' n { $$ = -$2/$4; } 313 | | '(' e ')' { $$ = $2; } 314 | ; 315 | 316 | n 317 | : NUMBER { $$ = parseFloat(yytext); } 318 | ; 319 | 320 | id 321 | : STRING { $$ = yytext; } 322 | ; 323 | 324 | rulename 325 | : STRING {$$ = $1; } 326 | ; 327 | 328 | primitive 329 | : BOX { $$ = yytext; } 330 | | SPHERE { $$ = yytext; } 331 | | GRID { $$ = yytext; } 332 | | LINE { $$ = yytext; } 333 | | POINT { $$ = yytext; } 334 | | TRIANGLE { $$ = yytext; } 335 | | MESH { $$ = yytext; } 336 | | CYLINDER { $$ = yytext; } 337 | | TUBE { $$ = yytext; } 338 | | SQUASH { $$ = yytext; } 339 | ; 340 | 341 | -------------------------------------------------------------------------------- /src/Interpreter.js: -------------------------------------------------------------------------------- 1 | const Symbol = require('./Symbol'); 2 | const Color = require('color-js'); 3 | const Matrix4 = require('./Matrix4'); 4 | const utils = require('./utils'); 5 | const MersenneTwister = require('./mt'); 6 | const { degToRad, clamp } = require('./math'); 7 | const csscolor = require('./csscolor'); 8 | const Primitive = require('./Primitive'); 9 | 10 | // module generate object code from ast 11 | module.exports = class Interpreter { 12 | constructor() { 13 | this.name = 'Interpreter'; 14 | this.objects = []; 15 | this.define = []; 16 | this.rules = {}; 17 | this.computed = []; 18 | this.maxdepth; 19 | this.depth = 0; 20 | this.maxobjects; 21 | this.objectnum = 0; 22 | this.minsize = .2; 23 | this.maxsize = 1.0; 24 | this.seed = 'initial'; // 'initial' represents random color 25 | this.stack = []; 26 | this.curr = {}; 27 | this.curr.matrix = new Matrix4(); 28 | this.curr.hsv = utils.extend(Color({ hue: 0, saturation: 1, value: 1 }), { computed: false }); 29 | this.curr.blend = { color: null, strength: 0 }; 30 | this.curr.alpha = 1; 31 | this.colorpool = null; 32 | this.colorscheme = []; 33 | this.mt = new MersenneTwister(); 34 | } 35 | 36 | // termination criteria 37 | terminated() { 38 | if (!this.maxobjects && !this.maxdepth) { 39 | if (this.depth >= 1000) { 40 | console.warn('[eisenscript.js] terminated because maximum number of generations reached (1000)'); 41 | return true; 42 | } 43 | } 44 | if (this.maxobjects && this.objectnum > this.maxobjects) return true; 45 | 46 | // NOTE: misterious working of structure synth 47 | // set maxdepth 10 48 | // rule R1 { box { x 1 hue 36 rx 10 } R1 } R1 49 | if (this.maxdepth && this.depth > this.maxdepth - 3) return true; 50 | return false; 51 | } 52 | 53 | // stack current transformation state 54 | pushState() { 55 | this.depth++; 56 | this.stack.push({ 57 | matrix: this.curr.matrix.clone(), 58 | hsv: this.curr.hsv.clone(), 59 | blend: utils.extend({}, this.curr.blend), 60 | alpha: this.curr.alpha 61 | }); 62 | return this; 63 | } 64 | 65 | // pull the parent transformation state 66 | popState() { 67 | if (this.stack.length > 0) { 68 | this.curr = this.stack.pop(); 69 | this.depth--; 70 | } 71 | return this; 72 | } 73 | 74 | translate(x, y, z) { 75 | this.curr.matrix.translate({ 76 | x: x, 77 | y: y, 78 | z: z 79 | }); 80 | return this; 81 | } 82 | 83 | rotateX(angle) { 84 | this.curr.matrix.rotateX(angle); 85 | return this; 86 | } 87 | 88 | rotateY(angle) { 89 | this.curr.matrix.rotateY(angle); 90 | return this; 91 | } 92 | 93 | rotateZ(angle) { 94 | this.curr.matrix.rotateZ(angle); 95 | return this; 96 | } 97 | 98 | scale(x, y, z) { 99 | this.curr.matrix.scale({ 100 | x: x, 101 | y: y, 102 | z: z 103 | }); 104 | return this; 105 | } 106 | 107 | // make 3x3 rotation matrix to 4x4 matrix 108 | // test: { m 1 0 0 0 .53 -.85 0 .85 .53 } box 109 | matrix(v) { 110 | this.curr.matrix.set( 111 | v[0], v[1], v[2], 0, 112 | v[3], v[4], v[5], 0, 113 | v[6], v[7], v[8], 0, 114 | 0, 0, 0, 1 115 | ); 116 | return this; 117 | } 118 | 119 | multiplyMatrices(v) { 120 | this.curr.matrix.multiplyMatrices(this.curr.matrix, new Matrix4( 121 | v[0], v[1], v[2], 0, 122 | v[3], v[4], v[5], 0, 123 | v[6], v[7], v[8], 0, 124 | 0, 0, 0, 1 125 | )); 126 | return this; 127 | } 128 | 129 | randomColor() { 130 | // if colorpool is set, choose from colorset 131 | if (this.colorpool === Symbol.ColorList) { 132 | if (this.colorscheme.length > 0) { 133 | const idx = Math.floor(this.mt.next() * this.colorpool.length); 134 | return this.colorscheme[idx]; 135 | } 136 | } 137 | else if (this.colorpool === Symbol.ColorGreyscale) { 138 | // random r=g=b 139 | const r = this.mt.next() * 255; 140 | return `#${utils.rgb2hex(r, r, r)}`; 141 | } 142 | else if (this.colorpool === Symbol.ColorRandomhue) { 143 | const h = Math.floor(this.mt.next() * 360); 144 | const rgb = utils.hsv2rgb(h, 1, 1); 145 | return `#${utils.rgb2hex(rgb[0], rgb[1], rgb[2])}`; 146 | } 147 | else if (this.colorpool === Symbol.ColorRandomrgb) { 148 | const rgb = [ 149 | this.mt.next() * 255, 150 | this.mt.next() * 255, 151 | this.mt.next() * 255 152 | ]; 153 | return `#${utils.rgb2hex(rgb[0], rgb[1], rgb[2])}`; 154 | } 155 | const rand = this.mt.next() * 0xffffff; 156 | const color = Math.floor(rand).toString(16); 157 | return `#${color}`; 158 | } 159 | 160 | setColor(color) { 161 | this.curr.hsv = Color(color === 'random' ? this.randomColor() : color).toHSV(); 162 | return this; 163 | } 164 | 165 | setHue(v) { 166 | this.curr.hsv.computed = true; 167 | this.curr.hsv.hue += v % 360; 168 | return this; 169 | } 170 | 171 | setSaturation(v) { 172 | this.curr.hsv.computed = true; 173 | const sat = this.curr.hsv.saturation; 174 | if (0 > sat * v || sat * v > 1) console.warn('[eisenscript.js] Saturation is measured from 0 to 1 and is clamped to this interval (i.e. values larger then 1 are set to 1.'); 175 | this.curr.hsv.saturation = clamp(sat * v, 0, 1); 176 | return this; 177 | } 178 | 179 | setBrightness(v) { 180 | this.curr.hsv.computed = true; 181 | const brightness = this.curr.hsv.value; 182 | if (0 > brightness * v || brightness * v > 1) console.warn('[eisenscript.js] Brightness is measured from 0 to 1 and is clamped to this interval.'); 183 | this.curr.hsv.value = clamp(brightness * v, 0, 1); 184 | return this; 185 | } 186 | 187 | setBlend(color, strength) { 188 | this.curr.blend.color = color; 189 | this.curr.blend.strength = this.curr.blend.strength + clamp(strength, 0, 1) / 2; 190 | // blend the current color with the specified color 191 | this.curr.hsv = this.curr.hsv.blend( 192 | Color(this.curr.blend.color === 'random' ? this.randomColor() : this.curr.blend.color).toHSV(), 193 | this.curr.blend.strength 194 | ); 195 | return this; 196 | } 197 | 198 | setAlpha(v) { 199 | const alpha = this.curr.alpha; 200 | if (0 > alpha * v || alpha * v > 1) console.warn('[eisenscript.js] Alpha is measured from 0 to 1 and is clamped to this interval.'); 201 | this.curr.alpha = clamp(this.curr.alpha * v, 0, 1); 202 | return this; 203 | } 204 | 205 | resolveVarname(symbol) { 206 | for (let i = 0; i < this.define.length; i++) { 207 | const statement = this.define[i]; 208 | switch (statement.type) { 209 | case Symbol.Define: 210 | if (statement.varname === symbol) { 211 | return statement.value; 212 | } 213 | } 214 | } 215 | if (csscolor[symbol]) { 216 | return csscolor[symbol]; 217 | } 218 | throw new Error(`Invalid symbol found: ${symbol}`); 219 | } 220 | 221 | // execute eisenscript 222 | generate(ast) { 223 | const that = this; 224 | 225 | // pull the defines 226 | ast.forEach(function(statement) { 227 | switch (statement.type) { 228 | case Symbol.Define: that.define.push(statement); break; 229 | case Symbol.Set: that.define.push(statement); break; 230 | case Symbol.Statement: if (statement.computed) that.computed.push(statement); break; 231 | case Symbol.Primitive: if (statement.computed) that.computed.push(statement); break; 232 | } 233 | }); 234 | 235 | // creating intermediate code... 236 | // promise 237 | this.define.forEach(function(statement) { 238 | switch (statement.type) { 239 | case Symbol.Set: 240 | switch (statement.key) { 241 | case Symbol.Maxdepth: that.maxdepth = statement.value; break; 242 | case Symbol.Maxobjects: that.maxobjects = statement.value; break; 243 | case Symbol.Minsize: 244 | console.warn('[eisenscript.js] \'set minsize\' not implement yet'); 245 | // that.minsize = statement.value; 246 | break; 247 | case Symbol.Maxsize: 248 | console.warn('[eisenscript.js] \'set maxsize\' not implement yet'); 249 | // that.maxsize = statement.value; 250 | break; 251 | case Symbol.Seed: that.seed = statement.value; break; 252 | case Symbol.ColorPool: 253 | // colorpool 254 | const m = statement.value.match(/^list:(.*)/); 255 | if (m) { 256 | that.colorpool = Symbol.ColorList; 257 | that.colorscheme = m[1].split(',').map(color => color.trim()); 258 | break; 259 | } 260 | if (statement.value === Symbol.ColorGreyscale 261 | || statement.value === Symbol.ColorRandomhue 262 | || statement.value === Symbol.ColorRandomrgb) { 263 | that.colorpool = statement.value; 264 | break; 265 | } 266 | break; 267 | } 268 | break; 269 | } 270 | }); 271 | 272 | // rewriting ast 273 | ast.forEach(function(statement) { 274 | switch (statement.type) { 275 | case Symbol.Rule: that.rewriteRule(statement); break; 276 | } 277 | }); 278 | 279 | // if 'initial' is set, set random to seed 280 | // @see https://sourceforge.net/p/structuresynth/news/ 281 | if (this.seed === 'initial') { 282 | this.mt.setSeed(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)); 283 | } else { 284 | this.mt.setSeed(this.seed); 285 | } 286 | 287 | // pull the statement of system environment 288 | this.define.forEach(function(statement) { 289 | switch (statement.type) { 290 | case Symbol.Set: 291 | if (statement.key === Symbol.Background) that.generateBackground(statement); 292 | break; 293 | } 294 | }); 295 | 296 | // execute main 297 | this.parseStatements(this.computed); 298 | 299 | // return the intermediate code 300 | return { 301 | maxdepth: this.maxdepth, 302 | maxobjects: this.maxobjects, 303 | minsize: this.minsize, 304 | maxsize: this.maxsize, 305 | seed: this.seed, 306 | objects: this.objects, 307 | num: this.objects.length 308 | }; 309 | } 310 | 311 | // rewrite subtree related to rule statement 312 | rewriteRule(rule) { 313 | const that = this; 314 | rule.params.forEach(function(param) { 315 | if (param.type === Symbol.Modifier) { 316 | switch (param.key) { 317 | case Symbol.Weight: rule.weight = param.value; break; 318 | case Symbol.Maxdepth: 319 | rule.maxdepth = param.defined ? +that.resolveVarname(param.value) : param.value; 320 | rule.alternate = param.alternate; 321 | break; 322 | } 323 | } 324 | }); 325 | if (!this.rules[rule.id]) this.rules[rule.id] = []; 326 | this.rules[rule.id].push(rule); 327 | return this; 328 | } 329 | 330 | // execute statements 331 | parseStatements(statements) { 332 | let i = 0, len = statements.length; 333 | while (i < len) { 334 | if (this.terminated()) break; 335 | this.parseStatement(statements[i], 0); 336 | i++; 337 | } 338 | return this; 339 | } 340 | 341 | // execute a statement 342 | parseStatement(statement, index) { 343 | // parse transformation expression 344 | const expr = statement.exprs[index]; 345 | if (expr) { 346 | this.pushState(); 347 | let iterations = (typeof expr.left === 'number') ? expr.left : +this.resolveVarname(expr.left); 348 | for (let i = 0; i < iterations; i++) { 349 | if (this.terminated()) break; 350 | this.parseTransformStatement(expr.right); 351 | // if statement.exprs[index + 1] is undefined, it would break the transformation loops. 352 | this.parseStatement(statement, index + 1); 353 | } 354 | this.popState(); 355 | return this; 356 | } 357 | 358 | // if not primitive, call rule and parse next transformation loops 359 | if (statement.type === 'statement') { 360 | this.rules[statement.id].depth = (this.rules[statement.id].depth || 0) + 1; 361 | let rule = this.sampling(statement.id); 362 | if (typeof rule === 'string') { 363 | const name = rule; 364 | this.rules[name].depth = (this.rules[name].depth || 0) + 1; 365 | rule = this.sampling(name); 366 | this.parseStatements(rule.body); 367 | this.rules[name].depth--; 368 | } else if (rule) { 369 | this.parseStatements(rule.body); 370 | } 371 | this.rules[statement.id].depth--; 372 | return this; 373 | } 374 | 375 | // achieve the end of nested transformation loops 376 | if (statement.type === 'primitive') { 377 | this.generatePrimitive(statement); 378 | return this 379 | } 380 | 381 | console.warn(`[eisenscript.js] Invalid statement found: ${JSON.stringify(statement)}`); 382 | return this; 383 | } 384 | 385 | // break down transformation set 386 | parseTransformStatement(transform) { 387 | let i = 0, len = transform.properties.length; 388 | while (i < len) { 389 | this.parseTransform(transform.properties[i]); 390 | i++; 391 | } 392 | return this; 393 | } 394 | 395 | // parse transformation property 396 | parseTransform(property) { 397 | const r = (p) => p.defined ? this.resolveVarname(p.value) : p.value; 398 | const p = property; 399 | const v = property.value; 400 | switch (property.key) { 401 | case Symbol.XShift: this.translate(r(p), 0, 0); break; 402 | case Symbol.YShift: this.translate(0, r(p), 0); break; 403 | case Symbol.ZShift: this.translate(0, 0, r(p)); break; 404 | case Symbol.RotateX: this.rotateX(degToRad(r(p))); break; 405 | case Symbol.RotateY: this.rotateY(degToRad(r(p))); break; 406 | case Symbol.RotateZ: this.rotateZ(degToRad(r(p))); break; 407 | case Symbol.FX: this.multiplyMatrices([-1, 0, 0, 0, 1, 0, 0, 0, 1]); break; 408 | case Symbol.FY: this.multiplyMatrices([1, 0, 0, 0, -1, 0, 0, 0, 1]); break; 409 | case Symbol.FZ: this.multiplyMatrices([1, 0, 0, 0, 1, 0, 0, 0, -1]); break; 410 | case Symbol.Size: 411 | if (p.defined) { 412 | this.scale(+this.resolveVarname(v.x), +this.resolveVarname(v.y), +this.resolveVarname(v.z)); 413 | } else { 414 | this.scale(v.x, v.y, v.z); 415 | } 416 | break; 417 | case Symbol.Matrix: 418 | if (p.defined) { 419 | this.matrix(property.value.map(v => this.resolveVarname(v))); 420 | } else { 421 | this.matrix(property.value); 422 | } 423 | break; 424 | case Symbol.Color: this.setColor(r(p)); break; 425 | case Symbol.Hue: this.setHue(r(p)); break; 426 | case Symbol.Saturation: this.setSaturation(r(p)); break; 427 | case Symbol.Brightness: this.setBrightness(r(p)); break; 428 | case Symbol.Blend: this.setBlend(property.color, property.strength); break; 429 | case Symbol.Alpha: this.setAlpha(r(p)); break; 430 | } 431 | return this; 432 | } 433 | 434 | // create primitive object and stack it as intermediate code for renderer 435 | generatePrimitive(statement) { 436 | // if achieved maxobjects 437 | this.objectnum++; 438 | if (this.terminated()) return; 439 | 440 | const object = { 441 | type: Symbol.Primitive, 442 | name: statement.id, 443 | matrix: this.curr.matrix.clone(), 444 | color: this.curr.hsv.toCSS(), 445 | opacity: this.curr.alpha, 446 | depth: this.depth 447 | }; 448 | 449 | if (statement.id === Primitive.Triangle) { 450 | if (statement.coords) { 451 | if (statement.coords.length !== 3) { 452 | throw new Error('The coordinates should be 3 points as follows: Triangle[0,0,0;1,0,0;0.5,0.5,0.5]'); 453 | } 454 | object.coords = statement.coords; 455 | } 456 | } 457 | 458 | // primitive object 459 | this.objects.push(object); 460 | } 461 | 462 | // create background object code and stack it as intermediate code for renderer 463 | generateBackground(statement) { 464 | if (statement.value === 'random') { 465 | throw new Error('\'background\' expected a valid color identifier: Found: random'); 466 | } 467 | this.objects.push({ 468 | type: Symbol.Background, 469 | color: statement.value 470 | }); 471 | } 472 | 473 | // randomly choose one of the rules according to their weights 474 | sampling(name, retry) { 475 | if (!this.rules[name]) { 476 | throw new Error( 477 | `ReferenceError: '${name}' is not defined. As reported by eisenscript interpreter.`, 478 | `${this.name}.js` 479 | ); 480 | } 481 | 482 | // sum weights of each rules 483 | let sum = 0; 484 | this.rules[name].forEach(function(rule) { 485 | rule.weight = rule.weight || 1; 486 | sum += rule.weight; 487 | }); 488 | 489 | // choosing... 490 | let rand = this.mt.next() * sum; 491 | let chosen; 492 | for (let i = 0; i < this.rules[name].length; i++) { 493 | const rule = this.rules[name][i]; 494 | if (rand - rule.weight > 0) { 495 | rand -= rule.weight 496 | continue; 497 | } 498 | chosen = rule; 499 | break; 500 | } 501 | 502 | // if rule could not be selected, interpreter tries to choose until 3 times 503 | if (!chosen) { 504 | retry = retry || 0; 505 | if (retry < 3) return this.sampling(name, ++retry); 506 | // if achieve max retry count 507 | return false; 508 | } 509 | 510 | // if achieved maxdepth 511 | // NOTE: maybe alternative code 512 | // if (chosen.maxdepth && chosen.maxdepth < this.rules[name].depth) { 513 | // if (chosen.alternate) return chosen.alternate; 514 | // return false 515 | // } 516 | if (chosen.maxdepth && chosen.maxdepth < this.rules[name].depth) { 517 | if (chosen.alternate) return chosen.alternate; 518 | if (this.rules[name].depth >= chosen.maxdepth) return false; 519 | if (this.depth < chosen.maxdepth) return chosen; 520 | return false; 521 | } 522 | 523 | // the rule randomly chosen 524 | return chosen; 525 | } 526 | } 527 | -------------------------------------------------------------------------------- /test/testset/modifiers/weight/w.es.txt: -------------------------------------------------------------------------------- 1 | /+ 2 | set seed 1 3 | 1 * { x 1 } 10 * { y 1 } 10 * { z 1 } oneBox 4 | 5 | rule oneBox w 0.25 6 | { 7 | { color red } box 8 | } 9 | 10 | rule oneBox 11 | { 12 | { color white } box 13 | } 14 | +/ 15 | {"minsize":0.2,"maxsize":1,"seed":1,"objects":[{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":1,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":3,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":5,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":6,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":7,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":9,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":1,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":1,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":5,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":6,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":9,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":2,"14":10,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":1,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":5,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":6,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":7,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":8,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":9,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":3,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":1,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":5,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":6,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":9,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":4,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":1,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":5,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":6,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":9,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":5,"14":10,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":1,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":5,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":6,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":8,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":9,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":6,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":1,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":5,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":6,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":9,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":7,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":1,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":2,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":3,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":5,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":6,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":9,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":8,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":1,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":5,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":6,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":9,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":9,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":1,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":2,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":3,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":4,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":5,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":6,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":7,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":8,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":9,"15":1}},"color":"#FF0000","opacity":1,"depth":4},{"type":"primitive","name":"box","matrix":{"elements":{"0":1,"1":0,"2":0,"3":0,"4":0,"5":1,"6":0,"7":0,"8":0,"9":0,"10":1,"11":0,"12":1,"13":10,"14":10,"15":1}},"color":"#FFFFFF","opacity":1,"depth":4}],"num":100} 16 | --------------------------------------------------------------------------------