├── examples.hip
├── houdini
├── otls
│ ├── merge_register.hda
│ └── threejs_exporter.hda
└── scripts
│ └── python
│ └── houthreeni
│ ├── host
│ ├── favicon.ico
│ ├── hou.html
│ └── js
│ │ ├── houthreeni.js
│ │ ├── OBJLoader.js
│ │ ├── OrbitControls.js
│ │ ├── dat.gui.js
│ │ └── jquery.js
│ ├── session.py
│ ├── server.py
│ ├── pysops.py
│ ├── classes.py
│ └── __init__.py
├── .gitignore
└── README.md
/examples.hip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arqtiq/houTHREEni/HEAD/examples.hip
--------------------------------------------------------------------------------
/houdini/otls/merge_register.hda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arqtiq/houTHREEni/HEAD/houdini/otls/merge_register.hda
--------------------------------------------------------------------------------
/houdini/otls/threejs_exporter.hda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arqtiq/houTHREEni/HEAD/houdini/otls/threejs_exporter.hda
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/host/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arqtiq/houTHREEni/HEAD/houdini/scripts/python/houthreeni/host/favicon.ico
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Houdini scene backups
9 | backup/
10 |
11 | # exports
12 | export/
13 |
14 | # VS
15 | .vs/
16 | .vscode/
17 |
18 | # temp server export
19 | **/host/export.json
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/session.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import hou
3 | import os, sys, shutil
4 | from collections import OrderedDict
5 |
6 | from classes import Exporter
7 | import server
8 |
9 |
10 | Current = None
11 |
12 | def is_exporting():
13 | return not Current == None
14 |
15 | def get_data_dir(node):
16 | path = node.evalParm("path")
17 | _dir = os.path.dirname(path)
18 | _name = os.path.splitext(os.path.basename(path))[0]
19 | return _dir + "/" + _name + "/"
20 |
21 | def clear_dir(dir_path):
22 | for f in os.listdir(dir_path):
23 | os.remove(os.path.join(dir_path, f))
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/server.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import hou
3 | import os, sys, shutil
4 | import subprocess
5 | import webbrowser
6 |
7 | import session
8 |
9 |
10 | Server = None
11 |
12 | host_tree = ["js", "hou.html", "favicon.ico"]
13 |
14 |
15 | def start_server(node, browse):
16 | if is_server_running():
17 | print("Server already running")
18 | return
19 | global Server
20 | path = node.evalParm("path")
21 | if not os.path.exists(path):
22 | hou.ui.displayMessage("Data never exported yet ! Can't start server.")
23 | copy_to_server(node)
24 | # start server
25 | port = str(node.evalParm("port"))
26 | v = int(sys.version[0])
27 | mod = ["", "", "SimpleHTTPServer", "http.server"][v]
28 | os.chdir(get_host_path())
29 | Server = subprocess.Popen(["python", "-m", mod, port])
30 | print("Server started")
31 | if browse:
32 | webbrowser.open("http://localhost:" + port + "/hou.html")
33 |
34 | def get_host_path():
35 | payload_path = os.path.dirname(__file__)
36 | payload_path = os.path.join(payload_path, "host")
37 | return payload_path
38 |
39 | def is_server_running():
40 | if not Server:
41 | return False
42 | return Server.poll() == None
43 |
44 | def has_data_dir(node):
45 | _p = ["geos","packed","instance"]
46 | _p = [node.evalParm(p) for p in _p]
47 | return any(_p)
48 |
49 | def copy_to_server(node):
50 | export_path = node.evalParm("path")
51 | sdir = get_host_path()
52 | target = os.path.join(sdir, "export.json")
53 | shutil.copy(export_path, target)
54 |
55 | if has_data_dir(node):
56 | geo_dir = session.get_data_dir(node)
57 | target_dir = os.path.join(sdir, os.path.basename(os.path.dirname(geo_dir)))
58 | if os.path.exists(target_dir):
59 | shutil.rmtree(target_dir)
60 | shutil.copytree(geo_dir, target_dir)
61 |
62 | def stop_server():
63 | if is_server_running():
64 | Server.terminate()
65 | print("Server Stopped")
66 | else:
67 | print("Server is not running")
68 |
69 | def clean_host_data():
70 | r,dirs,files = list(os.walk(get_host_path()))[0]
71 | for d in dirs:
72 | if d in host_tree: continue
73 | shutil.rmtree(os.path.join(r, d))
74 | for f in files:
75 | if f in host_tree: continue
76 | os.remove(os.path.join(r, f))
77 |
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/pysops.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import hou
3 | import os
4 |
5 | from classes import Frame
6 | import session
7 |
8 |
9 | def sop_pre_save_register_instances(node):
10 | if not session.is_exporting():
11 | return
12 | geo = node.geometry()
13 | ref_geo = node.inputs()[1].geometry()
14 | inst = ref_geo.attribValue("instance")
15 | session.Current.instances[inst] = [p.attribValue("index") for p in ref_geo.iterPoints()]
16 |
17 | save_path = os.path.join(session.get_data_dir(node.parent()), "inst_"+inst+".obj")
18 | geo.addAttrib(hou.attribType.Global, "path", "", False, False)
19 | geo.setGlobalAttribValue("path", save_path)
20 |
21 | def sop_write_pc_frame(geo, idx):
22 | if not session.is_exporting():
23 | return
24 | if not session.Current.meta["pointcloud"]:
25 | return
26 | frame = Frame(idx)
27 | for p in geo.iterPoints():
28 | session.Current.add_point(frame, p)
29 | session.Current.add_pc_frame(frame)
30 |
31 | def sop_write_pack_frame(geo, idx):
32 | if not session.is_exporting():
33 | return
34 | if not session.Current.meta["packed"]:
35 | return
36 | packed_prims = [p for p in geo.iterPrims()
37 | if issubclass(type(p), hou.PackedPrim)]
38 | frame = Frame(idx)
39 | for ppr in packed_prims:
40 | session.Current.add_pack(frame, ppr)
41 | session.Current.add_pack_frame(frame)
42 |
43 | def sop_pre_save(node):
44 | if not session.is_exporting():
45 | return
46 | path = session.get_data_dir(node.parent())
47 | geo = node.geometry()
48 | geo_op = geo.attribValue("imp")
49 |
50 | save_path = ""
51 | if geo_op:
52 | _op = geo_op.replace("/", "_").strip('_')
53 | save_path = path + _op + ".obj"
54 | session.Current.geos[_op] = {"frames": []}
55 |
56 | geo.addAttrib(hou.attribType.Global, "path", "", False, False)
57 | geo.setGlobalAttribValue("path", save_path)
58 |
59 | def sop_pre_save_register_pack(node):
60 | if not session.is_exporting():
61 | return
62 | geo = node.geometry()
63 | for pr in geo.iterPrims():
64 | p = pr.attribValue("path")
65 | p = p.split('/')[-1]
66 | session.Current.packed['fragments'].append(p)
67 |
68 | path = os.path.join(session.get_data_dir(node.parent()), "packed.obj")
69 | geo.addAttrib(hou.attribType.Global, "path", "", False, False)
70 | geo.setGlobalAttribValue("path", path)
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/classes.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import hou
3 | import json
4 | import os
5 | from distutils import dir_util
6 | from collections import OrderedDict
7 |
8 |
9 | class Frame(object):
10 | def __init__(self, idx=-1):
11 | self.index = idx
12 | self.positions = []
13 | self.colors = []
14 | self.transforms = []
15 |
16 | def get_count(self):
17 | return max(len(self.positions), len(self.transforms))
18 |
19 | def to_dict(self):
20 | d = {}
21 | if self.positions:
22 | d["pos"] = self.positions
23 | if self.transforms:
24 | d["transforms"] = self.transforms
25 | if self.colors:
26 | d["col"] = self.colors
27 | return d
28 |
29 | class Exporter(object):
30 | def __init__(self, **kwargs):
31 | self.meta = kwargs
32 | self.pointcloud = {}
33 | self.geos = OrderedDict()
34 | self.packed = {}
35 | self.instances = {}
36 |
37 | if self.meta["packed"]:
38 | self.packed = {'fragments': [], 'frames': []}
39 | if self.meta["pointcloud"]:
40 | self.pointcloud = {'channels': {}, 'frames': []}
41 |
42 | self.fpf = self.fp_list_format
43 |
44 | def add_point(self, frame, point):
45 | if not self.meta["pointcloud"]:
46 | return
47 | if self.pointcloud['channels']['position']:
48 | frame.positions.append(self.fpf(point.position()))
49 | if self.pointcloud['channels']['transforms']:
50 | frame.transforms.append(self.fpf(point.attribValue("xform")))
51 | if self.pointcloud['channels']['color']:
52 | frame.colors.append(self.fpf(point.attribValue("Cd")))
53 |
54 | def add_pc_frame(self, frame):
55 | if not self.meta["pointcloud"]:
56 | return
57 | self.pointcloud['frames'].append(frame)
58 |
59 | def add_pack(self, frame, pprim):
60 | if not self.meta["packed"]:
61 | return
62 | frame.transforms.append(self.fpf(pprim.fullTransform().asTuple()))
63 |
64 | def add_pack_frame(self, frame):
65 | if not self.meta["packed"]:
66 | return
67 | self.packed['frames'].append(frame)
68 |
69 | def fp_list_format(self, tuple_obj):
70 | return [round(p,self.meta['fp_acc']) for p in list(tuple_obj)]
71 |
72 | def dump(self, path):
73 | for g in self.geos:
74 | self.geos[g]["frames"] = [self.fpf(m) for m in self.geos[g]["frames"]]
75 |
76 | dump = { 'header': self.meta }
77 | if self.meta['pointcloud'] and self.pointcloud:
78 | self.pointcloud['frames'] = [f.to_dict() for f in self.pointcloud['frames']]
79 | dump['pointcloud'] = self.pointcloud
80 | if self.meta['packed'] and self.packed:
81 | self.packed['frames'] = [f.to_dict() for f in self.packed['frames']]
82 | dump['packed'] = self.packed
83 | if self.meta['geos'] and self.geos:
84 | dump['geos'] = self.geos
85 | if self.meta['instances'] and self.instances:
86 | dump['instances'] = self.instances
87 |
88 | if not path.endswith(".json"):
89 | path += ".json"
90 | dir_util.mkpath(os.path.dirname(path))
91 | with open(path, "w+") as f:
92 | json.dump(dump, f)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # houTHREEni
2 |
3 | ## Presentation
4 | ### Houdini exporter & JavaScript importer for THREE.js
5 |
6 | This toolset offers an exporter for Houdini and Javascript loading scripts to be used with [THREE.js](https://threejs.org/).
7 |
8 | Showcase : http://gratien-vernier.com/houthreeni \
9 | More tests will appear in the top-right list as development evolves.
10 |
11 | 

12 |
13 | ## Features
14 |
15 | Can be exported and played back in browser :
16 | - Fix count point cloud animated
17 | - Supports PC geometry instancing
18 | - Built-in instancer by attribute (replace CopyToPoint SOP)
19 | - Automatic models export / loading
20 | - Packed Primitives playback
21 | - Automatic fragments optimized export
22 | - Object level (scene) export with transforms animations
23 | - Automatic export
24 | - Runtime sub-frames interpolation
25 | - Allow to reduce payload size (faster client loading time !) and slow motion while keeping smooth animation playback
26 | - HDA can hosts local HTTP server which loads a lightweight HTML / JS setup to test what your exporting in your browser in real time !
27 |
28 | ## How-To
29 |
30 | ### Install
31 | Copy the **/houdini** folder from this repository root in your *$HOME* or *$HSITE*, according to your environment pipeline.
32 |
33 | Or just reference your local GitHub repository in your *houdini.env* file.
34 |
35 | ```
36 | HOUTHREENI = C:\Path\To\GitHub\houTHREEni\houdini
37 | HOUDINI_PATH = $HOUTHREENI;&
38 | ```
39 |
40 | ### Export
41 |
42 | Once installed, simply use the **threejs_exporter** SOP node. \
43 |
\
44 | Consult the attached *examples.hip* file to learn how to use it with different setups.
45 |
46 | ### Playback
47 |
48 | To use the JS loader, you'll need to copy these files to your web site / app from the **/houdini/scripts/python/houthreeni/host/js** folder :
49 | - [three.js](houdini/scripts/python/houthreeni/host/js/three.js) \
50 | Obviously this is THREE.js framework, copy it if you don't use it yet
51 | - [houthreeni.js](houdini/scripts/python/houthreeni/host/js/houthreeni.js) \
52 | This is the loader for the files generated from houdini
53 | - [jquery.js](houdini/scripts/python/houthreeni/host/js/jquery.js) \
54 | JQuery framework; used to async load JSON file
55 |
56 | [dat.gui.js](houdini/scripts/python/houthreeni/host/js/dat.gui.js) and [OrbitControls.js](houdini/scripts/python/houthreeni/host/js/OrbitControls.js) are used for the integrated player (UI and camera controls). They are not mandatory but you can get them too if you want these.
57 |
58 | You can consult [hou.html](houdini/scripts/python/houthreeni/host/hou.html) for an example of integration into a web page.
59 |
60 | ## Future / To-Do
61 |
62 | Improvements Backlog :
63 | - GPU instancing option for PC instances
64 | - Better model loading routine (too much is still assumed)
65 | - Match THREE.js Object3D structure for classes, improve scene management
66 | - Rewing loop mode
67 | - Test and adapt new SOP RBD workflow with packed prims export
68 | - Particle sprites
69 | - Dynamic particles count (birth & death)
70 | - Render options
71 | - Impact web runtime
72 | - Settable from houdini HDA, patches file without full re-export
73 | - Set the way the scene is rendered (materials, PC visibility, ...)
74 | - More scene objects exports (lights)
75 | - Point cloud with primitives (lines, surfaces)
76 |
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/host/hou.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | HouThreeNi Player
6 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
131 |
132 |
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/__init__.py:
--------------------------------------------------------------------------------
1 | from collections import OrderedDict
2 | import os, shutil
3 | import hou
4 |
5 | from classes import Exporter
6 | import server, session
7 |
8 |
9 | # export entry point
10 | def export(node):
11 | # check for errors
12 | errors_node = node.node("ERRORS")
13 | errors_node.cook(True)
14 | if errors_node.geometry().findGlobalAttrib("err"):
15 | hou.ui.displayMessage("Fix the reported errors before exporting")
16 | return
17 |
18 | out_path = node.evalParm("path")
19 | exp_pack = node.evalParm("packed")
20 | exp_xform = node.evalParm("xform")
21 | exp_inst = node.evalParm("instance")
22 | exp_sprite = node.evalParm("sprite")
23 | mode = node.evalParm("mode")
24 | start_frame = node.evalParm("rangex")
25 | use_xform = exp_xform and exp_inst
26 |
27 | session.Current = Exporter(
28 | name = os.path.splitext(os.path.basename(out_path))[0],
29 | pointcloud = 0 if mode == 0 else 1,
30 | packed = exp_pack,
31 | instances = exp_inst,
32 | geos = node.evalParm("geos"),
33 | fp_acc = node.evalParm("dec_acc"),
34 | frames = node.evalParm("rangey") - start_frame + 1)
35 |
36 | # force HDA to recook
37 | node.setHardLocked(True)
38 | node.setHardLocked(False)
39 |
40 | # clear data
41 | _d = session.get_data_dir(node)
42 | if os.path.exists(_d):
43 | session.clear_dir(_d)
44 |
45 | # pointcloud export
46 | in_geo = node.node("IN").geometry()
47 | if mode > 0:
48 | session.Current.pointcloud['channels'] = {
49 | 'count': len(in_geo.iterPoints()),
50 | 'mode': ["none","fix","dynamic"][mode],
51 | 'position': not use_xform,
52 | 'transforms': use_xform,
53 | 'color': node.evalParm("col"),
54 | 'sprite': {'path': node.evalParm("sprite_path"), 'scale': node.evalParm("sprite_scale")}
55 | if exp_sprite else None
56 | }
57 | if mode > 0 or exp_pack:
58 | frames_node = node.node("ALL_FRAMES")
59 | # network trigger : evaluate all frames
60 | frames_node.cook(True)
61 | bbox = frames_node.geometry().boundingBox()
62 | if mode > 0:
63 | session.Current.meta['bb_min'] = list(bbox.minvec())
64 | session.Current.meta['bb_max'] = list(bbox.maxvec())
65 | if mode == 2:
66 | max_count = max([f.get_count() for f in session.Current.pointcloud.frames])
67 | session.Current.pointcloud['channels']['count'] = max_count
68 |
69 | # packed
70 | if exp_pack:
71 | # network trigger : save packed fragments
72 | packed_node = node.node("ALL_PACKED")
73 | packed_node.cook(True)
74 |
75 | # geos
76 | geos = node.evalParm("geos")
77 | if geos:
78 | # network trigger : save all geos
79 | geo_node = node.node("ALL_GEO")
80 | geo_node.cook(True)
81 |
82 | _geo_nodes = OrderedDict()
83 | for g in range(1, geos+1):
84 | n = node.parm("geo" + str(g)).evalAsNode()
85 | a = node.evalParm("animated"+str(g))
86 | session.Current.geos.values()[g-1]["animated"] = a
87 | _geo_nodes[n] = a
88 |
89 | for f in range(start_frame, node.evalParm("rangey")+1):
90 | for i,g in enumerate(_geo_nodes):
91 | if not _geo_nodes[g]:
92 | if f == start_frame:
93 | t = hou.frameToTime(start_frame)
94 | m = g.worldTransformAtTime(t).asTuple()
95 | session.Current.geos.values()[i]["rest"] = m
96 | else:
97 | t = hou.frameToTime(f)
98 | m = g.worldTransformAtTime(t).asTuple()
99 | session.Current.geos.values()[i]["frames"].append(m)
100 |
101 | print("")
102 | if session.Current.pointcloud:
103 | print(str(len(session.Current.pointcloud['frames'])) + " point cloud frames saved")
104 | if session.Current.packed:
105 | print(str(len(session.Current.packed['frames'])) + " packed transforms frames saved")
106 | print(str(len(session.Current.packed['fragments'])) + " packed fragments saved")
107 | print(str(geos) + " geos saved")
108 | print(str(len(session.Current.instances.keys())) + " instance meshes saved")
109 |
110 | session.Current.dump(out_path)
111 | #session.Current = None
112 |
113 | # server copy
114 | if node.evalParm("copy_server"):
115 | cpy = True
116 | if node.evalParm("only_run"):
117 | if not server.is_server_running():
118 | cpy = False
119 | if cpy:
120 | server.copy_to_server(node)
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/host/js/houthreeni.js:
--------------------------------------------------------------------------------
1 |
2 | class HTN_Math {
3 | static matrixInterpolate(m1, m2, frac) {
4 | var t = new THREE.Vector3(), t2 = new THREE.Vector3();
5 | var r = new THREE.Quaternion(), r2 = new THREE.Quaternion();
6 | var s = new THREE.Vector3(), s2 = new THREE.Vector3();
7 | m1.decompose(t, r, s);
8 | m2.decompose(t2, r2, s2);
9 | var _t = t.lerp(t2, frac);
10 | var _r = r.slerp(r2, frac);
11 | var _s = s.lerp(s2, frac);
12 | return new THREE.Matrix4().compose(_t, _r, _s);
13 | }
14 | }
15 |
16 | class HTN_Frame {
17 | positions = [];
18 | colors = [];
19 | transforms = [];
20 |
21 | constructor(channels, input) {
22 | if(channels.position) {
23 | input['pos'].forEach(p =>
24 | this.positions.push(new THREE.Vector3().fromArray(p))
25 | );}
26 | if(channels.transforms) {
27 | input['transforms'].forEach(m => {
28 | var mat = new THREE.Matrix4().fromArray(m);
29 | this.transforms.push(mat);
30 | if('position' in channels)
31 | this.positions.push(new THREE.Vector3().setFromMatrixPosition(mat));
32 | });
33 | }
34 | if(channels.color) {
35 | input['col'].forEach(c =>
36 | this.colors.push(new THREE.Color().fromArray(c))
37 | );}
38 | }
39 | }
40 |
41 | class HTN_Geo {
42 | parent = null;
43 | frames = [];
44 | animated = 0;
45 | rest = new THREE.Matrix4();
46 | name = "";
47 | path = "";
48 | mesh = null;
49 | material = null;
50 | loaded = false;
51 |
52 | constructor(parent, name, input) {
53 | this.parent = parent;
54 | this.name = name;
55 | this.path = parent.workDir + parent.name + "/" + name + ".obj";
56 | this.animated = input["animated"];
57 | if(!this.animated) {
58 | this.rest.fromArray(input["rest"]);
59 | }
60 | else {
61 | input["frames"].forEach(m =>
62 | this.frames.push(new THREE.Matrix4().fromArray(m)));
63 | }
64 |
65 | var loader = new THREE.OBJLoader();
66 | let _this = this;
67 | loader.load(this.path, function(obj) {
68 | _this.mesh = obj;
69 | _this.material = new THREE.MeshPhongMaterial({color: 0xCCCCCC});
70 | _this.mesh.material = _this.material;
71 |
72 | _this.mesh.matrixAutoUpdate = false;
73 | var m = null;
74 | if(_this.animated)
75 | m = _this.frames[0];
76 | else
77 | m = _this.rest;
78 | _this.mesh.applyMatrix4(m);
79 |
80 | _this.loaded = true;
81 | parent.scene.add(_this.mesh);
82 | });
83 | }
84 |
85 | update(frame, frac, nextFrame) {
86 | if(!this.animated)
87 | return;
88 |
89 | var df1 = this.frames[f];
90 | var m = df1;
91 | if(this.parent.subframesInterpolation) {
92 | var df2 = this.frames[nextFrame];
93 | m = HTN_Math.matrixInterpolate(df1, df2, frac);
94 | }
95 | this.mesh.matrix = m;
96 | }
97 | }
98 |
99 | class HTN_Packed {
100 | parent = null;
101 | frames = [];
102 | fragments = [];
103 | material = null;
104 | loaded = false;
105 |
106 | constructor(parent, input) {
107 | this.parent = parent;
108 |
109 | input.frames.forEach(f =>
110 | this.frames.push(new HTN_Frame({'transforms': 1}, f)));
111 |
112 | var loader = new THREE.OBJLoader();
113 | this.material = new THREE.MeshNormalMaterial(/*{color: 0xCCCCCC}*/);
114 | var path = parent.workDir + parent.name + "/packed.obj";
115 | let _this = this;
116 | let i = 0;
117 | loader.load(path, function(obj) {
118 | for(var c of obj.children) {
119 | var mesh = new THREE.Mesh(c.geometry, _this.material);
120 | mesh.matrixAutoUpdate = false;
121 | _this.fragments.push(mesh);
122 |
123 | if(++i == obj.children.length) {
124 | _this.fragments.forEach(f => parent.scene.add(f));
125 | _this.loaded = true;
126 | }
127 | }
128 | });
129 | }
130 |
131 | update(frame, frac, nextFrame) {
132 | if(!this.loaded)
133 | return;
134 |
135 | var df1 = this.frames[frame];
136 | var df2 = this.frames[nextFrame];
137 |
138 | for(var frag = 0; frag < this.fragments.length; frag++) {
139 | var m = df1.transforms[frag];
140 | if(this.parent.subframesInterpolation) {
141 | m = HTN_Math.matrixInterpolate(df1.transforms[frag], df2.transforms[frag], frac);
142 | }
143 | this.fragments[frag].matrix = m;
144 | }
145 | }
146 | }
147 |
148 | class HTN_Instances {
149 | parent = null;
150 | meshes = [];
151 | loaded = false;
152 |
153 | constructor(parent, input) {
154 | this.parent = parent;
155 | var loader = new THREE.OBJLoader();
156 | this.material = new THREE.MeshNormalMaterial(/*{color: 0xCCCCCC}*/);
157 | let _this = this;
158 | let count = Object.keys(input).length;
159 | let i = 0;
160 | for(let inst in input) {
161 | var path = parent.workDir + parent.name + "/inst_" + inst + ".obj";
162 | loader.load(path, function(obj) {
163 | input[inst].forEach((idx) => {
164 | var mesh = new THREE.Mesh(obj.children[0].geometry, _this.material);
165 | mesh.name = idx.toString() + "_" + inst;
166 | mesh.matrixAutoUpdate = false;
167 | _this.meshes[idx] = mesh;
168 | });
169 |
170 | if(++i == count) {
171 | _this.meshes.forEach(m => parent.scene.add(m));
172 | _this.loaded = true;
173 | }
174 | });
175 | }
176 | }
177 |
178 | update(pointIndex, dataFrame, frac, dataNextFrame) {
179 | if(!this.loaded)
180 | return;
181 |
182 | var m = dataFrame.transforms[pointIndex];
183 | if(this.parent.subframesInterpolation) {
184 | m = HTN_Math.matrixInterpolate(m, dataNextFrame.transforms[pointIndex], frac);
185 | }
186 | this.meshes[pointIndex].matrix = m;
187 | }
188 | }
189 | class HTN_Instances_GPU {
190 | instancedMeshes = [];
191 | indicesTable = [];
192 |
193 | constructor(parent, input) {
194 | var loader = new THREE.OBJLoader();
195 | this.material = new THREE.MeshBasicMaterial({color: 0xCCCCCC});
196 | let _this = this;
197 | for(let inst in input) {
198 | var path = parent.workDir + parent.name + "/inst_" + inst + ".obj";
199 | loader.load(path, function(obj) {
200 | var count = input[inst].length;
201 | var buffer = new THREE.InstancedBufferGeometry(obj);
202 | var im = new THREE.InstancedMesh(buffer, _this.material, count);
203 | _this.instancedMeshes.push(im);
204 | input[inst].forEach((idx) => _this.indicesTable[idx] = inst);
205 |
206 | parent.scene.add(im);
207 | });
208 | }
209 | }
210 | }
211 |
212 | class HTN_PointCloud {
213 | parent = null;
214 | frames = [];
215 | channels = {};
216 | count = 0;
217 | particles = null;
218 | material = null;
219 | particleSystem = null;
220 | instances = null;
221 |
222 | constructor(parent, input, instInput=null) {
223 | this.parent = parent;
224 | this.channels = input.channels;
225 | this.count = this.channels.count;
226 | delete this.channels['count'];
227 |
228 | input.frames.forEach(f =>
229 | this.frames.push(new HTN_Frame(this.channels, f)));
230 |
231 | this.particles = new THREE.Geometry();
232 | this.particles.dynamic = true;
233 | this.material = new THREE.PointsMaterial({
234 | vertexColors: THREE.VertexColors,
235 | size: 0.02
236 | });
237 | this.particleSystem = new THREE.Points(this.particles, this.material);
238 |
239 | for(var i = 0; i < this.count; i++) {
240 | this.particles.vertices.push(new THREE.Vector3());
241 | this.particles.colors.push(new THREE.Color());
242 | }
243 |
244 | this.parent.scene.add(this.particleSystem);
245 |
246 | if(instInput != null) {
247 | this.instances = new HTN_Instances(this.parent, instInput);
248 | }
249 | }
250 |
251 | update(frame, frac, nextFrame) {
252 | var df1 = this.frames[frame];
253 | var df2 = this.frames[nextFrame];
254 |
255 | for(var pt = 0; pt < this.count; pt++) {
256 | // pos
257 | var p = new THREE.Vector3().copy(df1.positions[pt]);
258 | if(this.parent.subframesInterpolation) {
259 | p.lerp(df2.positions[pt], frac);
260 | }
261 | this.particles.vertices[pt] = p;
262 | // col
263 | if(this.channels["color"]) {
264 | var c = new THREE.Color().copy(df1.colors[pt]);
265 | if(this.parent.subframesInterpolation) {
266 | c.lerp(df2.colors[pt], frac);
267 | }
268 | this.particles.colors[pt] = c;
269 | }
270 |
271 | // instances
272 | if(this.instances != null) {
273 | this.instances.update(pt, df1, frac, df2);
274 | }
275 | }
276 | this.particles.verticesNeedUpdate = true;
277 | if(this.channels["color"])
278 | this.particles.colorsNeedUpdate = true;
279 | }
280 | }
281 |
282 | class HTN_Data {
283 | pointcloud = null;
284 | geos = [];
285 | packed = null;
286 | instances = null;
287 |
288 | name = "";
289 | workDir = "";
290 | frameCount = 0;
291 |
292 | loaded = false;
293 | loop = true;
294 | framesPerSecond = 30;
295 | subframesInterpolation = true;
296 |
297 | fframe = 0.0;
298 | playing = true;
299 | scene = null;
300 |
301 | constructor(scene, dir, json_file, callback) {
302 | this.scene = scene;
303 | this.workDir = dir;
304 | if(!this.workDir.endsWith("/"))
305 | this.workDir += "/";
306 | let _this = this;
307 | $.getJSON(_this.workDir + json_file, function(result) {
308 | console.log("file opened");
309 | _this.name = result.header.name;
310 | _this.frameCount = result.header.frames;
311 |
312 | if('bb_min' in result.header && 'bb_max' in result.header) {
313 | var bb_min = new THREE.Vector3().fromArray(result.header['bb_min']);
314 | var bb_max = new THREE.Vector3().fromArray(result.header['bb_max']);
315 | _this.bbox = new THREE.Box3(bb_min, bb_max);
316 | }
317 |
318 | if(result.header.pointcloud) {
319 | var inst = null;
320 | if(result.header.instances)
321 | inst = result.instances;
322 | _this.pointcloud = new HTN_PointCloud(_this, result.pointcloud, inst);
323 | }
324 |
325 | if (result.header.geos > 0) {
326 | for(var g in result.geos) {
327 | _this.geos.push(new HTN_Geo(_this, g, result.geos[g]));
328 | }
329 | }
330 |
331 | if(result.header.packed) {
332 | _this.packed = new HTN_Packed(_this, result.packed);
333 | }
334 |
335 | _this.clock = new THREE.Clock();
336 |
337 | callback.call(this);
338 | _this.loaded = true;
339 | });
340 | }
341 |
342 | removeFromScene() {
343 | if(this.pointcloud != null) {
344 | this.scene.remove(this.pointcloud.particleSystem);
345 | if(this.pointcloud.instances != null) {
346 | if(this.pointcloud.instances.loaded) {
347 | this.pointcloud.instances.meshes.forEach(m =>
348 | this.scene.remove(m));
349 | }
350 | }
351 | }
352 | for(var i = 0; i < this.geos.length; i++) {
353 | if(this.geos[i].loaded && this.geos[i].mesh != null) {
354 | this.scene.remove(this.geos[i].mesh);
355 | }
356 | }
357 | if(this.packed) {
358 |
359 | }
360 | }
361 |
362 | update() {
363 | if(!this.loaded)
364 | return;
365 |
366 | var delta = this.clock.getDelta();
367 | if(this.playing) {
368 | this.fframe += delta * this.framesPerSecond;
369 | }
370 | if(this.fframe >= this.frameCount) {
371 | if(this.loop) {
372 | this.fframe = 0.0;
373 | }
374 | else {
375 | this.fframe = this.frameCount - 1;
376 | }
377 | }
378 | var f = Math.floor(this.fframe);
379 | var frac = this.fframe - f;
380 | var nfIdx = Math.min(f+1, this.frameCount-1);
381 |
382 | // pointcloud + instances
383 | if(this.pointcloud != null) {
384 | this.pointcloud.update(f, frac, nfIdx);
385 | }
386 |
387 | // pack
388 | if(this.packed != null) {
389 | this.packed.update(f, frac, nfIdx);
390 | }
391 |
392 | // geos
393 | for(var g of this.geos) {
394 | g.update(f, frac, nfIdx);
395 | }
396 | }
397 | }
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/host/js/OBJLoader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | THREE.OBJLoader = ( function () {
6 |
7 | // o object_name | g group_name
8 | var object_pattern = /^[og]\s*(.+)?/;
9 | // mtllib file_reference
10 | var material_library_pattern = /^mtllib /;
11 | // usemtl material_name
12 | var material_use_pattern = /^usemtl /;
13 | // usemap map_name
14 | var map_use_pattern = /^usemap /;
15 |
16 | function ParserState() {
17 |
18 | var state = {
19 | objects: [],
20 | object: {},
21 |
22 | vertices: [],
23 | normals: [],
24 | colors: [],
25 | uvs: [],
26 |
27 | materials: {},
28 | materialLibraries: [],
29 |
30 | startObject: function ( name, fromDeclaration ) {
31 |
32 | // If the current object (initial from reset) is not from a g/o declaration in the parsed
33 | // file. We need to use it for the first parsed g/o to keep things in sync.
34 | if ( this.object && this.object.fromDeclaration === false ) {
35 |
36 | this.object.name = name;
37 | this.object.fromDeclaration = ( fromDeclaration !== false );
38 | return;
39 |
40 | }
41 |
42 | var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
43 |
44 | if ( this.object && typeof this.object._finalize === 'function' ) {
45 |
46 | this.object._finalize( true );
47 |
48 | }
49 |
50 | this.object = {
51 | name: name || '',
52 | fromDeclaration: ( fromDeclaration !== false ),
53 |
54 | geometry: {
55 | vertices: [],
56 | normals: [],
57 | colors: [],
58 | uvs: []
59 | },
60 | materials: [],
61 | smooth: true,
62 |
63 | startMaterial: function ( name, libraries ) {
64 |
65 | var previous = this._finalize( false );
66 |
67 | // New usemtl declaration overwrites an inherited material, except if faces were declared
68 | // after the material, then it must be preserved for proper MultiMaterial continuation.
69 | if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
70 |
71 | this.materials.splice( previous.index, 1 );
72 |
73 | }
74 |
75 | var material = {
76 | index: this.materials.length,
77 | name: name || '',
78 | mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
79 | smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
80 | groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
81 | groupEnd: - 1,
82 | groupCount: - 1,
83 | inherited: false,
84 |
85 | clone: function ( index ) {
86 |
87 | var cloned = {
88 | index: ( typeof index === 'number' ? index : this.index ),
89 | name: this.name,
90 | mtllib: this.mtllib,
91 | smooth: this.smooth,
92 | groupStart: 0,
93 | groupEnd: - 1,
94 | groupCount: - 1,
95 | inherited: false
96 | };
97 | cloned.clone = this.clone.bind( cloned );
98 | return cloned;
99 |
100 | }
101 | };
102 |
103 | this.materials.push( material );
104 |
105 | return material;
106 |
107 | },
108 |
109 | currentMaterial: function () {
110 |
111 | if ( this.materials.length > 0 ) {
112 |
113 | return this.materials[ this.materials.length - 1 ];
114 |
115 | }
116 |
117 | return undefined;
118 |
119 | },
120 |
121 | _finalize: function ( end ) {
122 |
123 | var lastMultiMaterial = this.currentMaterial();
124 | if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
125 |
126 | lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
127 | lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
128 | lastMultiMaterial.inherited = false;
129 |
130 | }
131 |
132 | // Ignore objects tail materials if no face declarations followed them before a new o/g started.
133 | if ( end && this.materials.length > 1 ) {
134 |
135 | for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) {
136 |
137 | if ( this.materials[ mi ].groupCount <= 0 ) {
138 |
139 | this.materials.splice( mi, 1 );
140 |
141 | }
142 |
143 | }
144 |
145 | }
146 |
147 | // Guarantee at least one empty material, this makes the creation later more straight forward.
148 | if ( end && this.materials.length === 0 ) {
149 |
150 | this.materials.push( {
151 | name: '',
152 | smooth: this.smooth
153 | } );
154 |
155 | }
156 |
157 | return lastMultiMaterial;
158 |
159 | }
160 | };
161 |
162 | // Inherit previous objects material.
163 | // Spec tells us that a declared material must be set to all objects until a new material is declared.
164 | // If a usemtl declaration is encountered while this new object is being parsed, it will
165 | // overwrite the inherited material. Exception being that there was already face declarations
166 | // to the inherited material, then it will be preserved for proper MultiMaterial continuation.
167 |
168 | if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
169 |
170 | var declared = previousMaterial.clone( 0 );
171 | declared.inherited = true;
172 | this.object.materials.push( declared );
173 |
174 | }
175 |
176 | this.objects.push( this.object );
177 |
178 | },
179 |
180 | finalize: function () {
181 |
182 | if ( this.object && typeof this.object._finalize === 'function' ) {
183 |
184 | this.object._finalize( true );
185 |
186 | }
187 |
188 | },
189 |
190 | parseVertexIndex: function ( value, len ) {
191 |
192 | var index = parseInt( value, 10 );
193 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
194 |
195 | },
196 |
197 | parseNormalIndex: function ( value, len ) {
198 |
199 | var index = parseInt( value, 10 );
200 | return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
201 |
202 | },
203 |
204 | parseUVIndex: function ( value, len ) {
205 |
206 | var index = parseInt( value, 10 );
207 | return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
208 |
209 | },
210 |
211 | addVertex: function ( a, b, c ) {
212 |
213 | var src = this.vertices;
214 | var dst = this.object.geometry.vertices;
215 |
216 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
217 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
218 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
219 |
220 | },
221 |
222 | addVertexPoint: function ( a ) {
223 |
224 | var src = this.vertices;
225 | var dst = this.object.geometry.vertices;
226 |
227 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
228 |
229 | },
230 |
231 | addVertexLine: function ( a ) {
232 |
233 | var src = this.vertices;
234 | var dst = this.object.geometry.vertices;
235 |
236 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
237 |
238 | },
239 |
240 | addNormal: function ( a, b, c ) {
241 |
242 | var src = this.normals;
243 | var dst = this.object.geometry.normals;
244 |
245 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
246 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
247 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
248 |
249 | },
250 |
251 | addColor: function ( a, b, c ) {
252 |
253 | var src = this.colors;
254 | var dst = this.object.geometry.colors;
255 |
256 | dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
257 | dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
258 | dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
259 |
260 | },
261 |
262 | addUV: function ( a, b, c ) {
263 |
264 | var src = this.uvs;
265 | var dst = this.object.geometry.uvs;
266 |
267 | dst.push( src[ a + 0 ], src[ a + 1 ] );
268 | dst.push( src[ b + 0 ], src[ b + 1 ] );
269 | dst.push( src[ c + 0 ], src[ c + 1 ] );
270 |
271 | },
272 |
273 | addUVLine: function ( a ) {
274 |
275 | var src = this.uvs;
276 | var dst = this.object.geometry.uvs;
277 |
278 | dst.push( src[ a + 0 ], src[ a + 1 ] );
279 |
280 | },
281 |
282 | addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
283 |
284 | var vLen = this.vertices.length;
285 |
286 | var ia = this.parseVertexIndex( a, vLen );
287 | var ib = this.parseVertexIndex( b, vLen );
288 | var ic = this.parseVertexIndex( c, vLen );
289 |
290 | this.addVertex( ia, ib, ic );
291 |
292 | if ( this.colors.length > 0 ) {
293 |
294 | this.addColor( ia, ib, ic );
295 |
296 | }
297 |
298 | if ( ua !== undefined && ua !== '' ) {
299 |
300 | var uvLen = this.uvs.length;
301 | ia = this.parseUVIndex( ua, uvLen );
302 | ib = this.parseUVIndex( ub, uvLen );
303 | ic = this.parseUVIndex( uc, uvLen );
304 | this.addUV( ia, ib, ic );
305 |
306 | }
307 |
308 | if ( na !== undefined && na !== '' ) {
309 |
310 | // Normals are many times the same. If so, skip function call and parseInt.
311 | var nLen = this.normals.length;
312 | ia = this.parseNormalIndex( na, nLen );
313 |
314 | ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
315 | ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );
316 |
317 | this.addNormal( ia, ib, ic );
318 |
319 | }
320 |
321 | },
322 |
323 | addPointGeometry: function ( vertices ) {
324 |
325 | this.object.geometry.type = 'Points';
326 |
327 | var vLen = this.vertices.length;
328 |
329 | for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
330 |
331 | this.addVertexPoint( this.parseVertexIndex( vertices[ vi ], vLen ) );
332 |
333 | }
334 |
335 | },
336 |
337 | addLineGeometry: function ( vertices, uvs ) {
338 |
339 | this.object.geometry.type = 'Line';
340 |
341 | var vLen = this.vertices.length;
342 | var uvLen = this.uvs.length;
343 |
344 | for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
345 |
346 | this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
347 |
348 | }
349 |
350 | for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
351 |
352 | this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
353 |
354 | }
355 |
356 | }
357 |
358 | };
359 |
360 | state.startObject( '', false );
361 |
362 | return state;
363 |
364 | }
365 |
366 | //
367 |
368 | function OBJLoader( manager ) {
369 |
370 | THREE.Loader.call( this, manager );
371 |
372 | this.materials = null;
373 |
374 | }
375 |
376 | OBJLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
377 |
378 | constructor: OBJLoader,
379 |
380 | load: function ( url, onLoad, onProgress, onError ) {
381 |
382 | var scope = this;
383 |
384 | var loader = new THREE.FileLoader( scope.manager );
385 | loader.setPath( this.path );
386 | loader.load( url, function ( text ) {
387 |
388 | onLoad( scope.parse( text ) );
389 |
390 | }, onProgress, onError );
391 |
392 | },
393 |
394 | setMaterials: function ( materials ) {
395 |
396 | this.materials = materials;
397 |
398 | return this;
399 |
400 | },
401 |
402 | parse: function ( text ) {
403 |
404 | var state = new ParserState();
405 |
406 | if ( text.indexOf( '\r\n' ) !== - 1 ) {
407 |
408 | // This is faster than String.split with regex that splits on both
409 | text = text.replace( /\r\n/g, '\n' );
410 |
411 | }
412 |
413 | if ( text.indexOf( '\\\n' ) !== - 1 ) {
414 |
415 | // join lines separated by a line continuation character (\)
416 | text = text.replace( /\\\n/g, '' );
417 |
418 | }
419 |
420 | var lines = text.split( '\n' );
421 | var line = '', lineFirstChar = '';
422 | var lineLength = 0;
423 | var result = [];
424 |
425 | // Faster to just trim left side of the line. Use if available.
426 | var trimLeft = ( typeof ''.trimLeft === 'function' );
427 |
428 | for ( var i = 0, l = lines.length; i < l; i ++ ) {
429 |
430 | line = lines[ i ];
431 |
432 | line = trimLeft ? line.trimLeft() : line.trim();
433 |
434 | lineLength = line.length;
435 |
436 | if ( lineLength === 0 ) continue;
437 |
438 | lineFirstChar = line.charAt( 0 );
439 |
440 | // @todo invoke passed in handler if any
441 | if ( lineFirstChar === '#' ) continue;
442 |
443 | if ( lineFirstChar === 'v' ) {
444 |
445 | var data = line.split( /\s+/ );
446 |
447 | switch ( data[ 0 ] ) {
448 |
449 | case 'v':
450 | state.vertices.push(
451 | parseFloat( data[ 1 ] ),
452 | parseFloat( data[ 2 ] ),
453 | parseFloat( data[ 3 ] )
454 | );
455 | if ( data.length >= 7 ) {
456 |
457 | state.colors.push(
458 | parseFloat( data[ 4 ] ),
459 | parseFloat( data[ 5 ] ),
460 | parseFloat( data[ 6 ] )
461 |
462 | );
463 |
464 | }
465 | break;
466 | case 'vn':
467 | state.normals.push(
468 | parseFloat( data[ 1 ] ),
469 | parseFloat( data[ 2 ] ),
470 | parseFloat( data[ 3 ] )
471 | );
472 | break;
473 | case 'vt':
474 | state.uvs.push(
475 | parseFloat( data[ 1 ] ),
476 | parseFloat( data[ 2 ] )
477 | );
478 | break;
479 |
480 | }
481 |
482 | } else if ( lineFirstChar === 'f' ) {
483 |
484 | var lineData = line.substr( 1 ).trim();
485 | var vertexData = lineData.split( /\s+/ );
486 | var faceVertices = [];
487 |
488 | // Parse the face vertex data into an easy to work with format
489 |
490 | for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {
491 |
492 | var vertex = vertexData[ j ];
493 |
494 | if ( vertex.length > 0 ) {
495 |
496 | var vertexParts = vertex.split( '/' );
497 | faceVertices.push( vertexParts );
498 |
499 | }
500 |
501 | }
502 |
503 | // Draw an edge between the first vertex and all subsequent vertices to form an n-gon
504 |
505 | var v1 = faceVertices[ 0 ];
506 |
507 | for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
508 |
509 | var v2 = faceVertices[ j ];
510 | var v3 = faceVertices[ j + 1 ];
511 |
512 | state.addFace(
513 | v1[ 0 ], v2[ 0 ], v3[ 0 ],
514 | v1[ 1 ], v2[ 1 ], v3[ 1 ],
515 | v1[ 2 ], v2[ 2 ], v3[ 2 ]
516 | );
517 |
518 | }
519 |
520 | } else if ( lineFirstChar === 'l' ) {
521 |
522 | var lineParts = line.substring( 1 ).trim().split( " " );
523 | var lineVertices = [], lineUVs = [];
524 |
525 | if ( line.indexOf( "/" ) === - 1 ) {
526 |
527 | lineVertices = lineParts;
528 |
529 | } else {
530 |
531 | for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
532 |
533 | var parts = lineParts[ li ].split( "/" );
534 |
535 | if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
536 | if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
537 |
538 | }
539 |
540 | }
541 | state.addLineGeometry( lineVertices, lineUVs );
542 |
543 | } else if ( lineFirstChar === 'p' ) {
544 |
545 | var lineData = line.substr( 1 ).trim();
546 | var pointData = lineData.split( " " );
547 |
548 | state.addPointGeometry( pointData );
549 |
550 | } else if ( ( result = object_pattern.exec( line ) ) !== null ) {
551 |
552 | // o object_name
553 | // or
554 | // g group_name
555 |
556 | // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
557 | // var name = result[ 0 ].substr( 1 ).trim();
558 | var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
559 |
560 | state.startObject( name );
561 |
562 | } else if ( material_use_pattern.test( line ) ) {
563 |
564 | // material
565 |
566 | state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
567 |
568 | } else if ( material_library_pattern.test( line ) ) {
569 |
570 | // mtl file
571 |
572 | state.materialLibraries.push( line.substring( 7 ).trim() );
573 |
574 | } else if ( map_use_pattern.test( line ) ) {
575 |
576 | // the line is parsed but ignored since the loader assumes textures are defined MTL files
577 | // (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
578 |
579 | console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' );
580 |
581 | } else if ( lineFirstChar === 's' ) {
582 |
583 | result = line.split( ' ' );
584 |
585 | // smooth shading
586 |
587 | // @todo Handle files that have varying smooth values for a set of faces inside one geometry,
588 | // but does not define a usemtl for each face set.
589 | // This should be detected and a dummy material created (later MultiMaterial and geometry groups).
590 | // This requires some care to not create extra material on each smooth value for "normal" obj files.
591 | // where explicit usemtl defines geometry groups.
592 | // Example asset: examples/models/obj/cerberus/Cerberus.obj
593 |
594 | /*
595 | * http://paulbourke.net/dataformats/obj/
596 | * or
597 | * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
598 | *
599 | * From chapter "Grouping" Syntax explanation "s group_number":
600 | * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
601 | * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
602 | * surfaces, smoothing groups are either turned on or off; there is no difference between values greater
603 | * than 0."
604 | */
605 | if ( result.length > 1 ) {
606 |
607 | var value = result[ 1 ].trim().toLowerCase();
608 | state.object.smooth = ( value !== '0' && value !== 'off' );
609 |
610 | } else {
611 |
612 | // ZBrush can produce "s" lines #11707
613 | state.object.smooth = true;
614 |
615 | }
616 | var material = state.object.currentMaterial();
617 | if ( material ) material.smooth = state.object.smooth;
618 |
619 | } else {
620 |
621 | // Handle null terminated files without exception
622 | if ( line === '\0' ) continue;
623 |
624 | console.warn( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
625 |
626 | }
627 |
628 | }
629 |
630 | state.finalize();
631 |
632 | var container = new THREE.Group();
633 | container.materialLibraries = [].concat( state.materialLibraries );
634 |
635 | for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
636 |
637 | var object = state.objects[ i ];
638 | var geometry = object.geometry;
639 | var materials = object.materials;
640 | var isLine = ( geometry.type === 'Line' );
641 | var isPoints = ( geometry.type === 'Points' );
642 | var hasVertexColors = false;
643 |
644 | // Skip o/g line declarations that did not follow with any faces
645 | if ( geometry.vertices.length === 0 ) continue;
646 |
647 | var buffergeometry = new THREE.BufferGeometry();
648 |
649 | buffergeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) );
650 |
651 | if ( geometry.normals.length > 0 ) {
652 |
653 | buffergeometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) );
654 |
655 | } else {
656 |
657 | buffergeometry.computeVertexNormals();
658 |
659 | }
660 |
661 | if ( geometry.colors.length > 0 ) {
662 |
663 | hasVertexColors = true;
664 | buffergeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) );
665 |
666 | }
667 |
668 | if ( geometry.uvs.length > 0 ) {
669 |
670 | buffergeometry.setAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) );
671 |
672 | }
673 |
674 | // Create materials
675 |
676 | var createdMaterials = [];
677 |
678 | for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
679 |
680 | var sourceMaterial = materials[ mi ];
681 | var materialHash = sourceMaterial.name + '_' + sourceMaterial.smooth + '_' + hasVertexColors;
682 | var material = state.materials[ materialHash ];
683 |
684 | if ( this.materials !== null ) {
685 |
686 | material = this.materials.create( sourceMaterial.name );
687 |
688 | // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
689 | if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
690 |
691 | var materialLine = new THREE.LineBasicMaterial();
692 | THREE.Material.prototype.copy.call( materialLine, material );
693 | materialLine.color.copy( material.color );
694 | material = materialLine;
695 |
696 | } else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) {
697 |
698 | var materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } );
699 | THREE.Material.prototype.copy.call( materialPoints, material );
700 | materialPoints.color.copy( material.color );
701 | materialPoints.map = material.map;
702 | material = materialPoints;
703 |
704 | }
705 |
706 | }
707 |
708 | if ( material === undefined ) {
709 |
710 | if ( isLine ) {
711 |
712 | material = new THREE.LineBasicMaterial();
713 |
714 | } else if ( isPoints ) {
715 |
716 | material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
717 |
718 | } else {
719 |
720 | material = new THREE.MeshPhongMaterial();
721 |
722 | }
723 |
724 | material.name = sourceMaterial.name;
725 | material.flatShading = sourceMaterial.smooth ? false : true;
726 | material.vertexColors = hasVertexColors ? THREE.VertexColors : THREE.NoColors;
727 |
728 | state.materials[ materialHash ] = material;
729 |
730 | }
731 |
732 | createdMaterials.push( material );
733 |
734 | }
735 |
736 | // Create mesh
737 |
738 | var mesh;
739 |
740 | if ( createdMaterials.length > 1 ) {
741 |
742 | for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
743 |
744 | var sourceMaterial = materials[ mi ];
745 | buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
746 |
747 | }
748 |
749 | if ( isLine ) {
750 |
751 | mesh = new THREE.LineSegments( buffergeometry, createdMaterials );
752 |
753 | } else if ( isPoints ) {
754 |
755 | mesh = new THREE.Points( buffergeometry, createdMaterials );
756 |
757 | } else {
758 |
759 | mesh = new THREE.Mesh( buffergeometry, createdMaterials );
760 |
761 | }
762 |
763 | } else {
764 |
765 | if ( isLine ) {
766 |
767 | mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] );
768 |
769 | } else if ( isPoints ) {
770 |
771 | mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] );
772 |
773 | } else {
774 |
775 | mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] );
776 |
777 | }
778 |
779 | }
780 |
781 | mesh.name = object.name;
782 |
783 | container.add( mesh );
784 |
785 | }
786 |
787 | return container;
788 |
789 | }
790 |
791 | } );
792 |
793 | return OBJLoader;
794 |
795 | } )();
796 |
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/host/js/OrbitControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author qiao / https://github.com/qiao
3 | * @author mrdoob / http://mrdoob.com
4 | * @author alteredq / http://alteredqualia.com/
5 | * @author WestLangley / http://github.com/WestLangley
6 | * @author erich666 / http://erichaines.com
7 | * @author ScieCode / http://github.com/sciecode
8 | */
9 |
10 | // This set of controls performs orbiting, dollying (zooming), and panning.
11 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
12 | //
13 | // Orbit - left mouse / touch: one-finger move
14 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
15 | // Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move
16 |
17 | THREE.OrbitControls = function ( object, domElement ) {
18 |
19 | if ( domElement === undefined ) console.warn( 'THREE.OrbitControls: The second parameter "domElement" is now mandatory.' );
20 | if ( domElement === document ) console.error( 'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' );
21 |
22 | this.object = object;
23 | this.domElement = domElement;
24 |
25 | // Set to false to disable this control
26 | this.enabled = true;
27 |
28 | // "target" sets the location of focus, where the object orbits around
29 | this.target = new THREE.Vector3();
30 |
31 | // How far you can dolly in and out ( PerspectiveCamera only )
32 | this.minDistance = 0;
33 | this.maxDistance = Infinity;
34 |
35 | // How far you can zoom in and out ( OrthographicCamera only )
36 | this.minZoom = 0;
37 | this.maxZoom = Infinity;
38 |
39 | // How far you can orbit vertically, upper and lower limits.
40 | // Range is 0 to Math.PI radians.
41 | this.minPolarAngle = 0; // radians
42 | this.maxPolarAngle = Math.PI; // radians
43 |
44 | // How far you can orbit horizontally, upper and lower limits.
45 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
46 | this.minAzimuthAngle = - Infinity; // radians
47 | this.maxAzimuthAngle = Infinity; // radians
48 |
49 | // Set to true to enable damping (inertia)
50 | // If damping is enabled, you must call controls.update() in your animation loop
51 | this.enableDamping = false;
52 | this.dampingFactor = 0.05;
53 |
54 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
55 | // Set to false to disable zooming
56 | this.enableZoom = true;
57 | this.zoomSpeed = 1.0;
58 |
59 | // Set to false to disable rotating
60 | this.enableRotate = true;
61 | this.rotateSpeed = 1.0;
62 |
63 | // Set to false to disable panning
64 | this.enablePan = true;
65 | this.panSpeed = 1.0;
66 | this.screenSpacePanning = false; // if true, pan in screen-space
67 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
68 |
69 | // Set to true to automatically rotate around the target
70 | // If auto-rotate is enabled, you must call controls.update() in your animation loop
71 | this.autoRotate = false;
72 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
73 |
74 | // Set to false to disable use of the keys
75 | this.enableKeys = true;
76 |
77 | // The four arrow keys
78 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
79 |
80 | // Mouse buttons
81 | this.mouseButtons = { LEFT: THREE.MOUSE.ROTATE, MIDDLE: THREE.MOUSE.DOLLY, RIGHT: THREE.MOUSE.PAN };
82 |
83 | // Touch fingers
84 | this.touches = { ONE: THREE.TOUCH.ROTATE, TWO: THREE.TOUCH.DOLLY_PAN };
85 |
86 | // for reset
87 | this.target0 = this.target.clone();
88 | this.position0 = this.object.position.clone();
89 | this.zoom0 = this.object.zoom;
90 |
91 | //
92 | // public methods
93 | //
94 |
95 | this.getPolarAngle = function () {
96 |
97 | return spherical.phi;
98 |
99 | };
100 |
101 | this.getAzimuthalAngle = function () {
102 |
103 | return spherical.theta;
104 |
105 | };
106 |
107 | this.saveState = function () {
108 |
109 | scope.target0.copy( scope.target );
110 | scope.position0.copy( scope.object.position );
111 | scope.zoom0 = scope.object.zoom;
112 |
113 | };
114 |
115 | this.reset = function () {
116 |
117 | scope.target.copy( scope.target0 );
118 | scope.object.position.copy( scope.position0 );
119 | scope.object.zoom = scope.zoom0;
120 |
121 | scope.object.updateProjectionMatrix();
122 | scope.dispatchEvent( changeEvent );
123 |
124 | scope.update();
125 |
126 | state = STATE.NONE;
127 |
128 | };
129 |
130 | // this method is exposed, but perhaps it would be better if we can make it private...
131 | this.update = function () {
132 |
133 | var offset = new THREE.Vector3();
134 |
135 | // so camera.up is the orbit axis
136 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
137 | var quatInverse = quat.clone().inverse();
138 |
139 | var lastPosition = new THREE.Vector3();
140 | var lastQuaternion = new THREE.Quaternion();
141 |
142 | return function update() {
143 |
144 | var position = scope.object.position;
145 |
146 | offset.copy( position ).sub( scope.target );
147 |
148 | // rotate offset to "y-axis-is-up" space
149 | offset.applyQuaternion( quat );
150 |
151 | // angle from z-axis around y-axis
152 | spherical.setFromVector3( offset );
153 |
154 | if ( scope.autoRotate && state === STATE.NONE ) {
155 |
156 | rotateLeft( getAutoRotationAngle() );
157 |
158 | }
159 |
160 | if ( scope.enableDamping ) {
161 |
162 | spherical.theta += sphericalDelta.theta * scope.dampingFactor;
163 | spherical.phi += sphericalDelta.phi * scope.dampingFactor;
164 |
165 | } else {
166 |
167 | spherical.theta += sphericalDelta.theta;
168 | spherical.phi += sphericalDelta.phi;
169 |
170 | }
171 |
172 | // restrict theta to be between desired limits
173 | spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );
174 |
175 | // restrict phi to be between desired limits
176 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
177 |
178 | spherical.makeSafe();
179 |
180 |
181 | spherical.radius *= scale;
182 |
183 | // restrict radius to be between desired limits
184 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
185 |
186 | // move target to panned location
187 |
188 | if ( scope.enableDamping === true ) {
189 |
190 | scope.target.addScaledVector( panOffset, scope.dampingFactor );
191 |
192 | } else {
193 |
194 | scope.target.add( panOffset );
195 |
196 | }
197 |
198 | offset.setFromSpherical( spherical );
199 |
200 | // rotate offset back to "camera-up-vector-is-up" space
201 | offset.applyQuaternion( quatInverse );
202 |
203 | position.copy( scope.target ).add( offset );
204 |
205 | scope.object.lookAt( scope.target );
206 |
207 | if ( scope.enableDamping === true ) {
208 |
209 | sphericalDelta.theta *= ( 1 - scope.dampingFactor );
210 | sphericalDelta.phi *= ( 1 - scope.dampingFactor );
211 |
212 | panOffset.multiplyScalar( 1 - scope.dampingFactor );
213 |
214 | } else {
215 |
216 | sphericalDelta.set( 0, 0, 0 );
217 |
218 | panOffset.set( 0, 0, 0 );
219 |
220 | }
221 |
222 | scale = 1;
223 |
224 | // update condition is:
225 | // min(camera displacement, camera rotation in radians)^2 > EPS
226 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
227 |
228 | if ( zoomChanged ||
229 | lastPosition.distanceToSquared( scope.object.position ) > EPS ||
230 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
231 |
232 | scope.dispatchEvent( changeEvent );
233 |
234 | lastPosition.copy( scope.object.position );
235 | lastQuaternion.copy( scope.object.quaternion );
236 | zoomChanged = false;
237 |
238 | return true;
239 |
240 | }
241 |
242 | return false;
243 |
244 | };
245 |
246 | }();
247 |
248 | this.dispose = function () {
249 |
250 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
251 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
252 | scope.domElement.removeEventListener( 'wheel', onMouseWheel, false );
253 |
254 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
255 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
256 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false );
257 |
258 | document.removeEventListener( 'mousemove', onMouseMove, false );
259 | document.removeEventListener( 'mouseup', onMouseUp, false );
260 |
261 | scope.domElement.removeEventListener( 'keydown', onKeyDown, false );
262 |
263 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
264 |
265 | };
266 |
267 | //
268 | // internals
269 | //
270 |
271 | var scope = this;
272 |
273 | var changeEvent = { type: 'change' };
274 | var startEvent = { type: 'start' };
275 | var endEvent = { type: 'end' };
276 |
277 | var STATE = {
278 | NONE: - 1,
279 | ROTATE: 0,
280 | DOLLY: 1,
281 | PAN: 2,
282 | TOUCH_ROTATE: 3,
283 | TOUCH_PAN: 4,
284 | TOUCH_DOLLY_PAN: 5,
285 | TOUCH_DOLLY_ROTATE: 6
286 | };
287 |
288 | var state = STATE.NONE;
289 |
290 | var EPS = 0.000001;
291 |
292 | // current position in spherical coordinates
293 | var spherical = new THREE.Spherical();
294 | var sphericalDelta = new THREE.Spherical();
295 |
296 | var scale = 1;
297 | var panOffset = new THREE.Vector3();
298 | var zoomChanged = false;
299 |
300 | var rotateStart = new THREE.Vector2();
301 | var rotateEnd = new THREE.Vector2();
302 | var rotateDelta = new THREE.Vector2();
303 |
304 | var panStart = new THREE.Vector2();
305 | var panEnd = new THREE.Vector2();
306 | var panDelta = new THREE.Vector2();
307 |
308 | var dollyStart = new THREE.Vector2();
309 | var dollyEnd = new THREE.Vector2();
310 | var dollyDelta = new THREE.Vector2();
311 |
312 | function getAutoRotationAngle() {
313 |
314 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
315 |
316 | }
317 |
318 | function getZoomScale() {
319 |
320 | return Math.pow( 0.95, scope.zoomSpeed );
321 |
322 | }
323 |
324 | function rotateLeft( angle ) {
325 |
326 | sphericalDelta.theta -= angle;
327 |
328 | }
329 |
330 | function rotateUp( angle ) {
331 |
332 | sphericalDelta.phi -= angle;
333 |
334 | }
335 |
336 | var panLeft = function () {
337 |
338 | var v = new THREE.Vector3();
339 |
340 | return function panLeft( distance, objectMatrix ) {
341 |
342 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
343 | v.multiplyScalar( - distance );
344 |
345 | panOffset.add( v );
346 |
347 | };
348 |
349 | }();
350 |
351 | var panUp = function () {
352 |
353 | var v = new THREE.Vector3();
354 |
355 | return function panUp( distance, objectMatrix ) {
356 |
357 | if ( scope.screenSpacePanning === true ) {
358 |
359 | v.setFromMatrixColumn( objectMatrix, 1 );
360 |
361 | } else {
362 |
363 | v.setFromMatrixColumn( objectMatrix, 0 );
364 | v.crossVectors( scope.object.up, v );
365 |
366 | }
367 |
368 | v.multiplyScalar( distance );
369 |
370 | panOffset.add( v );
371 |
372 | };
373 |
374 | }();
375 |
376 | // deltaX and deltaY are in pixels; right and down are positive
377 | var pan = function () {
378 |
379 | var offset = new THREE.Vector3();
380 |
381 | return function pan( deltaX, deltaY ) {
382 |
383 | var element = scope.domElement;
384 |
385 | if ( scope.object.isPerspectiveCamera ) {
386 |
387 | // perspective
388 | var position = scope.object.position;
389 | offset.copy( position ).sub( scope.target );
390 | var targetDistance = offset.length();
391 |
392 | // half of the fov is center to top of screen
393 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
394 |
395 | // we use only clientHeight here so aspect ratio does not distort speed
396 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
397 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
398 |
399 | } else if ( scope.object.isOrthographicCamera ) {
400 |
401 | // orthographic
402 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
403 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
404 |
405 | } else {
406 |
407 | // camera neither orthographic nor perspective
408 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
409 | scope.enablePan = false;
410 |
411 | }
412 |
413 | };
414 |
415 | }();
416 |
417 | function dollyIn( dollyScale ) {
418 |
419 | if ( scope.object.isPerspectiveCamera ) {
420 |
421 | scale /= dollyScale;
422 |
423 | } else if ( scope.object.isOrthographicCamera ) {
424 |
425 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
426 | scope.object.updateProjectionMatrix();
427 | zoomChanged = true;
428 |
429 | } else {
430 |
431 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
432 | scope.enableZoom = false;
433 |
434 | }
435 |
436 | }
437 |
438 | function dollyOut( dollyScale ) {
439 |
440 | if ( scope.object.isPerspectiveCamera ) {
441 |
442 | scale *= dollyScale;
443 |
444 | } else if ( scope.object.isOrthographicCamera ) {
445 |
446 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
447 | scope.object.updateProjectionMatrix();
448 | zoomChanged = true;
449 |
450 | } else {
451 |
452 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
453 | scope.enableZoom = false;
454 |
455 | }
456 |
457 | }
458 |
459 | //
460 | // event callbacks - update the object state
461 | //
462 |
463 | function handleMouseDownRotate( event ) {
464 |
465 | rotateStart.set( event.clientX, event.clientY );
466 |
467 | }
468 |
469 | function handleMouseDownDolly( event ) {
470 |
471 | dollyStart.set( event.clientX, event.clientY );
472 |
473 | }
474 |
475 | function handleMouseDownPan( event ) {
476 |
477 | panStart.set( event.clientX, event.clientY );
478 |
479 | }
480 |
481 | function handleMouseMoveRotate( event ) {
482 |
483 | rotateEnd.set( event.clientX, event.clientY );
484 |
485 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
486 |
487 | var element = scope.domElement;
488 |
489 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
490 |
491 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
492 |
493 | rotateStart.copy( rotateEnd );
494 |
495 | scope.update();
496 |
497 | }
498 |
499 | function handleMouseMoveDolly( event ) {
500 |
501 | dollyEnd.set( event.clientX, event.clientY );
502 |
503 | dollyDelta.subVectors( dollyEnd, dollyStart );
504 |
505 | if ( dollyDelta.y > 0 ) {
506 |
507 | dollyIn( getZoomScale() );
508 |
509 | } else if ( dollyDelta.y < 0 ) {
510 |
511 | dollyOut( getZoomScale() );
512 |
513 | }
514 |
515 | dollyStart.copy( dollyEnd );
516 |
517 | scope.update();
518 |
519 | }
520 |
521 | function handleMouseMovePan( event ) {
522 |
523 | panEnd.set( event.clientX, event.clientY );
524 |
525 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
526 |
527 | pan( panDelta.x, panDelta.y );
528 |
529 | panStart.copy( panEnd );
530 |
531 | scope.update();
532 |
533 | }
534 |
535 | function handleMouseUp( /*event*/ ) {
536 |
537 | // no-op
538 |
539 | }
540 |
541 | function handleMouseWheel( event ) {
542 |
543 | if ( event.deltaY < 0 ) {
544 |
545 | dollyOut( getZoomScale() );
546 |
547 | } else if ( event.deltaY > 0 ) {
548 |
549 | dollyIn( getZoomScale() );
550 |
551 | }
552 |
553 | scope.update();
554 |
555 | }
556 |
557 | function handleKeyDown( event ) {
558 |
559 | var needsUpdate = false;
560 |
561 | switch ( event.keyCode ) {
562 |
563 | case scope.keys.UP:
564 | pan( 0, scope.keyPanSpeed );
565 | needsUpdate = true;
566 | break;
567 |
568 | case scope.keys.BOTTOM:
569 | pan( 0, - scope.keyPanSpeed );
570 | needsUpdate = true;
571 | break;
572 |
573 | case scope.keys.LEFT:
574 | pan( scope.keyPanSpeed, 0 );
575 | needsUpdate = true;
576 | break;
577 |
578 | case scope.keys.RIGHT:
579 | pan( - scope.keyPanSpeed, 0 );
580 | needsUpdate = true;
581 | break;
582 |
583 | }
584 |
585 | if ( needsUpdate ) {
586 |
587 | // prevent the browser from scrolling on cursor keys
588 | event.preventDefault();
589 |
590 | scope.update();
591 |
592 | }
593 |
594 |
595 | }
596 |
597 | function handleTouchStartRotate( event ) {
598 |
599 | if ( event.touches.length == 1 ) {
600 |
601 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
602 |
603 | } else {
604 |
605 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
606 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
607 |
608 | rotateStart.set( x, y );
609 |
610 | }
611 |
612 | }
613 |
614 | function handleTouchStartPan( event ) {
615 |
616 | if ( event.touches.length == 1 ) {
617 |
618 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
619 |
620 | } else {
621 |
622 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
623 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
624 |
625 | panStart.set( x, y );
626 |
627 | }
628 |
629 | }
630 |
631 | function handleTouchStartDolly( event ) {
632 |
633 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
634 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
635 |
636 | var distance = Math.sqrt( dx * dx + dy * dy );
637 |
638 | dollyStart.set( 0, distance );
639 |
640 | }
641 |
642 | function handleTouchStartDollyPan( event ) {
643 |
644 | if ( scope.enableZoom ) handleTouchStartDolly( event );
645 |
646 | if ( scope.enablePan ) handleTouchStartPan( event );
647 |
648 | }
649 |
650 | function handleTouchStartDollyRotate( event ) {
651 |
652 | if ( scope.enableZoom ) handleTouchStartDolly( event );
653 |
654 | if ( scope.enableRotate ) handleTouchStartRotate( event );
655 |
656 | }
657 |
658 | function handleTouchMoveRotate( event ) {
659 |
660 | if ( event.touches.length == 1 ) {
661 |
662 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
663 |
664 | } else {
665 |
666 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
667 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
668 |
669 | rotateEnd.set( x, y );
670 |
671 | }
672 |
673 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
674 |
675 | var element = scope.domElement;
676 |
677 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
678 |
679 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
680 |
681 | rotateStart.copy( rotateEnd );
682 |
683 | }
684 |
685 | function handleTouchMovePan( event ) {
686 |
687 | if ( event.touches.length == 1 ) {
688 |
689 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
690 |
691 | } else {
692 |
693 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
694 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
695 |
696 | panEnd.set( x, y );
697 |
698 | }
699 |
700 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
701 |
702 | pan( panDelta.x, panDelta.y );
703 |
704 | panStart.copy( panEnd );
705 |
706 | }
707 |
708 | function handleTouchMoveDolly( event ) {
709 |
710 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
711 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
712 |
713 | var distance = Math.sqrt( dx * dx + dy * dy );
714 |
715 | dollyEnd.set( 0, distance );
716 |
717 | dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
718 |
719 | dollyIn( dollyDelta.y );
720 |
721 | dollyStart.copy( dollyEnd );
722 |
723 | }
724 |
725 | function handleTouchMoveDollyPan( event ) {
726 |
727 | if ( scope.enableZoom ) handleTouchMoveDolly( event );
728 |
729 | if ( scope.enablePan ) handleTouchMovePan( event );
730 |
731 | }
732 |
733 | function handleTouchMoveDollyRotate( event ) {
734 |
735 | if ( scope.enableZoom ) handleTouchMoveDolly( event );
736 |
737 | if ( scope.enableRotate ) handleTouchMoveRotate( event );
738 |
739 | }
740 |
741 | function handleTouchEnd( /*event*/ ) {
742 |
743 | // no-op
744 |
745 | }
746 |
747 | //
748 | // event handlers - FSM: listen for events and reset state
749 | //
750 |
751 | function onMouseDown( event ) {
752 |
753 | if ( scope.enabled === false ) return;
754 |
755 | // Prevent the browser from scrolling.
756 | event.preventDefault();
757 |
758 | // Manually set the focus since calling preventDefault above
759 | // prevents the browser from setting it automatically.
760 |
761 | scope.domElement.focus ? scope.domElement.focus() : window.focus();
762 |
763 | var mouseAction;
764 |
765 | switch ( event.button ) {
766 |
767 | case 0:
768 |
769 | mouseAction = scope.mouseButtons.LEFT;
770 | break;
771 |
772 | case 1:
773 |
774 | mouseAction = scope.mouseButtons.MIDDLE;
775 | break;
776 |
777 | case 2:
778 |
779 | mouseAction = scope.mouseButtons.RIGHT;
780 | break;
781 |
782 | default:
783 |
784 | mouseAction = - 1;
785 |
786 | }
787 |
788 | switch ( mouseAction ) {
789 |
790 | case THREE.MOUSE.DOLLY:
791 |
792 | if ( scope.enableZoom === false ) return;
793 |
794 | handleMouseDownDolly( event );
795 |
796 | state = STATE.DOLLY;
797 |
798 | break;
799 |
800 | case THREE.MOUSE.ROTATE:
801 |
802 | if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
803 |
804 | if ( scope.enablePan === false ) return;
805 |
806 | handleMouseDownPan( event );
807 |
808 | state = STATE.PAN;
809 |
810 | } else {
811 |
812 | if ( scope.enableRotate === false ) return;
813 |
814 | handleMouseDownRotate( event );
815 |
816 | state = STATE.ROTATE;
817 |
818 | }
819 |
820 | break;
821 |
822 | case THREE.MOUSE.PAN:
823 |
824 | if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
825 |
826 | if ( scope.enableRotate === false ) return;
827 |
828 | handleMouseDownRotate( event );
829 |
830 | state = STATE.ROTATE;
831 |
832 | } else {
833 |
834 | if ( scope.enablePan === false ) return;
835 |
836 | handleMouseDownPan( event );
837 |
838 | state = STATE.PAN;
839 |
840 | }
841 |
842 | break;
843 |
844 | default:
845 |
846 | state = STATE.NONE;
847 |
848 | }
849 |
850 | if ( state !== STATE.NONE ) {
851 |
852 | document.addEventListener( 'mousemove', onMouseMove, false );
853 | document.addEventListener( 'mouseup', onMouseUp, false );
854 |
855 | scope.dispatchEvent( startEvent );
856 |
857 | }
858 |
859 | }
860 |
861 | function onMouseMove( event ) {
862 |
863 | if ( scope.enabled === false ) return;
864 |
865 | event.preventDefault();
866 |
867 | switch ( state ) {
868 |
869 | case STATE.ROTATE:
870 |
871 | if ( scope.enableRotate === false ) return;
872 |
873 | handleMouseMoveRotate( event );
874 |
875 | break;
876 |
877 | case STATE.DOLLY:
878 |
879 | if ( scope.enableZoom === false ) return;
880 |
881 | handleMouseMoveDolly( event );
882 |
883 | break;
884 |
885 | case STATE.PAN:
886 |
887 | if ( scope.enablePan === false ) return;
888 |
889 | handleMouseMovePan( event );
890 |
891 | break;
892 |
893 | }
894 |
895 | }
896 |
897 | function onMouseUp( event ) {
898 |
899 | if ( scope.enabled === false ) return;
900 |
901 | handleMouseUp( event );
902 |
903 | document.removeEventListener( 'mousemove', onMouseMove, false );
904 | document.removeEventListener( 'mouseup', onMouseUp, false );
905 |
906 | scope.dispatchEvent( endEvent );
907 |
908 | state = STATE.NONE;
909 |
910 | }
911 |
912 | function onMouseWheel( event ) {
913 |
914 | if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
915 |
916 | event.preventDefault();
917 | event.stopPropagation();
918 |
919 | scope.dispatchEvent( startEvent );
920 |
921 | handleMouseWheel( event );
922 |
923 | scope.dispatchEvent( endEvent );
924 |
925 | }
926 |
927 | function onKeyDown( event ) {
928 |
929 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
930 |
931 | handleKeyDown( event );
932 |
933 | }
934 |
935 | function onTouchStart( event ) {
936 |
937 | if ( scope.enabled === false ) return;
938 |
939 | event.preventDefault();
940 |
941 | switch ( event.touches.length ) {
942 |
943 | case 1:
944 |
945 | switch ( scope.touches.ONE ) {
946 |
947 | case THREE.TOUCH.ROTATE:
948 |
949 | if ( scope.enableRotate === false ) return;
950 |
951 | handleTouchStartRotate( event );
952 |
953 | state = STATE.TOUCH_ROTATE;
954 |
955 | break;
956 |
957 | case THREE.TOUCH.PAN:
958 |
959 | if ( scope.enablePan === false ) return;
960 |
961 | handleTouchStartPan( event );
962 |
963 | state = STATE.TOUCH_PAN;
964 |
965 | break;
966 |
967 | default:
968 |
969 | state = STATE.NONE;
970 |
971 | }
972 |
973 | break;
974 |
975 | case 2:
976 |
977 | switch ( scope.touches.TWO ) {
978 |
979 | case THREE.TOUCH.DOLLY_PAN:
980 |
981 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
982 |
983 | handleTouchStartDollyPan( event );
984 |
985 | state = STATE.TOUCH_DOLLY_PAN;
986 |
987 | break;
988 |
989 | case THREE.TOUCH.DOLLY_ROTATE:
990 |
991 | if ( scope.enableZoom === false && scope.enableRotate === false ) return;
992 |
993 | handleTouchStartDollyRotate( event );
994 |
995 | state = STATE.TOUCH_DOLLY_ROTATE;
996 |
997 | break;
998 |
999 | default:
1000 |
1001 | state = STATE.NONE;
1002 |
1003 | }
1004 |
1005 | break;
1006 |
1007 | default:
1008 |
1009 | state = STATE.NONE;
1010 |
1011 | }
1012 |
1013 | if ( state !== STATE.NONE ) {
1014 |
1015 | scope.dispatchEvent( startEvent );
1016 |
1017 | }
1018 |
1019 | }
1020 |
1021 | function onTouchMove( event ) {
1022 |
1023 | if ( scope.enabled === false ) return;
1024 |
1025 | event.preventDefault();
1026 | event.stopPropagation();
1027 |
1028 | switch ( state ) {
1029 |
1030 | case STATE.TOUCH_ROTATE:
1031 |
1032 | if ( scope.enableRotate === false ) return;
1033 |
1034 | handleTouchMoveRotate( event );
1035 |
1036 | scope.update();
1037 |
1038 | break;
1039 |
1040 | case STATE.TOUCH_PAN:
1041 |
1042 | if ( scope.enablePan === false ) return;
1043 |
1044 | handleTouchMovePan( event );
1045 |
1046 | scope.update();
1047 |
1048 | break;
1049 |
1050 | case STATE.TOUCH_DOLLY_PAN:
1051 |
1052 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
1053 |
1054 | handleTouchMoveDollyPan( event );
1055 |
1056 | scope.update();
1057 |
1058 | break;
1059 |
1060 | case STATE.TOUCH_DOLLY_ROTATE:
1061 |
1062 | if ( scope.enableZoom === false && scope.enableRotate === false ) return;
1063 |
1064 | handleTouchMoveDollyRotate( event );
1065 |
1066 | scope.update();
1067 |
1068 | break;
1069 |
1070 | default:
1071 |
1072 | state = STATE.NONE;
1073 |
1074 | }
1075 |
1076 | }
1077 |
1078 | function onTouchEnd( event ) {
1079 |
1080 | if ( scope.enabled === false ) return;
1081 |
1082 | handleTouchEnd( event );
1083 |
1084 | scope.dispatchEvent( endEvent );
1085 |
1086 | state = STATE.NONE;
1087 |
1088 | }
1089 |
1090 | function onContextMenu( event ) {
1091 |
1092 | if ( scope.enabled === false ) return;
1093 |
1094 | event.preventDefault();
1095 |
1096 | }
1097 |
1098 | //
1099 |
1100 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
1101 |
1102 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
1103 | scope.domElement.addEventListener( 'wheel', onMouseWheel, false );
1104 |
1105 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
1106 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
1107 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
1108 |
1109 | scope.domElement.addEventListener( 'keydown', onKeyDown, false );
1110 |
1111 | // make sure element can receive keys.
1112 |
1113 | if ( scope.domElement.tabIndex === - 1 ) {
1114 |
1115 | scope.domElement.tabIndex = 0;
1116 |
1117 | }
1118 |
1119 | // force an update at start
1120 |
1121 | this.update();
1122 |
1123 | };
1124 |
1125 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
1126 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
1127 |
1128 |
1129 | // This set of controls performs orbiting, dollying (zooming), and panning.
1130 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
1131 | // This is very similar to OrbitControls, another set of touch behavior
1132 | //
1133 | // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate
1134 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
1135 | // Pan - left mouse, or arrow keys / touch: one-finger move
1136 |
1137 | THREE.MapControls = function ( object, domElement ) {
1138 |
1139 | THREE.OrbitControls.call( this, object, domElement );
1140 |
1141 | this.mouseButtons.LEFT = THREE.MOUSE.PAN;
1142 | this.mouseButtons.RIGHT = THREE.MOUSE.ROTATE;
1143 |
1144 | this.touches.ONE = THREE.TOUCH.PAN;
1145 | this.touches.TWO = THREE.TOUCH.DOLLY_ROTATE;
1146 |
1147 | };
1148 |
1149 | THREE.MapControls.prototype = Object.create( THREE.EventDispatcher.prototype );
1150 | THREE.MapControls.prototype.constructor = THREE.MapControls;
1151 |
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/host/js/dat.gui.js:
--------------------------------------------------------------------------------
1 | /**
2 | * dat-gui JavaScript Controller Library
3 | * http://code.google.com/p/dat-gui
4 | *
5 | * Copyright 2011 Data Arts Team, Google Creative Lab
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | */
13 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.dat={})}(this,function(e){"use strict";function t(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),s=e.a,a=Math.round(e.h),l=e.s.toFixed(1),d=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var c=e.hex.toString(16);c.length<6;)c="0"+c;return"#"+c}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+s+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+s+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+s+"}":"HSV_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+"}":"HSVA_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+",a:"+s+"}":"unknown format"}function n(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(I.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(I.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function o(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(I.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(I.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}function i(e){if("0"===e||S.isUndefined(e))return 0;var t=e.match(U);return S.isNull(t)?0:parseFloat(t[1])}function r(e){var t=e.toString();return t.indexOf(".")>-1?t.length-t.indexOf(".")-1:0}function s(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}function a(e,t,n,o,i){return o+(e-t)/(n-t)*(i-o)}function l(e,t,n,o){e.style.background="",S.each(ee,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function d(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}function c(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function u(e){X.unbind(window,"resize",e.__resizeHandler),e.saveToLocalStorageIfPossible&&X.unbind(window,"unload",e.saveToLocalStorageIfPossible)}function _(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];n.innerHTML=t?n.value+"*":n.value}function h(e,t,n){if(n.__li=t,n.__gui=e,S.extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),f(e,n.object,n.property,{before:o,factoryArgs:[S.toArray(arguments)]})}if(S.isArray(t)||S.isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),f(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){return n.__gui.remove(n),n}}),n instanceof q){var o=new Q(n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});S.each(["updateDisplay","onChange","onFinishChange","step","min","max"],function(e){var t=n[e],i=o[e];n[e]=o[e]=function(){var e=Array.prototype.slice.call(arguments);return i.apply(o,e),t.apply(n,e)}}),X.addClass(t,"has-slider"),n.domElement.insertBefore(o.domElement,n.domElement.firstElementChild)}else if(n instanceof Q){var i=function(t){if(S.isNumber(n.__min)&&S.isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=f(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=S.compose(i,n.min),n.max=S.compose(i,n.max)}else n instanceof K?(X.bind(t,"click",function(){X.fakeEvent(n.__checkbox,"click")}),X.bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof Z?(X.bind(t,"click",function(){X.fakeEvent(n.__button,"click")}),X.bind(t,"mouseover",function(){X.addClass(n.__button,"hover")}),X.bind(t,"mouseout",function(){X.removeClass(n.__button,"hover")})):n instanceof $&&(X.addClass(t,"color"),n.updateDisplay=S.compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=S.compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&_(e.getRoot(),!0),t},n.setValue)}function p(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(-1!==o){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,s=void 0;if(r[e.preset])s=r[e.preset];else{if(!r[se])return;s=r[se]}if(s[o]&&void 0!==s[o][t.property]){var a=s[o][t.property];t.initialValue=a,t.setValue(a)}}}}function f(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var i=void 0;if(o.color)i=new $(t,n);else{var r=[t,n].concat(o.factoryArgs);i=ne.apply(e,r)}o.before instanceof z&&(o.before=o.before.__li),p(e,i),X.addClass(i.domElement,"c");var s=document.createElement("span");X.addClass(s,"property-name"),s.innerHTML=i.property;var a=document.createElement("div");a.appendChild(s),a.appendChild(i.domElement);var l=c(e,a,o.before);return X.addClass(l,he.CLASS_CONTROLLER_ROW),i instanceof $?X.addClass(l,"color"):X.addClass(l,H(i.getValue())),h(e,l,i),e.__controllers.push(i),i}function m(e,t){return document.location.href+"."+t}function g(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function b(e,t){t.style.display=e.useLocalStorage?"block":"none"}function v(e){var t=e.__save_row=document.createElement("li");X.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),X.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",X.addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",X.addClass(o,"button"),X.addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",X.addClass(i,"button"),X.addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",X.addClass(r,"button"),X.addClass(r,"revert");var s=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?S.each(e.load.remembered,function(t,n){g(e,n,n===e.preset)}):g(e,se,!1),X.bind(s,"change",function(){for(var t=0;t=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,n){if(e)if(A&&e.forEach&&e.forEach===A)e.forEach(t,n);else if(e.length===e.length+0){var o=void 0,i=void 0;for(o=0,i=e.length;o1?S.toArray(arguments):arguments[0];return S.each(O,function(t){if(t.litmus(e))return S.each(t.conversions,function(t,n){if(T=t.read(e),!1===L&&!1!==T)return L=T,T.conversionName=n,T.conversion=t,S.BREAK}),S.BREAK}),L},B=void 0,N={hsv_to_rgb:function(e,t,n){var o=Math.floor(e/60)%6,i=e/60-Math.floor(e/60),r=n*(1-t),s=n*(1-i*t),a=n*(1-(1-i)*t),l=[[n,a,r],[s,n,r],[r,n,a],[r,s,n],[a,r,n],[n,r,s]][o];return{r:255*l[0],g:255*l[1],b:255*l[2]}},rgb_to_hsv:function(e,t,n){var o=Math.min(e,t,n),i=Math.max(e,t,n),r=i-o,s=void 0,a=void 0;return 0===i?{h:NaN,s:0,v:0}:(a=r/i,s=e===i?(t-n)/r:t===i?2+(n-e)/r:4+(e-t)/r,(s/=6)<0&&(s+=1),{h:360*s,s:a,v:i/255})},rgb_to_hex:function(e,t,n){var o=this.hex_with_component(0,2,e);return o=this.hex_with_component(o,1,t),o=this.hex_with_component(o,0,n)},component_from_hex:function(e,t){return e>>8*t&255},hex_with_component:function(e,t,n){return n<<(B=8*t)|e&~(255<this.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!=0&&(n=Math.round(n/this.__step)*this.__step),j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,n)}},{key:"min",value:function(e){return this.__min=e,this}},{key:"max",value:function(e){return this.__max=e,this}},{key:"step",value:function(e){return this.__step=e,this.__impliedStep=e,this.__precision=r(e),this}}]),t}(),Q=function(e){function t(e,n,o){function i(){l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())}function r(e){var t=d-e.clientY;l.setValue(l.getValue()+t*l.__impliedStep),d=e.clientY}function s(){X.unbind(window,"mousemove",r),X.unbind(window,"mouseup",s),i()}F(this,t);var a=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,o));a.__truncationSuspended=!1;var l=a,d=void 0;return a.__input=document.createElement("input"),a.__input.setAttribute("type","text"),X.bind(a.__input,"change",function(){var e=parseFloat(l.__input.value);S.isNaN(e)||l.setValue(e)}),X.bind(a.__input,"blur",function(){i()}),X.bind(a.__input,"mousedown",function(e){X.bind(window,"mousemove",r),X.bind(window,"mouseup",s),d=e.clientY}),X.bind(a.__input,"keydown",function(e){13===e.keyCode&&(l.__truncationSuspended=!0,this.blur(),l.__truncationSuspended=!1,i())}),a.updateDisplay(),a.domElement.appendChild(a.__input),a}return D(t,W),P(t,[{key:"updateDisplay",value:function(){return this.__input.value=this.__truncationSuspended?this.getValue():s(this.getValue(),this.__precision),j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),q=function(e){function t(e,n,o,i,r){function s(e){e.preventDefault();var t=_.__background.getBoundingClientRect();return _.setValue(a(e.clientX,t.left,t.right,_.__min,_.__max)),!1}function l(){X.unbind(window,"mousemove",s),X.unbind(window,"mouseup",l),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}function d(e){var t=e.touches[0].clientX,n=_.__background.getBoundingClientRect();_.setValue(a(t,n.left,n.right,_.__min,_.__max))}function c(){X.unbind(window,"touchmove",d),X.unbind(window,"touchend",c),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}F(this,t);var u=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,{min:o,max:i,step:r})),_=u;return u.__background=document.createElement("div"),u.__foreground=document.createElement("div"),X.bind(u.__background,"mousedown",function(e){document.activeElement.blur(),X.bind(window,"mousemove",s),X.bind(window,"mouseup",l),s(e)}),X.bind(u.__background,"touchstart",function(e){1===e.touches.length&&(X.bind(window,"touchmove",d),X.bind(window,"touchend",c),d(e))}),X.addClass(u.__background,"slider"),X.addClass(u.__foreground,"slider-fg"),u.updateDisplay(),u.__background.appendChild(u.__foreground),u.domElement.appendChild(u.__background),u}return D(t,W),P(t,[{key:"updateDisplay",value:function(){var e=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*e+"%",j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),Z=function(e){function t(e,n,o){F(this,t);var i=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=i;return i.__button=document.createElement("div"),i.__button.innerHTML=void 0===o?"Fire":o,X.bind(i.__button,"click",function(e){return e.preventDefault(),r.fire(),!1}),X.addClass(i.__button,"button"),i.domElement.appendChild(i.__button),i}return D(t,z),P(t,[{key:"fire",value:function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}}]),t}(),$=function(e){function t(e,n){function o(e){u(e),X.bind(window,"mousemove",u),X.bind(window,"touchmove",u),X.bind(window,"mouseup",r),X.bind(window,"touchend",r)}function i(e){_(e),X.bind(window,"mousemove",_),X.bind(window,"touchmove",_),X.bind(window,"mouseup",s),X.bind(window,"touchend",s)}function r(){X.unbind(window,"mousemove",u),X.unbind(window,"touchmove",u),X.unbind(window,"mouseup",r),X.unbind(window,"touchend",r),c()}function s(){X.unbind(window,"mousemove",_),X.unbind(window,"touchmove",_),X.unbind(window,"mouseup",s),X.unbind(window,"touchend",s),c()}function a(){var e=R(this.value);!1!==e?(p.__color.__state=e,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}function c(){p.__onFinishChange&&p.__onFinishChange.call(p,p.__color.toOriginal())}function u(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__saturation_field.getBoundingClientRect(),n=e.touches&&e.touches[0]||e,o=n.clientX,i=n.clientY,r=(o-t.left)/(t.right-t.left),s=1-(i-t.top)/(t.bottom-t.top);return s>1?s=1:s<0&&(s=0),r>1?r=1:r<0&&(r=0),p.__color.v=s,p.__color.s=r,p.setValue(p.__color.toOriginal()),!1}function _(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__hue_field.getBoundingClientRect(),n=1-((e.touches&&e.touches[0]||e).clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),p.__color.h=360*n,p.setValue(p.__color.toOriginal()),!1}F(this,t);var h=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n));h.__color=new I(h.getValue()),h.__temp=new I(0);var p=h;h.domElement=document.createElement("div"),X.makeSelectable(h.domElement,!1),h.__selector=document.createElement("div"),h.__selector.className="selector",h.__saturation_field=document.createElement("div"),h.__saturation_field.className="saturation-field",h.__field_knob=document.createElement("div"),h.__field_knob.className="field-knob",h.__field_knob_border="2px solid ",h.__hue_knob=document.createElement("div"),h.__hue_knob.className="hue-knob",h.__hue_field=document.createElement("div"),h.__hue_field.className="hue-field",h.__input=document.createElement("input"),h.__input.type="text",h.__input_textShadow="0 1px 1px ",X.bind(h.__input,"keydown",function(e){13===e.keyCode&&a.call(this)}),X.bind(h.__input,"blur",a),X.bind(h.__selector,"mousedown",function(){X.addClass(this,"drag").bind(window,"mouseup",function(){X.removeClass(p.__selector,"drag")})}),X.bind(h.__selector,"touchstart",function(){X.addClass(this,"drag").bind(window,"touchend",function(){X.removeClass(p.__selector,"drag")})});var f=document.createElement("div");return S.extend(h.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),S.extend(h.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:h.__field_knob_border+(h.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),S.extend(h.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),S.extend(h.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),S.extend(f.style,{width:"100%",height:"100%",background:"none"}),l(f,"top","rgba(0,0,0,0)","#000"),S.extend(h.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),d(h.__hue_field),S.extend(h.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:h.__input_textShadow+"rgba(0,0,0,0.7)"}),X.bind(h.__saturation_field,"mousedown",o),X.bind(h.__saturation_field,"touchstart",o),X.bind(h.__field_knob,"mousedown",o),X.bind(h.__field_knob,"touchstart",o),X.bind(h.__hue_field,"mousedown",i),X.bind(h.__hue_field,"touchstart",i),h.__saturation_field.appendChild(f),h.__selector.appendChild(h.__field_knob),h.__selector.appendChild(h.__saturation_field),h.__selector.appendChild(h.__hue_field),h.__hue_field.appendChild(h.__hue_knob),h.domElement.appendChild(h.__input),h.domElement.appendChild(h.__selector),h.updateDisplay(),h}return D(t,z),P(t,[{key:"updateDisplay",value:function(){var e=R(this.getValue());if(!1!==e){var t=!1;S.each(I.COMPONENTS,function(n){if(!S.isUndefined(e[n])&&!S.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&S.extend(this.__color.__state,e)}S.extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;S.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),S.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})}}]),t}(),ee=["-moz-","-o-","-webkit-","-ms-",""],te={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(e){}}},ne=function(e,t){var n=e[t];return S.isArray(arguments[2])||S.isObject(arguments[2])?new Y(e,t,arguments[2]):S.isNumber(n)?S.isNumber(arguments[2])&&S.isNumber(arguments[3])?S.isNumber(arguments[4])?new q(e,t,arguments[2],arguments[3],arguments[4]):new q(e,t,arguments[2],arguments[3]):S.isNumber(arguments[4])?new Q(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new Q(e,t,{min:arguments[2],max:arguments[3]}):S.isString(n)?new J(e,t):S.isFunction(n)?new Z(e,t,""):S.isBoolean(n)?new K(e,t):null},oe=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)},ie=function(){function e(){F(this,e),this.backgroundElement=document.createElement("div"),S.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),X.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),S.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;X.bind(this.backgroundElement,"click",function(){t.hide()})}return P(e,[{key:"show",value:function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),S.defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})}},{key:"hide",value:function(){var e=this,t=function t(){e.domElement.style.display="none",e.backgroundElement.style.display="none",X.unbind(e.domElement,"webkitTransitionEnd",t),X.unbind(e.domElement,"transitionend",t),X.unbind(e.domElement,"oTransitionEnd",t)};X.bind(this.domElement,"webkitTransitionEnd",t),X.bind(this.domElement,"transitionend",t),X.bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"}},{key:"layout",value:function(){this.domElement.style.left=window.innerWidth/2-X.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-X.getHeight(this.domElement)/2+"px"}}]),e}(),re=function(e){if(e&&"undefined"!=typeof window){var t=document.createElement("style");return t.setAttribute("type","text/css"),t.innerHTML=e,document.head.appendChild(t),e}}(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n");te.inject(re);var se="Default",ae=function(){try{return!!window.localStorage}catch(e){return!1}}(),le=void 0,de=!0,ce=void 0,ue=!1,_e=[],he=function e(t){var n=this,o=t||{};this.domElement=document.createElement("div"),this.__ul=document.createElement("ul"),this.domElement.appendChild(this.__ul),X.addClass(this.domElement,"dg"),this.__folders={},this.__controllers=[],this.__rememberedObjects=[],this.__rememberedObjectIndecesToControllers=[],this.__listening=[],o=S.defaults(o,{closeOnTop:!1,autoPlace:!0,width:e.DEFAULT_WIDTH}),o=S.defaults(o,{resizable:o.autoPlace,hideable:o.autoPlace}),S.isUndefined(o.load)?o.load={preset:se}:o.preset&&(o.load.preset=o.preset),S.isUndefined(o.parent)&&o.hideable&&_e.push(this),o.resizable=S.isUndefined(o.parent)&&o.resizable,o.autoPlace&&S.isUndefined(o.scrollable)&&(o.scrollable=!0);var i=ae&&"true"===localStorage.getItem(m(this,"isLocal")),r=void 0,s=void 0;if(Object.defineProperties(this,{parent:{get:function(){return o.parent}},scrollable:{get:function(){return o.scrollable}},autoPlace:{get:function(){return o.autoPlace}},closeOnTop:{get:function(){return o.closeOnTop}},preset:{get:function(){return n.parent?n.getRoot().preset:o.load.preset},set:function(e){n.parent?n.getRoot().preset=e:o.load.preset=e,E(this),n.revert()}},width:{get:function(){return o.width},set:function(e){o.width=e,w(n,e)}},name:{get:function(){return o.name},set:function(e){o.name=e,s&&(s.innerHTML=o.name)}},closed:{get:function(){return o.closed},set:function(t){o.closed=t,o.closed?X.addClass(n.__ul,e.CLASS_CLOSED):X.removeClass(n.__ul,e.CLASS_CLOSED),this.onResize(),n.__closeButton&&(n.__closeButton.innerHTML=t?e.TEXT_OPEN:e.TEXT_CLOSED)}},load:{get:function(){return o.load}},useLocalStorage:{get:function(){return i},set:function(e){ae&&(i=e,e?X.bind(window,"unload",r):X.unbind(window,"unload",r),localStorage.setItem(m(n,"isLocal"),e))}}}),S.isUndefined(o.parent)){if(this.closed=o.closed||!1,X.addClass(this.domElement,e.CLASS_MAIN),X.makeSelectable(this.domElement,!1),ae&&i){n.useLocalStorage=!0;var a=localStorage.getItem(m(this,"gui"));a&&(o.load=JSON.parse(a))}this.__closeButton=document.createElement("div"),this.__closeButton.innerHTML=e.TEXT_CLOSED,X.addClass(this.__closeButton,e.CLASS_CLOSE_BUTTON),o.closeOnTop?(X.addClass(this.__closeButton,e.CLASS_CLOSE_TOP),this.domElement.insertBefore(this.__closeButton,this.domElement.childNodes[0])):(X.addClass(this.__closeButton,e.CLASS_CLOSE_BOTTOM),this.domElement.appendChild(this.__closeButton)),X.bind(this.__closeButton,"click",function(){n.closed=!n.closed})}else{void 0===o.closed&&(o.closed=!0);var l=document.createTextNode(o.name);X.addClass(l,"controller-name"),s=c(n,l);X.addClass(this.__ul,e.CLASS_CLOSED),X.addClass(s,"title"),X.bind(s,"click",function(e){return e.preventDefault(),n.closed=!n.closed,!1}),o.closed||(this.closed=!1)}o.autoPlace&&(S.isUndefined(o.parent)&&(de&&(ce=document.createElement("div"),X.addClass(ce,"dg"),X.addClass(ce,e.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(ce),de=!1),ce.appendChild(this.domElement),X.addClass(this.domElement,e.CLASS_AUTO_PLACE)),this.parent||w(n,o.width)),this.__resizeHandler=function(){n.onResizeDebounced()},X.bind(window,"resize",this.__resizeHandler),X.bind(this.__ul,"webkitTransitionEnd",this.__resizeHandler),X.bind(this.__ul,"transitionend",this.__resizeHandler),X.bind(this.__ul,"oTransitionEnd",this.__resizeHandler),this.onResize(),o.resizable&&y(this),r=function(){ae&&"true"===localStorage.getItem(m(n,"isLocal"))&&localStorage.setItem(m(n,"gui"),JSON.stringify(n.getSaveObject()))},this.saveToLocalStorageIfPossible=r,o.parent||function(){var e=n.getRoot();e.width+=1,S.defer(function(){e.width-=1})}()};he.toggleHide=function(){ue=!ue,S.each(_e,function(e){e.domElement.style.display=ue?"none":""})},he.CLASS_AUTO_PLACE="a",he.CLASS_AUTO_PLACE_CONTAINER="ac",he.CLASS_MAIN="main",he.CLASS_CONTROLLER_ROW="cr",he.CLASS_TOO_TALL="taller-than-window",he.CLASS_CLOSED="closed",he.CLASS_CLOSE_BUTTON="close-button",he.CLASS_CLOSE_TOP="close-top",he.CLASS_CLOSE_BOTTOM="close-bottom",he.CLASS_DRAG="drag",he.DEFAULT_WIDTH=245,he.TEXT_CLOSED="Close Controls",he.TEXT_OPEN="Open Controls",he._keydownHandler=function(e){"text"===document.activeElement.type||72!==e.which&&72!==e.keyCode||he.toggleHide()},X.bind(window,"keydown",he._keydownHandler,!1),S.extend(he.prototype,{add:function(e,t){return f(this,e,t,{factoryArgs:Array.prototype.slice.call(arguments,2)})},addColor:function(e,t){return f(this,e,t,{color:!0})},remove:function(e){this.__ul.removeChild(e.__li),this.__controllers.splice(this.__controllers.indexOf(e),1);var t=this;S.defer(function(){t.onResize()})},destroy:function(){if(this.parent)throw new Error("Only the root GUI should be removed with .destroy(). For subfolders, use gui.removeFolder(folder) instead.");this.autoPlace&&ce.removeChild(this.domElement);var e=this;S.each(this.__folders,function(t){e.removeFolder(t)}),X.unbind(window,"keydown",he._keydownHandler,!1),u(this)},addFolder:function(e){if(void 0!==this.__folders[e])throw new Error('You already have a folder in this GUI by the name "'+e+'"');var t={name:e,parent:this};t.autoPlace=this.autoPlace,this.load&&this.load.folders&&this.load.folders[e]&&(t.closed=this.load.folders[e].closed,t.load=this.load.folders[e]);var n=new he(t);this.__folders[e]=n;var o=c(this,n.domElement);return X.addClass(o,"folder"),n},removeFolder:function(e){this.__ul.removeChild(e.domElement.parentElement),delete this.__folders[e.name],this.load&&this.load.folders&&this.load.folders[e.name]&&delete this.load.folders[e.name],u(e);var t=this;S.each(e.__folders,function(t){e.removeFolder(t)}),S.defer(function(){t.onResize()})},open:function(){this.closed=!1},close:function(){this.closed=!0},hide:function(){this.domElement.style.display="none"},show:function(){this.domElement.style.display=""},onResize:function(){var e=this.getRoot();if(e.scrollable){var t=X.getOffset(e.__ul).top,n=0;S.each(e.__ul.childNodes,function(t){e.autoPlace&&t===e.__save_row||(n+=X.getHeight(t))}),window.innerHeight-t-20\n\n Here\'s the new load parameter for your GUI\'s constructor:\n\n \n\n \n\n
Automatically save\n values to
localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI\'s constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n\n
\n\n
\n\n'),this.parent)throw new Error("You can only call remember on a top level GUI.");var e=this;S.each(Array.prototype.slice.call(arguments),function(t){0===e.__rememberedObjects.length&&v(e),-1===e.__rememberedObjects.indexOf(t)&&e.__rememberedObjects.push(t)}),this.autoPlace&&w(this,this.width)},getRoot:function(){for(var e=this;e.parent;)e=e.parent;return e},getSaveObject:function(){var e=this.load;return e.closed=this.closed,this.__rememberedObjects.length>0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=x(this)),e.folders={},S.each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=x(this),_(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[se]=x(this,!0)),this.load.remembered[e]=x(this),this.preset=e,g(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){S.each(this.__controllers,function(t){this.getRoot().load.remembered?p(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),S.each(this.__folders,function(e){e.revert(e)}),e||_(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&C(this.__listening)},updateDisplay:function(){S.each(this.__controllers,function(e){e.updateDisplay()}),S.each(this.__folders,function(e){e.updateDisplay()})}});var pe={Color:I,math:N,interpret:R},fe={Controller:z,BooleanController:K,OptionController:Y,StringController:J,NumberController:W,NumberControllerBox:Q,NumberControllerSlider:q,FunctionController:Z,ColorController:$},me={dom:X},ge={GUI:he},be=he,ve={color:pe,controllers:fe,dom:me,gui:ge,GUI:be};e.color=pe,e.controllers=fe,e.dom=me,e.gui=ge,e.GUI=be,e.default=ve,Object.defineProperty(e,"__esModule",{value:!0})});
14 |
--------------------------------------------------------------------------------
/houdini/scripts/python/houthreeni/host/js/jquery.js:
--------------------------------------------------------------------------------
1 | /*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
2 | !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/