three.js-r73/0000755000175500017550000000000012610076566012754 5ustar debacledebaclethree.js-r73/utils/0000755000175500017550000000000012640541267014112 5ustar debacledebaclethree.js-r73/utils/converters/0000755000175500017550000000000012610076566016306 5ustar debacledebaclethree.js-r73/utils/converters/obj/0000755000175500017550000000000012610076566017060 5ustar debacledebaclethree.js-r73/utils/converters/obj/split_obj.py0000644000175500017550000003061712610076566021426 0ustar debacledebacle"""Split single OBJ model into mutliple OBJ files by materials ------------------------------------- How to use ------------------------------------- python split_obj.py -i infile.obj -o outfile Will generate: outfile_000.obj outfile_001.obj ... outfile_XXX.obj ------------------------------------- Parser based on format description ------------------------------------- http://en.wikipedia.org/wiki/Obj ------ Author ------ AlteredQualia http://alteredqualia.com """ import fileinput import operator import random import os.path import getopt import sys import struct import math import glob # ##################################################### # Configuration # ##################################################### TRUNCATE = False SCALE = 1.0 # ##################################################### # Templates # ##################################################### TEMPLATE_OBJ = u"""\ ################################ # OBJ generated by split_obj.py ################################ # Faces: %(nfaces)d # Vertices: %(nvertices)d # Normals: %(nnormals)d # UVs: %(nuvs)d ################################ # vertices %(vertices)s # normals %(normals)s # uvs %(uvs)s # faces %(faces)s """ TEMPLATE_VERTEX = "v %f %f %f" TEMPLATE_VERTEX_TRUNCATE = "v %d %d %d" TEMPLATE_NORMAL = "vn %.5g %.5g %.5g" TEMPLATE_UV = "vt %.5g %.5g" TEMPLATE_FACE3_V = "f %d %d %d" TEMPLATE_FACE4_V = "f %d %d %d %d" TEMPLATE_FACE3_VT = "f %d/%d %d/%d %d/%d" TEMPLATE_FACE4_VT = "f %d/%d %d/%d %d/%d %d/%d" TEMPLATE_FACE3_VN = "f %d//%d %d//%d %d//%d" TEMPLATE_FACE4_VN = "f %d//%d %d//%d %d//%d %d//%d" TEMPLATE_FACE3_VTN = "f %d/%d/%d %d/%d/%d %d/%d/%d" TEMPLATE_FACE4_VTN = "f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d" # ##################################################### # Utils # ##################################################### def file_exists(filename): """Return true if file exists and is accessible for reading. Should be safer than just testing for existence due to links and permissions magic on Unix filesystems. @rtype: boolean """ try: f = open(filename, 'r') f.close() return True except IOError: return False # ##################################################### # OBJ parser # ##################################################### def parse_vertex(text): """Parse text chunk specifying single vertex. Possible formats: vertex index vertex index / texture index vertex index / texture index / normal index vertex index / / normal index """ v = 0 t = 0 n = 0 chunks = text.split("/") v = int(chunks[0]) if len(chunks) > 1: if chunks[1]: t = int(chunks[1]) if len(chunks) > 2: if chunks[2]: n = int(chunks[2]) return { 'v': v, 't': t, 'n': n } def parse_obj(fname): """Parse OBJ file. """ vertices = [] normals = [] uvs = [] faces = [] materials = {} mcounter = 0 mcurrent = 0 mtllib = "" # current face state group = 0 object = 0 smooth = 0 for line in fileinput.input(fname): chunks = line.split() if len(chunks) > 0: # Vertices as (x,y,z) coordinates # v 0.123 0.234 0.345 if chunks[0] == "v" and len(chunks) == 4: x = float(chunks[1]) y = float(chunks[2]) z = float(chunks[3]) vertices.append([x,y,z]) # Normals in (x,y,z) form; normals might not be unit # vn 0.707 0.000 0.707 if chunks[0] == "vn" and len(chunks) == 4: x = float(chunks[1]) y = float(chunks[2]) z = float(chunks[3]) normals.append([x,y,z]) # Texture coordinates in (u,v[,w]) coordinates, w is optional # vt 0.500 -1.352 [0.234] if chunks[0] == "vt" and len(chunks) >= 3: u = float(chunks[1]) v = float(chunks[2]) w = 0 if len(chunks)>3: w = float(chunks[3]) uvs.append([u,v,w]) # Face if chunks[0] == "f" and len(chunks) >= 4: vertex_index = [] uv_index = [] normal_index = [] for v in chunks[1:]: vertex = parse_vertex(v) if vertex['v']: vertex_index.append(vertex['v']) if vertex['t']: uv_index.append(vertex['t']) if vertex['n']: normal_index.append(vertex['n']) faces.append({ 'vertex':vertex_index, 'uv':uv_index, 'normal':normal_index, 'material':mcurrent, 'group':group, 'object':object, 'smooth':smooth, }) # Group if chunks[0] == "g" and len(chunks) == 2: group = chunks[1] # Object if chunks[0] == "o" and len(chunks) == 2: object = chunks[1] # Materials definition if chunks[0] == "mtllib" and len(chunks) == 2: mtllib = chunks[1] # Material if chunks[0] == "usemtl" and len(chunks) == 2: material = chunks[1] if not material in materials: mcurrent = mcounter materials[material] = mcounter mcounter += 1 else: mcurrent = materials[material] # Smooth shading if chunks[0] == "s" and len(chunks) == 2: smooth = chunks[1] return faces, vertices, uvs, normals, materials, mtllib # ############################################################################# # API - Breaker # ############################################################################# def break_obj(infile, outfile): """Break infile.obj to outfile.obj """ if not file_exists(infile): print "Couldn't find [%s]" % infile return faces, vertices, uvs, normals, materials, mtllib = parse_obj(infile) # sort faces by materials chunks = {} for face in faces: material = face["material"] if not material in chunks: chunks[material] = {"faces": [], "vertices": set(), "normals": set(), "uvs": set()} chunks[material]["faces"].append(face) # extract unique vertex / normal / uv indices used per chunk for material in chunks: chunk = chunks[material] for face in chunk["faces"]: for i in face["vertex"]: chunk["vertices"].add(i) for i in face["normal"]: chunk["normals"].add(i) for i in face["uv"]: chunk["uvs"].add(i) # generate new OBJs for mi, material in enumerate(chunks): chunk = chunks[material] # generate separate vertex / normal / uv index lists for each chunk # (including mapping from original to new indices) # get well defined order new_vertices = list(chunk["vertices"]) new_normals = list(chunk["normals"]) new_uvs = list(chunk["uvs"]) # map original => new indices vmap = {} for i, v in enumerate(new_vertices): vmap[v] = i + 1 nmap = {} for i, n in enumerate(new_normals): nmap[n] = i + 1 tmap = {} for i, t in enumerate(new_uvs): tmap[t] = i + 1 # vertices pieces = [] for i in new_vertices: vertex = vertices[i-1] txt = TEMPLATE_VERTEX % (vertex[0], vertex[1], vertex[2]) pieces.append(txt) str_vertices = "\n".join(pieces) # normals pieces = [] for i in new_normals: normal = normals[i-1] txt = TEMPLATE_NORMAL % (normal[0], normal[1], normal[2]) pieces.append(txt) str_normals = "\n".join(pieces) # uvs pieces = [] for i in new_uvs: uv = uvs[i-1] txt = TEMPLATE_UV % (uv[0], uv[1]) pieces.append(txt) str_uvs = "\n".join(pieces) # faces pieces = [] for face in chunk["faces"]: txt = "" fv = face["vertex"] fn = face["normal"] ft = face["uv"] if len(fv) == 3: va = vmap[fv[0]] vb = vmap[fv[1]] vc = vmap[fv[2]] if len(fn) == 3 and len(ft) == 3: na = nmap[fn[0]] nb = nmap[fn[1]] nc = nmap[fn[2]] ta = tmap[ft[0]] tb = tmap[ft[1]] tc = tmap[ft[2]] txt = TEMPLATE_FACE3_VTN % (va, ta, na, vb, tb, nb, vc, tc, nc) elif len(fn) == 3: na = nmap[fn[0]] nb = nmap[fn[1]] nc = nmap[fn[2]] txt = TEMPLATE_FACE3_VN % (va, na, vb, nb, vc, nc) elif len(ft) == 3: ta = tmap[ft[0]] tb = tmap[ft[1]] tc = tmap[ft[2]] txt = TEMPLATE_FACE3_VT % (va, ta, vb, tb, vc, tc) else: txt = TEMPLATE_FACE3_V % (va, vb, vc) elif len(fv) == 4: va = vmap[fv[0]] vb = vmap[fv[1]] vc = vmap[fv[2]] vd = vmap[fv[3]] if len(fn) == 4 and len(ft) == 4: na = nmap[fn[0]] nb = nmap[fn[1]] nc = nmap[fn[2]] nd = nmap[fn[3]] ta = tmap[ft[0]] tb = tmap[ft[1]] tc = tmap[ft[2]] td = tmap[ft[3]] txt = TEMPLATE_FACE4_VTN % (va, ta, na, vb, tb, nb, vc, tc, nc, vd, td, nd) elif len(fn) == 4: na = nmap[fn[0]] nb = nmap[fn[1]] nc = nmap[fn[2]] nd = nmap[fn[3]] txt = TEMPLATE_FACE4_VN % (va, na, vb, nb, vc, nc, vd, nd) elif len(ft) == 4: ta = tmap[ft[0]] tb = tmap[ft[1]] tc = tmap[ft[2]] td = tmap[ft[3]] txt = TEMPLATE_FACE4_VT % (va, ta, vb, tb, vc, tc, vd, td) else: txt = TEMPLATE_FACE4_V % (va, vb, vc, vd) pieces.append(txt) str_faces = "\n".join(pieces) # generate OBJ string content = TEMPLATE_OBJ % { "nfaces" : len(chunk["faces"]), "nvertices" : len(new_vertices), "nnormals" : len(new_normals), "nuvs" : len(new_uvs), "vertices" : str_vertices, "normals" : str_normals, "uvs" : str_uvs, "faces" : str_faces } # write OBJ file outname = "%s_%03d.obj" % (outfile, mi) f = open(outname, "w") f.write(content) f.close() # ############################################################################# # Helpers # ############################################################################# def usage(): print "Usage: %s -i filename.obj -o prefix" % os.path.basename(sys.argv[0]) # ##################################################### # Main # ##################################################### if __name__ == "__main__": # get parameters from the command line try: opts, args = getopt.getopt(sys.argv[1:], "hi:o:x:", ["help", "input=", "output=", "truncatescale="]) except getopt.GetoptError: usage() sys.exit(2) infile = outfile = "" for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-i", "--input"): infile = a elif o in ("-o", "--output"): outfile = a elif o in ("-x", "--truncatescale"): TRUNCATE = True SCALE = float(a) if infile == "" or outfile == "": usage() sys.exit(2) print "Splitting [%s] into [%s_XXX.obj] ..." % (infile, outfile) break_obj(infile, outfile) three.js-r73/utils/converters/obj/convert_obj_three.py0000644000175500017550000013701112610076566023136 0ustar debacledebacle"""Convert Wavefront OBJ / MTL files into Three.js (JSON model version, to be used with ascii / binary loader) ------------------------- How to use this converter ------------------------- python convert_obj_three.py -i infile.obj -o outfile.js [-m "morphfiles*.obj"] [-c "morphcolors*.obj"] [-a center|centerxz|top|bottom|none] [-s smooth|flat] [-t ascii|binary] [-d invert|normal] [-b] [-e] Notes: - flags -i infile.obj input OBJ file -o outfile.js output JS file -m "morphfiles*.obj" morph OBJ files (can use wildcards, enclosed in quotes multiple patterns separate by space) -c "morphcolors*.obj" morph colors OBJ files (can use wildcards, enclosed in quotes multiple patterns separate by space) -a center|centerxz|top|bottom|none model alignment -s smooth|flat smooth = export vertex normals, flat = no normals (face normals computed in loader) -t ascii|binary export ascii or binary format (ascii has more features, binary just supports vertices, faces, normals, uvs and materials) -d invert|normal invert transparency -b bake material colors into face colors -x 10.0 scale and truncate -f 2 morph frame sampling step - by default: use smooth shading (if there were vertex normals in the original model) will be in ASCII format original model is assumed to use non-inverted transparency / dissolve (0.0 fully transparent, 1.0 fully opaque) no face colors baking no scale and truncate morph frame step = 1 (all files will be processed) - binary conversion will create two files: outfile.js (materials) outfile.bin (binary buffers) -------------------------------------------------- How to use generated JS file in your HTML document -------------------------------------------------- ... ------------------------------------- Parsers based on formats descriptions ------------------------------------- http://en.wikipedia.org/wiki/Obj http://en.wikipedia.org/wiki/Material_Template_Library ------------------- Current limitations ------------------- - for the moment, only diffuse color and texture are used (will need to extend shaders / renderers / materials in Three) - texture coordinates can be wrong in canvas renderer (there is crude normalization, but it doesn't work for all cases) - smoothing can be turned on/off only for the whole mesh ---------------------------------------------- How to get proper OBJ + MTL files with Blender ---------------------------------------------- 0. Remove default cube (press DEL and ENTER) 1. Import / create model 2. Select all meshes (Select -> Select All by Type -> Mesh) 3. Export to OBJ (File -> Export -> Wavefront .obj) - enable following options in exporter Material Groups Rotate X90 Apply Modifiers High Quality Normals Copy Images Selection Only Objects as OBJ Objects UVs Normals Materials - select empty folder - give your exported file name with "obj" extension - click on "Export OBJ" button 4. Your model is now all files in this folder (OBJ, MTL, number of images) - this converter assumes all files staying in the same folder, (OBJ / MTL files use relative paths) - for WebGL, textures must be power of 2 sized ------ Author ------ AlteredQualia http://alteredqualia.com """ import fileinput import operator import random import os.path import getopt import sys import struct import math import glob # ##################################################### # Configuration # ##################################################### ALIGN = "none" # center centerxz bottom top none SHADING = "smooth" # smooth flat TYPE = "ascii" # ascii binary TRANSPARENCY = "normal" # normal invert TRUNCATE = False SCALE = 1.0 FRAMESTEP = 1 BAKE_COLORS = False # default colors for debugging (each material gets one distinct color): # white, red, green, blue, yellow, cyan, magenta COLORS = [0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee] # ##################################################### # Templates # ##################################################### TEMPLATE_FILE_ASCII = u"""\ { "metadata" : { "formatVersion" : 3.1, "sourceFile" : "%(fname)s", "generatedBy" : "OBJConverter", "vertices" : %(nvertex)d, "faces" : %(nface)d, "normals" : %(nnormal)d, "colors" : %(ncolor)d, "uvs" : %(nuv)d, "materials" : %(nmaterial)d }, "scale" : %(scale)f, "materials": [%(materials)s], "vertices": [%(vertices)s], "morphTargets": [%(morphTargets)s], "morphColors": [%(morphColors)s], "normals": [%(normals)s], "colors": [%(colors)s], "uvs": [[%(uvs)s]], "faces": [%(faces)s] } """ TEMPLATE_FILE_BIN = u"""\ { "metadata" : { "formatVersion" : 3.1, "sourceFile" : "%(fname)s", "generatedBy" : "OBJConverter", "vertices" : %(nvertex)d, "faces" : %(nface)d, "normals" : %(nnormal)d, "uvs" : %(nuv)d, "materials" : %(nmaterial)d }, "materials": [%(materials)s], "buffers": "%(buffers)s" } """ TEMPLATE_VERTEX = "%f,%f,%f" TEMPLATE_VERTEX_TRUNCATE = "%d,%d,%d" TEMPLATE_N = "%.5g,%.5g,%.5g" TEMPLATE_UV = "%.5g,%.5g" TEMPLATE_COLOR = "%.3g,%.3g,%.3g" TEMPLATE_COLOR_DEC = "%d" TEMPLATE_MORPH_VERTICES = '\t{ "name": "%s", "vertices": [%s] }' TEMPLATE_MORPH_COLORS = '\t{ "name": "%s", "colors": [%s] }' # ##################################################### # Utils # ##################################################### def file_exists(filename): """Return true if file exists and is accessible for reading. Should be safer than just testing for existence due to links and permissions magic on Unix filesystems. @rtype: boolean """ try: f = open(filename, 'r') f.close() return True except IOError: return False def get_name(fname): """Create model name based of filename ("path/fname.js" -> "fname"). """ return os.path.splitext(os.path.basename(fname))[0] def bbox(vertices): """Compute bounding box of vertex array. """ if len(vertices)>0: minx = maxx = vertices[0][0] miny = maxy = vertices[0][1] minz = maxz = vertices[0][2] for v in vertices[1:]: if v[0]maxx: maxx = v[0] if v[1]maxy: maxy = v[1] if v[2]maxz: maxz = v[2] return { 'x':[minx,maxx], 'y':[miny,maxy], 'z':[minz,maxz] } else: return { 'x':[0,0], 'y':[0,0], 'z':[0,0] } def translate(vertices, t): """Translate array of vertices by vector t. """ for i in xrange(len(vertices)): vertices[i][0] += t[0] vertices[i][1] += t[1] vertices[i][2] += t[2] def center(vertices): """Center model (middle of bounding box). """ bb = bbox(vertices) cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0 cy = bb['y'][0] + (bb['y'][1] - bb['y'][0])/2.0 cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0 translate(vertices, [-cx,-cy,-cz]) def top(vertices): """Align top of the model with the floor (Y-axis) and center it around X and Z. """ bb = bbox(vertices) cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0 cy = bb['y'][1] cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0 translate(vertices, [-cx,-cy,-cz]) def bottom(vertices): """Align bottom of the model with the floor (Y-axis) and center it around X and Z. """ bb = bbox(vertices) cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0 cy = bb['y'][0] cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0 translate(vertices, [-cx,-cy,-cz]) def centerxz(vertices): """Center model around X and Z. """ bb = bbox(vertices) cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0 cy = 0 cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0 translate(vertices, [-cx,-cy,-cz]) def normalize(v): """Normalize 3d vector""" l = math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) if l: v[0] /= l v[1] /= l v[2] /= l def veckey3(v): return round(v[0], 6), round(v[1], 6), round(v[2], 6) # ##################################################### # MTL parser # ##################################################### def texture_relative_path(fullpath): texture_file = os.path.basename(fullpath.replace("\\", "/")) return texture_file def parse_mtl(fname): """Parse MTL file. """ materials = {} previous_line = "" for line in fileinput.input(fname): line = previous_line + line if line[-2:-1] == '\\': previous_line = line[:-2] continue previous_line = "" # Only split once initially for single-parameter tags that might have additional spaces in # their values (i.e. "newmtl Material with spaces"). chunks = line.split(None, 1) if len(chunks) > 0: if len(chunks) > 1: chunks[1] = chunks[1].strip() # Material start # newmtl identifier if chunks[0] == "newmtl": if len(chunks) > 1: identifier = chunks[1] else: identifier = "" if not identifier in materials: materials[identifier] = {} # Diffuse texture # map_Kd texture_diffuse.jpg if chunks[0] == "map_Kd" and len(chunks) == 2: materials[identifier]["mapDiffuse"] = texture_relative_path(chunks[1]) # Ambient texture # map_Ka texture_ambient.jpg if chunks[0] == "map_Ka" and len(chunks) == 2: materials[identifier]["mapAmbient"] = texture_relative_path(chunks[1]) # Specular texture # map_Ks texture_specular.jpg if chunks[0] == "map_Ks" and len(chunks) == 2: materials[identifier]["mapSpecular"] = texture_relative_path(chunks[1]) # Alpha texture # map_d texture_alpha.png if chunks[0] == "map_d" and len(chunks) == 2: materials[identifier]["transparent"] = True materials[identifier]["mapAlpha"] = texture_relative_path(chunks[1]) # Bump texture # map_bump texture_bump.jpg or bump texture_bump.jpg if (chunks[0] == "map_bump" or chunks[0] == "bump") and len(chunks) == 2: materials[identifier]["mapBump"] = texture_relative_path(chunks[1]) # Split the remaining parameters. if len(chunks) > 1: chunks = [chunks[0]] + chunks[1].split() # Diffuse color # Kd 1.000 1.000 1.000 if chunks[0] == "Kd" and len(chunks) == 4: materials[identifier]["colorDiffuse"] = [float(chunks[1]), float(chunks[2]), float(chunks[3])] # Ambient color # Ka 1.000 1.000 1.000 if chunks[0] == "Ka" and len(chunks) == 4: materials[identifier]["colorAmbient"] = [float(chunks[1]), float(chunks[2]), float(chunks[3])] # Specular color # Ks 1.000 1.000 1.000 if chunks[0] == "Ks" and len(chunks) == 4: materials[identifier]["colorSpecular"] = [float(chunks[1]), float(chunks[2]), float(chunks[3])] # Specular coefficient # Ns 154.000 if chunks[0] == "Ns" and len(chunks) == 2: materials[identifier]["specularCoef"] = float(chunks[1]) # Transparency # Tr 0.9 or d 0.9 if (chunks[0] == "Tr" or chunks[0] == "d") and len(chunks) == 2: materials[identifier]["transparent"] = True if TRANSPARENCY == "invert": materials[identifier]["opacity"] = float(chunks[1]) else: materials[identifier]["opacity"] = 1.0 - float(chunks[1]) # Optical density # Ni 1.0 if chunks[0] == "Ni" and len(chunks) == 2: materials[identifier]["opticalDensity"] = float(chunks[1]) # Illumination # illum 2 # # 0. Color on and Ambient off # 1. Color on and Ambient on # 2. Highlight on # 3. Reflection on and Ray trace on # 4. Transparency: Glass on, Reflection: Ray trace on # 5. Reflection: Fresnel on and Ray trace on # 6. Transparency: Refraction on, Reflection: Fresnel off and Ray trace on # 7. Transparency: Refraction on, Reflection: Fresnel on and Ray trace on # 8. Reflection on and Ray trace off # 9. Transparency: Glass on, Reflection: Ray trace off # 10. Casts shadows onto invisible surfaces if chunks[0] == "illum" and len(chunks) == 2: materials[identifier]["illumination"] = int(chunks[1]) return materials # ##################################################### # OBJ parser # ##################################################### def parse_vertex(text): """Parse text chunk specifying single vertex. Possible formats: vertex index vertex index / texture index vertex index / texture index / normal index vertex index / / normal index """ v = 0 t = 0 n = 0 chunks = text.split("/") v = int(chunks[0]) if len(chunks) > 1: if chunks[1]: t = int(chunks[1]) if len(chunks) > 2: if chunks[2]: n = int(chunks[2]) return { 'v':v, 't':t, 'n':n } def parse_obj(fname): """Parse OBJ file. """ vertices = [] normals = [] uvs = [] faces = [] materials = {} material = "" mcounter = 0 mcurrent = 0 mtllib = "" # current face state group = 0 object = 0 smooth = 0 previous_line = "" for line in fileinput.input(fname): line = previous_line + line if line[-2:-1] == '\\': previous_line = line[:-2] continue previous_line = "" # Only split once initially for single-parameter tags that might have additional spaces in # their values (i.e. "usemtl Material with spaces"). chunks = line.split(None, 1) if len(chunks) > 0: if len(chunks) > 1: chunks[1] = chunks[1].strip() # Group if chunks[0] == "g" and len(chunks) == 2: group = chunks[1] # Object if chunks[0] == "o" and len(chunks) == 2: object = chunks[1] # Materials definition if chunks[0] == "mtllib" and len(chunks) == 2: mtllib = chunks[1] # Material if chunks[0] == "usemtl": if len(chunks) > 1: material = chunks[1] else: material = "" if not material in materials: mcurrent = mcounter materials[material] = mcounter mcounter += 1 else: mcurrent = materials[material] # Split the remaining parameters. if len(chunks) > 1: chunks = [chunks[0]] + chunks[1].split() # Vertices as (x,y,z) coordinates # v 0.123 0.234 0.345 if chunks[0] == "v" and len(chunks) == 4: x = float(chunks[1]) y = float(chunks[2]) z = float(chunks[3]) vertices.append([x,y,z]) # Normals in (x,y,z) form; normals might not be unit # vn 0.707 0.000 0.707 if chunks[0] == "vn" and len(chunks) == 4: x = float(chunks[1]) y = float(chunks[2]) z = float(chunks[3]) normals.append([x,y,z]) # Texture coordinates in (u,v[,w]) coordinates, w is optional # vt 0.500 -1.352 [0.234] if chunks[0] == "vt" and len(chunks) >= 3: u = float(chunks[1]) v = float(chunks[2]) w = 0 if len(chunks)>3: w = float(chunks[3]) uvs.append([u,v,w]) # Face if chunks[0] == "f" and len(chunks) >= 4: vertex_index = [] uv_index = [] normal_index = [] # Precompute vert / normal / uv lists # for negative index lookup vertlen = len(vertices) + 1 normlen = len(normals) + 1 uvlen = len(uvs) + 1 for v in chunks[1:]: vertex = parse_vertex(v) if vertex['v']: if vertex['v'] < 0: vertex['v'] += vertlen vertex_index.append(vertex['v']) if vertex['t']: if vertex['t'] < 0: vertex['t'] += uvlen uv_index.append(vertex['t']) if vertex['n']: if vertex['n'] < 0: vertex['n'] += normlen normal_index.append(vertex['n']) faces.append({ 'vertex':vertex_index, 'uv':uv_index, 'normal':normal_index, 'material':mcurrent, 'group':group, 'object':object, 'smooth':smooth, }) # Smooth shading if chunks[0] == "s" and len(chunks) == 2: smooth = chunks[1] return faces, vertices, uvs, normals, materials, mtllib # ##################################################### # Generator - faces # ##################################################### def setBit(value, position, on): if on: mask = 1 << position return (value | mask) else: mask = ~(1 << position) return (value & mask) def generate_face(f, fc): isTriangle = ( len(f['vertex']) == 3 ) if isTriangle: nVertices = 3 else: nVertices = 4 hasMaterial = True # for the moment OBJs without materials get default material hasFaceUvs = False # not supported in OBJ hasFaceVertexUvs = ( len(f['uv']) >= nVertices ) hasFaceNormals = False # don't export any face normals (as they are computed in engine) hasFaceVertexNormals = ( len(f["normal"]) >= nVertices and SHADING == "smooth" ) hasFaceColors = BAKE_COLORS hasFaceVertexColors = False # not supported in OBJ faceType = 0 faceType = setBit(faceType, 0, not isTriangle) faceType = setBit(faceType, 1, hasMaterial) faceType = setBit(faceType, 2, hasFaceUvs) faceType = setBit(faceType, 3, hasFaceVertexUvs) faceType = setBit(faceType, 4, hasFaceNormals) faceType = setBit(faceType, 5, hasFaceVertexNormals) faceType = setBit(faceType, 6, hasFaceColors) faceType = setBit(faceType, 7, hasFaceVertexColors) faceData = [] # order is important, must match order in JSONLoader # face type # vertex indices # material index # face uvs index # face vertex uvs indices # face normal index # face vertex normals indices # face color index # face vertex colors indices faceData.append(faceType) # must clamp in case on polygons bigger than quads for i in xrange(nVertices): index = f['vertex'][i] - 1 faceData.append(index) faceData.append( f['material'] ) if hasFaceVertexUvs: for i in xrange(nVertices): index = f['uv'][i] - 1 faceData.append(index) if hasFaceVertexNormals: for i in xrange(nVertices): index = f['normal'][i] - 1 faceData.append(index) if hasFaceColors: index = fc['material'] faceData.append(index) return ",".join( map(str, faceData) ) # ##################################################### # Generator - chunks # ##################################################### def hexcolor(c): return ( int(c[0] * 255) << 16 ) + ( int(c[1] * 255) << 8 ) + int(c[2] * 255) def generate_vertex(v, option_vertices_truncate, scale): if not option_vertices_truncate: return TEMPLATE_VERTEX % (v[0], v[1], v[2]) else: return TEMPLATE_VERTEX_TRUNCATE % (scale * v[0], scale * v[1], scale * v[2]) def generate_normal(n): return TEMPLATE_N % (n[0], n[1], n[2]) def generate_uv(uv): return TEMPLATE_UV % (uv[0], uv[1]) def generate_color_rgb(c): return TEMPLATE_COLOR % (c[0], c[1], c[2]) def generate_color_decimal(c): return TEMPLATE_COLOR_DEC % hexcolor(c) # ##################################################### # Morphs # ##################################################### def generate_morph_vertex(name, vertices): vertex_string = ",".join(generate_vertex(v, TRUNCATE, SCALE) for v in vertices) return TEMPLATE_MORPH_VERTICES % (name, vertex_string) def generate_morph_color(name, colors): color_string = ",".join(generate_color_rgb(c) for c in colors) return TEMPLATE_MORPH_COLORS % (name, color_string) def extract_material_colors(materials, mtlfilename, basename): """Extract diffuse colors from MTL materials """ if not materials: materials = { 'default': 0 } mtl = create_materials(materials, mtlfilename, basename) mtlColorArraySrt = [] for m in mtl: if m in materials: index = materials[m] color = mtl[m].get("colorDiffuse", [1,0,0]) mtlColorArraySrt.append([index, color]) mtlColorArraySrt.sort() mtlColorArray = [x[1] for x in mtlColorArraySrt] return mtlColorArray def extract_face_colors(faces, material_colors): """Extract colors from materials and assign them to faces """ faceColors = [] for face in faces: material_index = face['material'] faceColors.append(material_colors[material_index]) return faceColors def generate_morph_targets(morphfiles, n_vertices, infile): skipOriginalMorph = False norminfile = os.path.normpath(infile) morphVertexData = [] for mfilepattern in morphfiles.split(): matches = glob.glob(mfilepattern) matches.sort() indices = range(0, len(matches), FRAMESTEP) for i in indices: path = matches[i] normpath = os.path.normpath(path) if normpath != norminfile or not skipOriginalMorph: name = os.path.basename(normpath) morphFaces, morphVertices, morphUvs, morphNormals, morphMaterials, morphMtllib = parse_obj(normpath) n_morph_vertices = len(morphVertices) if n_vertices != n_morph_vertices: print "WARNING: skipping morph [%s] with different number of vertices [%d] than the original model [%d]" % (name, n_morph_vertices, n_vertices) else: if ALIGN == "center": center(morphVertices) elif ALIGN == "centerxz": centerxz(morphVertices) elif ALIGN == "bottom": bottom(morphVertices) elif ALIGN == "top": top(morphVertices) morphVertexData.append((get_name(name), morphVertices)) print "adding [%s] with %d vertices" % (name, n_morph_vertices) morphTargets = "" if len(morphVertexData): morphTargets = "\n%s\n\t" % ",\n".join(generate_morph_vertex(name, vertices) for name, vertices in morphVertexData) return morphTargets def generate_morph_colors(colorfiles, n_vertices, n_faces): morphColorData = [] colorFaces = [] materialColors = [] for mfilepattern in colorfiles.split(): matches = glob.glob(mfilepattern) matches.sort() for path in matches: normpath = os.path.normpath(path) name = os.path.basename(normpath) morphFaces, morphVertices, morphUvs, morphNormals, morphMaterials, morphMtllib = parse_obj(normpath) n_morph_vertices = len(morphVertices) n_morph_faces = len(morphFaces) if n_vertices != n_morph_vertices: print "WARNING: skipping morph color map [%s] with different number of vertices [%d] than the original model [%d]" % (name, n_morph_vertices, n_vertices) elif n_faces != n_morph_faces: print "WARNING: skipping morph color map [%s] with different number of faces [%d] than the original model [%d]" % (name, n_morph_faces, n_faces) else: morphMaterialColors = extract_material_colors(morphMaterials, morphMtllib, normpath) morphFaceColors = extract_face_colors(morphFaces, morphMaterialColors) morphColorData.append((get_name(name), morphFaceColors)) # take first color map for baking into face colors if len(colorFaces) == 0: colorFaces = morphFaces materialColors = morphMaterialColors print "adding [%s] with %d face colors" % (name, len(morphFaceColors)) morphColors = "" if len(morphColorData): morphColors = "\n%s\n\t" % ",\n".join(generate_morph_color(name, colors) for name, colors in morphColorData) return morphColors, colorFaces, materialColors # ##################################################### # Materials # ##################################################### def generate_color(i): """Generate hex color corresponding to integer. Colors should have well defined ordering. First N colors are hardcoded, then colors are random (must seed random number generator with deterministic value before getting colors). """ if i < len(COLORS): #return "0x%06x" % COLORS[i] return COLORS[i] else: #return "0x%06x" % int(0xffffff * random.random()) return int(0xffffff * random.random()) def value2string(v): if type(v)==str and v[0:2] != "0x": return '"%s"' % v elif type(v) == bool: return str(v).lower() return str(v) def generate_materials(mtl, materials): """Generate JS array of materials objects JS material objects are basically prettified one-to-one mappings of MTL properties in JSON format. """ mtl_array = [] for m in mtl: if m in materials: index = materials[m] # add debug information # materials should be sorted according to how # they appeared in OBJ file (for the first time) # this index is identifier used in face definitions mtl[m]['DbgName'] = m mtl[m]['DbgIndex'] = index mtl[m]['DbgColor'] = generate_color(index) if BAKE_COLORS: mtl[m]['vertexColors'] = "face" mtl_raw = ",\n".join(['\t"%s" : %s' % (n, value2string(v)) for n,v in sorted(mtl[m].items())]) mtl_string = "\t{\n%s\n\t}" % mtl_raw mtl_array.append([index, mtl_string]) return ",\n\n".join([m for i,m in sorted(mtl_array)]) def generate_mtl(materials): """Generate dummy materials (if there is no MTL file). """ mtl = {} for m in materials: index = materials[m] mtl[m] = { 'DbgName': m, 'DbgIndex': index, 'DbgColor': generate_color(index) } return mtl def generate_materials_string(materials, mtlfilename, basename): """Generate final materials string. """ if not materials: materials = { 'default': 0 } mtl = create_materials(materials, mtlfilename, basename) return generate_materials(mtl, materials) def create_materials(materials, mtlfilename, basename): """Parse MTL file and create mapping between its materials and OBJ materials. Eventual edge cases are handled here (missing materials, missing MTL file). """ random.seed(42) # to get well defined color order for debug colors # default materials with debug colors for when # there is no specified MTL / MTL loading failed, # or if there were no materials / null materials mtl = generate_mtl(materials) if mtlfilename: # create full pathname for MTL (included from OBJ) path = os.path.dirname(basename) fname = os.path.join(path, mtlfilename) if file_exists(fname): # override default materials with real ones from MTL # (where they exist, otherwise keep defaults) mtl.update(parse_mtl(fname)) else: print "Couldn't find [%s]" % fname return mtl # ##################################################### # Faces # ##################################################### def is_triangle_flat(f): return len(f['vertex'])==3 and not (f["normal"] and SHADING == "smooth") and not f['uv'] def is_triangle_flat_uv(f): return len(f['vertex'])==3 and not (f["normal"] and SHADING == "smooth") and len(f['uv'])==3 def is_triangle_smooth(f): return len(f['vertex'])==3 and f["normal"] and SHADING == "smooth" and not f['uv'] def is_triangle_smooth_uv(f): return len(f['vertex'])==3 and f["normal"] and SHADING == "smooth" and len(f['uv'])==3 def is_quad_flat(f): return len(f['vertex'])==4 and not (f["normal"] and SHADING == "smooth") and not f['uv'] def is_quad_flat_uv(f): return len(f['vertex'])==4 and not (f["normal"] and SHADING == "smooth") and len(f['uv'])==4 def is_quad_smooth(f): return len(f['vertex'])==4 and f["normal"] and SHADING == "smooth" and not f['uv'] def is_quad_smooth_uv(f): return len(f['vertex'])==4 and f["normal"] and SHADING == "smooth" and len(f['uv'])==4 def sort_faces(faces): data = { 'triangles_flat': [], 'triangles_flat_uv': [], 'triangles_smooth': [], 'triangles_smooth_uv': [], 'quads_flat': [], 'quads_flat_uv': [], 'quads_smooth': [], 'quads_smooth_uv': [] } for f in faces: if is_triangle_flat(f): data['triangles_flat'].append(f) elif is_triangle_flat_uv(f): data['triangles_flat_uv'].append(f) elif is_triangle_smooth(f): data['triangles_smooth'].append(f) elif is_triangle_smooth_uv(f): data['triangles_smooth_uv'].append(f) elif is_quad_flat(f): data['quads_flat'].append(f) elif is_quad_flat_uv(f): data['quads_flat_uv'].append(f) elif is_quad_smooth(f): data['quads_smooth'].append(f) elif is_quad_smooth_uv(f): data['quads_smooth_uv'].append(f) return data # ##################################################### # API - ASCII converter # ##################################################### def convert_ascii(infile, morphfiles, colorfiles, outfile): """Convert infile.obj to outfile.js Here is where everything happens. If you need to automate conversions, just import this file as Python module and call this method. """ if not file_exists(infile): print "Couldn't find [%s]" % infile return # parse OBJ / MTL files faces, vertices, uvs, normals, materials, mtllib = parse_obj(infile) n_vertices = len(vertices) n_faces = len(faces) # align model if ALIGN == "center": center(vertices) elif ALIGN == "centerxz": centerxz(vertices) elif ALIGN == "bottom": bottom(vertices) elif ALIGN == "top": top(vertices) # generate normals string nnormal = 0 normals_string = "" if SHADING == "smooth": normals_string = ",".join(generate_normal(n) for n in normals) nnormal = len(normals) # extract morph vertices morphTargets = generate_morph_targets(morphfiles, n_vertices, infile) # extract morph colors morphColors, colorFaces, materialColors = generate_morph_colors(colorfiles, n_vertices, n_faces) # generate colors string ncolor = 0 colors_string = "" if len(colorFaces) < len(faces): colorFaces = faces materialColors = extract_material_colors(materials, mtllib, infile) if BAKE_COLORS: colors_string = ",".join(generate_color_decimal(c) for c in materialColors) ncolor = len(materialColors) # generate ascii model string text = TEMPLATE_FILE_ASCII % { "name" : get_name(outfile), "fname" : os.path.basename(infile), "nvertex" : len(vertices), "nface" : len(faces), "nuv" : len(uvs), "nnormal" : nnormal, "ncolor" : ncolor, "nmaterial" : len(materials), "materials" : generate_materials_string(materials, mtllib, infile), "normals" : normals_string, "colors" : colors_string, "uvs" : ",".join(generate_uv(uv) for uv in uvs), "vertices" : ",".join(generate_vertex(v, TRUNCATE, SCALE) for v in vertices), "morphTargets" : morphTargets, "morphColors" : morphColors, "faces" : ",".join(generate_face(f, fc) for f, fc in zip(faces, colorFaces)), "scale" : SCALE } out = open(outfile, "w") out.write(text) out.close() print "%d vertices, %d faces, %d materials" % (len(vertices), len(faces), len(materials)) # ############################################################################# # API - Binary converter # ############################################################################# def dump_materials_to_buffer(faces, buffer): for f in faces: data = struct.pack('> 32UL); #endif _msgpack_store64(&buf[1], mem.i); msgpack_pack_append_buffer(x, buf, 9); } /* * Nil */ static inline int msgpack_pack_nil(msgpack_packer* x) { static const unsigned char d = 0xc0; msgpack_pack_append_buffer(x, &d, 1); } /* * Boolean */ static inline int msgpack_pack_true(msgpack_packer* x) { static const unsigned char d = 0xc3; msgpack_pack_append_buffer(x, &d, 1); } static inline int msgpack_pack_false(msgpack_packer* x) { static const unsigned char d = 0xc2; msgpack_pack_append_buffer(x, &d, 1); } /* * Array */ static inline int msgpack_pack_array(msgpack_packer* x, unsigned int n) { if(n < 16) { unsigned char d = 0x90 | n; msgpack_pack_append_buffer(x, &d, 1); } else if(n < 65536) { unsigned char buf[3]; buf[0] = 0xdc; _msgpack_store16(&buf[1], (uint16_t)n); msgpack_pack_append_buffer(x, buf, 3); } else { unsigned char buf[5]; buf[0] = 0xdd; _msgpack_store32(&buf[1], (uint32_t)n); msgpack_pack_append_buffer(x, buf, 5); } } /* * Map */ static inline int msgpack_pack_map(msgpack_packer* x, unsigned int n) { if(n < 16) { unsigned char d = 0x80 | n; msgpack_pack_append_buffer(x, &TAKE8_8(d), 1); } else if(n < 65536) { unsigned char buf[3]; buf[0] = 0xde; _msgpack_store16(&buf[1], (uint16_t)n); msgpack_pack_append_buffer(x, buf, 3); } else { unsigned char buf[5]; buf[0] = 0xdf; _msgpack_store32(&buf[1], (uint32_t)n); msgpack_pack_append_buffer(x, buf, 5); } } /* * Raw */ static inline int msgpack_pack_raw(msgpack_packer* x, size_t l) { if (l < 32) { unsigned char d = 0xa0 | (uint8_t)l; msgpack_pack_append_buffer(x, &TAKE8_8(d), 1); } else if (x->use_bin_type && l < 256) { // str8 is new format introduced with bin. unsigned char buf[2] = {0xd9, (uint8_t)l}; msgpack_pack_append_buffer(x, buf, 2); } else if (l < 65536) { unsigned char buf[3]; buf[0] = 0xda; _msgpack_store16(&buf[1], (uint16_t)l); msgpack_pack_append_buffer(x, buf, 3); } else { unsigned char buf[5]; buf[0] = 0xdb; _msgpack_store32(&buf[1], (uint32_t)l); msgpack_pack_append_buffer(x, buf, 5); } } /* * bin */ static inline int msgpack_pack_bin(msgpack_packer *x, size_t l) { if (!x->use_bin_type) { return msgpack_pack_raw(x, l); } if (l < 256) { unsigned char buf[2] = {0xc4, (unsigned char)l}; msgpack_pack_append_buffer(x, buf, 2); } else if (l < 65536) { unsigned char buf[3] = {0xc5}; _msgpack_store16(&buf[1], (uint16_t)l); msgpack_pack_append_buffer(x, buf, 3); } else { unsigned char buf[5] = {0xc6}; _msgpack_store32(&buf[1], (uint32_t)l); msgpack_pack_append_buffer(x, buf, 5); } } static inline int msgpack_pack_raw_body(msgpack_packer* x, const void* b, size_t l) { if (l > 0) msgpack_pack_append_buffer(x, (const unsigned char*)b, l); return 0; } /* * Ext */ static inline int msgpack_pack_ext(msgpack_packer* x, int8_t typecode, size_t l) { if (l == 1) { unsigned char buf[2]; buf[0] = 0xd4; buf[1] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 2); } else if(l == 2) { unsigned char buf[2]; buf[0] = 0xd5; buf[1] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 2); } else if(l == 4) { unsigned char buf[2]; buf[0] = 0xd6; buf[1] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 2); } else if(l == 8) { unsigned char buf[2]; buf[0] = 0xd7; buf[1] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 2); } else if(l == 16) { unsigned char buf[2]; buf[0] = 0xd8; buf[1] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 2); } else if(l < 256) { unsigned char buf[3]; buf[0] = 0xc7; buf[1] = l; buf[2] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 3); } else if(l < 65536) { unsigned char buf[4]; buf[0] = 0xc8; _msgpack_store16(&buf[1], (uint16_t)l); buf[3] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 4); } else { unsigned char buf[6]; buf[0] = 0xc9; _msgpack_store32(&buf[1], (uint32_t)l); buf[5] = (unsigned char)typecode; msgpack_pack_append_buffer(x, buf, 6); } } #undef msgpack_pack_append_buffer #undef TAKE8_8 #undef TAKE8_16 #undef TAKE8_32 #undef TAKE8_64 #undef msgpack_pack_real_uint8 #undef msgpack_pack_real_uint16 #undef msgpack_pack_real_uint32 #undef msgpack_pack_real_uint64 #undef msgpack_pack_real_int8 #undef msgpack_pack_real_int16 #undef msgpack_pack_real_int32 #undef msgpack_pack_real_int64 three.js-r73/utils/converters/msgpack/msgpack/unpack_template.h0000644000175500017550000003650512610076566024716 0ustar debacledebacle/* * MessagePack unpacking routine template * * Copyright (C) 2008-2010 FURUHASHI Sadayuki * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef USE_CASE_RANGE #if !defined(_MSC_VER) #define USE_CASE_RANGE #endif #endif typedef struct unpack_stack { PyObject* obj; size_t size; size_t count; unsigned int ct; PyObject* map_key; } unpack_stack; struct unpack_context { unpack_user user; unsigned int cs; unsigned int trail; unsigned int top; /* unpack_stack* stack; unsigned int stack_size; unpack_stack embed_stack[MSGPACK_EMBED_STACK_SIZE]; */ unpack_stack stack[MSGPACK_EMBED_STACK_SIZE]; }; static inline void unpack_init(unpack_context* ctx) { ctx->cs = CS_HEADER; ctx->trail = 0; ctx->top = 0; /* ctx->stack = ctx->embed_stack; ctx->stack_size = MSGPACK_EMBED_STACK_SIZE; */ ctx->stack[0].obj = unpack_callback_root(&ctx->user); } /* static inline void unpack_destroy(unpack_context* ctx) { if(ctx->stack_size != MSGPACK_EMBED_STACK_SIZE) { free(ctx->stack); } } */ static inline PyObject* unpack_data(unpack_context* ctx) { return (ctx)->stack[0].obj; } template static inline int unpack_execute(unpack_context* ctx, const char* data, size_t len, size_t* off) { assert(len >= *off); const unsigned char* p = (unsigned char*)data + *off; const unsigned char* const pe = (unsigned char*)data + len; const void* n = NULL; unsigned int trail = ctx->trail; unsigned int cs = ctx->cs; unsigned int top = ctx->top; unpack_stack* stack = ctx->stack; /* unsigned int stack_size = ctx->stack_size; */ unpack_user* user = &ctx->user; PyObject* obj; unpack_stack* c = NULL; int ret; #define construct_cb(name) \ construct && unpack_callback ## name #define push_simple_value(func) \ if(construct_cb(func)(user, &obj) < 0) { goto _failed; } \ goto _push #define push_fixed_value(func, arg) \ if(construct_cb(func)(user, arg, &obj) < 0) { goto _failed; } \ goto _push #define push_variable_value(func, base, pos, len) \ if(construct_cb(func)(user, \ (const char*)base, (const char*)pos, len, &obj) < 0) { goto _failed; } \ goto _push #define again_fixed_trail(_cs, trail_len) \ trail = trail_len; \ cs = _cs; \ goto _fixed_trail_again #define again_fixed_trail_if_zero(_cs, trail_len, ifzero) \ trail = trail_len; \ if(trail == 0) { goto ifzero; } \ cs = _cs; \ goto _fixed_trail_again #define start_container(func, count_, ct_) \ if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */ \ if(construct_cb(func)(user, count_, &stack[top].obj) < 0) { goto _failed; } \ if((count_) == 0) { obj = stack[top].obj; \ if (construct_cb(func##_end)(user, &obj) < 0) { goto _failed; } \ goto _push; } \ stack[top].ct = ct_; \ stack[top].size = count_; \ stack[top].count = 0; \ ++top; \ /*printf("container %d count %d stack %d\n",stack[top].obj,count_,top);*/ \ /*printf("stack push %d\n", top);*/ \ /* FIXME \ if(top >= stack_size) { \ if(stack_size == MSGPACK_EMBED_STACK_SIZE) { \ size_t csize = sizeof(unpack_stack) * MSGPACK_EMBED_STACK_SIZE; \ size_t nsize = csize * 2; \ unpack_stack* tmp = (unpack_stack*)malloc(nsize); \ if(tmp == NULL) { goto _failed; } \ memcpy(tmp, ctx->stack, csize); \ ctx->stack = stack = tmp; \ ctx->stack_size = stack_size = MSGPACK_EMBED_STACK_SIZE * 2; \ } else { \ size_t nsize = sizeof(unpack_stack) * ctx->stack_size * 2; \ unpack_stack* tmp = (unpack_stack*)realloc(ctx->stack, nsize); \ if(tmp == NULL) { goto _failed; } \ ctx->stack = stack = tmp; \ ctx->stack_size = stack_size = stack_size * 2; \ } \ } \ */ \ goto _header_again #define NEXT_CS(p) ((unsigned int)*p & 0x1f) #ifdef USE_CASE_RANGE #define SWITCH_RANGE_BEGIN switch(*p) { #define SWITCH_RANGE(FROM, TO) case FROM ... TO: #define SWITCH_RANGE_DEFAULT default: #define SWITCH_RANGE_END } #else #define SWITCH_RANGE_BEGIN { if(0) { #define SWITCH_RANGE(FROM, TO) } else if(FROM <= *p && *p <= TO) { #define SWITCH_RANGE_DEFAULT } else { #define SWITCH_RANGE_END } } #endif if(p == pe) { goto _out; } do { switch(cs) { case CS_HEADER: SWITCH_RANGE_BEGIN SWITCH_RANGE(0x00, 0x7f) // Positive Fixnum push_fixed_value(_uint8, *(uint8_t*)p); SWITCH_RANGE(0xe0, 0xff) // Negative Fixnum push_fixed_value(_int8, *(int8_t*)p); SWITCH_RANGE(0xc0, 0xdf) // Variable switch(*p) { case 0xc0: // nil push_simple_value(_nil); //case 0xc1: // never used case 0xc2: // false push_simple_value(_false); case 0xc3: // true push_simple_value(_true); case 0xc4: // bin 8 again_fixed_trail(NEXT_CS(p), 1); case 0xc5: // bin 16 again_fixed_trail(NEXT_CS(p), 2); case 0xc6: // bin 32 again_fixed_trail(NEXT_CS(p), 4); case 0xc7: // ext 8 again_fixed_trail(NEXT_CS(p), 1); case 0xc8: // ext 16 again_fixed_trail(NEXT_CS(p), 2); case 0xc9: // ext 32 again_fixed_trail(NEXT_CS(p), 4); case 0xca: // float case 0xcb: // double case 0xcc: // unsigned int 8 case 0xcd: // unsigned int 16 case 0xce: // unsigned int 32 case 0xcf: // unsigned int 64 case 0xd0: // signed int 8 case 0xd1: // signed int 16 case 0xd2: // signed int 32 case 0xd3: // signed int 64 again_fixed_trail(NEXT_CS(p), 1 << (((unsigned int)*p) & 0x03)); case 0xd4: // fixext 1 case 0xd5: // fixext 2 case 0xd6: // fixext 4 case 0xd7: // fixext 8 again_fixed_trail_if_zero(ACS_EXT_VALUE, (1 << (((unsigned int)*p) & 0x03))+1, _ext_zero); case 0xd8: // fixext 16 again_fixed_trail_if_zero(ACS_EXT_VALUE, 16+1, _ext_zero); case 0xd9: // str 8 again_fixed_trail(NEXT_CS(p), 1); case 0xda: // raw 16 case 0xdb: // raw 32 case 0xdc: // array 16 case 0xdd: // array 32 case 0xde: // map 16 case 0xdf: // map 32 again_fixed_trail(NEXT_CS(p), 2 << (((unsigned int)*p) & 0x01)); default: goto _failed; } SWITCH_RANGE(0xa0, 0xbf) // FixRaw again_fixed_trail_if_zero(ACS_RAW_VALUE, ((unsigned int)*p & 0x1f), _raw_zero); SWITCH_RANGE(0x90, 0x9f) // FixArray start_container(_array, ((unsigned int)*p) & 0x0f, CT_ARRAY_ITEM); SWITCH_RANGE(0x80, 0x8f) // FixMap start_container(_map, ((unsigned int)*p) & 0x0f, CT_MAP_KEY); SWITCH_RANGE_DEFAULT goto _failed; SWITCH_RANGE_END // end CS_HEADER _fixed_trail_again: ++p; default: if((size_t)(pe - p) < trail) { goto _out; } n = p; p += trail - 1; switch(cs) { case CS_EXT_8: again_fixed_trail_if_zero(ACS_EXT_VALUE, *(uint8_t*)n+1, _ext_zero); case CS_EXT_16: again_fixed_trail_if_zero(ACS_EXT_VALUE, _msgpack_load16(uint16_t,n)+1, _ext_zero); case CS_EXT_32: again_fixed_trail_if_zero(ACS_EXT_VALUE, _msgpack_load32(uint32_t,n)+1, _ext_zero); case CS_FLOAT: { union { uint32_t i; float f; } mem; mem.i = _msgpack_load32(uint32_t,n); push_fixed_value(_float, mem.f); } case CS_DOUBLE: { union { uint64_t i; double f; } mem; mem.i = _msgpack_load64(uint64_t,n); #if defined(__arm__) && !(__ARM_EABI__) // arm-oabi // https://github.com/msgpack/msgpack-perl/pull/1 mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL); #endif push_fixed_value(_double, mem.f); } case CS_UINT_8: push_fixed_value(_uint8, *(uint8_t*)n); case CS_UINT_16: push_fixed_value(_uint16, _msgpack_load16(uint16_t,n)); case CS_UINT_32: push_fixed_value(_uint32, _msgpack_load32(uint32_t,n)); case CS_UINT_64: push_fixed_value(_uint64, _msgpack_load64(uint64_t,n)); case CS_INT_8: push_fixed_value(_int8, *(int8_t*)n); case CS_INT_16: push_fixed_value(_int16, _msgpack_load16(int16_t,n)); case CS_INT_32: push_fixed_value(_int32, _msgpack_load32(int32_t,n)); case CS_INT_64: push_fixed_value(_int64, _msgpack_load64(int64_t,n)); case CS_BIN_8: again_fixed_trail_if_zero(ACS_BIN_VALUE, *(uint8_t*)n, _bin_zero); case CS_BIN_16: again_fixed_trail_if_zero(ACS_BIN_VALUE, _msgpack_load16(uint16_t,n), _bin_zero); case CS_BIN_32: again_fixed_trail_if_zero(ACS_BIN_VALUE, _msgpack_load32(uint32_t,n), _bin_zero); case ACS_BIN_VALUE: _bin_zero: push_variable_value(_bin, data, n, trail); case CS_RAW_8: again_fixed_trail_if_zero(ACS_RAW_VALUE, *(uint8_t*)n, _raw_zero); case CS_RAW_16: again_fixed_trail_if_zero(ACS_RAW_VALUE, _msgpack_load16(uint16_t,n), _raw_zero); case CS_RAW_32: again_fixed_trail_if_zero(ACS_RAW_VALUE, _msgpack_load32(uint32_t,n), _raw_zero); case ACS_RAW_VALUE: _raw_zero: push_variable_value(_raw, data, n, trail); case ACS_EXT_VALUE: _ext_zero: push_variable_value(_ext, data, n, trail); case CS_ARRAY_16: start_container(_array, _msgpack_load16(uint16_t,n), CT_ARRAY_ITEM); case CS_ARRAY_32: /* FIXME security guard */ start_container(_array, _msgpack_load32(uint32_t,n), CT_ARRAY_ITEM); case CS_MAP_16: start_container(_map, _msgpack_load16(uint16_t,n), CT_MAP_KEY); case CS_MAP_32: /* FIXME security guard */ start_container(_map, _msgpack_load32(uint32_t,n), CT_MAP_KEY); default: goto _failed; } } _push: if(top == 0) { goto _finish; } c = &stack[top-1]; switch(c->ct) { case CT_ARRAY_ITEM: if(construct_cb(_array_item)(user, c->count, &c->obj, obj) < 0) { goto _failed; } if(++c->count == c->size) { obj = c->obj; if (construct_cb(_array_end)(user, &obj) < 0) { goto _failed; } --top; /*printf("stack pop %d\n", top);*/ goto _push; } goto _header_again; case CT_MAP_KEY: c->map_key = obj; c->ct = CT_MAP_VALUE; goto _header_again; case CT_MAP_VALUE: if(construct_cb(_map_item)(user, c->count, &c->obj, c->map_key, obj) < 0) { goto _failed; } if(++c->count == c->size) { obj = c->obj; if (construct_cb(_map_end)(user, &obj) < 0) { goto _failed; } --top; /*printf("stack pop %d\n", top);*/ goto _push; } c->ct = CT_MAP_KEY; goto _header_again; default: goto _failed; } _header_again: cs = CS_HEADER; ++p; } while(p != pe); goto _out; _finish: if (!construct) unpack_callback_nil(user, &obj); stack[0].obj = obj; ++p; ret = 1; /*printf("-- finish --\n"); */ goto _end; _failed: /*printf("** FAILED **\n"); */ ret = -1; goto _end; _out: ret = 0; goto _end; _end: ctx->cs = cs; ctx->trail = trail; ctx->top = top; *off = p - (const unsigned char*)data; return ret; #undef construct_cb } #undef SWITCH_RANGE_BEGIN #undef SWITCH_RANGE #undef SWITCH_RANGE_DEFAULT #undef SWITCH_RANGE_END #undef push_simple_value #undef push_fixed_value #undef push_variable_value #undef again_fixed_trail #undef again_fixed_trail_if_zero #undef start_container template static inline int unpack_container_header(unpack_context* ctx, const char* data, size_t len, size_t* off) { assert(len >= *off); uint32_t size; const unsigned char *const p = (unsigned char*)data + *off; #define inc_offset(inc) \ if (len - *off < inc) \ return 0; \ *off += inc; switch (*p) { case var_offset: inc_offset(3); size = _msgpack_load16(uint16_t, p + 1); break; case var_offset + 1: inc_offset(5); size = _msgpack_load32(uint32_t, p + 1); break; #ifdef USE_CASE_RANGE case fixed_offset + 0x0 ... fixed_offset + 0xf: #else case fixed_offset + 0x0: case fixed_offset + 0x1: case fixed_offset + 0x2: case fixed_offset + 0x3: case fixed_offset + 0x4: case fixed_offset + 0x5: case fixed_offset + 0x6: case fixed_offset + 0x7: case fixed_offset + 0x8: case fixed_offset + 0x9: case fixed_offset + 0xa: case fixed_offset + 0xb: case fixed_offset + 0xc: case fixed_offset + 0xd: case fixed_offset + 0xe: case fixed_offset + 0xf: #endif ++*off; size = ((unsigned int)*p) & 0x0f; break; default: PyErr_SetString(PyExc_ValueError, "Unexpected type header on stream"); return -1; } unpack_callback_uint32(&ctx->user, size, &ctx->stack[0].obj); return 1; } #undef SWITCH_RANGE_BEGIN #undef SWITCH_RANGE #undef SWITCH_RANGE_DEFAULT #undef SWITCH_RANGE_END static const execute_fn unpack_construct = &unpack_execute; static const execute_fn unpack_skip = &unpack_execute; static const execute_fn read_array_header = &unpack_container_header<0x90, 0xdc>; static const execute_fn read_map_header = &unpack_container_header<0x80, 0xde>; #undef NEXT_CS /* vim: set ts=4 sw=4 sts=4 expandtab */ three.js-r73/utils/converters/msgpack/msgpack/__init__.py0000644000175500017550000000255112610076566023474 0ustar debacledebacle# coding: utf-8 from msgpack._version import version from msgpack.exceptions import * from collections import namedtuple class ExtType(namedtuple('ExtType', 'code data')): """ExtType represents ext type in msgpack.""" def __new__(cls, code, data): if not isinstance(code, int): raise TypeError("code must be int") if not isinstance(data, bytes): raise TypeError("data must be bytes") if not 0 <= code <= 127: raise ValueError("code must be 0~127") return super(ExtType, cls).__new__(cls, code, data) import os if os.environ.get('MSGPACK_PUREPYTHON'): from msgpack.fallback import Packer, unpack, unpackb, Unpacker else: try: from msgpack._packer import Packer from msgpack._unpacker import unpack, unpackb, Unpacker except ImportError: from msgpack.fallback import Packer, unpack, unpackb, Unpacker def pack(o, stream, **kwargs): """ Pack object `o` and write it to `stream` See :class:`Packer` for options. """ packer = Packer(**kwargs) stream.write(packer.pack(o)) def packb(o, **kwargs): """ Pack object `o` and return packed bytes See :class:`Packer` for options. """ return Packer(**kwargs).pack(o) # alias for compatibility to simplejson/marshal/pickle. load = unpack loads = unpackb dump = pack dumps = packb three.js-r73/utils/converters/msgpack/msgpack/sysdep.h0000644000175500017550000001450012610076566023040 0ustar debacledebacle/* * MessagePack system dependencies * * Copyright (C) 2008-2010 FURUHASHI Sadayuki * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_SYSDEP_H__ #define MSGPACK_SYSDEP_H__ #include #include #if defined(_MSC_VER) && _MSC_VER < 1600 typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #elif defined(_MSC_VER) // && _MSC_VER >= 1600 #include #else #include #include #endif #ifdef _WIN32 #define _msgpack_atomic_counter_header typedef long _msgpack_atomic_counter_t; #define _msgpack_sync_decr_and_fetch(ptr) InterlockedDecrement(ptr) #define _msgpack_sync_incr_and_fetch(ptr) InterlockedIncrement(ptr) #elif defined(__GNUC__) && ((__GNUC__*10 + __GNUC_MINOR__) < 41) #define _msgpack_atomic_counter_header "gcc_atomic.h" #else typedef unsigned int _msgpack_atomic_counter_t; #define _msgpack_sync_decr_and_fetch(ptr) __sync_sub_and_fetch(ptr, 1) #define _msgpack_sync_incr_and_fetch(ptr) __sync_add_and_fetch(ptr, 1) #endif #ifdef _WIN32 #ifdef __cplusplus /* numeric_limits::min,max */ #ifdef max #undef max #endif #ifdef min #undef min #endif #endif #else #include /* __BYTE_ORDER */ #endif #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) #if __BYTE_ORDER == __LITTLE_ENDIAN #define __LITTLE_ENDIAN__ #elif __BYTE_ORDER == __BIG_ENDIAN #define __BIG_ENDIAN__ #elif _WIN32 #define __LITTLE_ENDIAN__ #endif #endif #ifdef __LITTLE_ENDIAN__ #ifdef _WIN32 # if defined(ntohs) # define _msgpack_be16(x) ntohs(x) # elif defined(_byteswap_ushort) || (defined(_MSC_VER) && _MSC_VER >= 1400) # define _msgpack_be16(x) ((uint16_t)_byteswap_ushort((unsigned short)x)) # else # define _msgpack_be16(x) ( \ ((((uint16_t)x) << 8) ) | \ ((((uint16_t)x) >> 8) ) ) # endif #else # define _msgpack_be16(x) ntohs(x) #endif #ifdef _WIN32 # if defined(ntohl) # define _msgpack_be32(x) ntohl(x) # elif defined(_byteswap_ulong) || (defined(_MSC_VER) && _MSC_VER >= 1400) # define _msgpack_be32(x) ((uint32_t)_byteswap_ulong((unsigned long)x)) # else # define _msgpack_be32(x) \ ( ((((uint32_t)x) << 24) ) | \ ((((uint32_t)x) << 8) & 0x00ff0000U ) | \ ((((uint32_t)x) >> 8) & 0x0000ff00U ) | \ ((((uint32_t)x) >> 24) ) ) # endif #else # define _msgpack_be32(x) ntohl(x) #endif #if defined(_byteswap_uint64) || (defined(_MSC_VER) && _MSC_VER >= 1400) # define _msgpack_be64(x) (_byteswap_uint64(x)) #elif defined(bswap_64) # define _msgpack_be64(x) bswap_64(x) #elif defined(__DARWIN_OSSwapInt64) # define _msgpack_be64(x) __DARWIN_OSSwapInt64(x) #else #define _msgpack_be64(x) \ ( ((((uint64_t)x) << 56) ) | \ ((((uint64_t)x) << 40) & 0x00ff000000000000ULL ) | \ ((((uint64_t)x) << 24) & 0x0000ff0000000000ULL ) | \ ((((uint64_t)x) << 8) & 0x000000ff00000000ULL ) | \ ((((uint64_t)x) >> 8) & 0x00000000ff000000ULL ) | \ ((((uint64_t)x) >> 24) & 0x0000000000ff0000ULL ) | \ ((((uint64_t)x) >> 40) & 0x000000000000ff00ULL ) | \ ((((uint64_t)x) >> 56) ) ) #endif #define _msgpack_load16(cast, from) ((cast)( \ (((uint16_t)((uint8_t*)(from))[0]) << 8) | \ (((uint16_t)((uint8_t*)(from))[1]) ) )) #define _msgpack_load32(cast, from) ((cast)( \ (((uint32_t)((uint8_t*)(from))[0]) << 24) | \ (((uint32_t)((uint8_t*)(from))[1]) << 16) | \ (((uint32_t)((uint8_t*)(from))[2]) << 8) | \ (((uint32_t)((uint8_t*)(from))[3]) ) )) #define _msgpack_load64(cast, from) ((cast)( \ (((uint64_t)((uint8_t*)(from))[0]) << 56) | \ (((uint64_t)((uint8_t*)(from))[1]) << 48) | \ (((uint64_t)((uint8_t*)(from))[2]) << 40) | \ (((uint64_t)((uint8_t*)(from))[3]) << 32) | \ (((uint64_t)((uint8_t*)(from))[4]) << 24) | \ (((uint64_t)((uint8_t*)(from))[5]) << 16) | \ (((uint64_t)((uint8_t*)(from))[6]) << 8) | \ (((uint64_t)((uint8_t*)(from))[7]) ) )) #else #define _msgpack_be16(x) (x) #define _msgpack_be32(x) (x) #define _msgpack_be64(x) (x) #define _msgpack_load16(cast, from) ((cast)( \ (((uint16_t)((uint8_t*)from)[0]) << 8) | \ (((uint16_t)((uint8_t*)from)[1]) ) )) #define _msgpack_load32(cast, from) ((cast)( \ (((uint32_t)((uint8_t*)from)[0]) << 24) | \ (((uint32_t)((uint8_t*)from)[1]) << 16) | \ (((uint32_t)((uint8_t*)from)[2]) << 8) | \ (((uint32_t)((uint8_t*)from)[3]) ) )) #define _msgpack_load64(cast, from) ((cast)( \ (((uint64_t)((uint8_t*)from)[0]) << 56) | \ (((uint64_t)((uint8_t*)from)[1]) << 48) | \ (((uint64_t)((uint8_t*)from)[2]) << 40) | \ (((uint64_t)((uint8_t*)from)[3]) << 32) | \ (((uint64_t)((uint8_t*)from)[4]) << 24) | \ (((uint64_t)((uint8_t*)from)[5]) << 16) | \ (((uint64_t)((uint8_t*)from)[6]) << 8) | \ (((uint64_t)((uint8_t*)from)[7]) ) )) #endif #define _msgpack_store16(to, num) \ do { uint16_t val = _msgpack_be16(num); memcpy(to, &val, 2); } while(0) #define _msgpack_store32(to, num) \ do { uint32_t val = _msgpack_be32(num); memcpy(to, &val, 4); } while(0) #define _msgpack_store64(to, num) \ do { uint64_t val = _msgpack_be64(num); memcpy(to, &val, 8); } while(0) /* #define _msgpack_load16(cast, from) \ ({ cast val; memcpy(&val, (char*)from, 2); _msgpack_be16(val); }) #define _msgpack_load32(cast, from) \ ({ cast val; memcpy(&val, (char*)from, 4); _msgpack_be32(val); }) #define _msgpack_load64(cast, from) \ ({ cast val; memcpy(&val, (char*)from, 8); _msgpack_be64(val); }) */ #endif /* msgpack/sysdep.h */ three.js-r73/utils/converters/msgpack/msgpack/unpack.h0000644000175500017550000001555312610076566023023 0ustar debacledebacle/* * MessagePack for Python unpacking routine * * Copyright (C) 2009 Naoki INADA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MSGPACK_EMBED_STACK_SIZE (1024) #include "unpack_define.h" typedef struct unpack_user { int use_list; PyObject *object_hook; bool has_pairs_hook; PyObject *list_hook; PyObject *ext_hook; const char *encoding; const char *unicode_errors; } unpack_user; typedef PyObject* msgpack_unpack_object; struct unpack_context; typedef struct unpack_context unpack_context; typedef int (*execute_fn)(unpack_context *ctx, const char* data, size_t len, size_t* off); static inline msgpack_unpack_object unpack_callback_root(unpack_user* u) { return NULL; } static inline int unpack_callback_uint16(unpack_user* u, uint16_t d, msgpack_unpack_object* o) { PyObject *p = PyInt_FromLong((long)d); if (!p) return -1; *o = p; return 0; } static inline int unpack_callback_uint8(unpack_user* u, uint8_t d, msgpack_unpack_object* o) { return unpack_callback_uint16(u, d, o); } static inline int unpack_callback_uint32(unpack_user* u, uint32_t d, msgpack_unpack_object* o) { PyObject *p; #if UINT32_MAX > LONG_MAX if (d > LONG_MAX) { p = PyLong_FromUnsignedLong((unsigned long)d); } else #endif { p = PyInt_FromLong((long)d); } if (!p) return -1; *o = p; return 0; } static inline int unpack_callback_uint64(unpack_user* u, uint64_t d, msgpack_unpack_object* o) { PyObject *p; if (d > LONG_MAX) { p = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)d); } else { p = PyInt_FromLong((long)d); } if (!p) return -1; *o = p; return 0; } static inline int unpack_callback_int32(unpack_user* u, int32_t d, msgpack_unpack_object* o) { PyObject *p = PyInt_FromLong(d); if (!p) return -1; *o = p; return 0; } static inline int unpack_callback_int16(unpack_user* u, int16_t d, msgpack_unpack_object* o) { return unpack_callback_int32(u, d, o); } static inline int unpack_callback_int8(unpack_user* u, int8_t d, msgpack_unpack_object* o) { return unpack_callback_int32(u, d, o); } static inline int unpack_callback_int64(unpack_user* u, int64_t d, msgpack_unpack_object* o) { PyObject *p; if (d > LONG_MAX || d < LONG_MIN) { p = PyLong_FromLongLong((unsigned PY_LONG_LONG)d); } else { p = PyInt_FromLong((long)d); } *o = p; return 0; } static inline int unpack_callback_double(unpack_user* u, double d, msgpack_unpack_object* o) { PyObject *p = PyFloat_FromDouble(d); if (!p) return -1; *o = p; return 0; } static inline int unpack_callback_float(unpack_user* u, float d, msgpack_unpack_object* o) { return unpack_callback_double(u, d, o); } static inline int unpack_callback_nil(unpack_user* u, msgpack_unpack_object* o) { Py_INCREF(Py_None); *o = Py_None; return 0; } static inline int unpack_callback_true(unpack_user* u, msgpack_unpack_object* o) { Py_INCREF(Py_True); *o = Py_True; return 0; } static inline int unpack_callback_false(unpack_user* u, msgpack_unpack_object* o) { Py_INCREF(Py_False); *o = Py_False; return 0; } static inline int unpack_callback_array(unpack_user* u, unsigned int n, msgpack_unpack_object* o) { PyObject *p = u->use_list ? PyList_New(n) : PyTuple_New(n); if (!p) return -1; *o = p; return 0; } static inline int unpack_callback_array_item(unpack_user* u, unsigned int current, msgpack_unpack_object* c, msgpack_unpack_object o) { if (u->use_list) PyList_SET_ITEM(*c, current, o); else PyTuple_SET_ITEM(*c, current, o); return 0; } static inline int unpack_callback_array_end(unpack_user* u, msgpack_unpack_object* c) { if (u->list_hook) { PyObject *new_c = PyObject_CallFunctionObjArgs(u->list_hook, *c, NULL); if (!new_c) return -1; Py_DECREF(*c); *c = new_c; } return 0; } static inline int unpack_callback_map(unpack_user* u, unsigned int n, msgpack_unpack_object* o) { PyObject *p; if (u->has_pairs_hook) { p = PyList_New(n); // Or use tuple? } else { p = PyDict_New(); } if (!p) return -1; *o = p; return 0; } static inline int unpack_callback_map_item(unpack_user* u, unsigned int current, msgpack_unpack_object* c, msgpack_unpack_object k, msgpack_unpack_object v) { if (u->has_pairs_hook) { msgpack_unpack_object item = PyTuple_Pack(2, k, v); if (!item) return -1; Py_DECREF(k); Py_DECREF(v); PyList_SET_ITEM(*c, current, item); return 0; } else if (PyDict_SetItem(*c, k, v) == 0) { Py_DECREF(k); Py_DECREF(v); return 0; } return -1; } static inline int unpack_callback_map_end(unpack_user* u, msgpack_unpack_object* c) { if (u->object_hook) { PyObject *new_c = PyObject_CallFunctionObjArgs(u->object_hook, *c, NULL); if (!new_c) return -1; Py_DECREF(*c); *c = new_c; } return 0; } static inline int unpack_callback_raw(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_unpack_object* o) { PyObject *py; if(u->encoding) { py = PyUnicode_Decode(p, l, u->encoding, u->unicode_errors); } else { py = PyBytes_FromStringAndSize(p, l); } if (!py) return -1; *o = py; return 0; } static inline int unpack_callback_bin(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_unpack_object* o) { PyObject *py = PyBytes_FromStringAndSize(p, l); if (!py) return -1; *o = py; return 0; } static inline int unpack_callback_ext(unpack_user* u, const char* base, const char* pos, unsigned int lenght, msgpack_unpack_object* o) { PyObject *py; int8_t typecode = (int8_t)*pos++; if (!u->ext_hook) { PyErr_SetString(PyExc_AssertionError, "u->ext_hook cannot be NULL"); return -1; } // length also includes the typecode, so the actual data is lenght-1 #if PY_MAJOR_VERSION == 2 py = PyObject_CallFunction(u->ext_hook, "(is#)", typecode, pos, lenght-1); #else py = PyObject_CallFunction(u->ext_hook, "(iy#)", typecode, pos, lenght-1); #endif if (!py) return -1; *o = py; return 0; } #include "unpack_template.h" three.js-r73/utils/converters/msgpack/msgpack/unpack_define.h0000644000175500017550000000447612610076566024337 0ustar debacledebacle/* * MessagePack unpacking routine template * * Copyright (C) 2008-2010 FURUHASHI Sadayuki * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSGPACK_UNPACK_DEFINE_H__ #define MSGPACK_UNPACK_DEFINE_H__ #include "msgpack/sysdep.h" #include #include #include #include #ifdef __cplusplus extern "C" { #endif #ifndef MSGPACK_EMBED_STACK_SIZE #define MSGPACK_EMBED_STACK_SIZE 32 #endif // CS is first byte & 0x1f typedef enum { CS_HEADER = 0x00, // nil //CS_ = 0x01, //CS_ = 0x02, // false //CS_ = 0x03, // true CS_BIN_8 = 0x04, CS_BIN_16 = 0x05, CS_BIN_32 = 0x06, CS_EXT_8 = 0x07, CS_EXT_16 = 0x08, CS_EXT_32 = 0x09, CS_FLOAT = 0x0a, CS_DOUBLE = 0x0b, CS_UINT_8 = 0x0c, CS_UINT_16 = 0x0d, CS_UINT_32 = 0x0e, CS_UINT_64 = 0x0f, CS_INT_8 = 0x10, CS_INT_16 = 0x11, CS_INT_32 = 0x12, CS_INT_64 = 0x13, //CS_FIXEXT1 = 0x14, //CS_FIXEXT2 = 0x15, //CS_FIXEXT4 = 0x16, //CS_FIXEXT8 = 0x17, //CS_FIXEXT16 = 0x18, CS_RAW_8 = 0x19, CS_RAW_16 = 0x1a, CS_RAW_32 = 0x1b, CS_ARRAY_16 = 0x1c, CS_ARRAY_32 = 0x1d, CS_MAP_16 = 0x1e, CS_MAP_32 = 0x1f, ACS_RAW_VALUE, ACS_BIN_VALUE, ACS_EXT_VALUE, } msgpack_unpack_state; typedef enum { CT_ARRAY_ITEM, CT_MAP_KEY, CT_MAP_VALUE, } msgpack_container_type; #ifdef __cplusplus } #endif #endif /* msgpack/unpack_define.h */ three.js-r73/utils/converters/msgpack/msgpack/pack.h0000644000175500017550000000663512610076566022461 0ustar debacledebacle/* * MessagePack for Python packing routine * * Copyright (C) 2009 Naoki INADA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "sysdep.h" #include #include #ifdef __cplusplus extern "C" { #endif #ifdef _MSC_VER #define inline __inline #endif typedef struct msgpack_packer { char *buf; size_t length; size_t buf_size; bool use_bin_type; } msgpack_packer; typedef struct Packer Packer; static inline int msgpack_pack_int(msgpack_packer* pk, int d); static inline int msgpack_pack_long(msgpack_packer* pk, long d); static inline int msgpack_pack_long_long(msgpack_packer* pk, long long d); static inline int msgpack_pack_unsigned_short(msgpack_packer* pk, unsigned short d); static inline int msgpack_pack_unsigned_int(msgpack_packer* pk, unsigned int d); static inline int msgpack_pack_unsigned_long(msgpack_packer* pk, unsigned long d); //static inline int msgpack_pack_unsigned_long_long(msgpack_packer* pk, unsigned long long d); static inline int msgpack_pack_uint8(msgpack_packer* pk, uint8_t d); static inline int msgpack_pack_uint16(msgpack_packer* pk, uint16_t d); static inline int msgpack_pack_uint32(msgpack_packer* pk, uint32_t d); static inline int msgpack_pack_uint64(msgpack_packer* pk, uint64_t d); static inline int msgpack_pack_int8(msgpack_packer* pk, int8_t d); static inline int msgpack_pack_int16(msgpack_packer* pk, int16_t d); static inline int msgpack_pack_int32(msgpack_packer* pk, int32_t d); static inline int msgpack_pack_int64(msgpack_packer* pk, int64_t d); static inline int msgpack_pack_float(msgpack_packer* pk, float d); static inline int msgpack_pack_double(msgpack_packer* pk, double d); static inline int msgpack_pack_nil(msgpack_packer* pk); static inline int msgpack_pack_true(msgpack_packer* pk); static inline int msgpack_pack_false(msgpack_packer* pk); static inline int msgpack_pack_array(msgpack_packer* pk, unsigned int n); static inline int msgpack_pack_map(msgpack_packer* pk, unsigned int n); static inline int msgpack_pack_raw(msgpack_packer* pk, size_t l); static inline int msgpack_pack_bin(msgpack_packer* pk, size_t l); static inline int msgpack_pack_raw_body(msgpack_packer* pk, const void* b, size_t l); static inline int msgpack_pack_ext(msgpack_packer* pk, int8_t typecode, size_t l); static inline int msgpack_pack_write(msgpack_packer* pk, const char *data, size_t l) { char* buf = pk->buf; size_t bs = pk->buf_size; size_t len = pk->length; if (len + l > bs) { bs = (len + l) * 2; buf = (char*)realloc(buf, bs); if (!buf) return -1; } memcpy(buf + len, data, l); len += l; pk->buf = buf; pk->buf_size = bs; pk->length = len; return 0; } #define msgpack_pack_append_buffer(user, buf, len) \ return msgpack_pack_write(user, (const char*)buf, len) #include "pack_template.h" #ifdef __cplusplus } #endif three.js-r73/utils/converters/msgpack/msgpack/_unpacker.pyx0000644000175500017550000003471412610076566024102 0ustar debacledebacle# coding: utf-8 #cython: embedsignature=True from cpython cimport * cdef extern from "Python.h": ctypedef struct PyObject cdef int PyObject_AsReadBuffer(object o, const void** buff, Py_ssize_t* buf_len) except -1 from libc.stdlib cimport * from libc.string cimport * from libc.limits cimport * from msgpack.exceptions import ( BufferFull, OutOfData, UnpackValueError, ExtraData, ) from msgpack import ExtType cdef extern from "unpack.h": ctypedef struct msgpack_user: bint use_list PyObject* object_hook bint has_pairs_hook # call object_hook with k-v pairs PyObject* list_hook PyObject* ext_hook char *encoding char *unicode_errors ctypedef struct unpack_context: msgpack_user user PyObject* obj size_t count ctypedef int (*execute_fn)(unpack_context* ctx, const char* data, size_t len, size_t* off) except? -1 execute_fn unpack_construct execute_fn unpack_skip execute_fn read_array_header execute_fn read_map_header void unpack_init(unpack_context* ctx) object unpack_data(unpack_context* ctx) cdef inline init_ctx(unpack_context *ctx, object object_hook, object object_pairs_hook, object list_hook, object ext_hook, bint use_list, char* encoding, char* unicode_errors): unpack_init(ctx) ctx.user.use_list = use_list ctx.user.object_hook = ctx.user.list_hook = NULL if object_hook is not None and object_pairs_hook is not None: raise TypeError("object_pairs_hook and object_hook are mutually exclusive.") if object_hook is not None: if not PyCallable_Check(object_hook): raise TypeError("object_hook must be a callable.") ctx.user.object_hook = object_hook if object_pairs_hook is None: ctx.user.has_pairs_hook = False else: if not PyCallable_Check(object_pairs_hook): raise TypeError("object_pairs_hook must be a callable.") ctx.user.object_hook = object_pairs_hook ctx.user.has_pairs_hook = True if list_hook is not None: if not PyCallable_Check(list_hook): raise TypeError("list_hook must be a callable.") ctx.user.list_hook = list_hook if ext_hook is not None: if not PyCallable_Check(ext_hook): raise TypeError("ext_hook must be a callable.") ctx.user.ext_hook = ext_hook ctx.user.encoding = encoding ctx.user.unicode_errors = unicode_errors def default_read_extended_type(typecode, data): raise NotImplementedError("Cannot decode extended type with typecode=%d" % typecode) def unpackb(object packed, object object_hook=None, object list_hook=None, bint use_list=1, encoding=None, unicode_errors="strict", object_pairs_hook=None, ext_hook=ExtType): """ Unpack packed_bytes to object. Returns an unpacked object. Raises `ValueError` when `packed` contains extra bytes. See :class:`Unpacker` for options. """ cdef unpack_context ctx cdef size_t off = 0 cdef int ret cdef char* buf cdef Py_ssize_t buf_len cdef char* cenc = NULL cdef char* cerr = NULL PyObject_AsReadBuffer(packed, &buf, &buf_len) if encoding is not None: if isinstance(encoding, unicode): encoding = encoding.encode('ascii') cenc = PyBytes_AsString(encoding) if unicode_errors is not None: if isinstance(unicode_errors, unicode): unicode_errors = unicode_errors.encode('ascii') cerr = PyBytes_AsString(unicode_errors) init_ctx(&ctx, object_hook, object_pairs_hook, list_hook, ext_hook, use_list, cenc, cerr) ret = unpack_construct(&ctx, buf, buf_len, &off) if ret == 1: obj = unpack_data(&ctx) if off < buf_len: raise ExtraData(obj, PyBytes_FromStringAndSize(buf+off, buf_len-off)) return obj else: raise UnpackValueError("Unpack failed: error = %d" % (ret,)) def unpack(object stream, object object_hook=None, object list_hook=None, bint use_list=1, encoding=None, unicode_errors="strict", object_pairs_hook=None, ): """ Unpack an object from `stream`. Raises `ValueError` when `stream` has extra bytes. See :class:`Unpacker` for options. """ return unpackb(stream.read(), use_list=use_list, object_hook=object_hook, object_pairs_hook=object_pairs_hook, list_hook=list_hook, encoding=encoding, unicode_errors=unicode_errors, ) cdef class Unpacker(object): """ Streaming unpacker. arguments: :param file_like: File-like object having `.read(n)` method. If specified, unpacker reads serialized data from it and :meth:`feed()` is not usable. :param int read_size: Used as `file_like.read(read_size)`. (default: `min(1024**2, max_buffer_size)`) :param bool use_list: If true, unpack msgpack array to Python list. Otherwise, unpack to Python tuple. (default: True) :param callable object_hook: When specified, it should be callable. Unpacker calls it with a dict argument after unpacking msgpack map. (See also simplejson) :param callable object_pairs_hook: When specified, it should be callable. Unpacker calls it with a list of key-value pairs after unpacking msgpack map. (See also simplejson) :param str encoding: Encoding used for decoding msgpack raw. If it is None (default), msgpack raw is deserialized to Python bytes. :param str unicode_errors: Used for decoding msgpack raw with *encoding*. (default: `'strict'`) :param int max_buffer_size: Limits size of data waiting unpacked. 0 means system's INT_MAX (default). Raises `BufferFull` exception when it is insufficient. You shoud set this parameter when unpacking data from untrasted source. example of streaming deserialize from file-like object:: unpacker = Unpacker(file_like) for o in unpacker: process(o) example of streaming deserialize from socket:: unpacker = Unpacker() while True: buf = sock.recv(1024**2) if not buf: break unpacker.feed(buf) for o in unpacker: process(o) """ cdef unpack_context ctx cdef char* buf cdef size_t buf_size, buf_head, buf_tail cdef object file_like cdef object file_like_read cdef Py_ssize_t read_size # To maintain refcnt. cdef object object_hook, object_pairs_hook, list_hook, ext_hook cdef object encoding, unicode_errors cdef size_t max_buffer_size def __cinit__(self): self.buf = NULL def __dealloc__(self): free(self.buf) self.buf = NULL def __init__(self, file_like=None, Py_ssize_t read_size=0, bint use_list=1, object object_hook=None, object object_pairs_hook=None, object list_hook=None, str encoding=None, str unicode_errors='strict', int max_buffer_size=0, object ext_hook=ExtType): cdef char *cenc=NULL, cdef char *cerr=NULL self.object_hook = object_hook self.object_pairs_hook = object_pairs_hook self.list_hook = list_hook self.ext_hook = ext_hook self.file_like = file_like if file_like: self.file_like_read = file_like.read if not PyCallable_Check(self.file_like_read): raise TypeError("`file_like.read` must be a callable.") if not max_buffer_size: max_buffer_size = INT_MAX if read_size > max_buffer_size: raise ValueError("read_size should be less or equal to max_buffer_size") if not read_size: read_size = min(max_buffer_size, 1024**2) self.max_buffer_size = max_buffer_size self.read_size = read_size self.buf = malloc(read_size) if self.buf == NULL: raise MemoryError("Unable to allocate internal buffer.") self.buf_size = read_size self.buf_head = 0 self.buf_tail = 0 if encoding is not None: if isinstance(encoding, unicode): self.encoding = encoding.encode('ascii') else: self.encoding = encoding cenc = PyBytes_AsString(self.encoding) if unicode_errors is not None: if isinstance(unicode_errors, unicode): self.unicode_errors = unicode_errors.encode('ascii') else: self.unicode_errors = unicode_errors cerr = PyBytes_AsString(self.unicode_errors) init_ctx(&self.ctx, object_hook, object_pairs_hook, list_hook, ext_hook, use_list, cenc, cerr) def feed(self, object next_bytes): """Append `next_bytes` to internal buffer.""" cdef Py_buffer pybuff if self.file_like is not None: raise AssertionError( "unpacker.feed() is not be able to use with `file_like`.") PyObject_GetBuffer(next_bytes, &pybuff, PyBUF_SIMPLE) try: self.append_buffer(pybuff.buf, pybuff.len) finally: PyBuffer_Release(&pybuff) cdef append_buffer(self, void* _buf, Py_ssize_t _buf_len): cdef: char* buf = self.buf char* new_buf size_t head = self.buf_head size_t tail = self.buf_tail size_t buf_size = self.buf_size size_t new_size if tail + _buf_len > buf_size: if ((tail - head) + _buf_len) <= buf_size: # move to front. memmove(buf, buf + head, tail - head) tail -= head head = 0 else: # expand buffer. new_size = (tail-head) + _buf_len if new_size > self.max_buffer_size: raise BufferFull new_size = min(new_size*2, self.max_buffer_size) new_buf = malloc(new_size) if new_buf == NULL: # self.buf still holds old buffer and will be freed during # obj destruction raise MemoryError("Unable to enlarge internal buffer.") memcpy(new_buf, buf + head, tail - head) free(buf) buf = new_buf buf_size = new_size tail -= head head = 0 memcpy(buf + tail, (_buf), _buf_len) self.buf = buf self.buf_head = head self.buf_size = buf_size self.buf_tail = tail + _buf_len cdef read_from_file(self): next_bytes = self.file_like_read( min(self.read_size, self.max_buffer_size - (self.buf_tail - self.buf_head) )) if next_bytes: self.append_buffer(PyBytes_AsString(next_bytes), PyBytes_Size(next_bytes)) else: self.file_like = None cdef object _unpack(self, execute_fn execute, object write_bytes, bint iter=0): cdef int ret cdef object obj cdef size_t prev_head if self.buf_head >= self.buf_tail and self.file_like is not None: self.read_from_file() while 1: prev_head = self.buf_head if prev_head >= self.buf_tail: if iter: raise StopIteration("No more data to unpack.") else: raise OutOfData("No more data to unpack.") ret = execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head) if write_bytes is not None: write_bytes(PyBytes_FromStringAndSize(self.buf + prev_head, self.buf_head - prev_head)) if ret == 1: obj = unpack_data(&self.ctx) unpack_init(&self.ctx) return obj elif ret == 0: if self.file_like is not None: self.read_from_file() continue if iter: raise StopIteration("No more data to unpack.") else: raise OutOfData("No more data to unpack.") else: raise ValueError("Unpack failed: error = %d" % (ret,)) def read_bytes(self, Py_ssize_t nbytes): """read a specified number of raw bytes from the stream""" cdef size_t nread nread = min(self.buf_tail - self.buf_head, nbytes) ret = PyBytes_FromStringAndSize(self.buf + self.buf_head, nread) self.buf_head += nread if len(ret) < nbytes and self.file_like is not None: ret += self.file_like.read(nbytes - len(ret)) return ret def unpack(self, object write_bytes=None): """ unpack one object If write_bytes is not None, it will be called with parts of the raw message as it is unpacked. Raises `OutOfData` when there are no more bytes to unpack. """ return self._unpack(unpack_construct, write_bytes) def skip(self, object write_bytes=None): """ read and ignore one object, returning None If write_bytes is not None, it will be called with parts of the raw message as it is unpacked. Raises `OutOfData` when there are no more bytes to unpack. """ return self._unpack(unpack_skip, write_bytes) def read_array_header(self, object write_bytes=None): """assuming the next object is an array, return its size n, such that the next n unpack() calls will iterate over its contents. Raises `OutOfData` when there are no more bytes to unpack. """ return self._unpack(read_array_header, write_bytes) def read_map_header(self, object write_bytes=None): """assuming the next object is a map, return its size n, such that the next n * 2 unpack() calls will iterate over its key-value pairs. Raises `OutOfData` when there are no more bytes to unpack. """ return self._unpack(read_map_header, write_bytes) def __iter__(self): return self def __next__(self): return self._unpack(unpack_construct, None, 1) # for debug. #def _buf(self): # return PyString_FromStringAndSize(self.buf, self.buf_tail) #def _off(self): # return self.buf_head three.js-r73/utils/converters/msgpack/msgpack/_packer.pyx0000644000175500017550000002503512610076566023533 0ustar debacledebacle# coding: utf-8 #cython: embedsignature=True from cpython cimport * from libc.stdlib cimport * from libc.string cimport * from libc.limits cimport * from libc.stdint cimport int8_t from msgpack.exceptions import PackValueError from msgpack import ExtType cdef extern from "pack.h": struct msgpack_packer: char* buf size_t length size_t buf_size bint use_bin_type int msgpack_pack_int(msgpack_packer* pk, int d) int msgpack_pack_nil(msgpack_packer* pk) int msgpack_pack_true(msgpack_packer* pk) int msgpack_pack_false(msgpack_packer* pk) int msgpack_pack_long(msgpack_packer* pk, long d) int msgpack_pack_long_long(msgpack_packer* pk, long long d) int msgpack_pack_unsigned_long_long(msgpack_packer* pk, unsigned long long d) int msgpack_pack_float(msgpack_packer* pk, float d) int msgpack_pack_double(msgpack_packer* pk, double d) int msgpack_pack_array(msgpack_packer* pk, size_t l) int msgpack_pack_map(msgpack_packer* pk, size_t l) int msgpack_pack_raw(msgpack_packer* pk, size_t l) int msgpack_pack_bin(msgpack_packer* pk, size_t l) int msgpack_pack_raw_body(msgpack_packer* pk, char* body, size_t l) int msgpack_pack_ext(msgpack_packer* pk, int8_t typecode, size_t l) cdef int DEFAULT_RECURSE_LIMIT=511 cdef class Packer(object): """ MessagePack Packer usage:: packer = Packer() astream.write(packer.pack(a)) astream.write(packer.pack(b)) Packer's constructor has some keyword arguments: :param callable default: Convert user type to builtin type that Packer supports. See also simplejson's document. :param str encoding: Convert unicode to bytes with this encoding. (default: 'utf-8') :param str unicode_errors: Error handler for encoding unicode. (default: 'strict') :param bool use_single_float: Use single precision float type for float. (default: False) :param bool autoreset: Reset buffer after each pack and return it's content as `bytes`. (default: True). If set this to false, use `bytes()` to get content and `.reset()` to clear buffer. :param bool use_bin_type: Use bin type introduced in msgpack spec 2.0 for bytes. It also enable str8 type for unicode. """ cdef msgpack_packer pk cdef object _default cdef object _bencoding cdef object _berrors cdef char *encoding cdef char *unicode_errors cdef bool use_float cdef bint autoreset def __cinit__(self): cdef int buf_size = 1024*1024 self.pk.buf = malloc(buf_size); if self.pk.buf == NULL: raise MemoryError("Unable to allocate internal buffer.") self.pk.buf_size = buf_size self.pk.length = 0 def __init__(self, default=None, encoding='utf-8', unicode_errors='strict', use_single_float=False, bint autoreset=1, bint use_bin_type=0): """ """ self.use_float = use_single_float self.autoreset = autoreset self.pk.use_bin_type = use_bin_type if default is not None: if not PyCallable_Check(default): raise TypeError("default must be a callable.") self._default = default if encoding is None: self.encoding = NULL self.unicode_errors = NULL else: if isinstance(encoding, unicode): self._bencoding = encoding.encode('ascii') else: self._bencoding = encoding self.encoding = PyBytes_AsString(self._bencoding) if isinstance(unicode_errors, unicode): self._berrors = unicode_errors.encode('ascii') else: self._berrors = unicode_errors self.unicode_errors = PyBytes_AsString(self._berrors) def __dealloc__(self): free(self.pk.buf); cdef int _pack(self, object o, int nest_limit=DEFAULT_RECURSE_LIMIT) except -1: cdef long long llval cdef unsigned long long ullval cdef long longval cdef float fval cdef double dval cdef char* rawval cdef int ret cdef dict d cdef size_t L cdef int default_used = 0 if nest_limit < 0: raise PackValueError("recursion limit exceeded.") while True: if o is None: ret = msgpack_pack_nil(&self.pk) elif isinstance(o, bool): if o: ret = msgpack_pack_true(&self.pk) else: ret = msgpack_pack_false(&self.pk) elif PyLong_Check(o): # PyInt_Check(long) is True for Python 3. # Sow we should test long before int. if o > 0: ullval = o ret = msgpack_pack_unsigned_long_long(&self.pk, ullval) else: llval = o ret = msgpack_pack_long_long(&self.pk, llval) elif PyInt_Check(o): longval = o ret = msgpack_pack_long(&self.pk, longval) elif PyFloat_Check(o): if self.use_float: fval = o ret = msgpack_pack_float(&self.pk, fval) else: dval = o ret = msgpack_pack_double(&self.pk, dval) elif PyBytes_Check(o): L = len(o) if L > (2**32)-1: raise ValueError("bytes is too large") rawval = o ret = msgpack_pack_bin(&self.pk, L) if ret == 0: ret = msgpack_pack_raw_body(&self.pk, rawval, L) elif PyUnicode_Check(o): if not self.encoding: raise TypeError("Can't encode unicode string: no encoding is specified") o = PyUnicode_AsEncodedString(o, self.encoding, self.unicode_errors) L = len(o) if L > (2**32)-1: raise ValueError("dict is too large") rawval = o ret = msgpack_pack_raw(&self.pk, len(o)) if ret == 0: ret = msgpack_pack_raw_body(&self.pk, rawval, len(o)) elif PyDict_CheckExact(o): d = o L = len(d) if L > (2**32)-1: raise ValueError("dict is too large") ret = msgpack_pack_map(&self.pk, L) if ret == 0: for k, v in d.iteritems(): ret = self._pack(k, nest_limit-1) if ret != 0: break ret = self._pack(v, nest_limit-1) if ret != 0: break elif PyDict_Check(o): L = len(o) if L > (2**32)-1: raise ValueError("dict is too large") ret = msgpack_pack_map(&self.pk, L) if ret == 0: for k, v in o.items(): ret = self._pack(k, nest_limit-1) if ret != 0: break ret = self._pack(v, nest_limit-1) if ret != 0: break elif isinstance(o, ExtType): # This should be before Tuple because ExtType is namedtuple. longval = o.code rawval = o.data L = len(o.data) if L > (2**32)-1: raise ValueError("EXT data is too large") ret = msgpack_pack_ext(&self.pk, longval, L) ret = msgpack_pack_raw_body(&self.pk, rawval, L) elif PyTuple_Check(o) or PyList_Check(o): L = len(o) if L > (2**32)-1: raise ValueError("list is too large") ret = msgpack_pack_array(&self.pk, L) if ret == 0: for v in o: ret = self._pack(v, nest_limit-1) if ret != 0: break elif not default_used and self._default: o = self._default(o) default_used = 1 continue else: raise TypeError("can't serialize %r" % (o,)) return ret cpdef pack(self, object obj): cdef int ret ret = self._pack(obj, DEFAULT_RECURSE_LIMIT) if ret == -1: raise MemoryError elif ret: # should not happen. raise TypeError if self.autoreset: buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length) self.pk.length = 0 return buf def pack_ext_type(self, typecode, data): msgpack_pack_ext(&self.pk, typecode, len(data)) msgpack_pack_raw_body(&self.pk, data, len(data)) def pack_array_header(self, size_t size): if size > (2**32-1): raise ValueError cdef int ret = msgpack_pack_array(&self.pk, size) if ret == -1: raise MemoryError elif ret: # should not happen raise TypeError if self.autoreset: buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length) self.pk.length = 0 return buf def pack_map_header(self, size_t size): if size > (2**32-1): raise ValueError cdef int ret = msgpack_pack_map(&self.pk, size) if ret == -1: raise MemoryError elif ret: # should not happen raise TypeError if self.autoreset: buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length) self.pk.length = 0 return buf def pack_map_pairs(self, object pairs): """ Pack *pairs* as msgpack map type. *pairs* should sequence of pair. (`len(pairs)` and `for k, v in pairs:` should be supported.) """ cdef int ret = msgpack_pack_map(&self.pk, len(pairs)) if ret == 0: for k, v in pairs: ret = self._pack(k) if ret != 0: break ret = self._pack(v) if ret != 0: break if ret == -1: raise MemoryError elif ret: # should not happen raise TypeError if self.autoreset: buf = PyBytes_FromStringAndSize(self.pk.buf, self.pk.length) self.pk.length = 0 return buf def reset(self): """Clear internal buffer.""" self.pk.length = 0 def bytes(self): """Return buffer content.""" return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length) three.js-r73/utils/converters/msgpack/msgpack/fallback.py0000644000175500017550000006344312610076566023503 0ustar debacledebacle"""Fallback pure Python implementation of msgpack""" import sys import array import struct if sys.version_info[0] == 3: PY3 = True int_types = int Unicode = str xrange = range def dict_iteritems(d): return d.items() else: PY3 = False int_types = (int, long) Unicode = unicode def dict_iteritems(d): return d.iteritems() if hasattr(sys, 'pypy_version_info'): # cStringIO is slow on PyPy, StringIO is faster. However: PyPy's own # StringBuilder is fastest. from __pypy__ import newlist_hint from __pypy__.builders import StringBuilder USING_STRINGBUILDER = True class StringIO(object): def __init__(self, s=b''): if s: self.builder = StringBuilder(len(s)) self.builder.append(s) else: self.builder = StringBuilder() def write(self, s): self.builder.append(s) def getvalue(self): return self.builder.build() else: USING_STRINGBUILDER = False from io import BytesIO as StringIO newlist_hint = lambda size: [] from msgpack.exceptions import ( BufferFull, OutOfData, UnpackValueError, PackValueError, ExtraData) from msgpack import ExtType EX_SKIP = 0 EX_CONSTRUCT = 1 EX_READ_ARRAY_HEADER = 2 EX_READ_MAP_HEADER = 3 TYPE_IMMEDIATE = 0 TYPE_ARRAY = 1 TYPE_MAP = 2 TYPE_RAW = 3 TYPE_BIN = 4 TYPE_EXT = 5 DEFAULT_RECURSE_LIMIT = 511 def unpack(stream, **kwargs): """ Unpack an object from `stream`. Raises `ExtraData` when `packed` contains extra bytes. See :class:`Unpacker` for options. """ unpacker = Unpacker(stream, **kwargs) ret = unpacker._fb_unpack() if unpacker._fb_got_extradata(): raise ExtraData(ret, unpacker._fb_get_extradata()) return ret def unpackb(packed, **kwargs): """ Unpack an object from `packed`. Raises `ExtraData` when `packed` contains extra bytes. See :class:`Unpacker` for options. """ unpacker = Unpacker(None, **kwargs) unpacker.feed(packed) try: ret = unpacker._fb_unpack() except OutOfData: raise UnpackValueError("Data is not enough.") if unpacker._fb_got_extradata(): raise ExtraData(ret, unpacker._fb_get_extradata()) return ret class Unpacker(object): """ Streaming unpacker. `file_like` is a file-like object having a `.read(n)` method. When `Unpacker` is initialized with a `file_like`, `.feed()` is not usable. `read_size` is used for `file_like.read(read_size)`. If `use_list` is True (default), msgpack lists are deserialized to Python lists. Otherwise they are deserialized to tuples. `object_hook` is the same as in simplejson. If it is not None, it should be callable and Unpacker calls it with a dict argument after deserializing a map. `object_pairs_hook` is the same as in simplejson. If it is not None, it should be callable and Unpacker calls it with a list of key-value pairs after deserializing a map. `ext_hook` is callback for ext (User defined) type. It called with two arguments: (code, bytes). default: `msgpack.ExtType` `encoding` is the encoding used for decoding msgpack bytes. If it is None (default), msgpack bytes are deserialized to Python bytes. `unicode_errors` is used for decoding bytes. `max_buffer_size` limits the buffer size. 0 means INT_MAX (default). Raises `BufferFull` exception when it is unsufficient. You should set this parameter when unpacking data from an untrustred source. example of streaming deserialization from file-like object:: unpacker = Unpacker(file_like) for o in unpacker: do_something(o) example of streaming deserialization from socket:: unpacker = Unpacker() while 1: buf = sock.recv(1024*2) if not buf: break unpacker.feed(buf) for o in unpacker: do_something(o) """ def __init__(self, file_like=None, read_size=0, use_list=True, object_hook=None, object_pairs_hook=None, list_hook=None, encoding=None, unicode_errors='strict', max_buffer_size=0, ext_hook=ExtType): if file_like is None: self._fb_feeding = True else: if not callable(file_like.read): raise TypeError("`file_like.read` must be callable") self.file_like = file_like self._fb_feeding = False self._fb_buffers = [] self._fb_buf_o = 0 self._fb_buf_i = 0 self._fb_buf_n = 0 self._max_buffer_size = max_buffer_size or 2**31-1 if read_size > self._max_buffer_size: raise ValueError("read_size must be smaller than max_buffer_size") self._read_size = read_size or min(self._max_buffer_size, 2048) self._encoding = encoding self._unicode_errors = unicode_errors self._use_list = use_list self._list_hook = list_hook self._object_hook = object_hook self._object_pairs_hook = object_pairs_hook self._ext_hook = ext_hook if list_hook is not None and not callable(list_hook): raise TypeError('`list_hook` is not callable') if object_hook is not None and not callable(object_hook): raise TypeError('`object_hook` is not callable') if object_pairs_hook is not None and not callable(object_pairs_hook): raise TypeError('`object_pairs_hook` is not callable') if object_hook is not None and object_pairs_hook is not None: raise TypeError("object_pairs_hook and object_hook are mutually " "exclusive") if not callable(ext_hook): raise TypeError("`ext_hook` is not callable") def feed(self, next_bytes): if isinstance(next_bytes, array.array): next_bytes = next_bytes.tostring() elif isinstance(next_bytes, bytearray): next_bytes = bytes(next_bytes) assert self._fb_feeding if self._fb_buf_n + len(next_bytes) > self._max_buffer_size: raise BufferFull self._fb_buf_n += len(next_bytes) self._fb_buffers.append(next_bytes) def _fb_consume(self): self._fb_buffers = self._fb_buffers[self._fb_buf_i:] if self._fb_buffers: self._fb_buffers[0] = self._fb_buffers[0][self._fb_buf_o:] self._fb_buf_o = 0 self._fb_buf_i = 0 self._fb_buf_n = sum(map(len, self._fb_buffers)) def _fb_got_extradata(self): if self._fb_buf_i != len(self._fb_buffers): return True if self._fb_feeding: return False if not self.file_like: return False if self.file_like.read(1): return True return False def __iter__(self): return self def read_bytes(self, n): return self._fb_read(n) def _fb_rollback(self): self._fb_buf_i = 0 self._fb_buf_o = 0 def _fb_get_extradata(self): bufs = self._fb_buffers[self._fb_buf_i:] if bufs: bufs[0] = bufs[0][self._fb_buf_o:] return b''.join(bufs) def _fb_read(self, n, write_bytes=None): buffs = self._fb_buffers if (write_bytes is None and self._fb_buf_i < len(buffs) and self._fb_buf_o + n < len(buffs[self._fb_buf_i])): self._fb_buf_o += n return buffs[self._fb_buf_i][self._fb_buf_o - n:self._fb_buf_o] ret = b'' while len(ret) != n: if self._fb_buf_i == len(buffs): if self._fb_feeding: break tmp = self.file_like.read(self._read_size) if not tmp: break buffs.append(tmp) continue sliced = n - len(ret) ret += buffs[self._fb_buf_i][self._fb_buf_o:self._fb_buf_o + sliced] self._fb_buf_o += sliced if self._fb_buf_o >= len(buffs[self._fb_buf_i]): self._fb_buf_o = 0 self._fb_buf_i += 1 if len(ret) != n: self._fb_rollback() raise OutOfData if write_bytes is not None: write_bytes(ret) return ret def _read_header(self, execute=EX_CONSTRUCT, write_bytes=None): typ = TYPE_IMMEDIATE n = 0 obj = None c = self._fb_read(1, write_bytes) b = ord(c) if b & 0b10000000 == 0: obj = b elif b & 0b11100000 == 0b11100000: obj = struct.unpack("b", c)[0] elif b & 0b11100000 == 0b10100000: n = b & 0b00011111 obj = self._fb_read(n, write_bytes) typ = TYPE_RAW elif b & 0b11110000 == 0b10010000: n = b & 0b00001111 typ = TYPE_ARRAY elif b & 0b11110000 == 0b10000000: n = b & 0b00001111 typ = TYPE_MAP elif b == 0xc0: obj = None elif b == 0xc2: obj = False elif b == 0xc3: obj = True elif b == 0xc4: typ = TYPE_BIN n = struct.unpack("B", self._fb_read(1, write_bytes))[0] obj = self._fb_read(n, write_bytes) elif b == 0xc5: typ = TYPE_BIN n = struct.unpack(">H", self._fb_read(2, write_bytes))[0] obj = self._fb_read(n, write_bytes) elif b == 0xc6: typ = TYPE_BIN n = struct.unpack(">I", self._fb_read(4, write_bytes))[0] obj = self._fb_read(n, write_bytes) elif b == 0xc7: # ext 8 typ = TYPE_EXT L, n = struct.unpack('Bb', self._fb_read(2, write_bytes)) obj = self._fb_read(L, write_bytes) elif b == 0xc8: # ext 16 typ = TYPE_EXT L, n = struct.unpack('>Hb', self._fb_read(3, write_bytes)) obj = self._fb_read(L, write_bytes) elif b == 0xc9: # ext 32 typ = TYPE_EXT L, n = struct.unpack('>Ib', self._fb_read(5, write_bytes)) obj = self._fb_read(L, write_bytes) elif b == 0xca: obj = struct.unpack(">f", self._fb_read(4, write_bytes))[0] elif b == 0xcb: obj = struct.unpack(">d", self._fb_read(8, write_bytes))[0] elif b == 0xcc: obj = struct.unpack("B", self._fb_read(1, write_bytes))[0] elif b == 0xcd: obj = struct.unpack(">H", self._fb_read(2, write_bytes))[0] elif b == 0xce: obj = struct.unpack(">I", self._fb_read(4, write_bytes))[0] elif b == 0xcf: obj = struct.unpack(">Q", self._fb_read(8, write_bytes))[0] elif b == 0xd0: obj = struct.unpack("b", self._fb_read(1, write_bytes))[0] elif b == 0xd1: obj = struct.unpack(">h", self._fb_read(2, write_bytes))[0] elif b == 0xd2: obj = struct.unpack(">i", self._fb_read(4, write_bytes))[0] elif b == 0xd3: obj = struct.unpack(">q", self._fb_read(8, write_bytes))[0] elif b == 0xd4: # fixext 1 typ = TYPE_EXT n, obj = struct.unpack('b1s', self._fb_read(2, write_bytes)) elif b == 0xd5: # fixext 2 typ = TYPE_EXT n, obj = struct.unpack('b2s', self._fb_read(3, write_bytes)) elif b == 0xd6: # fixext 4 typ = TYPE_EXT n, obj = struct.unpack('b4s', self._fb_read(5, write_bytes)) elif b == 0xd7: # fixext 8 typ = TYPE_EXT n, obj = struct.unpack('b8s', self._fb_read(9, write_bytes)) elif b == 0xd8: # fixext 16 typ = TYPE_EXT n, obj = struct.unpack('b16s', self._fb_read(17, write_bytes)) elif b == 0xd9: typ = TYPE_RAW n = struct.unpack("B", self._fb_read(1, write_bytes))[0] obj = self._fb_read(n, write_bytes) elif b == 0xda: typ = TYPE_RAW n = struct.unpack(">H", self._fb_read(2, write_bytes))[0] obj = self._fb_read(n, write_bytes) elif b == 0xdb: typ = TYPE_RAW n = struct.unpack(">I", self._fb_read(4, write_bytes))[0] obj = self._fb_read(n, write_bytes) elif b == 0xdc: n = struct.unpack(">H", self._fb_read(2, write_bytes))[0] typ = TYPE_ARRAY elif b == 0xdd: n = struct.unpack(">I", self._fb_read(4, write_bytes))[0] typ = TYPE_ARRAY elif b == 0xde: n = struct.unpack(">H", self._fb_read(2, write_bytes))[0] typ = TYPE_MAP elif b == 0xdf: n = struct.unpack(">I", self._fb_read(4, write_bytes))[0] typ = TYPE_MAP else: raise UnpackValueError("Unknown header: 0x%x" % b) return typ, n, obj def _fb_unpack(self, execute=EX_CONSTRUCT, write_bytes=None): typ, n, obj = self._read_header(execute, write_bytes) if execute == EX_READ_ARRAY_HEADER: if typ != TYPE_ARRAY: raise UnpackValueError("Expected array") return n if execute == EX_READ_MAP_HEADER: if typ != TYPE_MAP: raise UnpackValueError("Expected map") return n # TODO should we eliminate the recursion? if typ == TYPE_ARRAY: if execute == EX_SKIP: for i in xrange(n): # TODO check whether we need to call `list_hook` self._fb_unpack(EX_SKIP, write_bytes) return ret = newlist_hint(n) for i in xrange(n): ret.append(self._fb_unpack(EX_CONSTRUCT, write_bytes)) if self._list_hook is not None: ret = self._list_hook(ret) # TODO is the interaction between `list_hook` and `use_list` ok? return ret if self._use_list else tuple(ret) if typ == TYPE_MAP: if execute == EX_SKIP: for i in xrange(n): # TODO check whether we need to call hooks self._fb_unpack(EX_SKIP, write_bytes) self._fb_unpack(EX_SKIP, write_bytes) return if self._object_pairs_hook is not None: ret = self._object_pairs_hook( (self._fb_unpack(EX_CONSTRUCT, write_bytes), self._fb_unpack(EX_CONSTRUCT, write_bytes)) for _ in xrange(n)) else: ret = {} for _ in xrange(n): key = self._fb_unpack(EX_CONSTRUCT, write_bytes) ret[key] = self._fb_unpack(EX_CONSTRUCT, write_bytes) if self._object_hook is not None: ret = self._object_hook(ret) return ret if execute == EX_SKIP: return if typ == TYPE_RAW: if self._encoding is not None: obj = obj.decode(self._encoding, self._unicode_errors) return obj if typ == TYPE_EXT: return self._ext_hook(n, obj) if typ == TYPE_BIN: return obj assert typ == TYPE_IMMEDIATE return obj def next(self): try: ret = self._fb_unpack(EX_CONSTRUCT, None) self._fb_consume() return ret except OutOfData: raise StopIteration __next__ = next def skip(self, write_bytes=None): self._fb_unpack(EX_SKIP, write_bytes) self._fb_consume() def unpack(self, write_bytes=None): ret = self._fb_unpack(EX_CONSTRUCT, write_bytes) self._fb_consume() return ret def read_array_header(self, write_bytes=None): ret = self._fb_unpack(EX_READ_ARRAY_HEADER, write_bytes) self._fb_consume() return ret def read_map_header(self, write_bytes=None): ret = self._fb_unpack(EX_READ_MAP_HEADER, write_bytes) self._fb_consume() return ret class Packer(object): """ MessagePack Packer usage: packer = Packer() astream.write(packer.pack(a)) astream.write(packer.pack(b)) Packer's constructor has some keyword arguments: :param callable default: Convert user type to builtin type that Packer supports. See also simplejson's document. :param str encoding: Convert unicode to bytes with this encoding. (default: 'utf-8') :param str unicode_errors: Error handler for encoding unicode. (default: 'strict') :param bool use_single_float: Use single precision float type for float. (default: False) :param bool autoreset: Reset buffer after each pack and return it's content as `bytes`. (default: True). If set this to false, use `bytes()` to get content and `.reset()` to clear buffer. :param bool use_bin_type: Use bin type introduced in msgpack spec 2.0 for bytes. It also enable str8 type for unicode. """ def __init__(self, default=None, encoding='utf-8', unicode_errors='strict', use_single_float=False, autoreset=True, use_bin_type=False): self._use_float = use_single_float self._autoreset = autoreset self._use_bin_type = use_bin_type self._encoding = encoding self._unicode_errors = unicode_errors self._buffer = StringIO() if default is not None: if not callable(default): raise TypeError("default must be callable") self._default = default def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT, isinstance=isinstance): default_used = False while True: if nest_limit < 0: raise PackValueError("recursion limit exceeded") if obj is None: return self._buffer.write(b"\xc0") if isinstance(obj, bool): if obj: return self._buffer.write(b"\xc3") return self._buffer.write(b"\xc2") if isinstance(obj, int_types): if 0 <= obj < 0x80: return self._buffer.write(struct.pack("B", obj)) if -0x20 <= obj < 0: return self._buffer.write(struct.pack("b", obj)) if 0x80 <= obj <= 0xff: return self._buffer.write(struct.pack("BB", 0xcc, obj)) if -0x80 <= obj < 0: return self._buffer.write(struct.pack(">Bb", 0xd0, obj)) if 0xff < obj <= 0xffff: return self._buffer.write(struct.pack(">BH", 0xcd, obj)) if -0x8000 <= obj < -0x80: return self._buffer.write(struct.pack(">Bh", 0xd1, obj)) if 0xffff < obj <= 0xffffffff: return self._buffer.write(struct.pack(">BI", 0xce, obj)) if -0x80000000 <= obj < -0x8000: return self._buffer.write(struct.pack(">Bi", 0xd2, obj)) if 0xffffffff < obj <= 0xffffffffffffffff: return self._buffer.write(struct.pack(">BQ", 0xcf, obj)) if -0x8000000000000000 <= obj < -0x80000000: return self._buffer.write(struct.pack(">Bq", 0xd3, obj)) raise PackValueError("Integer value out of range") if self._use_bin_type and isinstance(obj, bytes): n = len(obj) if n <= 0xff: self._buffer.write(struct.pack('>BB', 0xc4, n)) elif n <= 0xffff: self._buffer.write(struct.pack(">BH", 0xc5, n)) elif n <= 0xffffffff: self._buffer.write(struct.pack(">BI", 0xc6, n)) else: raise PackValueError("Bytes is too large") return self._buffer.write(obj) if isinstance(obj, (Unicode, bytes)): if isinstance(obj, Unicode): if self._encoding is None: raise TypeError( "Can't encode unicode string: " "no encoding is specified") obj = obj.encode(self._encoding, self._unicode_errors) n = len(obj) if n <= 0x1f: self._buffer.write(struct.pack('B', 0xa0 + n)) elif self._use_bin_type and n <= 0xff: self._buffer.write(struct.pack('>BB', 0xd9, n)) elif n <= 0xffff: self._buffer.write(struct.pack(">BH", 0xda, n)) elif n <= 0xffffffff: self._buffer.write(struct.pack(">BI", 0xdb, n)) else: raise PackValueError("String is too large") return self._buffer.write(obj) if isinstance(obj, float): if self._use_float: return self._buffer.write(struct.pack(">Bf", 0xca, obj)) return self._buffer.write(struct.pack(">Bd", 0xcb, obj)) if isinstance(obj, ExtType): code = obj.code data = obj.data assert isinstance(code, int) assert isinstance(data, bytes) L = len(data) if L == 1: self._buffer.write(b'\xd4') elif L == 2: self._buffer.write(b'\xd5') elif L == 4: self._buffer.write(b'\xd6') elif L == 8: self._buffer.write(b'\xd7') elif L == 16: self._buffer.write(b'\xd8') elif L <= 0xff: self._buffer.write(struct.pack(">BB", 0xc7, L)) elif L <= 0xffff: self._buffer.write(struct.pack(">BH", 0xc8, L)) else: self._buffer.write(struct.pack(">BI", 0xc9, L)) self._buffer.write(struct.pack("b", code)) self._buffer.write(data) return if isinstance(obj, (list, tuple)): n = len(obj) self._fb_pack_array_header(n) for i in xrange(n): self._pack(obj[i], nest_limit - 1) return if isinstance(obj, dict): return self._fb_pack_map_pairs(len(obj), dict_iteritems(obj), nest_limit - 1) if not default_used and self._default is not None: obj = self._default(obj) default_used = 1 continue raise TypeError("Cannot serialize %r" % obj) def pack(self, obj): self._pack(obj) ret = self._buffer.getvalue() if self._autoreset: self._buffer = StringIO() elif USING_STRINGBUILDER: self._buffer = StringIO(ret) return ret def pack_map_pairs(self, pairs): self._fb_pack_map_pairs(len(pairs), pairs) ret = self._buffer.getvalue() if self._autoreset: self._buffer = StringIO() elif USING_STRINGBUILDER: self._buffer = StringIO(ret) return ret def pack_array_header(self, n): if n >= 2**32: raise ValueError self._fb_pack_array_header(n) ret = self._buffer.getvalue() if self._autoreset: self._buffer = StringIO() elif USING_STRINGBUILDER: self._buffer = StringIO(ret) return ret def pack_map_header(self, n): if n >= 2**32: raise ValueError self._fb_pack_map_header(n) ret = self._buffer.getvalue() if self._autoreset: self._buffer = StringIO() elif USING_STRINGBUILDER: self._buffer = StringIO(ret) return ret def pack_ext_type(self, typecode, data): if not isinstance(typecode, int): raise TypeError("typecode must have int type.") if not 0 <= typecode <= 127: raise ValueError("typecode should be 0-127") if not isinstance(data, bytes): raise TypeError("data must have bytes type") L = len(data) if L > 0xffffffff: raise ValueError("Too large data") if L == 1: self._buffer.write(b'\xd4') elif L == 2: self._buffer.write(b'\xd5') elif L == 4: self._buffer.write(b'\xd6') elif L == 8: self._buffer.write(b'\xd7') elif L == 16: self._buffer.write(b'\xd8') elif L <= 0xff: self._buffer.write(b'\xc7' + struct.pack('B', L)) elif L <= 0xffff: self._buffer.write(b'\xc8' + struct.pack('>H', L)) else: self._buffer.write(b'\xc9' + struct.pack('>I', L)) self._buffer.write(struct.pack('B', typecode)) self._buffer.write(data) def _fb_pack_array_header(self, n): if n <= 0x0f: return self._buffer.write(struct.pack('B', 0x90 + n)) if n <= 0xffff: return self._buffer.write(struct.pack(">BH", 0xdc, n)) if n <= 0xffffffff: return self._buffer.write(struct.pack(">BI", 0xdd, n)) raise PackValueError("Array is too large") def _fb_pack_map_header(self, n): if n <= 0x0f: return self._buffer.write(struct.pack('B', 0x80 + n)) if n <= 0xffff: return self._buffer.write(struct.pack(">BH", 0xde, n)) if n <= 0xffffffff: return self._buffer.write(struct.pack(">BI", 0xdf, n)) raise PackValueError("Dict is too large") def _fb_pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT): self._fb_pack_map_header(n) for (k, v) in pairs: self._pack(k, nest_limit - 1) self._pack(v, nest_limit - 1) def bytes(self): return self._buffer.getvalue() def reset(self): self._buffer = StringIO() three.js-r73/utils/converters/msgpack/msgpack/exceptions.py0000644000175500017550000000076712610076566024125 0ustar debacledebacleclass UnpackException(Exception): pass class BufferFull(UnpackException): pass class OutOfData(UnpackException): pass class UnpackValueError(UnpackException, ValueError): pass class ExtraData(ValueError): def __init__(self, unpacked, extra): self.unpacked = unpacked self.extra = extra def __str__(self): return "unpack(b) received extra data." class PackException(Exception): pass class PackValueError(PackException, ValueError): pass three.js-r73/utils/converters/msgpack/json2msgpack.py0000755000175500017550000000252612610076566022716 0ustar debacledebacle#!/usr/bin/env python __doc__ = ''' Convert a json file to msgpack. If fed only an input file the converted will write out a .pack file of the same base name in the same directory $ json2msgpack.py -i foo.json foo.json > foo.pack Specify an output file path $ json2msgpack.py -i foo.json -o /bar/tmp/bar.pack foo.json > /bar/tmp/bar.pack Dependencies: https://github.com/msgpack/msgpack-python ''' import os import sys import json import argparse sys.path.append(os.path.dirname(os.path.realpath(__file__))) import msgpack EXT = '.pack' def main(): parser = argparse.ArgumentParser() parser.add_argument('-i', '--infile', required=True, help='Input json file to convert to msgpack') parser.add_argument('-o', '--outfile', help=('Optional output. If not specified the .pack file '\ 'will write to the same director as the input file.')) args = parser.parse_args() convert(args.infile, args.outfile) def convert(infile, outfile): if not outfile: ext = infile.split('.')[-1] outfile = '%s%s' % (infile[:-len(ext)-1], EXT) print('%s > %s' % (infile, outfile)) print('reading in JSON') with open(infile) as op: data = json.load(op) print('writing to msgpack') with open(outfile, 'wb') as op: msgpack.dump(data, op) if __name__ == '__main__': main() three.js-r73/utils/converters/utf8/0000755000175500017550000000000012640541325017165 5ustar debacledebaclethree.js-r73/utils/converters/utf8/src/0000755000175500017550000000000012610076566017763 5ustar debacledebaclethree.js-r73/utils/converters/utf8/src/optimize.h0000644000175500017550000002270412610076566022001 0ustar debacledebacle// Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #ifndef WEBGL_LOADER_OPTIMIZE_H_ #define WEBGL_LOADER_OPTIMIZE_H_ #include #include #include #include "base.h" // TODO: since most vertices are part of 6 faces, you can optimize // this by using a small inline buffer. typedef std::vector FaceList; // Linear-Speed Vertex Cache Optimisation, via: // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html class VertexOptimizer { public: struct TriangleData { bool active; // true iff triangle has not been optimized and emitted. // TODO: eliminate some wasted computation by using this cache. // float score; }; VertexOptimizer(const QuantizedAttribList& attribs) : attribs_(attribs), per_vertex_(attribs_.size() / 8), next_unused_index_(0) { // The cache has an extra slot allocated to simplify the logic in // InsertIndexToCache. for (unsigned int i = 0; i < kCacheSize + 1; ++i) { cache_[i] = kUnknownIndex; } // Initialize per-vertex state. for (size_t i = 0; i < per_vertex_.size(); ++i) { VertexData& vertex_data = per_vertex_[i]; vertex_data.cache_tag = kCacheSize; vertex_data.output_index = kMaxOutputIndex; } } void AddTriangles(const int* indices, size_t length, WebGLMeshList* meshes) { std::vector per_tri(length / 3); // Loop through the triangles, updating vertex->face lists. for (size_t i = 0; i < per_tri.size(); ++i) { per_tri[i].active = true; per_vertex_[indices[3*i + 0]].faces.push_back(i); per_vertex_[indices[3*i + 1]].faces.push_back(i); per_vertex_[indices[3*i + 2]].faces.push_back(i); } // TODO: with index bounds, no need to recompute everything. // Compute initial vertex scores. for (size_t i = 0; i < per_vertex_.size(); ++i) { VertexData& vertex_data = per_vertex_[i]; vertex_data.cache_tag = kCacheSize; vertex_data.output_index = kMaxOutputIndex; vertex_data.UpdateScore(); } // Prepare output. if (meshes->empty()) { meshes->push_back(WebGLMesh()); } WebGLMesh* mesh = &meshes->back(); // Consume indices, one triangle at a time. for (size_t c = 0; c < per_tri.size(); ++c) { const int best_triangle = FindBestTriangle(indices, per_tri); per_tri[best_triangle].active = false; // Iterate through triangle indices. for (size_t i = 0; i < 3; ++i) { const int index = indices[3*best_triangle + i]; VertexData& vertex_data = per_vertex_[index]; vertex_data.RemoveFace(best_triangle); InsertIndexToCache(index); const int cached_output_index = per_vertex_[index].output_index; // Have we seen this index before? if (cached_output_index != kMaxOutputIndex) { mesh->indices.push_back(cached_output_index); continue; } // The first time we see an index, not only do we increment // next_unused_index_ counter, but we must also copy the // corresponding attributes. TODO: do quantization here? per_vertex_[index].output_index = next_unused_index_; for (size_t j = 0; j < 8; ++j) { mesh->attribs.push_back(attribs_[8*index + j]); } mesh->indices.push_back(next_unused_index_++); } // Check if there is room for another triangle. if (next_unused_index_ > kMaxOutputIndex - 3) { // Is it worth figuring out which other triangles can be added // given the verties already added? Then, perhaps // re-optimizing? next_unused_index_ = 0; meshes->push_back(WebGLMesh()); mesh = &meshes->back(); for (size_t i = 0; i <= kCacheSize; ++i) { cache_[i] = kUnknownIndex; } for (size_t i = 0; i < per_vertex_.size(); ++i) { per_vertex_[i].output_index = kMaxOutputIndex; } } } } private: static const int kUnknownIndex = -1; static const uint16 kMaxOutputIndex = 0xD800; static const size_t kCacheSize = 32; // Does larger improve compression? struct VertexData { // Should this also update scores for incident triangles? void UpdateScore() { const size_t active_tris = faces.size(); if (active_tris <= 0) { score = -1.f; return; } // TODO: build initial score table. if (cache_tag < 3) { // The most recent triangle should has a fixed score to // discourage generating nothing but really long strips. If we // want strips, we should use a different optimizer. const float kLastTriScore = 0.75f; score = kLastTriScore; } else if (cache_tag < kCacheSize) { // Points for being recently used. const float kScale = 1.f / (kCacheSize - 3); const float kCacheDecayPower = 1.5f; score = powf(1.f - kScale * (cache_tag - 3), kCacheDecayPower); } else { // Not in cache. score = 0.f; } // Bonus points for having a low number of tris still to use the // vert, so we get rid of lone verts quickly. const float kValenceBoostScale = 2.0f; const float kValenceBoostPower = 0.5f; // rsqrt? const float valence_boost = powf(active_tris, -kValenceBoostPower); score += valence_boost * kValenceBoostScale; } // TODO: this assumes that "tri" is in the list! void RemoveFace(int tri) { FaceList::iterator face = faces.begin(); while (*face != tri) ++face; *face = faces.back(); faces.pop_back(); } FaceList faces; unsigned int cache_tag; // kCacheSize means not in cache. float score; uint16 output_index; }; int FindBestTriangle(const int* indices, const std::vector& per_tri) { float best_score = -HUGE_VALF; int best_triangle = -1; // The trick to making this algorithm run in linear time (with // respect to the vertices) is to only scan the triangles incident // on the simulated cache for the next triangle. It is an // approximation, but the score is heuristic. Anyway, most of the // time the best triangle will be found this way. for (size_t i = 0; i < kCacheSize; ++i) { if (cache_[i] == kUnknownIndex) { break; } const VertexData& vertex_data = per_vertex_[cache_[i]]; for (size_t j = 0; j < vertex_data.faces.size(); ++j) { const int tri_index = vertex_data.faces[j]; if (per_tri[tri_index].active) { const float score = per_vertex_[indices[3*tri_index + 0]].score + per_vertex_[indices[3*tri_index + 1]].score + per_vertex_[indices[3*tri_index + 2]].score; if (score > best_score) { best_score = score; best_triangle = tri_index; } } } } // TODO: keep a range of active triangles to make the slow scan a // little faster. Does this ever happen? if (best_triangle == -1) { // If no triangles can be found through the cache (e.g. for the // first triangle) go through all the active triangles and find // the best one. for (size_t i = 0; i < per_tri.size(); ++i) { if (per_tri[i].active) { const float score = per_vertex_[indices[3*i + 0]].score + per_vertex_[indices[3*i + 1]].score + per_vertex_[indices[3*i + 2]].score; if (score > best_score) { best_score = score; best_triangle = i; } } } CHECK(-1 != best_triangle); } return best_triangle; } // TODO: faster to update an entire triangle. // This also updates the vertex scores! void InsertIndexToCache(int index) { // Find how recently the vertex was used. const unsigned int cache_tag = per_vertex_[index].cache_tag; // Don't do anything if the vertex is already at the head of the // LRU list. if (cache_tag == 0) return; // Loop through the cache, inserting the index at the front, and // bubbling down to where the index was originally found. If the // index was not originally in the cache, then it claims to be at // the (kCacheSize + 1)th entry, and we use an extra slot to make // that case simpler. int to_insert = index; for (unsigned int i = 0; i <= cache_tag; ++i) { const int current_index = cache_[i]; // Update cross references between the entry of the cache and // the per-vertex data. cache_[i] = to_insert; per_vertex_[to_insert].cache_tag = i; per_vertex_[to_insert].UpdateScore(); // No need to continue if we find an empty entry. if (current_index == kUnknownIndex) { break; } to_insert = current_index; } } const QuantizedAttribList& attribs_; std::vector per_vertex_; int cache_[kCacheSize + 1]; uint16 next_unused_index_; }; #endif // WEBGL_LOADER_OPTIMIZE_H_ three.js-r73/utils/converters/utf8/src/stream.h0000644000175500017550000001407212610076566021433 0ustar debacledebacle// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #ifndef WEBGL_LOADER_STREAM_H_ #define WEBGL_LOADER_STREAM_H_ #include #include #include #include "base.h" namespace webgl_loader { // An abstract interface to allow appending bytes to various streams. class ByteSinkInterface { public: virtual void Put(char c) = 0; virtual size_t PutN(const char* data, size_t len) = 0; virtual ~ByteSinkInterface() { } protected: ByteSinkInterface() { } private: // Disallow copy and assignment. ByteSinkInterface(const ByteSinkInterface&); void operator=(const ByteSinkInterface&); }; // None of the concrete implementations actually own the backing data. // They should be safe to copy. class NullSink : public ByteSinkInterface { public: NullSink() { } virtual void Put(char) { } virtual size_t PutN(const char*, size_t len) { return len; } }; class FileSink : public ByteSinkInterface { public: // |fp| is unowned and must not be NULL. explicit FileSink(FILE* fp) : fp_(fp) { } virtual void Put(char c) { PutChar(c, fp_); } virtual size_t PutN(const char* data, size_t len) { return fwrite(data, 1, len, fp_); } private: FILE *fp_; // unowned. }; class VectorSink : public ByteSinkInterface { public: // |vec| is unowned and must not be NULL. explicit VectorSink(std::vector* vec) : vec_(vec) { } virtual void Put(char c) { vec_->push_back(c); } virtual size_t PutN(const char* data, size_t len) { vec_->insert(vec_->end(), data, data + len); return len; } private: std::vector* vec_; // unowned. }; class StringSink : public ByteSinkInterface { public: // |str| is unowned and must not be NULL. explicit StringSink(std::string* str) : str_(str) { DCHECK(str != NULL); } virtual void Put(char c) { str_->push_back(c); } virtual size_t PutN(const char* data, size_t len) { str_->append(data, len); return len; } private: std::string* str_; // unowned. }; class ByteHistogramSink : public ByteSinkInterface { public: // |sink| in unowned and must not be NULL. explicit ByteHistogramSink(ByteSinkInterface* sink) : sink_(sink) { memset(histo_, 0, sizeof(histo_)); } virtual void Put(char c) { histo_[static_cast(c)]++; sink_->Put(c); } virtual size_t PutN(const char* data, size_t len) { const char* const end = data + len; for (const char* iter = data; iter != end; ++iter) { histo_[static_cast(*iter)]++; } return sink_->PutN(data, len); } const size_t* histo() const { return histo_; } private: size_t histo_[256]; ByteSinkInterface* sink_; // unowned. }; // TODO: does it make sense to have a global enum? How should // new BufferedInput implementations define new error codes? enum ErrorCode { kNoError = 0, kEndOfFile = 1, kFileError = 2, // TODO: translate errno. }; // Adapted from ryg's BufferedStream abstraction: // http://fgiesen.wordpress.com/2011/11/21/buffer-centric-io/ class BufferedInput { public: typedef ErrorCode (*Refiller)(BufferedInput*); BufferedInput(Refiller refiller = RefillZeroes) : cursor(NULL), begin_(NULL), end_(NULL), refiller_(refiller), error_(kNoError) { } // InitFromMemory. BufferedInput(const char* data, size_t length) : cursor(data), begin_(data), end_(data + length), refiller_(RefillEndOfFile), error_(kNoError) { } const char* begin() const { return begin_; } const char* end() const { return end_; } const char* cursor; ErrorCode error() const { DCHECK(begin() <= cursor); DCHECK(cursor <= end()); return error_; } ErrorCode Refill() { DCHECK(begin() <= cursor); DCHECK(cursor <= end()); if (cursor == end()) { error_ = refiller_(this); } return error_; } protected: static ErrorCode RefillZeroes(BufferedInput* bi) { static const char kZeroes[64] = { 0 }; bi->cursor = kZeroes; bi->begin_ = kZeroes; bi->end_ = kZeroes + sizeof(kZeroes); return bi->error_; } static ErrorCode RefillEndOfFile(BufferedInput* bi) { return bi->fail(kEndOfFile); } ErrorCode fail(ErrorCode why) { error_ = why; refiller_ = RefillZeroes; return Refill(); } const char* begin_; const char* end_; Refiller refiller_; ErrorCode error_; private: // Disallow copy and assign. BufferedInput(const BufferedInput&); void operator=(const BufferedInput&); }; class BufferedInputStream : public BufferedInput { public: BufferedInputStream(FILE* fp, char* buf, size_t size) : BufferedInput(RefillFread), fp_(fp), buf_(buf), size_(size) { DCHECK(buf != NULL); // Disable buffering since we're doing it ourselves. // TODO check error. setvbuf(fp_, NULL, _IONBF, 0); cursor = buf; begin_ = buf; end_ = buf; } protected: // TODO: figure out how to automate this casting pattern. static ErrorCode RefillFread(BufferedInput* bi) { return static_cast(bi)->DoRefillFread(); } private: ErrorCode DoRefillFread() { const size_t bytes_read = fread(buf_, 1, size_, fp_); cursor = begin_; end_ = begin_ + bytes_read; if (bytes_read < size_) { if (feof(fp_)) { refiller_ = RefillEndOfFile; } else if (ferror(fp_)) { return fail(kFileError); } } return kNoError; } FILE* fp_; char* buf_; size_t size_; }; } // namespace webgl_loader #endif // WEBGL_LOADER_STREAM_H_ three.js-r73/utils/converters/utf8/src/bounds.h0000644000175500017550000000721112610076566021427 0ustar debacledebacle// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #ifndef WEBGL_LOADER_BOUNDS_H_ #define WEBGL_LOADER_BOUNDS_H_ #include #include "base.h" namespace webgl_loader { // TODO: arbitrary vertex formats. struct Bounds { float mins[8]; float maxes[8]; void Clear() { for (size_t i = 0; i < 8; ++i) { mins[i] = FLT_MAX; maxes[i] = -FLT_MAX; } } void EncloseAttrib(const float* attribs) { for (size_t i = 0; i < 8; ++i) { const float attrib = attribs[i]; if (mins[i] > attrib) { mins[i] = attrib; } if (maxes[i] < attrib) { maxes[i] = attrib; } } } void Enclose(const AttribList& attribs) { for (size_t i = 0; i < attribs.size(); i += 8) { EncloseAttrib(&attribs[i]); } } float UniformScale() const { const float x = maxes[0] - mins[0]; const float y = maxes[1] - mins[1]; const float z = maxes[2] - mins[2]; return (x > y) // TODO: max3 ? ((x > z) ? x : z) : ((y > z) ? y : z); } }; // TODO: make maxPosition et. al. configurable. struct BoundsParams { static BoundsParams FromBounds(const Bounds& bounds) { BoundsParams ret; const float scale = bounds.UniformScale(); // Position. Use a uniform scale. for (size_t i = 0; i < 3; ++i) { const int maxPosition = (1 << 14) - 1; // 16383; ret.mins[i] = bounds.mins[i]; ret.scales[i] = scale; ret.outputMaxes[i] = maxPosition; ret.decodeOffsets[i] = maxPosition * bounds.mins[i] / scale; ret.decodeScales[i] = scale / maxPosition; } // TexCoord. // TODO: get bounds-dependent texcoords working! for (size_t i = 3; i < 5; ++i) { // const float texScale = bounds.maxes[i] - bounds.mins[i]; const int maxTexcoord = (1 << 10) - 1; // 1023 ret.mins[i] = 0; //bounds.mins[i]; ret.scales[i] = 1; //texScale; ret.outputMaxes[i] = maxTexcoord; ret.decodeOffsets[i] = 0; //maxTexcoord * bounds.mins[i] / texScale; ret.decodeScales[i] = 1.0f / maxTexcoord; // texScale / maxTexcoord; } // Normal. Always uniform range. for (size_t i = 5; i < 8; ++i) { ret.mins[i] = -1; ret.scales[i] = 2.f; ret.outputMaxes[i] = (1 << 10) - 1; // 1023 ret.decodeOffsets[i] = 1 - (1 << 9); // -511 ret.decodeScales[i] = 1.0 / 511; } return ret; } void DumpJson(FILE* out = stdout) { // TODO: use JsonSink. fputs("{\n", out); fprintf(out, " \"decodeOffsets\": [%d,%d,%d,%d,%d,%d,%d,%d],\n", decodeOffsets[0], decodeOffsets[1], decodeOffsets[2], decodeOffsets[3], decodeOffsets[4], decodeOffsets[5], decodeOffsets[6], decodeOffsets[7]); fprintf(out, " \"decodeScales\": [%f,%f,%f,%f,%f,%f,%f,%f]\n", decodeScales[0], decodeScales[1], decodeScales[2], decodeScales[3], decodeScales[4], decodeScales[5], decodeScales[6], decodeScales[7]); fputs(" }", out); } float mins[8]; float scales[8]; int outputMaxes[8]; int decodeOffsets[8]; float decodeScales[8]; }; } // namespace webgl_loader #endif // WEBGL_LOADER_BOUNDS_H_ three.js-r73/utils/converters/utf8/src/README0000644000175500017550000000136212610076566020645 0ustar debacledebacleUsage: ./objcompress in.obj [out.utf8] If 'out' is specified, then attempt to write out a compressed, UTF-8 version to 'out.' If not, write a JSON version to STDOUT. Usage: ./objanalyze in.obj [list of cache sizes] Perform vertex cache analysis on in.obj using specified sizes. For example: ./objanalyze in.obj 6 16 24 32 Maximum cache size is 32. Building: Since there are no external dependences outside of the C/C++ standard libraries, you can pretty much build this however you please. I've included a cheeky way to do this on POSIX-like systems by including a build shell script at the top of the file itself. You can build by making the .cc file executable, and running it on the command line. three.js-r73/utils/converters/utf8/src/objcompress.cc0000644000175500017550000001433412610076566022625 0ustar debacledebacle#if 0 // A cute trick to making this .cc self-building from shell. g++ $0 -O2 -Wall -Werror -o `basename $0 .cc`; exit; #endif // Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #include "bounds.h" #include "compress.h" #include "mesh.h" #include "optimize.h" #include "stream.h" int main(int argc, const char* argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s in.obj out.utf8\n\n" "\tCompress in.obj to out.utf8 and writes JS to STDOUT.\n\n", argv[0]); return -1; } FILE* fp = fopen(argv[1], "r"); WavefrontObjFile obj(fp); fclose(fp); printf("MODELS[\'%s\'] = {\n", StripLeadingDir(argv[1])); puts(" materials: {"); const MaterialList& materials = obj.materials(); for (size_t i = 0; i < materials.size(); ++i) { materials[i].DumpJson(); } puts(" },"); const MaterialBatches& batches = obj.material_batches(); // Pass 1: compute bounds. webgl_loader::Bounds bounds; bounds.Clear(); for (MaterialBatches::const_iterator iter = batches.begin(); iter != batches.end(); ++iter) { const DrawBatch& draw_batch = iter->second; bounds.Enclose(draw_batch.draw_mesh().attribs); } webgl_loader::BoundsParams bounds_params = webgl_loader::BoundsParams::FromBounds(bounds); printf(" decodeParams: "); bounds_params.DumpJson(); puts(" urls: {"); std::vector utf8; webgl_loader::VectorSink sink(&utf8); // Pass 2: quantize, optimize, compress, report. for (MaterialBatches::const_iterator iter = batches.begin(); iter != batches.end(); ++iter) { size_t offset = 0; utf8.clear(); const DrawMesh& draw_mesh = iter->second.draw_mesh(); if (draw_mesh.indices.empty()) continue; QuantizedAttribList quantized_attribs; webgl_loader::AttribsToQuantizedAttribs(draw_mesh.attribs, bounds_params, &quantized_attribs); VertexOptimizer vertex_optimizer(quantized_attribs); const std::vector& group_starts = iter->second.group_starts(); WebGLMeshList webgl_meshes; std::vector group_lengths; for (size_t i = 1; i < group_starts.size(); ++i) { const size_t here = group_starts[i-1].offset; const size_t length = group_starts[i].offset - here; group_lengths.push_back(length); vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length, &webgl_meshes); } const size_t here = group_starts.back().offset; const size_t length = draw_mesh.indices.size() - here; const bool divisible_by_3 = length % 3 == 0; CHECK(divisible_by_3); group_lengths.push_back(length); vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length, &webgl_meshes); std::vector material; std::vector attrib_start, attrib_length, index_start, index_length; for (size_t i = 0; i < webgl_meshes.size(); ++i) { const size_t num_attribs = webgl_meshes[i].attribs.size(); const size_t num_indices = webgl_meshes[i].indices.size(); const bool kBadSizes = num_attribs % 8 || num_indices % 3; CHECK(!kBadSizes); webgl_loader::CompressQuantizedAttribsToUtf8(webgl_meshes[i].attribs, &sink); webgl_loader::CompressIndicesToUtf8(webgl_meshes[i].indices, &sink); material.push_back(iter->first); attrib_start.push_back(offset); attrib_length.push_back(num_attribs / 8); index_start.push_back(offset + num_attribs); index_length.push_back(num_indices / 3); offset += num_attribs + num_indices; } const uint32 hash = SimpleHash(&utf8[0], utf8.size()); char buf[9] = { '\0' }; ToHex(hash, buf); // TODO: this needs to handle paths. std::string out_fn = std::string(buf) + "." + argv[2]; FILE* out_fp = fopen(out_fn.c_str(), "wb"); printf(" \'%s\': [\n", out_fn.c_str()); size_t group_index = 0; for (size_t i = 0; i < webgl_meshes.size(); ++i) { printf(" { material: \'%s\',\n" " attribRange: [" PRIuS ", " PRIuS "],\n" " indexRange: [" PRIuS ", " PRIuS "],\n" " bboxes: " PRIuS ",\n" " names: [", material[i].c_str(), attrib_start[i], attrib_length[i], index_start[i], index_length[i], offset); std::vector buffered_lengths; size_t group_start = 0; while (group_index < group_lengths.size()) { printf("\'%s\', ", obj.LineToGroup(group_starts[group_index].group_line).c_str()); const size_t group_length = group_lengths[group_index]; const size_t next_start = group_start + group_length; const size_t webgl_index_length = webgl_meshes[i].indices.size(); // TODO: bbox info is better placed at the head of the file, // perhaps transposed. Also, when a group gets split between // batches, the bbox gets stored twice. webgl_loader::CompressAABBToUtf8(group_starts[group_index].bounds, bounds_params, &sink); offset += 6; if (next_start < webgl_index_length) { buffered_lengths.push_back(group_length); group_start = next_start; ++group_index; } else { const size_t fits = webgl_index_length - group_start; buffered_lengths.push_back(fits); group_start = 0; group_lengths[group_index] -= fits; break; } } printf("],\n lengths: ["); for (size_t k = 0; k < buffered_lengths.size(); ++k) { printf(PRIuS ", ", buffered_lengths[k]); } puts("],\n },"); } fwrite(&utf8[0], 1, utf8.size(), out_fp); fclose(out_fp); puts(" ],"); } puts(" }\n};"); return 0; } three.js-r73/utils/converters/utf8/src/obj2utf8.cc0000644000175500017550000001173212610076566021741 0ustar debacledebacle#if 0 // A cute trick to making this .cc self-building from shell. g++ $0 -O2 -Wall -Werror -o `basename $0 .cc`; exit; #endif // Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #include "bounds.h" #include "compress.h" #include "mesh.h" #include "optimize.h" #include "stream.h" int main(int argc, const char* argv[]) { FILE* json_out = stdout; if (argc != 3 && argc != 4) { fprintf(stderr, "Usage: %s in.obj out.utf8\n\n" "\tCompress in.obj to out.utf8 and writes JS to STDOUT.\n\n", argv[0]); return -1; } else if (argc == 4) { json_out = fopen(argv[3], "w"); CHECK(json_out != NULL); } FILE* fp = fopen(argv[1], "r"); WavefrontObjFile obj(fp); fclose(fp); fputs("{\n \"materials\": {\n", json_out); const MaterialList& materials = obj.materials(); for (size_t i = 0; i < materials.size(); ++i) { materials[i].DumpJson(json_out); const bool last = i == materials.size() - 1; fputs(",\n" + last, json_out); } fputs(" },\n", json_out); const MaterialBatches& batches = obj.material_batches(); // Pass 1: compute bounds. webgl_loader::Bounds bounds; bounds.Clear(); for (MaterialBatches::const_iterator iter = batches.begin(); iter != batches.end(); ++iter) { const DrawBatch& draw_batch = iter->second; bounds.Enclose(draw_batch.draw_mesh().attribs); } webgl_loader::BoundsParams bounds_params = webgl_loader::BoundsParams::FromBounds(bounds); fputs(" \"decodeParams\": ", json_out); bounds_params.DumpJson(json_out); fputs(", \"urls\": {\n", json_out); // Pass 2: quantize, optimize, compress, report. FILE* utf8_out_fp = fopen(argv[2], "wb"); CHECK(utf8_out_fp != NULL); fprintf(json_out, " \"%s\": [\n", argv[2]); webgl_loader::FileSink utf8_sink(utf8_out_fp); size_t offset = 0; MaterialBatches::const_iterator iter = batches.begin(); while (iter != batches.end()) { const DrawMesh& draw_mesh = iter->second.draw_mesh(); if (draw_mesh.indices.empty()) { ++iter; continue; } QuantizedAttribList quantized_attribs; webgl_loader::AttribsToQuantizedAttribs(draw_mesh.attribs, bounds_params, &quantized_attribs); VertexOptimizer vertex_optimizer(quantized_attribs); const std::vector& group_starts = iter->second.group_starts(); WebGLMeshList webgl_meshes; std::vector group_lengths; for (size_t i = 1; i < group_starts.size(); ++i) { const size_t here = group_starts[i-1].offset; const size_t length = group_starts[i].offset - here; group_lengths.push_back(length); vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length, &webgl_meshes); } const size_t here = group_starts.back().offset; const size_t length = draw_mesh.indices.size() - here; CHECK(length % 3 == 0); group_lengths.push_back(length); vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length, &webgl_meshes); std::vector material; std::vector attrib_start, attrib_length, index_start, index_length; for (size_t i = 0; i < webgl_meshes.size(); ++i) { const size_t num_attribs = webgl_meshes[i].attribs.size(); const size_t num_indices = webgl_meshes[i].indices.size(); CHECK(num_attribs % 8 == 0); CHECK(num_indices % 3 == 0); webgl_loader::CompressQuantizedAttribsToUtf8(webgl_meshes[i].attribs, &utf8_sink); webgl_loader::CompressIndicesToUtf8(webgl_meshes[i].indices, &utf8_sink); material.push_back(iter->first); attrib_start.push_back(offset); attrib_length.push_back(num_attribs / 8); index_start.push_back(offset + num_attribs); index_length.push_back(num_indices / 3); offset += num_attribs + num_indices; } for (size_t i = 0; i < webgl_meshes.size(); ++i) { fprintf(json_out, " { \"material\": \"%s\",\n" " \"attribRange\": [" PRIuS ", " PRIuS "],\n" " \"indexRange\": [" PRIuS ", " PRIuS "]\n" " }", material[i].c_str(), attrib_start[i], attrib_length[i], index_start[i], index_length[i]); if (i != webgl_meshes.size() - 1) { fputs(",\n", json_out); } } const bool last = (++iter == batches.end()); fputs(",\n" + last, json_out); } fputs(" ]\n", json_out); fputs(" }\n}", json_out); return 0; } three.js-r73/utils/converters/utf8/src/mesh.h0000644000175500017550000005236312610076566021101 0ustar debacledebacle// Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #ifndef WEBGL_LOADER_MESH_H_ #define WEBGL_LOADER_MESH_H_ #include #include #include #include #include #include #include #include #include #include "base.h" #include "bounds.h" #include "stream.h" #include "utf8.h" // A short list of floats, useful for parsing a single vector // attribute. class ShortFloatList { public: // MeshLab can create position attributes with // color coordinates like: v x y z r g b static const size_t kMaxNumFloats = 6; ShortFloatList() : size_(0) { clear(); } void clear() { for (size_t i = 0; i < kMaxNumFloats; ++i) { a_[i] = 0.f; } } // Parse up to kMaxNumFloats from C string. // TODO: this should instead return endptr, since size // is recoverable. size_t ParseLine(const char* line) { for (size_ = 0; size_ != kMaxNumFloats; ++size_) { char* endptr = NULL; a_[size_] = strtof(line, &endptr); if (endptr == NULL || line == endptr) break; line = endptr; } return size_; } float operator[](size_t idx) const { return a_[idx]; } void AppendTo(AttribList* attribs) const { AppendNTo(attribs, size_); } void AppendNTo(AttribList* attribs, const size_t sz) const { attribs->insert(attribs->end(), a_, a_ + sz); } bool empty() const { return size_ == 0; } size_t size() const { return size_; } private: float a_[kMaxNumFloats]; size_t size_; }; class IndexFlattener { public: explicit IndexFlattener(size_t num_positions) : count_(0), table_(num_positions) { } int count() const { return count_; } void reserve(size_t size) { table_.reserve(size); } // Returns a pair of: < flattened index, newly inserted >. std::pair GetFlattenedIndex(int position_index, int texcoord_index, int normal_index) { if (position_index >= static_cast(table_.size())) { table_.resize(position_index + 1); } // First, optimistically look up position_index in the table. IndexType& index = table_[position_index]; if (index.position_or_flat == kIndexUnknown) { // This is the first time we've seen this position in the table, // so fill it. Since the table is indexed by position, we can // use the position_or_flat_index field to store the flat index. const int flat_index = count_++; index.position_or_flat = flat_index; index.texcoord = texcoord_index; index.normal = normal_index; return std::make_pair(flat_index, true); } else if (index.position_or_flat == kIndexNotInTable) { // There are multiple flattened indices at this position index, // so resort to the map. return GetFlattenedIndexFromMap(position_index, texcoord_index, normal_index); } else if (index.texcoord == texcoord_index && index.normal == normal_index) { // The other indices match, so we can use the value cached in // the table. return std::make_pair(index.position_or_flat, false); } // The other indices don't match, so we mark this table entry, // and insert both the old and new indices into the map. const IndexType old_index(position_index, index.texcoord, index.normal); map_.insert(std::make_pair(old_index, index.position_or_flat)); index.position_or_flat = kIndexNotInTable; const IndexType new_index(position_index, texcoord_index, normal_index); const int flat_index = count_++; map_.insert(std::make_pair(new_index, flat_index)); return std::make_pair(flat_index, true); } private: std::pair GetFlattenedIndexFromMap(int position_index, int texcoord_index, int normal_index) { IndexType index(position_index, texcoord_index, normal_index); MapType::iterator iter = map_.lower_bound(index); if (iter == map_.end() || iter->first != index) { const int flat_index = count_++; map_.insert(iter, std::make_pair(index, flat_index)); return std::make_pair(flat_index, true); } else { return std::make_pair(iter->second, false); } } static const int kIndexUnknown = -1; static const int kIndexNotInTable = -2; struct IndexType { IndexType() : position_or_flat(kIndexUnknown), texcoord(kIndexUnknown), normal(kIndexUnknown) { } IndexType(int position_index, int texcoord_index, int normal_index) : position_or_flat(position_index), texcoord(texcoord_index), normal(normal_index) { } // I'm being tricky/lazy here. The table_ stores the flattened // index in the first field, since it is indexed by position. The // map_ stores position and uses this struct as a key to lookup the // flattened index. int position_or_flat; int texcoord; int normal; // An ordering for std::map. bool operator<(const IndexType& that) const { if (position_or_flat == that.position_or_flat) { if (texcoord == that.texcoord) { return normal < that.normal; } else { return texcoord < that.texcoord; } } else { return position_or_flat < that.position_or_flat; } } bool operator==(const IndexType& that) const { return position_or_flat == that.position_or_flat && texcoord == that.texcoord && normal == that.normal; } bool operator!=(const IndexType& that) const { return !operator==(that); } }; typedef std::map MapType; int count_; std::vector table_; MapType map_; }; static inline size_t positionDim() { return 3; } static inline size_t texcoordDim() { return 2; } static inline size_t normalDim() { return 3; } // TODO(wonchun): Make a c'tor to properly initialize. struct GroupStart { size_t offset; // offset into draw_mesh_.indices. unsigned int group_line; int min_index, max_index; // range into attribs. webgl_loader::Bounds bounds; }; class DrawBatch { public: DrawBatch() : flattener_(0), current_group_line_(0xFFFFFFFF) { } const std::vector& group_starts() const { return group_starts_; } void Init(AttribList* positions, AttribList* texcoords, AttribList* normals) { positions_ = positions; texcoords_ = texcoords; normals_ = normals; flattener_.reserve(1024); } void AddTriangle(unsigned int group_line, int* indices) { if (group_line != current_group_line_) { current_group_line_ = group_line; GroupStart group_start; group_start.offset = draw_mesh_.indices.size(); group_start.group_line = group_line; group_start.min_index = INT_MAX; group_start.max_index = INT_MIN; group_start.bounds.Clear(); group_starts_.push_back(group_start); } GroupStart& group = group_starts_.back(); for (size_t i = 0; i < 9; i += 3) { // .OBJ files use 1-based indexing. const int position_index = indices[i + 0] - 1; const int texcoord_index = indices[i + 1] - 1; const int normal_index = indices[i + 2] - 1; const std::pair flattened = flattener_.GetFlattenedIndex( position_index, texcoord_index, normal_index); const int flat_index = flattened.first; CHECK(flat_index >= 0); draw_mesh_.indices.push_back(flat_index); if (flattened.second) { // This is a new index. Keep track of index ranges and vertex // bounds. if (flat_index > group.max_index) { group.max_index = flat_index; } if (flat_index < group.min_index) { group.min_index = flat_index; } const size_t new_loc = draw_mesh_.attribs.size(); CHECK(8*size_t(flat_index) == new_loc); for (size_t i = 0; i < positionDim(); ++i) { draw_mesh_.attribs.push_back( positions_->at(positionDim() * position_index + i)); } if (texcoord_index == -1) { for (size_t i = 0; i < texcoordDim(); ++i) { draw_mesh_.attribs.push_back(0); } } else { for (size_t i = 0; i < texcoordDim(); ++i) { draw_mesh_.attribs.push_back( texcoords_->at(texcoordDim() * texcoord_index + i)); } } if (normal_index == -1) { for (size_t i = 0; i < normalDim(); ++i) { draw_mesh_.attribs.push_back(0); } } else { for (size_t i = 0; i < normalDim(); ++i) { draw_mesh_.attribs.push_back( normals_->at(normalDim() * normal_index + i)); } } // TODO: is the covariance body useful for anything? group.bounds.EncloseAttrib(&draw_mesh_.attribs[new_loc]); } } } const DrawMesh& draw_mesh() const { return draw_mesh_; } private: AttribList* positions_, *texcoords_, *normals_; DrawMesh draw_mesh_; IndexFlattener flattener_; unsigned int current_group_line_; std::vector group_starts_; }; struct Material { std::string name; float Kd[3]; std::string map_Kd; void DumpJson(FILE* out = stdout) const { fprintf(out, " \"%s\": { ", name.c_str()); if (map_Kd.empty()) { fprintf(out, "\"Kd\": [%hu, %hu, %hu] }", Quantize(Kd[0], 0, 1, 255), Quantize(Kd[1], 0, 1, 255), Quantize(Kd[2], 0, 1, 255)); } else { fprintf(out, "\"map_Kd\": \"%s\" }", map_Kd.c_str()); } } }; typedef std::vector MaterialList; class WavefrontMtlFile { public: explicit WavefrontMtlFile(FILE* fp) { ParseFile(fp); } const MaterialList& materials() const { return materials_; } private: // TODO: factor this parsing stuff out. void ParseFile(FILE* fp) { // TODO: don't use a fixed-size buffer. const size_t kLineBufferSize = 256; char buffer[kLineBufferSize]; unsigned int line_num = 1; while (fgets(buffer, kLineBufferSize, fp) != NULL) { char* stripped = StripLeadingWhitespace(buffer); TerminateAtNewlineOrComment(stripped); ParseLine(stripped, line_num++); } } void ParseLine(const char* line, unsigned int line_num) { switch (*line) { case 'K': ParseColor(line + 1, line_num); break; case 'm': if (0 == strncmp(line + 1, "ap_Kd", 5)) { ParseMapKd(line + 6, line_num); } break; case 'n': if (0 == strncmp(line + 1, "ewmtl", 5)) { ParseNewmtl(line + 6, line_num); } default: break; } } void ParseColor(const char* line, unsigned int line_num) { switch (*line) { case 'd': { ShortFloatList floats; floats.ParseLine(line + 1); float* Kd = current_->Kd; Kd[0] = floats[0]; Kd[1] = floats[1]; Kd[2] = floats[2]; break; } default: break; } } void ParseMapKd(const char* line, unsigned int line_num) { current_->map_Kd = StripLeadingWhitespace(line); } void ParseNewmtl(const char* line, unsigned int line_num) { materials_.push_back(Material()); current_ = &materials_.back(); ToLower(StripLeadingWhitespace(line), ¤t_->name); } Material* current_; MaterialList materials_; }; typedef std::map MaterialBatches; // TODO: consider splitting this into a low-level parser and a high-level // object. class WavefrontObjFile { public: explicit WavefrontObjFile(FILE* fp) { current_batch_ = &material_batches_[""]; current_batch_->Init(&positions_, &texcoords_, &normals_); current_group_line_ = 0; line_to_groups_.insert(std::make_pair(0, "default")); ParseFile(fp); } const MaterialList& materials() const { return materials_; } const MaterialBatches& material_batches() const { return material_batches_; } const std::string& LineToGroup(unsigned int line) const { typedef LineToGroups::const_iterator Iterator; typedef std::pair EqualRange; EqualRange equal_range = line_to_groups_.equal_range(line); const std::string* best_group = NULL; int best_count = 0; for (Iterator iter = equal_range.first; iter != equal_range.second; ++iter) { const std::string& group = iter->second; const int count = group_counts_.find(group)->second; if (!best_group || (count < best_count)) { best_group = &group; best_count = count; } } if (!best_group) { ErrorLine("no suitable group found", line); } return *best_group; } void DumpDebug() const { printf("positions size: " PRIuS "\n" "texcoords size: " PRIuS "\n" "normals size: " PRIuS "\n", positions_.size(), texcoords_.size(), normals_.size()); } private: WavefrontObjFile() { } // For testing. void ParseFile(FILE* fp) { // TODO: don't use a fixed-size buffer. const size_t kLineBufferSize = 256; char buffer[kLineBufferSize] = { 0 }; unsigned int line_num = 1; while (fgets(buffer, kLineBufferSize, fp) != NULL) { char* stripped = StripLeadingWhitespace(buffer); TerminateAtNewlineOrComment(stripped); ParseLine(stripped, line_num++); } } void ParseLine(const char* line, unsigned int line_num) { switch (*line) { case 'v': ParseAttrib(line + 1, line_num); break; case 'f': ParseFace(line + 1, line_num); break; case 'g': if (isspace(line[1])) { ParseGroup(line + 2, line_num); } else { goto unknown; } break; case '\0': case '#': break; // Do nothing for comments or blank lines. case 'p': WarnLine("point unsupported", line_num); break; case 'l': WarnLine("line unsupported", line_num); break; case 'u': if (0 == strncmp(line + 1, "semtl", 5)) { ParseUsemtl(line + 6, line_num); } else { goto unknown; } break; case 'm': if (0 == strncmp(line + 1, "tllib", 5)) { ParseMtllib(line + 6, line_num); } else { goto unknown; } break; case 's': ParseSmoothingGroup(line + 1, line_num); break; unknown: default: WarnLine("unknown keyword", line_num); break; } } void ParseAttrib(const char* line, unsigned int line_num) { ShortFloatList floats; floats.ParseLine(line + 1); if (isspace(*line)) { ParsePosition(floats, line_num); } else if (*line == 't') { ParseTexCoord(floats, line_num); } else if (*line == 'n') { ParseNormal(floats, line_num); } else { WarnLine("unknown attribute format", line_num); } } void ParsePosition(const ShortFloatList& floats, unsigned int line_num) { if (floats.size() != positionDim() && floats.size() != 6) { // ignore r g b for now. ErrorLine("bad position", line_num); } floats.AppendNTo(&positions_, positionDim()); } void ParseTexCoord(const ShortFloatList& floats, unsigned int line_num) { if ((floats.size() < 1) || (floats.size() > 3)) { // TODO: correctly handle 3-D texcoords intead of just // truncating. ErrorLine("bad texcoord", line_num); } floats.AppendNTo(&texcoords_, texcoordDim()); } void ParseNormal(const ShortFloatList& floats, unsigned int line_num) { if (floats.size() != normalDim()) { ErrorLine("bad normal", line_num); } // Normalize to avoid out-of-bounds quantization. This should be // optional, in case someone wants to be using the normal magnitude as // something meaningful. const float x = floats[0]; const float y = floats[1]; const float z = floats[2]; const float scale = 1.0/sqrt(x*x + y*y + z*z); if (isfinite(scale)) { normals_.push_back(scale * x); normals_.push_back(scale * y); normals_.push_back(scale * z); } else { normals_.push_back(0); normals_.push_back(0); normals_.push_back(0); } } // Parses faces and converts to triangle fans. This is not a // particularly good tesselation in general case, but it is really // simple, and is perfectly fine for triangles and quads. void ParseFace(const char* line, unsigned int line_num) { // Also handle face outlines as faces. if (*line == 'o') ++line; // TODO: instead of storing these indices as-is, it might make // sense to flatten them right away. This can reduce memory // consumption and improve access locality, especially since .OBJ // face indices are so needlessly large. int indices[9] = { 0 }; // The first index acts as the pivot for the triangle fan. line = ParseIndices(line, line_num, indices + 0, indices + 1, indices + 2); if (line == NULL) { ErrorLine("bad first index", line_num); } line = ParseIndices(line, line_num, indices + 3, indices + 4, indices + 5); if (line == NULL) { ErrorLine("bad second index", line_num); } // After the first two indices, each index introduces a new // triangle to the fan. while ((line = ParseIndices(line, line_num, indices + 6, indices + 7, indices + 8))) { current_batch_->AddTriangle(current_group_line_, indices); // The most recent vertex is reused for the next triangle. indices[3] = indices[6]; indices[4] = indices[7]; indices[5] = indices[8]; indices[6] = indices[7] = indices[8] = 0; } } // Parse a single group of indices, separated by slashes ('/'). // TODO: convert negative indices (that is, relative to the end of // the current vertex positions) to more conventional positive // indices. const char* ParseIndices(const char* line, unsigned int line_num, int* position_index, int* texcoord_index, int* normal_index) { const char* endptr = NULL; *position_index = strtoint(line, &endptr); if (*position_index == 0) { return NULL; } if (endptr != NULL && *endptr == '/') { *texcoord_index = strtoint(endptr + 1, &endptr); } else { *texcoord_index = *normal_index = 0; } if (endptr != NULL && *endptr == '/') { *normal_index = strtoint(endptr + 1, &endptr); } else { *normal_index = 0; } return endptr; } // .OBJ files can specify multiple groups for a set of faces. This // implementation finds the "most unique" group for a set of faces // and uses that for the batch. In the first pass, we use the line // number of the "g" command to tag the faces. Afterwards, after we // collect group populations, we can go back and give them real // names. void ParseGroup(const char* line, unsigned int line_num) { std::string token; while ((line = ConsumeFirstToken(line, &token))) { ToLowerInplace(&token); group_counts_[token]++; line_to_groups_.insert(std::make_pair(line_num, token)); } current_group_line_ = line_num; } void ParseSmoothingGroup(const char* line, unsigned int line_num) { static bool once = true; if (once) { WarnLine("s ignored", line_num); once = false; } } void ParseMtllib(const char* line, unsigned int line_num) { FILE* fp = fopen(StripLeadingWhitespace(line), "r"); if (!fp) { WarnLine("mtllib not found", line_num); return; } WavefrontMtlFile mtlfile(fp); fclose(fp); materials_ = mtlfile.materials(); for (size_t i = 0; i < materials_.size(); ++i) { DrawBatch& draw_batch = material_batches_[materials_[i].name]; draw_batch.Init(&positions_, &texcoords_, &normals_); } } void ParseUsemtl(const char* line, unsigned int line_num) { std::string usemtl; ToLower(StripLeadingWhitespace(line), &usemtl); MaterialBatches::iterator iter = material_batches_.find(usemtl); if (iter == material_batches_.end()) { ErrorLine("material not found", line_num); } current_batch_ = &iter->second; } void WarnLine(const char* why, unsigned int line_num) const { fprintf(stderr, "WARNING: %s at line %u\n", why, line_num); } void ErrorLine(const char* why, unsigned int line_num) const { fprintf(stderr, "ERROR: %s at line %u\n", why, line_num); exit(-1); } AttribList positions_; AttribList texcoords_; AttribList normals_; MaterialList materials_; // Currently, batch by texture (i.e. map_Kd). MaterialBatches material_batches_; DrawBatch* current_batch_; typedef std::multimap LineToGroups; LineToGroups line_to_groups_; std::map group_counts_; unsigned int current_group_line_; }; #endif // WEBGL_LOADER_MESH_H_ three.js-r73/utils/converters/utf8/src/obj2utf8x.cc0000644000175500017550000001220512610076566022125 0ustar debacledebacle#if 0 // A cute trick to making this .cc self-building from shell. g++ $0 -O2 -Wall -Werror -o `basename $0 .cc`; exit; #endif // Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #include "bounds.h" #include "compress.h" #include "mesh.h" #include "optimize.h" #include "stream.h" int main(int argc, const char* argv[]) { FILE* json_out = stdout; if (argc != 3 && argc != 4) { fprintf(stderr, "Usage: %s in.obj out.utf8\n\n" "\tCompress in.obj to out.utf8 and writes JS to STDOUT.\n\n", argv[0]); return -1; } else if (argc == 4) { json_out = fopen(argv[3], "w"); CHECK(json_out != NULL); } FILE* fp = fopen(argv[1], "r"); WavefrontObjFile obj(fp); fclose(fp); fputs("{\n \"materials\": {\n", json_out); const MaterialList& materials = obj.materials(); for (size_t i = 0; i < materials.size(); ++i) { materials[i].DumpJson(json_out); const bool last = i == materials.size() - 1; fputs(",\n" + last, json_out); } fputs(" },\n", json_out); const MaterialBatches& batches = obj.material_batches(); // Pass 1: compute bounds. webgl_loader::Bounds bounds; bounds.Clear(); for (MaterialBatches::const_iterator iter = batches.begin(); iter != batches.end(); ++iter) { const DrawBatch& draw_batch = iter->second; bounds.Enclose(draw_batch.draw_mesh().attribs); } webgl_loader::BoundsParams bounds_params = webgl_loader::BoundsParams::FromBounds(bounds); fputs(" \"decodeParams\": ", json_out); bounds_params.DumpJson(json_out); fputs(",\n \"urls\": {\n", json_out); // Pass 2: quantize, optimize, compress, report. FILE* utf8_out_fp = fopen(argv[2], "wb"); CHECK(utf8_out_fp != NULL); fprintf(json_out, " \"%s\": [\n", argv[2]); webgl_loader::FileSink utf8_sink(utf8_out_fp); size_t offset = 0; MaterialBatches::const_iterator iter = batches.begin(); while (iter != batches.end()) { const DrawMesh& draw_mesh = iter->second.draw_mesh(); if (draw_mesh.indices.empty()) { ++iter; continue; } QuantizedAttribList quantized_attribs; webgl_loader::AttribsToQuantizedAttribs(draw_mesh.attribs, bounds_params, &quantized_attribs); VertexOptimizer vertex_optimizer(quantized_attribs); const std::vector& group_starts = iter->second.group_starts(); WebGLMeshList webgl_meshes; std::vector group_lengths; for (size_t i = 1; i < group_starts.size(); ++i) { const size_t here = group_starts[i-1].offset; const size_t length = group_starts[i].offset - here; group_lengths.push_back(length); vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length, &webgl_meshes); } const size_t here = group_starts.back().offset; const size_t length = draw_mesh.indices.size() - here; CHECK(length % 3 == 0); group_lengths.push_back(length); vertex_optimizer.AddTriangles(&draw_mesh.indices[here], length, &webgl_meshes); std::vector material; // TODO: is this buffering still necessary? std::vector attrib_start, attrib_length, code_start, code_length, num_tris; for (size_t i = 0; i < webgl_meshes.size(); ++i) { const size_t num_attribs = webgl_meshes[i].attribs.size(); const size_t num_indices = webgl_meshes[i].indices.size(); CHECK(num_attribs % 8 == 0); CHECK(num_indices % 3 == 0); webgl_loader::EdgeCachingCompressor compressor(webgl_meshes[i].attribs, webgl_meshes[i].indices); compressor.Compress(&utf8_sink); material.push_back(iter->first); attrib_start.push_back(offset); attrib_length.push_back(num_attribs / 8); code_start.push_back(offset + num_attribs); code_length.push_back(compressor.codes().size()); num_tris.push_back(num_indices / 3); offset += num_attribs + compressor.codes().size(); } for (size_t i = 0; i < webgl_meshes.size(); ++i) { fprintf(json_out, " { \"material\": \"%s\",\n" " \"attribRange\": [" PRIuS ", " PRIuS "],\n" " \"codeRange\": [" PRIuS ", " PRIuS ", " PRIuS "]\n" " }", material[i].c_str(), attrib_start[i], attrib_length[i], code_start[i], code_length[i], num_tris[i]); if (i != webgl_meshes.size() - 1) { fputs(",\n", json_out); } } const bool last = (++iter == batches.end()); fputs(",\n" + last, json_out); } fputs(" ]\n", json_out); fputs(" }\n}", json_out); return 0; } three.js-r73/utils/converters/utf8/src/base.h0000644000175500017550000001076212610076566021054 0ustar debacledebacle// Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #ifndef WEBGL_LOADER_BASE_H_ #define WEBGL_LOADER_BASE_H_ #include #include #include #include #include #include #include // TODO: consider using C99 spellings. typedef unsigned char uint8; typedef unsigned short uint16; typedef short int16; typedef unsigned int uint32; // printf format strings for size_t. #ifdef _WIN32 # define PRIuS "%Iu" #else // Most compilers use the C99 format string. # define PRIuS "%zu" #endif #ifndef isfinite # define isfinite _finite #endif typedef std::vector AttribList; typedef std::vector IndexList; typedef std::vector QuantizedAttribList; typedef std::vector OptimizedIndexList; // TODO: these data structures ought to go elsewhere. struct DrawMesh { // Interleaved vertex format: // 3-D Position // 3-D Normal // 2-D TexCoord // Note that these AttribList attribs; // Indices are 0-indexed. IndexList indices; }; struct WebGLMesh { QuantizedAttribList attribs; OptimizedIndexList indices; }; typedef std::vector WebGLMeshList; static inline int strtoint(const char* str, const char** endptr) { return static_cast(strtol(str, const_cast(endptr), 10)); } static inline const char* StripLeadingWhitespace(const char* str) { while (isspace(*str)) { ++str; } return str; } static inline char* StripLeadingWhitespace(char* str) { while (isspace(*str)) { ++str; } return str; } // Like basename. static inline const char* StripLeadingDir(const char* const str) { const char* last_slash = NULL; const char* pos = str; while (const char ch = *pos) { if (ch == '/' || ch == '\\') { last_slash = pos; } ++pos; } return last_slash ? (last_slash + 1) : str; } static inline void TerminateAtNewlineOrComment(char* str) { char* newline = strpbrk(str, "#\r\n"); if (newline) { *newline = '\0'; } } static inline const char* ConsumeFirstToken(const char* const line, std::string* token) { const char* curr = line; while (char ch = *curr) { if (isspace(ch)) { token->assign(line, curr); return curr + 1; } ++curr; } if (curr == line) { return NULL; } token->assign(line, curr); return curr; } static inline void ToLower(const char* in, std::string* out) { while (char ch = *in) { out->push_back(tolower(ch)); ++in; } } static inline void ToLowerInplace(std::string* in) { std::string& s = *in; for (size_t i = 0; i < s.size(); ++i) { s[i] = tolower(s[i]); } } // Jenkin's One-at-a-time Hash. Not the best, but simple and // portable. uint32 SimpleHash(char *key, size_t len, uint32 seed = 0) { uint32 hash = seed; for(size_t i = 0; i < len; ++i) { hash += static_cast(key[i]); hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } void ToHex(uint32 w, char out[9]) { const char kOffset0 = '0'; const char kOffset10 = 'a' - 10; out[8] = '\0'; for (size_t i = 8; i > 0;) { uint32 bits = w & 0xF; out[--i] = bits + ((bits < 10) ? kOffset0 : kOffset10); w >>= 4; } } uint16 Quantize(float f, float in_min, float in_scale, uint16 out_max) { return static_cast(out_max * ((f-in_min) / in_scale)); } // TODO: Visual Studio calls this someting different. #ifdef putc_unlocked # define PutChar putc_unlocked #else # define PutChar putc #endif // putc_unlocked #ifndef CHECK # define CHECK(PRED) if (!(PRED)) { \ fprintf(stderr, "%s:%d CHECK failed: ", __FILE__, __LINE__); \ fputs(#PRED "\n", stderr); \ exit(-1); } else #endif // CHECK #ifndef DCHECK # ifdef DEBUG # define DCHECK(PRED) CHECK(PRED) # else # define DCHECK(PRED) # endif // DEBUG #endif // DCHECK #endif // WEBGL_LOADER_BASE_H_ three.js-r73/utils/converters/utf8/src/utf8.h0000644000175500017550000000407112610076566021024 0ustar debacledebacle// Copyright 2011 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #ifndef WEBGL_LOADER_UTF8_H_ #define WEBGL_LOADER_UTF8_H_ #include "base.h" #include "stream.h" namespace webgl_loader { const uint8 kUtf8MoreBytesPrefix = 0x80; const uint8 kUtf8TwoBytePrefix = 0xC0; const uint8 kUtf8ThreeBytePrefix = 0xE0; const uint16 kUtf8TwoByteLimit = 0x0800; const uint16 kUtf8SurrogatePairStart = 0xD800; const uint16 kUtf8SurrogatePairNum = 0x0800; const uint16 kUtf8EncodableEnd = 0x10000 - kUtf8SurrogatePairNum; const uint16 kUtf8MoreBytesMask = 0x3F; bool Uint16ToUtf8(uint16 word, ByteSinkInterface* sink) { if (word < 0x80) { sink->Put(static_cast(word)); } else if (word < kUtf8TwoByteLimit) { sink->Put(static_cast(kUtf8TwoBytePrefix + (word >> 6))); sink->Put(static_cast(kUtf8MoreBytesPrefix + (word & kUtf8MoreBytesMask))); } else if (word < kUtf8EncodableEnd) { // We can only encode 65535 - 2048 values because of illegal UTF-8 // characters, such as surrogate pairs in [0xD800, 0xDFFF]. if (word >= kUtf8SurrogatePairStart) { // Shift the result to avoid the surrogate pair range. word += kUtf8SurrogatePairNum; } sink->Put(static_cast(kUtf8ThreeBytePrefix + (word >> 12))); sink->Put(static_cast(kUtf8MoreBytesPrefix + ((word >> 6) & kUtf8MoreBytesMask))); sink->Put(static_cast(kUtf8MoreBytesPrefix + (word & kUtf8MoreBytesMask))); } else { return false; } return true; } } // namespace webgl_loader #endif // WEBGL_LOADER_UTF8_H_ three.js-r73/utils/converters/utf8/src/compress.h0000644000175500017550000005020112610076566021765 0ustar debacledebacle// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You // may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. #ifndef WEBGL_LOADER_COMPRESS_H_ #define WEBGL_LOADER_COMPRESS_H_ #include #include "base.h" #include "bounds.h" #include "stream.h" #include "utf8.h" namespace webgl_loader { void AttribsToQuantizedAttribs(const AttribList& interleaved_attribs, const BoundsParams& bounds_params, QuantizedAttribList* quantized_attribs) { quantized_attribs->resize(interleaved_attribs.size()); for (size_t i = 0; i < interleaved_attribs.size(); i += 8) { for (size_t j = 0; j < 8; ++j) { quantized_attribs->at(i + j) = Quantize(interleaved_attribs[i + j], bounds_params.mins[j], bounds_params.scales[j], bounds_params.outputMaxes[j]); } } } uint16 ZigZag(int16 word) { return (word >> 15) ^ (word << 1); } void CompressAABBToUtf8(const Bounds& bounds, const BoundsParams& total_bounds, ByteSinkInterface* utf8) { const int maxPosition = (1 << 14) - 1; // 16383; uint16 mins[3] = { 0 }; uint16 maxes[3] = { 0 }; for (int i = 0; i < 3; ++i) { float total_min = total_bounds.mins[i]; float total_scale = total_bounds.scales[i]; mins[i] = Quantize(bounds.mins[i], total_min, total_scale, maxPosition); maxes[i] = Quantize(bounds.maxes[i], total_min, total_scale, maxPosition); } for (int i = 0; i < 3; ++i) { Uint16ToUtf8(mins[i], utf8); } for (int i = 0; i < 3; ++i) { Uint16ToUtf8(maxes[i] - mins[i], utf8); } } void CompressIndicesToUtf8(const OptimizedIndexList& list, ByteSinkInterface* utf8) { // For indices, we don't do delta from the most recent index, but // from the high water mark. The assumption is that the high water // mark only ever moves by one at a time. Foruntately, the vertex // optimizer does that for us, to optimize for per-transform vertex // fetch order. uint16 index_high_water_mark = 0; for (size_t i = 0; i < list.size(); ++i) { const int index = list[i]; CHECK(index >= 0); CHECK(index <= index_high_water_mark); CHECK(Uint16ToUtf8(index_high_water_mark - index, utf8)); if (index == index_high_water_mark) { ++index_high_water_mark; } } } void CompressQuantizedAttribsToUtf8(const QuantizedAttribList& attribs, ByteSinkInterface* utf8) { for (size_t i = 0; i < 8; ++i) { // Use a transposed representation, and delta compression. uint16 prev = 0; for (size_t j = i; j < attribs.size(); j += 8) { const uint16 word = attribs[j]; const uint16 za = ZigZag(static_cast(word - prev)); prev = word; CHECK(Uint16ToUtf8(za, utf8)); } } } class EdgeCachingCompressor { public: // Assuming that the vertex cache optimizer LRU is 32 vertices, we // expect ~64 triangles, and ~96 edges. static const size_t kMaxLruSize = 96; static const int kLruSentinel = -1; EdgeCachingCompressor(const QuantizedAttribList& attribs, OptimizedIndexList& indices) : attribs_(attribs), indices_(indices), deltas_(attribs.size()), index_high_water_mark_(0), lru_size_(0) { memset(last_attrib_, 0, sizeof(last_attrib_)); } // Work in progress. Does not remotely work. void CompressWithLRU(ByteSinkInterface* utf8) { size_t match_indices[3]; size_t match_winding[3]; for (size_t i = 0; i < indices_.size(); i += 3) { const uint16* triangle = &indices_[i]; // Try to find edge matches to cheaply encode indices and employ // parallelogram prediction. const size_t num_matches = LruEdge(triangle, match_indices, match_winding); switch (num_matches) { case 0: LruEdgeZero(triangle); // No edges match, so use simple predictor. continue; case 1: LruEdgeOne(triangle[match_winding[1]], triangle[match_winding[2]], match_indices[0]); break; case 2: LruEdgeTwo(triangle[match_winding[2]], match_indices[0], match_indices[1]); break; case 3: LruEdgeThree(match_indices[0], match_indices[1], match_indices[2]); break; default: DumpDebug(); CHECK(false); } } } // Instead of using an LRU cache of edges, simply scan the history // for matching edges. void Compress(ByteSinkInterface* utf8) { // TODO: do this pre-quantization. // Normal prediction. const size_t num_attribs = attribs_.size() / 8; std::vector crosses(3 * num_attribs); for (size_t i = 0; i < indices_.size(); i += 3) { // Compute face cross products. const uint16 i0 = indices_[i + 0]; const uint16 i1 = indices_[i + 1]; const uint16 i2 = indices_[i + 2]; int e1[3], e2[3], cross[3]; e1[0] = attribs_[8*i1 + 0] - attribs_[8*i0 + 0]; e1[1] = attribs_[8*i1 + 1] - attribs_[8*i0 + 1]; e1[2] = attribs_[8*i1 + 2] - attribs_[8*i0 + 2]; e2[0] = attribs_[8*i2 + 0] - attribs_[8*i0 + 0]; e2[1] = attribs_[8*i2 + 1] - attribs_[8*i0 + 1]; e2[2] = attribs_[8*i2 + 2] - attribs_[8*i0 + 2]; cross[0] = e1[1] * e2[2] - e1[2] * e2[1]; cross[1] = e1[2] * e2[0] - e1[0] * e2[2]; cross[2] = e1[0] * e2[1] - e1[1] * e2[0]; // Accumulate face cross product into each vertex. for (size_t j = 0; j < 3; ++j) { crosses[3*i0 + j] += cross[j]; crosses[3*i1 + j] += cross[j]; crosses[3*i2 + j] += cross[j]; } } // Compute normal residues. for (size_t idx = 0; idx < num_attribs; ++idx) { float pnx = crosses[3*idx + 0]; float pny = crosses[3*idx + 1]; float pnz = crosses[3*idx + 2]; const float pnorm = 511.0 / sqrt(pnx*pnx + pny*pny + pnz*pnz); pnx *= pnorm; pny *= pnorm; pnz *= pnorm; float nx = attribs_[8*idx + 5] - 511; float ny = attribs_[8*idx + 6] - 511; float nz = attribs_[8*idx + 7] - 511; const float norm = 511.0 / sqrt(nx*nx + ny*ny + nz*nz); nx *= norm; ny *= norm; nz *= norm; const uint16 dx = ZigZag(nx - pnx); const uint16 dy = ZigZag(ny - pny); const uint16 dz = ZigZag(nz - pnz); deltas_[5*num_attribs + idx] = dx; deltas_[6*num_attribs + idx] = dy; deltas_[7*num_attribs + idx] = dz; } for (size_t triangle_start_index = 0; triangle_start_index < indices_.size(); triangle_start_index += 3) { const uint16 i0 = indices_[triangle_start_index + 0]; const uint16 i1 = indices_[triangle_start_index + 1]; const uint16 i2 = indices_[triangle_start_index + 2]; // To force simple compression, set |max_backref| to 0 here // and in loader.js. // |max_backref| should be configurable and communicated. const uint16 max_backref = triangle_start_index < kMaxLruSize ? triangle_start_index : kMaxLruSize; // Scan the index list for matching edges. uint16 backref = 0; for (; backref < max_backref; backref += 3) { const size_t candidate_start_index = triangle_start_index - backref; const uint16 j0 = indices_[candidate_start_index + 0]; const uint16 j1 = indices_[candidate_start_index + 1]; const uint16 j2 = indices_[candidate_start_index + 2]; // Compare input and candidate triangle edges in a // winding-sensitive order. Matching edges must reference // vertices in opposite order, and the first check sees if the // triangles are in strip order. If necessary, re-order the // triangle in |indices_| so that the matching edge appears // first. if (j1 == i1 && j2 == i0) { ParallelogramPredictor(backref, j0, triangle_start_index); break; } else if (j1 == i0 && j2 == i2) { indices_[triangle_start_index + 0] = i2; indices_[triangle_start_index + 1] = i0; indices_[triangle_start_index + 2] = i1; ParallelogramPredictor(backref, j0, triangle_start_index); break; } else if (j1 == i2 && j2 == i1) { indices_[triangle_start_index + 0] = i1; indices_[triangle_start_index + 1] = i2; indices_[triangle_start_index + 2] = i0; ParallelogramPredictor(backref, j0, triangle_start_index); break; } else if (j2 == i1 && j0 == i0) { ParallelogramPredictor(backref + 1, j1, triangle_start_index); break; } else if (j2 == i0 && j0 == i2) { indices_[triangle_start_index + 0] = i2; indices_[triangle_start_index + 1] = i0; indices_[triangle_start_index + 2] = i1; ParallelogramPredictor(backref + 1, j1, triangle_start_index); break; } else if (j2 == i2 && j0 == i1) { indices_[triangle_start_index + 0] = i1; indices_[triangle_start_index + 1] = i2; indices_[triangle_start_index + 2] = i0; ParallelogramPredictor(backref + 1, j1, triangle_start_index); break; } else if (j0 == i1 && j1 == i0) { ParallelogramPredictor(backref + 2, j2, triangle_start_index); break; } else if (j0 == i0 && j1 == i2) { indices_[triangle_start_index + 0] = i2; indices_[triangle_start_index + 1] = i0; indices_[triangle_start_index + 2] = i1; ParallelogramPredictor(backref + 2, j2, triangle_start_index); break; } else if (j0 == i2 && j1 == i1) { indices_[triangle_start_index + 0] = i1; indices_[triangle_start_index + 1] = i2; indices_[triangle_start_index + 2] = i0; ParallelogramPredictor(backref + 2, j2, triangle_start_index); break; } } if (backref == max_backref) { SimplePredictor(max_backref, triangle_start_index); } } // Emit as UTF-8. for (size_t i = 0; i < deltas_.size(); ++i) { if (!Uint16ToUtf8(deltas_[i], utf8)) { // TODO: bounds-dependent texcoords are still busted :( Uint16ToUtf8(0, utf8); } } for (size_t i = 0; i < codes_.size(); ++i) { CHECK(Uint16ToUtf8(codes_[i], utf8)); } } const QuantizedAttribList& deltas() const { return deltas_; } const OptimizedIndexList& codes() const { return codes_; } void DumpDebug(FILE* fp = stdout) { for (size_t i = 0; i < lru_size_; ++i) { fprintf(fp, PRIuS ": %d\n", i, edge_lru_[i]); } } private: // The simple predictor is slightly (maybe 5%) more effective than // |CompressQuantizedAttribsToUtf8|. Instead of delta encoding in // attribute order, we use the last referenced attribute as the // predictor. void SimplePredictor(size_t max_backref, size_t triangle_start_index) { const uint16 i0 = indices_[triangle_start_index + 0]; const uint16 i1 = indices_[triangle_start_index + 1]; const uint16 i2 = indices_[triangle_start_index + 2]; if (HighWaterMark(i0, max_backref)) { // Would it be faster to do the dumb delta, in this case? EncodeDeltaAttrib(i0, last_attrib_); } if (HighWaterMark(i1)) { EncodeDeltaAttrib(i1, &attribs_[8*i0]); } if (HighWaterMark(i2)) { // We get a little frisky with the third vertex in the triangle. // Instead of simply using the previous vertex, use the average // of the first two. for (size_t j = 0; j < 8; ++j) { int average = attribs_[8*i0 + j]; average += attribs_[8*i1 + j]; average /= 2; last_attrib_[j] = average; } EncodeDeltaAttrib(i2, last_attrib_); // The above doesn't add much. Consider the simpler: // EncodeDeltaAttrib(i2, &attribs_[8*i1]); } } void EncodeDeltaAttrib(size_t index, const uint16* predicted) { const size_t num_attribs = attribs_.size() / 8; for (size_t i = 0; i < 5; ++i) { const int delta = attribs_[8*index + i] - predicted[i]; const uint16 code = ZigZag(delta); deltas_[num_attribs*i + index] = code; } UpdateLastAttrib(index); } void ParallelogramPredictor(uint16 backref_edge, size_t backref_vert, size_t triangle_start_index) { codes_.push_back(backref_edge); // Encoding matching edge. const uint16 i2 = indices_[triangle_start_index + 2]; if (HighWaterMark(i2)) { // Encode third vertex. // Parallelogram prediction for the new vertex. const uint16 i0 = indices_[triangle_start_index + 0]; const uint16 i1 = indices_[triangle_start_index + 1]; const size_t num_attribs = attribs_.size() / 8; for (size_t j = 0; j < 5; ++j) { const uint16 orig = attribs_[8*i2 + j]; int delta = attribs_[8*i0 + j]; delta += attribs_[8*i1 + j]; delta -= attribs_[8*backref_vert + j]; last_attrib_[j] = orig; const uint16 code = ZigZag(orig - delta); deltas_[num_attribs*j + i2] = code; } } } // Returns |true| if |index_high_water_mark_| is incremented, otherwise // returns |false| and automatically updates |last_attrib_|. bool HighWaterMark(uint16 index, uint16 start_code = 0) { codes_.push_back(index_high_water_mark_ - index + start_code); if (index == index_high_water_mark_) { ++index_high_water_mark_; return true; } else { UpdateLastAttrib(index); } return false; } void UpdateLastAttrib(uint16 index) { for (size_t i = 0; i < 8; ++i) { last_attrib_[i] = attribs_[8*index + i]; } } // Find edge matches of |triangle| referenced in |edge_lru_| // |match_indices| stores where the matches occur in |edge_lru_| // |match_winding| stores where the matches occur in |triangle| size_t LruEdge(const uint16* triangle, size_t* match_indices, size_t* match_winding) { const uint16 i0 = triangle[0]; const uint16 i1 = triangle[1]; const uint16 i2 = triangle[2]; // The primary thing is to find the first matching edge, if // any. If we assume that our mesh is mostly manifold, then each // edge is shared by at most two triangles (with the indices in // opposite order), so we actually want to eventually remove all // matching edges. However, this means we have to continue // scanning the array to find all matching edges, not just the // first. The edges that don't match will then pushed to the // front. size_t num_matches = 0; for (size_t i = 0; i < lru_size_ && num_matches < 3; ++i) { const int edge_index = edge_lru_[i]; // |winding| is a tricky detail used to dereference the edge to // yield |e0| and |e1|, since we must handle the edge that wraps // the last and first vertex. For now, just implement this in a // straightforward way using a switch, but since this code would // actually also need to run in the decompressor, we must // optimize it. const int winding = edge_index % 3; uint16 e0, e1; switch (winding) { case 0: e0 = indices_[edge_index + 1]; e1 = indices_[edge_index + 2]; break; case 1: e0 = indices_[edge_index + 2]; e1 = indices_[edge_index]; break; case 2: e0 = indices_[edge_index]; e1 = indices_[edge_index + 1]; break; default: DumpDebug(); CHECK(false); } // Check each edge of the input triangle against |e0| and // |e1|. Note that we reverse the winding of the input triangle. // TODO: does this properly handle degenerate input? if (e0 == i1 && e1 == i0) { match_winding[num_matches] = 2; match_indices[++num_matches] = i; } else if (e0 == i2 && e1 == i1) { match_winding[num_matches] = 0; match_indices[++num_matches] = i; } else if (e0 == i0 && e1 == i2) { match_winding[num_matches] = 1; match_indices[++num_matches] = i; } } switch (num_matches) { case 1: match_winding[1] = (match_winding[0] + 1) % 3; // Fall through. case 2: match_winding[2] = 3 - match_winding[1] - match_winding[0]; default: ; // Do nothing. } return num_matches; } // If no edges were found in |triangle|, then simply push the edges // onto |edge_lru_|. void LruEdgeZero(const uint16* triangle) { // Shift |edge_lru_| by three elements. Note that the |edge_lru_| // array has at least three extra elements to make this simple. lru_size_ += 3; if (lru_size_ > kMaxLruSize) lru_size_ = kMaxLruSize; memmove(edge_lru_ + 3, edge_lru_, lru_size_ * sizeof(int)); // Push |triangle| to front of |edge_lru_| edge_lru_[0] = triangle[0]; edge_lru_[1] = triangle[1]; edge_lru_[2] = triangle[2]; } // Remove one edge and add two. void LruEdgeOne(size_t i0, size_t i1, size_t match_index) { CHECK(match_index < lru_size_); // Shift |edge_lru_| by one element, starting with |match_index| + 1. memmove(edge_lru_ + match_index + 2, edge_lru_ + match_index + 1, (lru_size_ - match_index) * sizeof(int)); // Shift |edge_lru_| by two elements until reaching |match_index|. memmove(edge_lru_ + 2, edge_lru_, match_index * sizeof(int)); edge_lru_[0] = i0; edge_lru_[1] = i1; } // Remove two edges and add one. void LruEdgeTwo(int i0, size_t match_index0, size_t match_index1) { CHECK(match_index0 < lru_size_); CHECK(match_index1 < lru_size_); // memmove 1 // memmove 2 edge_lru_[0] = i0; } // All edges were found, so just remove them from |edge_lru_|. void LruEdgeThree(size_t match_index0, size_t match_index1, size_t match_index2) { const size_t shift_two = match_index1 - 1; for (size_t i = match_index0; i < shift_two; ++i) { edge_lru_[i] = edge_lru_[i + 1]; } const size_t shift_three = match_index2 - 2; for (size_t i = shift_two; i < shift_three; ++i) { edge_lru_[i] = edge_lru_[i + 2]; } lru_size_ -= 3; for (size_t i = shift_three; i < lru_size_; ++i) { edge_lru_[i] = edge_lru_[i + 3]; } } // |attribs_| and |indices_| is the input mesh. const QuantizedAttribList& attribs_; // |indices_| are non-const because |Compress| may update triangle // winding order. OptimizedIndexList& indices_; // |deltas_| contains the compressed attributes. They can be // compressed in one of two ways: // (1) with parallelogram prediction, compared with the predicted vertex, // (2) otherwise, compared with the last referenced vertex. // Note that even (2) is different and probably better than what // |CompressQuantizedAttribsToutf8| does, which is comparing with // the last encoded vertex. QuantizedAttribList deltas_; // |codes_| contains the compressed indices. Small values encode an // edge match; that is, the first edge of the next triangle matches // a recently-seen edge. OptimizedIndexList codes_; // |index_high_water_mark_| is used as it is in |CompressIndicesToUtf8|. uint16 index_high_water_mark_; // |last_attrib_referenced_| is the index of the last referenced // attribute. This is used to delta encode attributes when no edge match // is found. uint16 last_attrib_[8]; size_t lru_size_; // |edge_lru_| contains the LRU lits of edge references. It stores // indices to the input |indices_|. By convention, an edge points to // the vertex opposite the edge in question. We pad the array by a // triangle to simplify edge cases. int edge_lru_[kMaxLruSize + 3]; }; } // namespace webgl_loader #endif // WEBGL_LOADER_COMPRESS_H_ three.js-r73/utils/converters/utf8/build.bat0000644000175500017550000000021312610076566020757 0ustar debacledebacleg++ ./src/objcompress.cc -O2 -Wall -o objcompress g++ ./src/obj2utf8.cc -O2 -Wall -o obj2utf8 g++ ./src/obj2utf8x.cc -O2 -Wall -o obj2utf8xthree.js-r73/utils/converters/ctm/0000755000175500017550000000000012640541325017062 5ustar debacledebaclethree.js-r73/utils/converters/ctm/join_ctm.py0000644000175500017550000000473112610076566021252 0ustar debacledebacle"""Join multiple binary files into single file and generate JSON snippet with offsets ------------------------------------- How to use ------------------------------------- python join_ctm.py -i "part_*.ctm" -o joined.ctm [-j offsets.js] Will read multiple files following wildcard pattern (ordered lexicographically): part_000.ctm part_001.ctm part_002.ctm ... part_XXX.ctm And generate single concatenated files: joined.ctm offsets.js (optional, offsets are also dumped to standard output) """ import getopt import glob import sys import os # ##################################################### # Templates # ##################################################### TEMPLATE_JSON = u"""\ "offsets": [ %(offsets)s ], """ # ############################################################################# # Helpers # ############################################################################# def usage(): print 'Usage: %s -i "filename_*.ctm" -o filename.ctm [-j offsets.js]' % os.path.basename(sys.argv[0]) # ##################################################### # Main # ##################################################### if __name__ == "__main__": # get parameters from the command line try: opts, args = getopt.getopt(sys.argv[1:], "hi:o:j:", ["help", "input=", "output=", "json="]) except getopt.GetoptError: usage() sys.exit(2) inpattern = "" outname = "" jsonname = "" for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-i", "--input"): inpattern = a elif o in ("-o", "--output"): outname = a elif o in ("-j", "--json"): jsonname = a # quit if required parameters are missing if inpattern == "" or outname == "": usage() sys.exit(2) outfile = open(outname, "wb") matches = glob.glob(inpattern) matches.sort() total = 0 offsets = [] for filename in matches: filesize = os.path.getsize(filename) offsets.append(total) total += filesize print filename, filesize infile = open(filename, "rb") buffer = infile.read() outfile.write(buffer) infile.close() outfile.close() json_str = TEMPLATE_JSON % { "offsets" : ", ".join(["%d" % o for o in offsets]) } print json_str if jsonname: jsonfile = open(jsonname, "w") jsonfile.write(json_str) jsonfile.close()three.js-r73/utils/converters/ctm/LICENSE.txt0000644000175500017550000000156112610076566020717 0ustar debacledebacleCopyright (c) 2009-2010 Marcus Geelnard This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. three.js-r73/utils/converters/ctm/openctm.dll0000644000175500017550000025600012610076566021236 0ustar debacledebacleMZÿÿ¸@€º´ Í!¸LÍ!This program cannot be run in DOS mode. $PEL™PKà# 8<XÀP$kÀrÁ €×” P°°.textt:<``.data@P@@À.rdata`B@@.bssÐp€À.edata×€F@@.idata”N@À.rsrcP R@À.reloc°°V@BU‰åƒì‹EÇD$p%kÇD$p%k‰$è9Éö¼'U‰åƒì‹EÇD$p%kÇD$p%k‰$è_9ɃøÀô&U‰åSƒì‹p%k…Òt6¡p%kXü9Úwv‹…ÀtÿЋp%kƒë9Úvë‰$è9Çp%kÇ$èõ8ƒÄ[]ô&U‰åVSƒì‹] ƒût8‹E‰\$‰D$‹E‰$è4ƒì …Û‰Æu¡p%k…Àt_ècÿÿÿeø‰ð[^] Ç$€è|8…À£p%ktGÇ£p%kèó2è®3‹EÇD$‰D$‹E‰$è´3ƒì …À‰Æt£ë¦1öeø‰ð[^] è/81öÇ ëŠU‰å]é74U‰åW‰ÇVSƒì 8„úÇG‹wÇGÇG ÇGÇGë‹F…Àu9‹^‰4$è¾7‰Þ…ötI?t0‹…ÀtÚ‰$è¢7‹F…ÀtÒt&¼'‰$èˆ7ë½¶‹F …Àtɉ$èq7ë¿ÇG‹w$ÇGë‹F…Àu5‹^‰4$èJ7‰Þ…ötk?t,‹…ÀtÚ‰$è.7‹F…ÀtÒ´&‰$è7ëÁ¶‹F …Àt͉$è7ëË@…Àu?‹G …Àu.‹G…À„íþÿÿ‰$èÞ6éàþÿÿÇG$ÇG ƒÄ [^_]É$è»6ëȉ$è±6ë·ë U‰åƒì‰]ô‰Ã‰uø‰}ü‹H…Ét‹x …ÿu1À‹]ô‹uø‹}ü‰ì]ËP…Òté‹@…Àtâ@1öƒøv´&9·sËF9ðwöR1öƒøwë ‹SF R9ñv‹K‹±‰$è±4öÄtâëš‹K…Ét6tÝØÇF(‹$‹t$‹|$‰ì] ÙîÝéßàžs'‹N»ë‹IC…É•À1Ò9û•Â…Ðuì…ÉtÙYë¿ÝØÇF(‹$‹t$‹|$‰ì] ¶ÝØ‹$‹t$‹|$‰ì] ¶¼'U‰åƒì ‰$‰t$‰|$‹u‹} ÙE…ötr>tÝØÇF(‹$‹t$‹|$‰ì] ÙîÝéßàžs'‹N$»ë‹IC…É•À1Ò9û•Â…Ðuì…ÉtÙYë¿ÝØÇF(‹$‹t$‹|$‰ì] ¶ÝØ‹$‹t$‹|$‰ì] ¶¼'U‰åƒì‰]ø‹]‰uü‹u …Ût;tÇC(‹]ø‹uü‰ì]‹C<…Àu.…öté‰4$è,,…ÀtÝ@‰$èÏ+‰C<…Àt‰t$‰$è,뿉$èÂ+ÇC<ëÁÇC(ë¥U‰åƒì‰]ô‹]‰uø‹u …Û‰}ü‹}t;tÇC(‹]ô‹uø‹}ü‰ì]¶…ö”À…ÿ” Шu‹E‹U…À”À…Ò”Á ȨtÇC(‹]ô‹uø‹}ü‰ì]‰Øèóÿÿ‰s‹M‹u‰{ ‹}‰K‰s‰{ëŽvU‰åWVSƒì‹]‰Eð‹u‰Uì‹…À„‘‰Ã‹@…Àu÷Ç$èË*‰C‰Ç…ÿ‰û„ ü1À¹ó«‹Uì¹€:…ö‰K‰S t ‰4$èè*…ÀuY‹M …Ét‹} ‰<$èÒ*…Àu ‰ØƒÄ[^_]Ã@‰$èk*‰C…ÀtV‹U ‰T$‹s‰4$èš*ëÒÇ$èD*‰‰Çéuÿÿÿ@‰$è2*‰…Àt=‰t$‹‰$èf*눋EðÇ@(1Àë’‹EðÇ@(‹…Àu‰$è*1Àésÿÿÿ‹uðÇF(ëå‰$èë)ëÛ‰ö¼'U1À‰åSƒì‹]‹U …Ût:C‹M‰D$‹E‰L$‰$‰Øè¢þÿÿ‰Â1À…Òt¸€9‰B‹SJ‰K‚ƒÄ[]Ât&¼'U1À‰åSƒì‹]‹U …Ût9C$1ɉD$‹E‰L$‰$‰ØèCþÿÿ‰Â1À…Òt¸€;‰B‹S J‰K ‚ƒÄ[] ¶¿Uº‰åƒì‹E‰T$‹M ‰D$ ‹E‰L$‰$è()É t&U‰åƒì8‰uø‹u‰]ô‰}ü…öt>tÇF(‹]ô‹uø‹}ü‰ì] ‹U ‹E‰V@‰FH‰ðè™ðÿÿ‰4$è1=OCTMtÇF(‹]ô‹uø‹}ü‰ì] ‰4$è ƒøt ÇF( 룉4$èö=RAW„N=MG1„O=MG2u¯ÇF,‰4$èʉF…Àt™‰4$軉F…ÀtЉ4$謉F‰4$衉F ‰4$è–‰4$‰ÃF<‰D$è‹~ Áበ$èÔ'‰F…À„È‹NIÁâ‰$è¸'‰F …À„¥öÃ…¯ÇEè‹FV‰Uì‰Eð9E胣Ç$è|'‰Â‹Eì…Ò‰„^ü1À‰×¹ó«‹F‹UìÁà‰Eä‹:‰$èK'‰G ‹]ì‹ ‹y …ÿ„)‹Mä‰úƒùvöÂt ǃƒéü1À‰×Áéó«ÿEè‹Uì‹Eð‹ƒÃ‰]ìélÿÿÿÇF,é¿þÿÿÇF,é³þÿÿÇEØ‹N ^$9M؉]܉Màƒ…Ç$è½&‹}Ü…À‰Â‰„Ÿü1À‰×¹ó«‹~‹MÜÁ狉<$è&‰C ‹UÜ‹‹@ …Àtqƒÿ‰Â‰ùv¨t ǃƒéü1ÀÁé‰×ó«ÿEØ‹MÜ‹Uà‹ƒÃ9U؉]Üéuÿÿÿ‹F,=t~wk=tZÇF( ‰ðè“ïÿÿ…À…`ýÿÿÇF(éTýÿÿÇF(‰ðèîÿÿÇF(é:ýÿÿ‹~Áã‰$èä%‰F…À…5þÿÿëω4$èë£=u•‰4$èž3ë’‰4$è”ëˆfU‰åƒì‰]ø‹]‰uü…Ût;tÇC(‹]ø‹uü‰ì]Âf‹E º$a%k‰T$‰$è¤%…À‰Æt"‰$¹€ $k‰L$‰D$èqüÿÿƒì ‰4$èv%ë¶ÇC(ë­t&¼'Uº‰åƒì‹E‰T$‹M ‰D$ ‹E‰L$‰$è0%É t&U‰åƒì‰]ø‹]‰uü…Ût;tÇC(‹]ø‹uü‰ì] f‰Øè9îÿÿ…Àu ÇC(ëÞ‹s‹M ‹U…ö•À¶ð‰KD¹‰SHº'a%k‰L$‰T$‰$èë‰$¸‰D$èš‹C,=„µ‡œ=…˜¸‰D$¸,a%k‰D$‰$è¡‹S‰$‰T$èR‹C‰$‰D$èC‹K‰$‰L$è4‹S ‰$‰T$è%‰t$‰$è‹s<‰$‰t$èÚ‹C,=tgw>=u‰$èéìþÿÿ=t7ÇC( éÙþÿÿ¹º1a%k‰L$‰T$éWÿÿÿ=uÖ‰$èAé®þÿÿ¸‰D$¸6a%ké,ÿÿÿ‰$è!éŽþÿÿ¶¿U‰åƒì‰]ø‹]‰uü…Ût;tÇC(‹]ø‹uü‰ì]Âf‹E ¹;a%k‰L$‰$èT#…À‰Æt"‰$º`$$k‰T$‰D$èþÿÿƒì ‰4$è&#ë¶ÇC(ë­U‰åƒì‹U‹BH…Àt‹R@…Òu É1ÀÃt&‰D$‹M‰L$‹E ‰$ÿÒƒì Éô&U‰åƒì‹U‹BH…Àt‹RD…Òu É1ÀÃt&‰D$‹M‰L$‹E ‰$ÿÒƒì Éô&U‰åSƒì]ø‹U‹BH…Àt‹R@…Òu%¶S¶Eø¶KÁâ жSÁá‹]üÉ ÈÁâ ÐÉD$¸‰$‰D$ÿÒ¶S¶Eø¶Kƒì Áâ ÐÁá ȶS‹]üÉÁâ Ðô&U‰åƒì‹E ‹UˆEüÁèˆEýÁèˆEþÁèˆEÿ‹BH…Àt‹RD…ÒuÉÉD$Mü¸‰D$‰ $ÿÒƒì ÉÃt&U‰åSƒì]ø‹U‹BH…Àt‹R@…Òu*¶K¶Uø¶CÁá ʶKÁà ‹]üÁá ʉUôÙEôÉÉD$¸‰D$‰$ÿÒƒì ë¿t&U‰åƒì‹E ‹UˆEüÁèˆEýÁèˆEþÁèˆEÿ‹BH…Àt‹RD…ÒuÉÉD$Mü¸‰D$‰ $ÿÒƒì ÉÃt&U‰åƒì(‰}ü‹} ‰uø‹u‰]ô‹…ÀuE‹FH]ð…Àt‹V@…Òuv¶K¶Uð¶CÁá ʶKÁà ‰ÓÁá Ëu!‹]ô‹uø‹}ü‰ì]Ãt&‰$èˆ Çë«S‰$èe ‰…Àt΋VH…Òt‹N@…Éu-‹7Æ3‹]ô‹uø‹}ü‰ì]ÉD$¸‰D$‰$ÿÒƒì épÿÿÿ‰T$‰\$‰$ÿуì ëÁfU‰åƒì(‰}ü‹} ‰]ô1Û…ÿ‰uø‹ut ‰<$è= ‰Ãˆ]ð‰Ù‰Ú‰ØÁéÁèˆMñÁêˆUòˆEó‹FH…Àt‹VD…Òu"…Ût‹FH…Àt‹VD…Òu*‹]ô‹uø‹}ü‰ì]Ãv‰D$¹Eð‰L$‰$ÿÒƒì ëĉD$‰\$‰<$ÿÒƒì ëÄt&U‰åWVSƒì|]Ô‹E‹HH…Ét ‹@@…À…m¶s¶{¶UÔ¶CÁæÁç ò]Ø úÁà …ɉUÐt‹}‹G@…À…ý‰$è…À‰Ç„‹U‹MЋBH…À…‡‹M‹E¯È‰MÀ‰ÎÁæ‰4$è܉EÄ…À„¢‰uÌM̺‰\$EЉL$‰T$‰D$ ‰|$‹Uĉ$èä‰<$‰Ã誅Ûu ;ūˋ}‹uÄÇG(‰4$èˆeô1À[^_]ËR@…Ò„nÿÿÿ‰L$‰D$‰<$ÿÒ‹M‹Eƒì ¯È‰ÎÁæ‰MÀ‰4$è:‰EÄ…À…^ÿÿÿ‰<$è7‹}ÇG(룉L$º‰T$‰$ÿЋUÐƒì ‰$èû…À‰Ç…ëþÿÿ‹]ÇC(éjÿÿÿ‰L$¹‰L$‰$ÿЋu‹NHƒì ésþÿÿÇEÈ‹]9]ȃÄÇE¸‹MÀ‰M¼f1ÿ;}ƒ•‹U¼‹MÈ‹uÈR‹]ÄÈ‹MÄ‹U ñ4‹E¸‚‰]¤‹U…Ò…·t&¶‹E¼¶A‹EÁã Ú‹]û¯Ø‹EÄGËEȉ]´¶‹]¤‰E´Áà ¶Áà ‰‹UƒÃ‰]¤‹EÖÁ;}r¬¶¿ÿEÈ‹}‹u}¸9uÈ‚Kÿÿÿ‹Mĉ $èðeô¸[^_]ÃvBÑè÷Ø‹U¤G‰ƒÂ‹]‰U¤‹UÞÑ;}s®¶‹E¼¶A‹EÁã Ú‹]û¯Ø‹EÄÉ]´‹Eȶ‰E´Áà ¶Áà ÂöÂu ‰ÐÑèë¡v¼'U‰åWVS윋u‹]¯Þ‰$è<‰EÀ…À„„ÇEÈ9uȃ§‰]¼ÇE¸´&ÇEÄ‹M9MÄsu‹EÈ‹}¼‹MÀ‹UÈ‹]ÀÁЋUØ‹}¸‰E¤‹E …Ò¸…uf‹ƒÃ‹}¤ˆ‹U¼ÁøˆQ‹UÄÁø‹}ú¯Ö‹}Àú‹}ȉU´ˆ:Áøˆ‹}ñÿEÄu¤9}Är¼ÿEÈ‹]]¸9uÈ‚jÿÿÿ‹M¯ñµ³è‰uЉ4$è\…À‰Æ„³ÇEÔ‹E1É¿ÿÿÿÿ‹P0¸ÿÿÿÿ‰|$0…Ò¿ÿÿÿÿ‰|$$•Á}Ô‰L$4¹ÿÿÿÿ‰D$,¸ÿÿÿÿ‰L$(1ɉ|$}؉D$ EЉL$‰\$ ‰T$‰|$‹UÀ‰D$‰4$‰T$è{‹MÀ‰Ã‰ $èÞ…Û…ý‹UЋ]ˆUÌÁêˆUÍÁêˆUÎÁêˆUÏ‹CH…Àt‹SD…Ò…›…Àt‹]‹SD…Ò……À‹MÐt‹]‹SD…Ò…”‰4$èzeô¸[^_]Ë…ÀxO‹}¤ƒÃˆ‹E¼ÁúˆA‹EÄÁú‹}ø¯Æ‹}Àø‹}ȉE°ˆ8Áúˆ‹UñÿEÄu¤9Uă‚þÿÿ‹…Ày±÷Ò몉D$M̸‰D$‰ $ÿÒ‹CHƒì éEÿÿÿ‰D$‰L$‰4$ÿÒƒì éWÿÿÿ‹]ÇC(‰4$èÇ1Àeô[^_]ËU1ÀÇB(ëê‹UÀ‰$褋EÇ@(1Àëщ<$¹‰D$‰L$ÿÒ‹}‹GHƒì éßþÿÿ¶U‰åWVSƒìl]Ô‹E‹HH…Ét ‹@@…À…m¶s¶{¶UÔ¶CÁæÁç ò]Ø úÁà …ɉUÐt‹}‹G@…À…ý‰$è…À‰Ç„‹U‹MЋBH…À…‡‹M‹E¯È‰MÀ‰ÎÁæ‰4$è̉EÄ…À„¢‰uÌM̺‰\$EЉL$‰T$‰D$ ‰|$‹Uĉ$èÔ‰<$‰Ãèš…Ûu ;ūˋ}‹uÄÇG(‰4$èxeô1À[^_]ËR@…Ò„nÿÿÿ‰L$‰D$‰<$ÿÒ‹M‹Eƒì ¯È‰ÎÁæ‰MÀ‰4$è*‰EÄ…À…^ÿÿÿ‰<$è'‹}ÇG(룉L$º‰T$‰$ÿЋUÐƒì ‰$èë…À‰Ç…ëþÿÿ‹]ÇC(éjÿÿÿ‰L$¹‰L$‰$ÿЋu‹NHƒì ésþÿÿÇEÈ‹]9]ȃ£ÇE¸‹MÀ‰M¼f1ÿ;}sx‹UÈ‹MÄ‹E¼‹uÈÑ‹UÄ@ó‹E 4‹]¸˜‰U´t&¶‹]¼¶Y‹]Áà ‹]G¯Ã‹]ÄØ‹]ȶ‹]´Áà ¶Áà ‰ƒÃ‹E‰]´‹]ÆÙ;}r±ÿEÈ‹M‹}M¸9}È‚lÿÿÿ‹uĉ4$èeô¸[^_]Ãt&U‰åWVS윋}‹]¯ß‰$載EÀ…À„ÇEÈ9}ȃ§‰]¼ÇE¸´&ÇEÄ‹M9MÄsu‹]È‹MÀ‹E¼‹uÈÙ‹]À@ò‹E 4‹U¸‰]¤¶¿‹]¤‹ˆ‹U¼ÁøþˆQ‹UÄÁø‹]گ׋]ÀÚ‹]ȉU´ˆÁøˆ‹UùÿEăE¤9UÄr¼ÿEÈ‹MM¸9}È‚jÿÿÿ‹u¯þ½»è‰}Љ<$èÜ…À‰Æ„IÇEÔ‹E1É¿ÿÿÿÿ‹P0¸ÿÿÿÿ‰|$0…Ò¿ÿÿÿÿ‰|$$•Á}Ô‰L$4¹ÿÿÿÿ‰D$,¸ÿÿÿÿ‰L$(1ɉ|$}؉D$ EЉL$‰\$ ‰T$‰|$‹UÀ‰D$‰4$‰T$èû‹MÀ‰Ã‰ $è^…Û…“‹UЈUÌÁêˆUÍÁêˆUÎÁêˆUÏ‹U‹BH…Àt‹RD…Òu8…Àt‹]‹SD…Ò…›…À‹MÐt ‹]‹SD…Òu5‰4$èeô¸[^_]ÉD$¹ẺL$‰$ÿÒ‹]‹CHƒì 먉D$‰L$‰4$ÿÒƒì 빋]ÇC(‰4$è±1Àeô[^_]ËU1ÀÇB(ëê‹UÀ‰$莋EÇ@(1ÀëщD$¸‰<$‰D$ÿÒ‹}‹GHƒì éEÿÿÿU¹@a%k‰åWVSƒì »‰\$‹}1Û‰L$‰<$èˆñÿÿ‹WRƒøv*¶¼'‹O ‹™C‰<$‰T$èòÿÿ‹G4@9Þwã‰<$º»Ea%k‰\$1Û‰T$è7ñÿÿ‹G4@ƒþv)¶¿‹W‹šC‰<$‰D$è}òÿÿ‹w v9Ùwã‹_…Û…ù‹w…ött‰<$¹ºJa%k‰L$‰T$èÖðÿÿ‹‰<$‰D$èXóÿÿ‹^‰<$‰\$1ÛèGóÿÿ‹OɃùv)¶¼'‹N ‹™C‰<$‰T$èýñÿÿ‹GÀ9Øwä‹v…öu‹w$…ötj¶‰<$¹ºOa%k‰L$‰T$èVðÿÿ‹‰<$‰\$1ÛèÖòÿÿ‹GÁàƒøv(t&¼'‹N ‹™C‰<$‰T$èñÿÿ‹GÁà9Øwã‹v…öuœƒÄ ¸[^_]É<$º¸Ta%k‰T$1Û‰D$èãïÿÿ‹w vƒù†Üþÿÿ‹W‹šC‰<$‰D$è1ñÿÿ‹w v9ÙwãéºþÿÿfU‰åWVSƒì ‹u‰4$èÜïÿÿ=INDXtÇF(1ÀƒÄ [^_]Ãt&‹V1ÛRƒøvv‰4$è¨ïÿÿ‹V ‰š‹~C 9Ùwç‰4$èïÿÿ=VERTu³‹N1ÛIƒøv$t&¼'‰4$è8ðÿÿ‹F‹VÙ˜‰×÷´&ÙD¸Ø,ŸØtÜÙ$è]Ù½&ÿÿÿ·…&ÿÿÿf f‰…$ÿÿÿÙ­$ÿÿÿß½ÿÿÿÙ­&ÿÿÿ‹•ÿÿÿ‹DЉTˆ9ÂrH‰DˆCƒûv¦‹}Ô‹E‹]Œ‹UЯNjMˆ‹½ÿÿÿد‹ðþÿÿȉ\>C‰D>ƒÆ 9Œþÿÿ‰ðþÿÿ‡Cÿÿÿ¿À>$k» ‰|$ ‰\$‹•Œþÿÿ‰T$‹½ÿÿÿ‰<$è¡‹M‹A4@Áæ‰4$è%‰…ÿÿÿ…À„ª‹EÙè1Û‰àþÿÿ1Ò¿ÿÿÿ‰½èþÿÿ‹HØp4‰•ìþÿÿƒù‰|þÿÿÙäþÿÿ†ì‹P1À‹MЉ…€þÿÿ‹uÔ‰•xþÿÿ‰˜þÿÿ‰µ”þÿÿ‰ö¼'‹€þÿÿ‹½ÿÿÿ‹•”þÿÿ‹˜þÿÿ‹t;‹˜þÿÿ¯Ê‰ð1Ò‰÷÷ñ1Ò‰E¯Á1É)ljø÷µ˜þÿÿ‰EŒ¯Ã)lj}ˆ‹Dˆ1ÒRPß,$ƒÄØLÜØD¸Ù\¨AƒùvàÙE¨‹€þÿÿ‹•ÿÿÿ‹½xþÿÿ‹\[Ø,‡ØäþÿÿØ´a%kÙ$èÙ½&ÿÿÿ·&ÿÿÿfÉ f‰$ÿÿÿ;µèþÿÿÙ­$ÿÿÿÛ ÿÿÿÙ­&ÿÿÿ‹½ ÿÿÿ„æ‹€þÿÿ‹…ÿÿÿ‰<ÙE¬‹•xþÿÿ[šØkØäþÿÿØ´a%kÙ$èÙ½&ÿÿÿ‹€þÿÿ‹•ÿÿÿ·…&ÿÿÿf f‰…$ÿÿÿÙ­$ÿÿÿÛ\Ù­&ÿÿÿÙE°ØkØäþÿÿØ´a%kÙ$èÁÙ½&ÿÿÿÿ…ìþÿÿ‹€þÿÿ‰µèþÿÿ‹•ÿÿÿ‹µìþÿÿ·…&ÿÿÿ‰½àþÿÿf f‰…$ÿÿÿÙ­$ÿÿÿÛ\Ù­&ÿÿÿƒÃ 9µ|þÿÿ‰€þÿÿ‡@þÿÿº‰a%k¿1Û‰T$‰|$‹}‰<$è1ßÿÿ‰\$¸‰D$ ‹O‰L$‹µÿÿÿ‰<$‰t$èKåÿÿ…À…ø‹µÿÿÿ‰4$襋µÿÿÿ‰4$è—1ÀÄÜ[^_]ÃÝØÙÉÙU¸ÙBÙÊÝâßàžvJÝØÙÉÙU¼ÙBÙËÝãßàžvÝØÙÊÙUÀFƒÂ 9÷†ðùÿÿÙÊéJùÿÿÝÛÙBÙEÌÙÉÝáßàÝÙž‡ÃùÿÿÝØÙÊëÐÝÚÙBÙEÈÙÉÝáßàÝÙž‡vùÿÿÝØÙÉë ÝØÙÉë‡ÝØÙÉë¢ÝØÙÉ뉋•àþÿÿ‰ø‹€þÿÿ)Ћ•ÿÿÿ‰é þÿÿ‰TÐé]úÿÿÝØÇEÐÇEÔÇEØéGúÿÿ‹]‹KÁበ$èš…À‰Æ„¸ ‹•ÿÿÿ¹‹Z‰‹E‹Xƒûvº ‹½ÿÿÿ‹D:+D:øƒÂ ‰ŽA9Ëw繎a%k»‰\$‰L$‹}‰<$èšÝÿÿ1Àº‰D$‰T$ ‹M‹Y‰t$‰ $‰\$èµãÿÿ…Àu6‰4$苵ÿÿÿ‰4$è ‹½ÿÿÿ‰<$éaþÿÿÇC(ÄÜ[^_]Ë}‹G@Áâ‰$èÇÿ‰…øþÿÿ…À„Ä ‹Mº‹y‰½tþÿÿƒÿë‹\–ü–B9•tþÿÿwð1À1Ò‹Mƒ½tþÿÿ¿ÿÿÿ‰½ÐþÿÿÙA4‰…Ìþÿÿ‰•Ôþÿÿ†ú‹}Ð1Û‹EÔ‰„þÿÿ‰ú¯Ð‰•Èþÿÿ‹Ôþÿÿ1Ò‹Ž‰Ø‰Ù÷µÈþÿÿ‹•Èþÿÿ‰E¯Â1Ò)Á‰È÷÷‰EŒ¯Ç)Á‰Mˆ1ɶ‹Dˆ1ÒRPß,$ƒÄØLÜØD¸Ù\¨Aƒùvà;Ðþÿÿ‹…„þÿÿ‹•ÿÿÿ‹ „[Q‹…„þÿÿ‹•øþÿÿÛ$ƒÄÿ…Ôþÿÿ‰Ðþÿÿƒ…„þÿÿ ‹Ôþÿÿ‰ÌþÿÿØÉØE¨Ù‰Â…ÿÿÿ•øþÿÿ9tþÿÿÛ@ØÉØE¬ÙZÛ@ØÉØE°ÙZ‡ÿÿÿÝØ‰4$èqþ‹½ÿÿÿ‰<$ècþ‹}‹O4IÁæ‰4$è?þ‰… ÿÿÿ…À„¬‹U‹BÁà‰$è þ…À‰Ã„S ‹}1É‹wƒþv‹•ÿÿÿƒÂ‹ƒÂ ‰ ƒA9Îwó‹M1Ò‹y4ƒþv‹I ‹<‘‹»‹½ ÿÿÿ‰—B9Öwì‰$èÔý‹M1ö‹yƒÿv\‹… ÿÿÿë‹P9Ús 9Ês‰‰H‰XFƒÀ 9÷v9‹H‹9ÙsÜ‹P9Ñs؉‰P‰XëÞ‹•ÌþÿÿÑé˜þÿÿ‹uÇF(‰<$éÏûÿÿ‰|$¹ » ?$k‰\$ ‰L$‹½ ÿÿÿ‰<$èŸý‹E‹pvÁâ‰$è#ý‹ ÿÿÿ‰Æ…Û„b ‹E1Ò‹HIƒû닽 ÿÿÿ‹—‰–B9ÓwïIx=Ižë ‹B‹)؉B‹)B…É~‹zô)ø‰ƒê Ix…É~Ü‹Bô9uÕ‹B‹zø)øëÒº¹“a%k1Û‰T$‰L$‹}‰<$èóÙÿÿ‰\$¸‰D$ ‹M‹Q‰t$‰ $‰T$èàÿÿ…Àu$‰4$ètü‹µ ÿÿÿ‰4$èfü‹øþÿÿ‰$éHüÿÿ‰4$èPü‹E‹X…Û„%‹xÁà‰$è!ü‰…ÿÿÿ…À„Ï ‹}‹G@Áã‰$èÿû‰…´þÿÿ…À„ž ‹´þÿÿ‰L$‹½ ÿÿÿ‰<$‹E‹•øþÿÿèñÿÿ‹]Ùè1À‰…ÀþÿÿÙÀ‹sØs8…öÙ¸þÿÿ„7‹µÀþÿÿ‹½ÿÿÿ‹] v‹t‹{vÁâÙ:úÙBÙÉØÈÙÉØÈÞÁÙBØÈÞÁÙ¸a%kÙÉÙúÙÉÝéßàžvÝØÙÀ‹…Àþÿÿ v‹´þÿÿÁá@ÁâÙ9ùØ ÚÙAØJÞÁÙAØJÞÁÙîÚéßàžvÙàÙ…¸þÿÿ‹ÀþÿÿØÉIÁãØ´a%kÙ$ÙXþÿÿÙHþÿÿècúÙ…HþÿÿÙ½&ÿÿÿ‹•ÿÿÿ vÙ…XþÿÿÙÁ·…&ÿÿÿÞñÙÊf f‰…$ÿÿÿÙ­$ÿÿÿÛÙ­&ÿÿÿ1ÒÙƒÀØÊÙ\•¨BƒúvïÝÙ‹•Àþÿÿ‹½´þÿÿ4R ·1Ò‹‘‰œ•`ÿÿÿBƒúvð‹y‰½DþÿÿÙ…DþÿÿÙ…DþÿÿÙÉÙàÙ•HÿÿÿÙAÙÙËÙ•PÿÿÿÙËÞáÙÁÙÀØÁÙÊÙ•LÿÿÿÙÊÞÉÙÁØÊÞÁÙ]¤ÙE¤ÙÀÙúÝàßàžŠb…\ÝÙÙ¼a%kÙÉÝáßàÝÙž†ÅÙÄÞñÜÊÜÉÞËÙÉÙ•HÿÿÿÙÉÙ•LÿÿÿÙÊÙ•PÿÿÿÙÊÙ…`ÿÿÿ1ÒEèÙ…dÿÿÿÙÁÙ…hÿÿÿÙÎØÊÙÌØÎÙÉØPÿÿÿÙÎØÍÙÊÞÍÙÊØLÿÿÿÙËÞâÞäÙTÿÿÿÞáÙÉÙXÿÿÿÙE¨ÙE¬ÙE°ÙËÙ\ÿÿÿÙ€`ÿÿÿÙ€dÿÿÿÙÉØËÙÉØÊÞÁÙ€hÿÿÿƒÀ ØÌÞÁÙœ•xÿÿÿBƒúvÐÝØÝØÝØÙE€ÝáßàÝÙž‚nÝØÙîÙ¼þÿÿ‹•xÿÿÿ‰T$‹µ|ÿÿÿ‰4$èøÙ…¸þÿÿØ5Àa%kؼþÿÿØ´a%kÙ$ÙXþÿÿèYøÙ½&ÿÿÿ·&ÿÿÿÙ…XþÿÿÙÉfÉ f‰$ÿÿÿÙ­$ÿÿÿÛ ÿÿÿÙ­&ÿÿÿ‹ ÿÿÿ…Éu}ÙîÙÉØÌa%k‹…Àþÿÿ‹½ÿÿÿÞÉ@4Ÿ‰NØ´a%kÙ$èí÷Ù½&ÿÿÿÿ…Àþÿÿ‹M·•&ÿÿÿ‹…ÀþÿÿfÊ f‰•$ÿÿÿÙ­$ÿÿÿÛ^Ù­&ÿÿÿ9A†ÉÙèé‰üÿÿÝØéXþÿÿƒù‡ÄÙÄa%kéqÿÿÿ‹ÿÿÿ‰ $èø‹… ÿÿÿ‰$èø‹½øþÿÿ‰<$èø‹]‹S…Ò‰•ÿÿÿ„‹}‹wÁæ‰4$èÌ÷‰…ÿÿÿ…À„?‹µÿÿÿ1À1Û‰…¨þÿÿ‹O1Ò‰¬þÿÿÙFƒùØ=¬a%k‰•°þÿÿ‰pþÿÿÙ¤þÿÿ†þ‹½ÿÿÿƒÇ‰½ˆþÿÿÙ…¤þÿÿ‹ˆþÿÿ‹…ÿÿÿ‹1‹X Ø óØ´a%kÙ$è¸öÙ½&ÿÿÿ·½&ÿÿÿfÏ f‰½$ÿÿÿÙ­$ÿÿÿÛ ÿÿÿÙ­&ÿÿÿÙ…¤þÿÿ‹½ ÿÿÿØLóØ´a%kÙ$èoöÙ½&ÿÿÿ‹¬þÿÿ‰ø·•&ÿÿÿ‰½¬þÿÿ‹ÿÿÿ)ȃ…ˆþÿÿ fÊ ‹°þÿÿf‰•$ÿÿÿ‹µ¨þÿÿÙ­$ÿÿÿÛ ÿÿÿÙ­&ÿÿÿ‹• ÿÿÿ‰ˉÐ)ð‰DËA9pþÿÿ‰•¨þÿÿ‰°þÿÿ‡ÿÿÿº¿˜a%k‰T$‰|$‹}‰<$èÄÓÿÿ‹ÿÿÿ‹‰<$‰D$è@Öÿÿ‹µÿÿÿ‹^‰<$‰\$è+Öÿÿ‹ÿÿÿ‹S‰<$‰T$èöÔÿÿ¹¸‰L$‰D$ ‹w‰t$‹½ÿÿÿ‰|$‹U‰$è˜Ùÿÿ…À„c‰<$èøõ‹s…ö‰µÿÿÿéõýÿÿÇC(‹½ÿÿÿ‰<$é)ôÿÿÙ$èÛôé‰üÿÿÝØÝÙÝÙÝÙÝÙÙ$èäôÙ…HÿÿÿÙèÙ…LÿÿÿÙ…PÿÿÿÙËÙÊÙÌéuûÿÿÇG(‹…øþÿÿ‰$è€õ‹ÿÿÿ‰$éÖóÿÿ1ÿWQß,$ƒÄØ5Èa%ké£üÿÿ‹]‹K$‰lþÿÿ…É„^‹M‹AÁà‰$è(õ‰…üþÿÿ…À„¸‹½lþÿÿ1ÀÙGØ=¬a%kÙœþÿÿ1Ò‰”…(ÿÿÿ@ƒøvñ‹]1À‰… þÿÿ‹sƒþ‰µhþÿÿ†Ï‹ÿÿÿƒÁ‰@þÿÿ‹½@þÿÿ1Û‹7´&¼'Ù…œþÿÿ‹½lþÿÿ³‹O Ø Ø´a%kÙ$èýóÙ½&ÿÿÿ‹… þÿÿ·•&ÿÿÿ ƒfÊ f‰•$ÿÿÿÙ­$ÿÿÿÛ ÿÿÿÙ­&ÿÿÿ‹• ÿÿÿ‹¼(ÿÿÿ‰”8ÿÿÿ‰Ð)ø‹½üþÿÿ‰‰”(ÿÿÿCƒû†wÿÿÿÿ… þÿÿƒ…@þÿÿ ‹µ þÿÿ9µhþÿÿ‡@ÿÿÿ¾¸a%k‰t$¾‰D$‹M‰ $èFÑÿÿ‹lþÿÿ‹;‰|$‹]‰$è¿Óÿÿ‹½lþÿÿ‹W‰$‰T$èŠÒÿÿ‰t$¸‰D$ ‹K‰L$‹•üþÿÿ‰$‰T$è4×ÿÿ…À„‹•üþÿÿ‰$èŽó‹Oé/þÿÿÝØ‹•´þÿÿ¾¢a%k1ÿ»‰$èjó‰t$¹‰L$‹E‰$è¢Ðÿÿ‰|$‰\$ ‹u‹V‰T$‹ÿÿÿ‰4$‰L$è¾Öÿÿ…À…ûúÿÿ‹• ÿÿÿ‰$èó‹½ÿÿÿ‰<$è óéwýÿÿÇG(‰4$èöò‹…ÿÿÿécýÿÿ‹½ÿÿÿ‰<$èÝò¸é>ñÿÿ‹u‹½ ÿÿÿÇF(믋UÇB(Ç$è«ò‹½øþÿÿ‰<$éóðÿÿ‹½ÿÿÿ‰<$éåðÿÿ‹]ÇC(éuòÿÿ‹üþÿÿ‰$ébòÿÿ‹EÇ@(é¾ðÿÿ‹MÇA(é.ÿÿÿ‹u‹• ÿÿÿÇF(‰$ëë U‰åìx‰]ô‹]‰uø‰}ü‰$è£Ïÿÿ=MG2Ht"ÇC(1Û‰$ÿÿÿ‹…$ÿÿÿ‹]ô‹uø‹}ü‰ì]É$èBÐÿÿÙîÝéßàÙ[4žsʉ$è.ÐÿÿÙîÝéßàÙ[8žs¶‰$èÐÿÿ‰$Ù]¸èÐÿÿ‰$Ù]¼èÐÿÿ‰$Ù]ÀèùÏÿÿ‰$Ù]ÄèîÏÿÿ‰$Ù]ÈèãÏÿÿÙE¸ÙÉÙ´þÿÿ‹•´þÿÿÙEÄÙɉUÌÚéßàž‡SÿÿÿÙE¼ÙEÈÙÉÚéßàž‡@ÿÿÿÙEÀÙ…´þÿÿÙÉÚéßàž‡*ÿÿÿ‰$è¾Îÿÿ‰EЉ$è³Îÿÿ‰EÔ‰$è¨Îÿÿ‰EØ‹MÐ…É„þþÿÿ‹uÔ…ö„óþÿÿ1É…À„éþÿÿÙD¸1Ò‹|ÐRØlÄWß,$ƒÄÞùÙ\ÜAƒùvÞ‰$è[Îÿÿ=VERT…´þÿÿ‹KIÁà‰$èŸð‰… ÿÿÿ…ÀtR1Àº‹µ ÿÿÿ‰D$‰T$ ‹{‰t$‰$‰|$èýÐÿÿ…À„–‰$èýÍÿÿ=GIDXt‹ ÿÿÿ‰ $èXðéGþÿÿÇC(éBþÿÿ‹sÁæ‰4$è)ð…À‰ÆtM1Àº‰D$‰T$ ‹{‰t$‰$‰|$è‘Ðÿÿ…À„A‹{ºƒÿ‰½Øþÿÿv*‹D–ü–B9•ØþÿÿëîÇC(‹ ÿÿÿ‰$èÑïéÇýÿÿÙC41É1Òƒ½Øþÿÿ¿ÿÿÿ‰ÿÿÿ‹C‰½ÿÿÿ‰•ÿÿÿ‰…ÿÿÿ†‹MÐ1Ò‹}Ô‰•Ìþÿÿ‰Üþÿÿ¯Ï‰ ÿÿÿ‹•ÿÿÿ‹ ÿÿÿ‹<–1Ò‰ø÷µ ÿÿÿ1Ò‰E ¯Á‰ù)Á‰È÷µÜþÿÿ‹•Üþÿÿ‰Eœ¯Â)Á‰M˜1É‹D˜1ÒRPß,$ƒÄØLÜØD¸Ù\¨Aƒùvà;½ÿÿÿ‹…Ìþÿÿ‹• ÿÿÿ‹ u‹•ÿÿÿÑQ‹…Ìþÿÿ‹•ÿÿÿÛ$ƒÄÿ…ÿÿÿ‰½ÿÿÿƒ…Ìþÿÿ ‹½ÿÿÿ‰ÿÿÿØÉØE¨Ù‰Â… ÿÿÿ•ÿÿÿ9½ØþÿÿÛ@ØÉØE¬ÙZÛ@ØÉØE°ÙZ‡ÿÿÿÝØ‰4$èˆî‹µ ÿÿÿ‰4$èzî‰$èÌÿÿ=INDX…[üÿÿ1öº‰t$‰T$ ‹C‰D$‹{ ‰$‰|$èÂÎÿÿ1É…À‰$ÿÿÿ„5üÿÿ‹C1É‹s ƒøv-‰ò…Ét‹zô:‹B…Ét ;Bô„V‹BAƒÂ ‹C9ÈwÕ@1Òƒøv‹K9 –ƒ8B9Ðwò‹K…É…4‹{…ÿ„‹‹sÁæ‰4$è©í…À‰Æ„\ýÿÿ‰$è7Ëÿÿ=TEXC…(‰|$‰$è Ìÿÿ‰$O‰L$è‘Ìÿÿ‰$èÙËÿÿÙîÝéßàÙ_žƒõ¹¸‰L$‰D$ ‹S‰t$‰$‰T$èÄÍÿÿ…À„ÏÙG1É1Ò‰°þÿÿ‹C1ɉ…ÀþÿÿƒøvE‹G ‰…Ôþÿÿ‹…°þÿÿΉ…°þÿÿ‹DÎÛ…°þÿÿ‹…ÔþÿÿØÉÙÈRÛ$ƒÄØÉÙ\ÈA9ÀþÿÿwÄÝØ‰4$èÐì‹éùþÿÿ‰4$èÀì‹ ÿÿÿ‰ $éÜüÿÿ‹Bøé¤þÿÿÇC(é™úÿÿ‹SRÁà‰$è}ì…À‰Æ„0üÿÿ‰$è Êÿÿ=NORMtÇC(‰4$éüÿÿ1À¹‰D$‰L$ ‹{‰t$‰$‰|$èÃÌÿÿ…ÀtÒ‹{Áâ‰$è쉅ðþÿÿ…À„`‹ðþÿÿ‰Ø‹S‰L$‹{ ‰<$è¶áÿÿÙC81À‹K‰…ÿÿÿƒùÙôþÿÿ‰Äþÿÿ†Œ1À1Ò½Xÿÿÿ‰…Ðþÿÿ‰•Èþÿÿ‹…Ðþÿÿ1Ò‹L0Û0ØôþÿÿRQß,$ÙɃÄ…ÉÙÿÿÿÙÐa%kØÉØôþÿÿÙüþÿÿÙî„ÝØºÛÉ?ƒù‰•´þÿÿÙ…´þÿÿ†tÝØÙÔa%kÞñ‹…ÐþÿÿÛD0ÞÉØ%Øa%kÙøþÿÿÙ…üþÿÿÙ$èêÙ…øþÿÿÙÉÙìþÿÿÙ$èØéØìþÿÿÙ]ˆÙ…üþÿÿÙ$èééÙ…øþÿÿÙÉÙèþÿÿÙ$èÓéØèþÿÿÙ]ŒÙ…üþÿÿÙ$è”é‹ðþÿÿ‹•ÐþÿÿÙ]Ê1É‹Љ„pÿÿÿAƒùvð‹J‰´þÿÿÙ…´þÿÿÙàÙÙBÙÞáÙÁÙÀØÁÙÊÙWÙʉ´þÿÿÞÉÙÁÙ…´þÿÿÙÉØËÙÉÙWÙÊÞÁÙTÿÿÿÙ…TÿÿÿÙÀÙúÝàßàžŠv…pÝÙÙÜa%kÙÉÝáßàÝÙž†RÙèÞñÜËÜÊÞÉÙÊÙÙÉÙWÙÊÙWÙÉÙÊÙÉÙ…tÿÿÿ1ÀÙ…xÿÿÿÙ…pÿÿÿÙËØÊÙÌØÉÙÃÙÊØÎÙÍÞáÙEŒÙËÞÎÙdÿÿÿØOÞëÙÊÙhÿÿÿØOÙEÙÉÞãÙEˆÙËÙlÿÿÿÙ„…XÿÿÿÙ„…dÿÿÿÙÉØÌÙÉØËÞÁÙ„…pÿÿÿØÊÞÁÙ\…¨@ƒøvÓÝØÝØÝØ‹…Èþÿÿ1Ò‹KÈÙ…ÿÿÿØL•¨BÙƒÀƒúvëÿ…ÿÿÿƒ…Èþÿÿ ƒ…Ðþÿÿ ‹•ÿÿÿ9•Äþÿÿ‡Šýÿÿ‹½ðþÿÿ‰<$èIé‰4$èAééjûÿÿ‹{$…ÿ„}‹sÁæ‰4$èé…À‰Æ„Æøÿÿ‰$è¡Æÿÿ=ATTR…’üÿÿ‰|$‰$è Èÿÿ‰$èRÇÿÿÙîÝéßàÙ_žƒnüÿÿ¸¹‰D$‰L$ ‹S‰t$‰$‰T$è=Éÿÿ…À„HüÿÿÙG1À1Ò‰”…(ÿÿÿ@ƒøvñ‹K1À‰…äþÿÿƒù‰¼þÿÿv‹W ‰•¸þÿÿ‹…äþÿÿ1ÉÁà‰…àþÿÿ‹…àþÿÿ‹”(ÿÿÿȉ…¬þÿÿ‹†‰•°þÿÿ‹…¸þÿÿÛ…°þÿÿ‰”8ÿÿÿ‹•¬þÿÿØÉÙ‹•°þÿÿ‰”(ÿÿÿAƒùv¯ÿ…äþÿÿ‹äþÿÿ9¼þÿÿwŠÝ؉4$èè‹éÁþÿÿÝÙéüÿÿÝØéÅýÿÿÝØÝÙÝÙÝÙÙ$è çÙ‹SÙGÙGÙÉÙÊÙˉ•ÄþÿÿéfýÿÿÇC(éGûÿÿ»é§õÿÿU‰å‹E…Àt]é€ç]1Àö¿U‰å]éwç´&U1À‰åƒì‹U…Òt%‰T$¹¸‰L$ ‰D$Ç$èÏçƒìÉÃv¼'U‰åƒì‹E…Àt‰$¹€1Ò‰L$‰T$è”çƒì Éô&U‰å]Ãt&¼'U1À‰åƒì‹U…Òt%‰T$¹¸‰L$ ‰D$Ç$èOçƒìÉÃv¼'U‰åƒì‹E…Àt‰$¹€1Ò‰L$‰T$èçƒì ÉÃU‰å‹E]‹Ã¶U‰å‹M‹E ]‹¶Ãë U‰å‹U]‹B ‹J)ÈÃU‰å‹E‹U )P)P)P ]ö¿U‰åSƒì‹]‹K‹C ‹S@)ÈЉD$‹)ЉD$‹K0‰ $èZæ‹C@‹S0ЉƒÄ[]ÃfU‰å‹U]‹J0‹B<È‹ )È;BD–À¶ÀÃvU‰åSƒì‹]‹C8…Àuo‹K ‹S‰È)Ð9CDr`‹Ch…ÀuY‰ö¼'‹)Ñ‹S0Á‹C<Ð)È…À‰Eøt9‹C4Uø‰T$‰L$‰$ÿ‰Ch…Àu‹Eø…Àt‹K ‹SȉC ‰Á)Ð;CDv´t&ƒÄ[]ÃÇC8ëñU‰åV‹uS1ÛÇF0ÇF ÇF, ÇFPÇFHÇFLÇFTt&‰Ú¹‰ö¼'‰ÐƒâÑèJ÷Òâ ƒ¸í1ÂIyë‰TžlCûÿvÎ[^]Ãv¼'U‰åƒì‰]ø‹]‰uü‹u ‹S ‰4$‰T$ÿVÇC ‹CL…Àt ‹]ø‹uü‰ì]ËK0‰4$‰L$ÿVÇC0‹]ø‹uü‰ì]Ãt&¼'U‰åWVSƒì ‹} ‹]‹MÿÀ‹u‡Š‰úÑêÿ€‡6‹EȉEððÑè„T‹M‰S@ñʉKD4‹CL…À„‰s<‹KHwºÿÿ‹EÇC\ƒù‰Ct2Wÿ‰ÐÑè ЉÂÁê ‰ÐÁè ЉÂÁê ÂÑêÊÿÿú‡ ‰S(ƒùBvC\ƒùvC\ƒùvC\‰{X‹S\‰Á‰s‹C`‹{PÑ‹Sd‰K`Â…ÿ‰ðtÀ‰Cd‹{ 4…ÿ•À9ò”Á¶Ñ…й…¦‰|$‹E‰$ÿP µ1Ò‰ÏÁï9÷„¼‰S …Òt\‹{` º‰K$ƒÄ ¹[‰È^_]ÉúÁêéÀþÿÿ‹C0…Àt9s‹E ]ð‰\$ ‰L$‰D$‹E‰T$‰D$‹M‰ $è¨ùÿÿ‰Eè‹]‹UðU‹E)Uì‹H‹X$)óΉ\$)߉t$‹u ‰4$èE¦] ‹U‹Mè…Éu@…Û”À…ÿ” Шu&‹uì‹E‰uð‹P(‹p$9Ö…_ÿÿÿÇ@$1öéQÿÿÿ1ÀƒÄ,[^_]ËEèƒÄ,[^_]Ãt&¼'U‰åSƒì‹]‹U ‹C‰$‰D$ÿRÇCƒÄ[]Éö¼'U‰åƒì‰uü‹u‰]ø‹] ‹V‰$‰T$ÿSÇF‹F‰$‰D$ÿSÇF‹]ø‹uü‰ì]ö¿U¸‰åƒ}V‹U S‹u†’¶B¶J¶ZÁà Á¶BÁã ÙÁà Áùÿvo‰N ¸¶€ûàw[f¶ËÍ)ÈÁàȉÁÁéÐéˆÊÀâÊ(Ó¶Ãf¶Ñ‰•ÐÁàЀ‰ÚÁêÀêˆÓ¶ÂÀã‰FÓ(Ù¶Ñ1À‰V[^]ù늉ö¼'U¸‰åƒì8‹U ƒ}‰uø‹u‰}ü‹}‰]ôv7¶B¶J¶ZÁà Á¶BÁã ÙÁà Áùÿv&‰Mä¶€ûàv+¸‰Â‹]ô‰Ð‹uø‹}ü‰ì]Ãt&¹‰Mä¶€ûàwÕf¶ËÍ)ÈÁàȉÁÁéÐéˆÈÀàf¶ÑÈ(Õ¶Û‰]ØÐÁàЀ‰ÂÁêÀê¶Â‰EàˆÐÀàÐ(Áº¶Á Óâ‰EÜ‹Fš6…Àt9^Tt0‰D$‰<$ÿWÇF‰T$‰<$ÿ‰^Tº…À‰F„6ÿÿÿ‹MØ1Ò‰‹E܉F‹]à‰Ð‰^‹}ä‰~ ‹]ô‹uø‹}ü‰ì]ÃfU¸‰åƒì8‹U ƒ}‰uø‹u‰}ü‹}‰]ôv7¶B¶J¶ZÁà Á¶BÁã ÙÁà Áùÿv&‰Mä¶€ûàv+¸‰Â‹]ô‰Ð‹uø‹}ü‰ì]Ãt&¹‰Mä¶€ûàwÕf¶ËÍ)ÈÁàȉÁÁéÐéˆÈÀàf¶ÑÈ(Õ¶Û‰]ØÐÁàЀ‰ÂÁêÀê¶Â‰EàˆÐÀàÐ(Áº¶Á Óâ‰EÜ‹Fš6…Àt9^Tt0‰D$‰<$ÿWÇF‰T$‰<$ÿ‰^Tº…À‰F„6ÿÿÿ‹F‹]ä…Àt9^(t!‰D$‰<$ÿWÇF‰\$‰<$ÿ‰F…Àt+‰^(‹U؉‹MÜ1Ò‰N‹Eà‰F‹}ä‰Ð‰~ ‹]ô‹uø‹}ü‰ì]Ë^‰<$‰\$ÿWÇFºé½þÿÿU‰åWVS켋u‹} ‹U‹‹Ç‰dÿÿÿƒ½dÿÿÿ‰…`ÿÿÿ¸Çvdƒ}ÇEŒ¸ÇEˆvC¶Z¶J¶BÁã Ù¶ZÁà ÁÁã Ùùÿw¹‰tÿÿÿ¶€ûà†Î¸‰Â…Ò‰Ðt ļ[^_]ÃfÇEœ‹E‹•`ÿÿÿÇEÄ‹dÿÿÿ‹M$‰U ‰EŒÇEÀÇEÐÇE¤ÇE¨ÇEȉ‰L$‹E ‰t$ µxÿÿÿ‰D$‹U‰T$‹`ÿÿÿ‰4$‰\$è·óÿÿ…À‰Ãu ‹u$ƒ>„‹Uœ‹Mˆ‰‰L$‹}(‰<$ÿWÇEˆÄ¼‰Ø[^_]Ãf¶ËÍ)ÈÁàȉÁÁéÐéˆÈÀàf¶ÑÈ(Õ¶Û‰hÿÿÿÐÁàЀ‰ÂÁêÀê¶Â‰…pÿÿÿˆÐÀàÐ(Á¶Á‰…lÿÿÿ »Óã1ÉÃ6‰L$‹U(‰$ÿRÇEˆ‰D$‹M(‰ $ÿ‰]̺…À‰Eˆ„Žþÿÿ‹•pÿÿÿ‹hÿÿÿ‹…lÿÿÿ‰U€‹tÿÿÿ1Ò‰xÿÿÿ‰…|ÿÿÿ‰]„é]þÿÿ»éñþÿÿU‰å‹EÇÇ@$Ç@Ç@,ÿÿÿÿÇ@ ÿÿÿÿÇ@ÿÿÿÿÇ@ÿÿÿÿÇ@ÿÿÿÿÇ@ÿÿÿÿÇ@ ÿÿÿÿÇ@ÿÿÿÿÇ@(]Ãt&U‰åƒì ‰$‰t$‰|$‹U‹2…öˆé‰2‹B…Àuƒþ€L6¸Óà‰Bf‹Z…Ûˆ‹z …ÿˆî‹B…Àˆ×‹z…ÿˆ»‹Z…Ûx}‹J…Éxf‹r …öxO‹z$…ÿuÑû…ÉCuÑø‰B$‹Z,…Ûxt‹$‹t$‹|$‰ì]Ãt&1Àƒþ•ÀH%þ‰Béuÿÿÿt&ÇB 먴&1É…ÿ•Á‰JëŽt&1ÀƒþŸÀHƒààX@‰Zélÿÿÿ¾é ÿÿÿÇB,‹$‹t$‹|$‰ì]ÃþŸÁ¶ù‰zé4ÿÿÿÇBéÿÿÿÇB éÿÿÿÇBéïþÿÿt&Uü‰åWE¸V¹ SƒìL‰Ç‹uó¥‰Ç‹U¸…ÒˆÞ‰U¸‹]¼…Ûu"ƒúއ1Àƒú•ÀH%þ‰G‹]¼‹G…Àˆó‹w …öˆØ‹O…Ɉ¿‹w…öˆ£‹O…Éxk‹W…ÒxT‹w …öx=‹G$…ÀuÑù…ÒAuÑø‰G$‹W,…ÒxaƒÄL‰Ø[^_]ô&L¸Óàé|ÿÿÿÇG 뺴&1Ò…ö•‰Wë t&1ÀƒúŸÀHƒààH@‰OëºéÿÿÿfÇG,ƒÄL‰Ø[^_]ÃúŸÀ¶ð‰wéLÿÿÿÇGé5ÿÿÿfÇG éÿÿÿt&ÇGéÿÿÿt&Uº‰åW¿V‹uS»ÆÆF‰Ù‰øÑùIÓà‰Á1Àëˆ2@B9Èr÷Cƒû~á[^_]ö¿U‰åƒì‰uø‹u‰}ü‹}‰]ô‹F‹9Øs‰Ã‹V‰\$‹E ‰T$‰$躛)^1À^‰‹]ô‹uø‹}ü‰ì]ÃvU‰åWVSƒì»HH‰\$‹U‹E‹}€Á*‰$Ç»‰D$èh›‹]¹HH‹u‰L$ÃÈ ÆXr‰t$‰$èA›ÇEð‹U‹‚H‰‡—t&¼'‹]ð‹UÁã4;ÓN‹ƒ¬#“¬#‰F‹B‰A‹B‰A‹B ‰A ‹B‰A‹B‰A‹B‰A‹B“Œ%‰A‹ƒŒ%Žä‰†ä‹r‰q‹Z‰Y‹B ‰A ‹r‰q‹Z‰Y‹B‰A‹r‰qÿEðƒ}ð ŽgÿÿÿÇEì‹uŸdÆ '‰t$¹€ƒî€‰$ƒë€‰L$èUšÿMìyà‹M‹™,%‰Ÿ„‹±0%‰·ˆ‹‘4%‰—Œ‹8%‰‡‹™<%‰Ÿ”‹±@%‰·˜‹‘D%‰—œ‹H%‰‡ ‹™L%‰Ÿ¤‹±P%‰·¨‹‘T%‰—¬‹X%‰‡°‹™\%‰Ÿ´‹±`%‰·¸‹‘d%‰—¼‹h%‰‡À‹™l%‰ŸÄ‹±p%‰·È‹‘t%‰—Ì‹x%‰‡Ð‹™|%‰ŸÔ‹±€%»ä‰·Ø‹‘„%‰ÎÆ )‰—Ü‹ˆ%—d‰‡à‰\$‰t$‰$è ™‹U‹Šð)‰H‹‚ô)‰‡L‹šø)‰ŸP‹²ü)‰·T‹Š*‰X‹‚*‰‡\‹š*‰Ÿ`‹² *‰·d‹Š8‰ø–‹‚<‰‡ü–‹š@‰Ÿ—‹²D»‰·—‹E‹Š º‹7‹¸¨#Óã‰\$‰|$‰4$èO˜ƒÄ[^_]ô&U‰åWVSƒì»HH‰\$‹U‹E‹}Â*€Á‰$Ç»‰D$蘋]¹HH‹u‰L$ÃXrÆÈ ‰t$‰$èá—ÇEð‹‡—‹U‰‚Ht&¼'‹]ð‹MÁã4 ûެ#‹CS‰†¬#‹B‰A‹B‰A‹B ‰A ‹B‰A‹B‰A‹B‰A‹B“ä‰A‹ƒäŽŒ%‰†Œ%‹r‰q‹Z‰Y‹B ‰A ‹r‰q‹Z‰Y‹B‰A‹r‰qÿEðƒ}ð ŽgÿÿÿÇEì‹]·dà '‰t$º€ƒî€‰$ƒë€‰T$èõ–ÿMìyà‹M‹·„‰±,%‹Ÿˆ‰™0%‹—Œ‰‘4%‹‡‰8%‹·”‰±<%‹Ÿ˜‰™@%‹—œ‰‘D%‹‡ ‰H%‹·¤‰±L%‹Ÿ¨‰™P%‹—¬‰‘T%‹‡°‰X%‹·´‰±\%‹Ÿ¸‰™`%‹—¼‰‘d%‹‡À‰h%‹·Ä‰±l%‹ŸÈ‰™p%‹—̉‘t%‹‡Ð‰x%‹·Ô‰±|%‹ŸØ¾ä‰™€%‹—ÜŸd‰‘„%‹‡à‰ˆ%‹U‰t$‰\$ )‰$è©•‹H‹U‰Šð)‹‡L‰‚ô)‹ŸP‰šø)‹·T‰²ü)‹X‰Š*‹‡\‰‚*‹Ÿ`‰š*‹·d‰² *‹ø–‰Š8‹‡ü–‹Š º‰‚<‹Ÿ—¸Óà‰š@‹·—‰²D‹‹²¨#‰D$‰\$‰4$èñ”ƒÄ[^_]Éö¼'Uü‰åWE¸V¹ SƒìL‰Ç‹u ‹]ó¥‰Ç‹U¸…Òˆ¾‰U¸‹E¼…ÀuƒúTL¸Óà‰G¶‹w…öˆÕ‹G …Àˆº‹O…Ɉ ‹w…öˆ„‹O…ɈI‹W…Òˆ.‹w …öˆ‹G$…ÀuÑù…ÒAuÑø‰G$‹W,…Òˆ4‹MÀƒù·‹Uăú«‹uȃþŸ‹E¼=‡‘=@‡†‰ƒ»‹}܉»»‹EЃø†'=v¸‰ƒ01À‰“˜#º‰‹”#‰³œ#ƒ}Ì”À‰ƒ¤º‹MԅɉKlt‹E؃øŽãƒø‰Â‰Sd1À‰{H‹}à‰»àºëv¸ƒÄL[^_]Ãv1Àƒú•ÀH%þ‰Gé¥þÿÿt&ÇG éáþÿÿt&1Ò…ö•‰WéÃþÿÿ1ÀƒúŸÀHƒààH@‰Oé þÿÿºé8þÿÿÇG,éÀþÿÿvƒúŸÀ¶ð‰wékþÿÿÇGéTþÿÿvÇG é:þÿÿt&ÇGéþÿÿ¸éÛþÿÿºéÿÿÿU‰åW‹}V¾°S»‰Ø1ɺt&¯ÀÉëÑèA=ÿÿwöJyì‰ð‰Ú)ȃÃÁêƒè‰—ûÿvÅ[^_]ö¼'U‰åWVSƒì‹˜H‰Eð‹u‰Uì‰]è‰ÓÁã ‹UðÁἉ}ä·:·ÇÁè‹ †÷ÿ‹Eð·×Áê‰Mà‹ –·P·úÁòÿ·úÁï‹UðȉEÜ‹¾1ÿtÁ‰Mض¼';}èƒñ‰ù1ÛƒÉë ‰ÊÑêƒá·V÷Ùáÿ1È‹MÁø‰ÑƒùuÛ‹Uà ‹]ä‰ »Gƒÿv·ƒÿwZ‹Eì‹]ðÁà´;}胓Oø1ÛƒÉë ‰ÊÑêƒá·V÷Ùáÿ1È‹MÁø‰ÑƒùuÛ‹UÜ ‹]ä‰ »Gƒÿv¶;}èsM‹Eð°Oð1ÛÉë ‰ÊÑêƒá·V÷Ùáÿ1È‹MÁø‰ÑƒùuÛ‹UØ ‹]ä‰ »G;}èr¼‹uð‹}싆H‰„¾HƒÄ[^_]Ãt&¼'U‰åWVS쬋M‰Eì‹E‹]‰Uè‹U ƒø‰Eä‰M܉Uà‰]؇<‹u칋}è‹Eì·‹7Áî ¯ó)ÙÁéËf‰þÿÿÿ‰7†ÝÇEЋMà‹UìÇEÌÁá\‰]ÔÿMÌ‹Eä‹UÔ¶MÌÓè‹MÐJ‰ñÁé ‰\ÿÿÿ·¯Ëƒà‰EÈ…”¾‰Ê)ÞÁî3‹\ÿÿÿùÿÿÿf‰‡M‹uèÁá‹^‰ûÿÿÿþ†‹N ‹V …É…ˆ‹}è‹W‹O‹uèƒÂƒÑÁãÑeЉV‹Ủ^‹]È ]Ð…Ò‰NÇF …v¼'‹EÜ…Àt‹Uà‹M싼‘HO…ÿ‰¼‘H„ôĬ[^_]Ë]è‹}ì‹ ·1ÿ‰ÈÁè ¯Â‰Æs{ )Á‰Ð‰uˆÁè)‰}Œ‹Eìùÿÿÿ‰M„‰ f‰†Åƒ}ä‡~‹]츋M„·SÁé ‹]è¯Ê)ÐÁè‹Eìùÿÿÿ‰M€‰ f‰P†aÇE¸‹Uà‹EìÇE´‹MäÁ✃é‰]À‰M¼ÿM´‹E¼‹UÀ¶M´Óè‹M¸J· ‰]¬‹]€Áë ¯Ùƒà‰E°…;¸‰Ú)ÈÁè‹M¬ûÿÿÿf‰‡H‹uèÁã‹Eˆ‹UŒ‰‰F‹^‰V ûÿÿÿþv…ÿ„U‹]è¶C‹[ë#‹uè°ÿ‹V‹NƒÂÿƒÑÿ‰Ï ×tp‹}è‰W‰O‹ øˆ‹MèC9Y‰YuÍ‹A0…ÀuÆ‹y ‹Q$)û‰\$‰|$‰$ÿ9Øt ‹MèÇA0 ‹uè‰Ø1ÛF(°ÿ^,‹^ ‰^‹uè‹V‹NƒÂÿƒÑÿ‰Ï ×u‹^‰ØÁèˆF‹}èƒÂƒÑÁã‰Þ‰W‹U´Ñe¸‰]ˆ‹]°‰O1ÿ ]¸…Ò‰}Œ…l‹Eè‹}ˆ‹uŒ‰x‰p éÉýÿÿ‰sÁá‰{ ‹[‰M„ûÿÿÿþ‡‹uè‹]„¶F‰‹^ë#‹uè°ÿ‹V‹NƒÂÿƒÑÿ‰Ï ×tr‹}è‰W‰O‹ ‰úЈ‹MèC9Y‰YuË‹A0…ÀuÄ‹y ‹q$)û‰\$‰|$‰4$ÿ9Øt ‹MèÇA0 ‹uè‰Ú1Û°ÿV(^,‹^ ‰^‹uè‹V‹NƒÂÿƒÑÿ‰Ï ×uŽ‹^‰ØÁèˆF‹‰E„éò‹WÁæúÿÿÿþ†­‹G ‹_ …À„‰7‹Mè‹Q¶Aë$‹uè°ÿ‹N‹^ƒÁÿƒÓÿ‰ß Ïtm‹}è‰_‹_ ‰O؈‹}èB9W‰WuÍ‹_0…ÛuÆ‹G ‰Ó‹W$‰D$)É\$‰$ÿ9ØtÇG0 ‹uè1ÿ°ÿ^(‹V ~,‰V‹uè‹N‹^ƒÁÿƒÓÿ‰ß Ïu“‹V‰ÐÁèˆF‹Eè‹0‹EèƒÁƒÓÁâ‰H‰X‰PÇ@ é?ûÿÿÑeЋMè‹]È ]Љ‹UÌ…Ò„üÿÿ‹}è‹7é:ûÿÿ‰pÿÿÿ1ÿ‹…pÿÿÿ‰½tÿÿÿ‹}è‹•tÿÿÿGW ‰ß‰òÁï)Ê)û‰Ñ‰ØéDûÿÿ‹uè‹V ‹Mè‹}è¶Yˆ]Ç‹_ë%ÆEÇÿ‹Eè‹P‹HƒÂÿƒÑÿ‰Ï ×tw‹uè‰V‹V ‰NUǶULj‹UèC9Z‰ZuÆ‹z0…ÿu¿‹B ‹r$)É\$‰D$‰4$ÿ9Øt ‹UèÇB0 ÆEÇÿ‹}è‰Þ‹Eè1Ûw(‹P‹H_,‹_ ƒÂÿƒÑÿ‰_‰Ï ×u‰‹X‹uè‰ØÁèˆFéÌúÿÿ‹Eì1É‹]„‰dÿÿÿ‹M„‹Uè·@Áë ‰lÿÿÿ¯Ø‰…pÿÿÿ‰`ÿÿÿµ`ÿÿÿ‹µ`ÿÿÿ½dÿÿÿ)ىÉ ‹UìÁë‰|ÿÿÿ)Øùÿÿÿ‹½dÿÿÿf‰B†ÉÇE ‹]ì‹UäÇEœÃƒê‰]¨‰U¤´&ÿMœ‹] ‹U¨¶Mœ‹E¤Óè Z·‰M”‰U‹•|ÿÿÿ‹]Áê ¯Óƒà‰E˜…7‰•xÿÿÿ‹M¸‹])ÈÁèØ‹M”úÿÿÿf‰‡Ý‹uèÁâ‹`ÿÿÿ‹…dÿÿÿ‰‰^‹^‰F ûÿÿÿþv…ÿ„|‹uè‹^¶Fë't&‹uè°ÿ‹V‹NƒÂÿƒÑÿ‰Ï ×tt‹}è‰W‰O‹ ‰úЈ‹MèC9Y‰YuË‹A0…ÀuÄ‹y ‹q$)û‰\$‰|$‰4$ÿ9Øt ‹MèÇA0 ‹uè‰Ø1ÛF(°ÿ‹V ^,‰Ó‰V‹uè‹V‹NƒÂÿƒÑÿ‰Ï ×uŒ‹^‰ØÁèˆF‹}èƒÂƒÑÁã‰Þ‰O1ɉW‰ÏÑe ‹U˜‰dÿÿÿ‹Mœ U ‰`ÿÿÿ…É…ñ‹}è‹`ÿÿÿ‹µdÿÿÿ‰_‰w éèøÿÿ‹u؉ȉuĬ[^_]éáõÿÿÁ¥|ÿÿÿ‰ò‹uè‰V‹V‰~ úÿÿÿþv…ÿ„ê‹Uè‹…|ÿÿÿ‰¶B‹Rë'‹Mè°ÿ‹Y‹qƒÃÿƒÖÿ‰÷ ß„5‹}è‰_‰w‹ ‰ùȈ‹]èB9S‰SuÇ‹s0…öuÀ‹uè‹C ‰Ó‹V$)É\$‰D$‰$ÿ9ØtÇF0 ‰Ù‹]è1ÿK(‹S {,‰S놅ÿ…húÿÿ‹uè‹V‹N‹}èƒÂƒÑÁã‰Þ‰W‰O1ÿ‰]ˆ‰}Œé^øÿÿÁe€‹Mˆ‹uŒ‰K‹K‰s ùÿÿÿþv…ÿ„‹uè‹M€‹V¶F‰ë'‹Mè°ÿ‹Y‹qƒÃÿƒÖÿ‰÷ ß„™‹}è‰_‰w‹ øˆ‹]èB9S‰SuÉ‹C0…Àu‹uè‹K ‰Ó‹V$)ˉ\$‰L$‰$ÿ9ØtÇF0 ‰Þ‹]è1ÿs(‹S {,‰S눋Uè‹Z ‰2éVúÿÿvÑe ‹Mœ‹…xÿÿÿ‹]è‹U˜ U …ɉ„þÿÿ‹M苉…|ÿÿÿé‘üÿÿ‰•`ÿÿÿ1Û‹Eµ`ÿÿÿ‹|ÿÿÿ‰dÿÿÿ‹]‹µ`ÿÿÿ½dÿÿÿÁè)щxÿÿÿ)Éʋ½dÿÿÿ‰Øé™üÿÿ1ÒÞ‰È׋U€Áè‰uˆ)Á‰È‰}Œ)Ú‹M¬‰Óûÿÿÿf‰†¸÷ÿÿÑe¸‹Mè‹]° ]¸‰‹U´…Ò„”øÿÿ‹]è‹ ‰M€éA÷ÿÿ‹uè‹V‹Néýÿÿ‹uè‹V‹Né;øÿÿ‹Q‰ÐÁèˆA‹‰…|ÿÿÿ‹}èƒÃƒÖÁâ‰w1ö‰µdÿÿÿ‰•`ÿÿÿ‹µ`ÿÿÿ‰_‹½dÿÿÿéjûÿÿ‹I‹Uè‰ÈÁèˆB‹‰E€‹EèƒÃƒÖÁá1ÿ‰p‰Î‰X‰Mˆ‰}Œéƒöÿÿ‹}è‹O‹_é†ùÿÿ‹Mè‹Y‹që‚‹Uè‹Z‹rë»¶¿U‰åWVS켋ˆŒ9ˆˆ‰E¼‰U¸t6‹E¼IÁã‹u¼œ‹W‹_‰‹G)Ë‹}¼‰‡Œļ‰Ø[^_]ËE¼1ö1ÿ‰°ˆ‹ˆ4‰¸Œ…É„‹]¼‹}¼‹“”‹‰UÄ‹“˜‰M°‰U´ƒú†’}´vÇE´‹u¼‹^‰$ÿV ÇE¬1Épÿ´&‹U¼‹œŠ8‰ò‰\Ø)Úzÿ¶Bÿ8tc1ÿ‰|ÈAƒùv׋M¬‹TÈ‹M¼‰•Äþÿÿ‹09‚Ӌ]¬‰Ð‹uH‰…‹Äþÿÿéÿÿÿ‹E»Çÿÿÿÿ[^_]Ãf¶G8Fu”»;]´s¶B8FuC;]´s ¶;83tñ‰\È‹}¬9\½Èƒgÿÿÿ‰M¬é_ÿÿÿ‹x1ö‰<$ÿP‹U¼‰‚˜‰Ðœ‰D$‹Z‰$ÿR…À‰Ãt<…‹E¼‹´8”9°0„‹}¼‹—˜ë`‹}¼Çœ;E°‰½´þÿÿv`¶‰÷‹U؈]“)×¶Gÿƒ}°ˆE’–Â8ÕÁ¶Á…Âttƒ½Äþÿÿwk‹u»Çÿÿÿÿéÿÿÿ‹M¼‹‘˜‰u°‹E¼ÿ€4‰]Äé7þÿÿ‹uÄ‹E°‹U‹L·üƒÁH‰ u‹]°éÎýÿÿ‹}¼‡4‰D$‹_‰$ÿW‹]°é°ýÿÿ‹E¼‹U¸‹ˆH‹E¼‰àþÿÿ‹˜¤#‰ˆ ‹¸ #!Ú‰U¨‹U¸‹˜”#!úˆÙÓâ¶~ÿ¹)Ù‹µàþÿÿ‹]¼ÓÿúÁ朋K‹s…É„û‹S N…Ò„?‹S‹}¼RÁà‹„ ƒ{‡‹…@b%k‹…Àb%k‹…¸þÿÿH9ð„è…É„*‹{ …ÿ„‹s‹K‹•@b%k‰•þÿÿ‹U¼vÁàƒù´œ‡ñ‹|Ž º9ʉ}Øw‹D–‰D•ØB9Êvóƒúw‹L– ‰L•ØBƒúvò‹…þÿÿ‰C‹uØ‹‰s ‹M܉…hÿÿÿ‰K$‹Uà‰S(‹}ä‰{,1Û‰Xÿÿÿ‹]¼‹s‰4$ÿS ‹UØpÿ‰÷‰µPÿÿÿ)׋•þÿÿ¶HÿÁâˆWÿÿÿ‹‹¤#¶Gÿ‹}¸!ψ…Vÿÿÿú·„S¬#‹“ #‰½pÿÿÿ‹½hÿÿÿÁ苌ƒœ ‹E¸ω½dÿÿÿ‹}¼!жVÿ‹Ÿ”#ˆÙÓà¹)ÙÓú‹M¼Ð4@Áæ ‹™¨#‰¨þÿÿÞƒ½þÿÿ‰µ8ÿÿÿ†ú¶Wÿÿÿ1ÿ¾¶VÿÿÿÉ´&ۉȉÚ!òÁèÐ0‹…8ÿÿÿ·P‰ÈÁèƒàÉ÷Ø%ÿ1‹…¼þÿÿÁú<‰Ú1Ê÷Ò!Öùÿÿv·‹dÿÿÿß‹•¸þÿÿ‹M¼4RÁ拃̋Ì9ø‰…lþÿÿv(‰Qº‰½lþÿÿ‰»ÌÇAÿÿÿÿÇA‰•Xÿÿÿ‹•þÿÿ‹µpÿÿÿÁâò‹u¼‰•tþÿÿ·„V¬#‹•hÿÿÿ5ÿÁ蔆œ ‹…þÿÿ·„F,%‰•`ÿÿÿf‰…Èþÿÿ5ÿ·ÀÁ蔆œ ¶…Wÿÿÿ8…Vÿÿÿ‰•\ÿÿÿ„° ‹E¼‹¸þÿÿ‹°˜¸ÿ)È9ð‰µxÿÿÿs‰…xÿÿÿƒ½xÿÿÿ‡ù‹µ¸þÿÿF‰µ¸þÿÿéüÿÿ¹ÿÿ‹U¼‰ð)ñÁãÁé÷Ùƒá ƒÁÓè¶„œ‰òƒâ H ‹]¼‹„‹L‹Œ“L#‹•|ÿÿÿÈÂénûÿÿ‹Kƒù†Ûüÿÿ‹•b%kéÖüÿÿ‹U¼‹‚0éüÿÿ¶Wÿÿÿ1Ûɉö¼'‹µ8ÿÿÿ‰Ï‰ÈÁïÉÁè·~ƒà÷Ø%ÿ‹½¼þÿÿ1ÂÁú‹4—óùÿÿvÈ‹½dÿÿÿßéþÿÿ‹}¼vÁà‹” é'üÿÿ‹]¼‹‹0‹xÿÿÿ‰Œþÿÿ9Ùv‰Œþÿÿ¶•Wÿÿÿ‹µXÿÿÿ…ö”À8•Vÿÿÿ•öӅЄ ‹]ØA‹…Pÿÿÿ)ØXÿ;xÿÿÿv‹xÿÿÿº9Ês"¶‹µPÿÿÿ8FuB9Ês¶‹µPÿÿÿ82tìJÿƒù†Ž ‹µþÿÿ‹U¼‹µÀb%k‹u¸‹š¤#‰…4ÿÿÿFÁà!Þð·„B¬#5ÿÁ苜‚œ ß‹4ÿÿÿ·„Z,%5ÿÁ苜‚œ ‹•¸þÿÿß\ 9]¤s$‹U¤R‹U¼Áà„œÿE¤ƒÀ0Ç@9]¤rï‰ò‹…4ÿÿÿÁâòÁâʉ•tþÿÿ‹U¼·ŒBD%Áà‰…4ÿÿÿðÁé·„BŒ%‹´Šœ ‹tþÿÿ5ÿÁè‹„‚œ ð‹´ŠTvð8‹}¼[Áàøˆœ9œ†9ÿ…¸þÿÿ‰œÇA‹¸þÿÿÇAÇA ‰Y‹pÿÿÿ¿‹]¤‰½lÿÿÿ‹µpÿÿÿ1ÿ‹U¼Áá[ñÁàЉ…˜þÿÿÁá‰$ÿÿÿ‰…”þÿÿ‹\½Ø‹•Pÿÿÿ)ÚJÿ‹Pÿÿÿ‰(ÿÿÿ¶Bÿ8„±GƒÿvÓ‹•Œþÿÿ9•DÿÿÿvTÇEÀ‹½´þÿÿ1À‰•tÿÿÿ9s&º´&‹´þÿÿ‰ÐR‹Œþÿÿ9L“øré‰EÀ‹•Œþÿÿ‹µ´þÿÿ‰†ƒÀ‰EÀ‹…lÿÿÿ9…tÿÿÿ‚øÿÿ·•Èþÿÿ‹]¼‹½tÿÿÿ‹`ÿÿÿÁê‹´“œ ‹U ñú;U¤‰ ÿÿÿv.‹}¤Áà„œ¶¼'ÿE¤ƒÀ0Ç@;U¤wï‹´þÿÿ1ö‹lÿÿÿ‰µÿÿÿ9ë#´&ƒ…ÿÿÿ‹…´þÿÿ‹•lÿÿÿ‹½ÿÿÿ9¸r⋽ÿÿÿ¹ÿÿ‹µ´þÿÿ‹T¾‹½pÿÿÿ)щ•ÿÿÿÁé‰Ð÷Ù‹U¼ƒá ƒÁÓè¶œœ‹…pÿÿÿ4K‰µÿÿÿ‹M¤Áà‹µlÿÿÿøÁà‰…üþÿÿIÁãÓ‰œþÿÿë|‹•ÿÿÿÁà‰Ë‹}¼ЋŒ‡LË‹} ‹M¼÷‰½¬þÿÿÁàÈœ9˜œv‰˜œ‹…ÿÿÿ‹M ÇBƒÀ‰J‰B‹…ÿÿÿ~‹•´þÿÿ‰½Àþÿÿ94‚tj‹µÀþÿÿ‹…üþÿÿ‹]¼‹ ÿÿÿð‹”ƒ .¸уþwFþƒ½ÿÿÿ†Pÿÿÿ‹ÿÿÿÁà‹}¼‹…ÿÿÿ‹œ—Lƒà‹„‡L#Øé9ÿÿÿ‹•ÿÿÿ‹Pÿÿÿ)ÑI‰ú‰dþÿÿ‰ù‹}¼‹‡0Á;xÿÿÿv‹xÿÿÿ9Àþÿÿs?‹…dþÿÿ‹½Pÿÿÿ¶D08D7u(´&¼'B9Ês‹…dþÿÿ‹½Pÿÿÿ¶8:tæ)òJƒú‰•€þÿÿ†T‹•þÿÿ‹M¼‹•b%k‹U¸‹¹¤#‰…ôþÿÿòÁà‰½|þÿÿ!×ø‰½ðþÿÿ‹}¼·„G¬#Á苌‡œ ‹‡ #Ë!‰ìþÿÿ‹Ÿ”#‹½PÿÿÿˆÙÓâ¹¶D7ÿ)ÙÓø‹¨þÿÿRÁã ‹•dþÿÿˉèþÿÿ¶ >1ÿ¶¾É¶¿ۉȉÚ!òÁèÐ0‹…èþÿÿ·P‰ÈÁèƒàÉ÷Ø%ÿ1‹…¼þÿÿÁú<‰Ø1È÷Ð!Æùÿÿv·‹ìþÿÿ‹µôþÿÿ‹•|þÿÿω½øþÿÿ‹<µÀb%k‹µðþÿÿ‰øFÁà!Ö‹U¼ð·œB¬#·„z,%óÿÁë5ÿ‹Œšœ Áèøþÿÿ‹œ‚œ ‹¬þÿÿøþÿÿ‹…€þÿÿ\9]¤s+‹…œþÿÿœ´&ÿE¤ƒÀ0ƒ…œþÿÿ0Ç@9]¤rè‰ò‹€þÿÿÁâ‹E¼òÁâÊ·ŒxD%Áç7‹u¼Áé‹¼Žœ ·„FŒ%‹Œ–Tv5ÿÁè‹„†œ ø‹½øþÿÿÈ8[Áàð9œˆœv7‰œ‹ÿÿÿ‹•¬þÿÿÇA‹u ƒÃÇAB‰QÇA ‰q‰Yƒ…ÿÿÿ‹•ÿÿÿ;UÀ„šóÿÿ‹…´þÿÿ‹|ƒÿ‰½ÿÿÿ†ˆüÿÿ‹½ÿÿÿ¹ÿÿ‹•ÿÿÿ‹]¼)ùÁé÷Ùƒá ƒÁÓê¶´œ N‰ÿÿÿéOüÿÿ¶A8C…Búÿÿ¾;µŒþÿÿs'¶J8KuF;µŒþÿÿs‹…(ÿÿÿ‹•Pÿÿÿ¶8tâ‹] ó;]¤v*‹…”þÿÿœÿE¤ƒÀ0ƒ…”þÿÿ0ƒ…˜þÿÿ0;]¤Ç@wት0ÿÿÿ…ÿ…Ü‹…þÿÿ‹U¼·ŒBD%‹•þÿÿ‹…pÿÿÿÁéÁâ‰pþÿÿ‹M¼‰È·”QŒ%òÿÁꋌ‘œ ‹•pþÿÿŒœ ‹…\ÿÿÿÁ‰,ÿÿÿë‹M 1‹…$ÿÿÿ‹U¼‹,ÿÿÿðŒ‚Tv[ÁàМ9ˆœv‰ˆœ‹] ‰zÇB‰ZNƒþw°‹µ0ÿÿÿ…ÿFu‰…lÿÿÿ‰Â‹E¼‹ˆ0Ñ;xÿÿÿv‹xÿÿÿ9Ês7‹(ÿÿÿ‹µ0ÿÿÿ¶D3‹Pÿÿÿ8D3uB9Ês‹(ÿÿÿ‹µPÿÿÿ¶82tæ‹0ÿÿÿ)ÊJ‰•ˆþÿÿƒú†–øÿÿ‹M¼‹0ÿÿÿ‹E¸‹‘¤#‹µþÿÿ؉…¤þÿÿ‹0ÿÿÿ‹4µ@b%k‰•°þÿÿ‰Â‹…$ÿÿÿ‰µÿÿÿ‹°þÿÿÈ‹M¼!Ú‹,ÿÿÿœTv‰ðÁàЋ± #·„A¬#Áè‹”œ ‹…¤þÿÿÓ!ð‰ÿÿÿ‹™”#‹µPÿÿÿˆÙÓà‹0ÿÿÿ¶Tÿ¹)ÙÓúЋ¨þÿÿ@‹…0ÿÿÿÁã Ë1Ò‰ÿÿÿ¶ 0‹µ(ÿÿÿɶ0¾‰•ÿÿÿۉȉÚ!òÁèÐ0‹…ÿÿÿ·P‰ÈÁèƒàÉ÷Ø%ÿ1‹…¼þÿÿÁú‹…ÿÿÿ‰Ø1È÷Ð!Æùÿÿv±‹µÿÿÿ‹…°þÿÿ‹ÿÿÿ‹µÀb%k‹µ¤þÿÿ‹•ÿÿÿ‰„þÿÿF!Ɖ؋]¼ÁàðÊ·„C¬#5ÿÁ苌ƒœ ‹…„þÿÿÊ·ŒC,%‹…ˆþÿÿ‰• ÿÿÿñÿÁé‹”‹œ ‹0ÿÿÿ‹M • ÿÿÿÙ\9]¤‰äþÿÿs*‹…˜þÿÿœÿE¤ƒÀ0ƒ…”þÿÿ0ƒ…˜þÿÿ09]¤Ç@rá‰ñ‹•ˆþÿÿÁáñ‹E¼ÁáÑ‹•„þÿÿ‰tþÿÿ·ŒPD%Áâ‰Ð‹U¼ðÁé·„BŒ%‹´Šœ ‹tþÿÿ5ÿÁè‹„‚œ ð‹´ŠTvð‹µ ÿÿÿ0[‹]¼ÁàØ9œˆœ† öÿÿ‰œ‹µäþÿÿ‹] ÇAF‰qÇAÇA ‰Y‰yé×õÿÿQü‰Uغ‹|–‰|•ØBƒúvòé"ðÿÿ‹…¸þÿÿ9As ‹Q…Ò„:òÿÿ‹…þÿÿ‹U¼·´BD%‹…tþÿÿÁî·”BŒ%‹E¼‰µpþÿÿ‹µpþÿÿÁê‹”œ ”°œ ‹µ\ÿÿÿ29…lþÿÿ‚ãñÿÿ‰ƒÌ‹•¸þÿÿ»ÇA‰QÇA‰Xÿÿÿé¶ñÿÿ‹K…É…æ‹•€b%k‰•þÿÿékïÿÿ‹}¼vÁà‹„ éÐîÿÿ‹½¸þÿÿG‰½¸þÿÿésôÿÿ‹E¼…ÿ‹°H…Æ·”pD%Áæ‹M¨‹u¼Áê·„FŒ%5ÿÁ苌†œ ‹„–œ Á‹E˜‹• þÿÿ4‹M¼[ÁàÈŒšTv´&¼'‹ò9œv‰œ1Ò‰´1Ò‰¸¸‰¤Kƒéƒè0ƒûwÌéóëÿÿ‹•Àb%kéÿÿÿ‹…b%kéùíÿÿ‹µ¸þÿÿF‰µ¸þÿÿéœóÿÿ‹U¼·ŒrD%ñÿÁé‹„Šœ ƒÿ‰…tþÿÿ„ì‹M¼‹U¼·„q\%‹tþÿÿ5ÿÁ茂œ ·”rt%¾)þæÿ1ò‹u¼Áúéùþÿÿ‹J‰ $ÿR ‹}¼Hÿ‹—˜‹„7˜@úvº‰Î)Æ9•Dÿÿÿs‹½Dÿÿÿ¶78uÿ…Dÿÿÿ9•Dÿÿÿrã‹u¼‹†0é ìÿÿ·„wD%·”WŒ%ÁèÁê‹´‡œ ‹”—œ ò9Á†¼éÿÿ‰‡Ì1ɉèé©éÿÿ‹U¼‹þÿÿ·„JD%5ÿÁè‹„‚œ ƒÿ‰…tþÿÿ„ò‹•þÿÿ‹M¼·„Q\%‹U¼‹tþÿÿ5ÿÁ茂œ ‹…þÿÿ·„Bt%‰…tþÿÿ¸)ø%ÿ1…tþÿÿÁ½tþÿÿ‹…tþÿÿŒ‚œ éâøÿÿ‹¸þÿÿA‰¸þÿÿéßñÿÿ‹u¼I‰ËÁâ‹M¼¼2 ‹G‹w‰™ˆ‰…Lÿÿÿ‹}¼[Áàø‰Çlj…Hÿÿÿ‹O…Ét_‹E¼ vÁႜÇ@ÿÿÿÿÇ@Fÿ‰‚´‹W…Òt/‹U¼1ÿ‰¼ t‹•HÿÿÿÁp‹}¼Â ‹B ‰D9‹B‰D9‰ðäÿÿ‰ž”‹¸þÿÿ‹M¼‰¾[Áâ¼2 ‹G‹w‰™ˆ‰…@ÿÿÿ‹}¼ [Ááù‰Ïlj<ÿÿÿ‹G…Àt_‹E¼ vÁႜÇ@ÿÿÿÿÇ@Fÿ‰‚´‹W…Òt/‹}¼1Ò‰”t‹•<ÿÿÿÁp‹}¼Â ‹B ‰D9‹B‰D9‰ð‹}Œ8>…åÿÿF9΃øäÿÿ‹…dþÿÿ¶‹}Œ8>tåéáäÿÿ·„r\%‹tþÿÿÁè‹´‚œ ñé<ûÿÿ·ŒJ\%Áé‰pþÿÿ‰Á‹…pþÿÿéLýÿÿv¼'U‰åWVSƒì|‰Eì‹M쨺‰E¸‹]ì‹Eì‰U英H‹M¸‹¸¨º‰u´ÁæÞ‰}œV‰ø·“¬#Áè 1ÿ¯Â‰Æqy ‰q‹uì‰y ‹Mœ)Á‰MÀ‰ÐÁ艎¨º)Âùÿÿÿf‰“¬#‡‹E¸Áá‹uì‹P‰Ž¨ºúÿÿÿþ‰U¼‡¨‹U¸¶B‹Rë#‹u¸°ÿ‹N‹^ƒÁÿƒÓÿ‰ß Ïtq‹}¸‰O‰_‹ ‰ùȈ‹u¸B9V‰VuË‹F0…ÀuÄ‹~ ‰Ó‹V$‰|$)û‰\$‰$ÿ9ØtÇF0 ‹u¸1ɰÿ^(‹^ N,‰Ú‰^‹u¸‹N‹^ƒÁÿƒÓÿ‰ß Ïu‹}¸‹U¸‹G‰E¼ÁèˆBë…ÿ…Pÿÿÿ‹u¸‹N‹^‹}¸ƒÁ‹EìƒÓ‰O‹Mì‰_‹HÁe¼‹™¨ºÇG ‹u¼‰U´‰]À‰w‹]츋u´‹}ì s‹]À·‘,%Áë ¯Ú)ÐÁ艟¨ºûÿÿÿf‰‘,%‡í‹E¸Áã‹P‰úÿÿÿþ‡‹U¸‹Z ‹M¸‹Q¶Aë#‹}¸°ÿ‹O‹_ƒÁÿƒÓÿ‰Þ Îtt‹}¸‰_‹_ ‰O؈‹E¸B9P‰PuÍ‹X0…ÛuƉƋ@ ‰Ó‹V$)É\$‰D$‰$ÿ9Øt ‹}¸ÇG0 ‹M¸1Ò°ÿ‹}¸Y(‹Y Q,‰Ú‰Y‹O‹_ƒÁÿƒÓÿ‰Þ ÎuŒ‹}¸‹u¸‹W‰ÐÁèƒÁˆF‹E¸ƒÓÁâ‰X‹]ì‰H‰P‹‹HÇ@ ‰M´‹U´1Û‹uì‹}è‹•b%k‰ñÁœ ‹U¸‰†H‰ð*‰L$ ƒ¾¤º‰|$Ç$”É\$èÓÿÿÇEà‹UìÇEÜ '‰UäÿMܸ?‹]ä‹u¸¶MÜÓè‹Mà;}´†äíÿÿ‰M¸‰}´éÙíÿÿ‹ÿÿÿ‰Ñ¥Xÿÿÿ‹•Pÿÿÿ‹hÿÿÿÿ…Tÿÿÿ •XÿÿÿÑ­\ÿÿÿ9TÿÿÿŒ&úÿÿéüûÿÿ‰ðþÿÿ1ö‹…ðþÿÿ‰µôþÿÿ‹µÿÿÿ‹•ôþÿÿF‰ØV ‹•ÌþÿÿÁè)ÉØ)ʉÑé-úÿÿ‹UØMè‹Eà‰ $èüºÿÿ‰EÈ‹}à‹uØ‹‡¤#!ƃ}ȉuÄ…„íÿÿƒ}èÿ…zíÿÿ‹ŸHÁãû s‹Ÿ¨º·‘¬#Áë ¯Ú‰Ÿ¨º¿)×Áïúûÿÿÿf‰‘¬#‡ ‹…ÿÿÿÁã‹P‰úÿÿÿþ†'‹X ‹@ …À…"‹µÿÿÿ‹N‹^éà t&=ÿ†Òëÿÿ‹]à1öƒèº‹ƒüº³ìº…À…Këÿÿ‹ƒØº…Àt º ‰“üº‹uà‹ž„…Ût ¹‰Žüº‹}à‹‡üº…À„ ëÿÿ¾‰·ôºéýêÿÿ‹Uà‹Mà‹Eàœ ‰T$ ‹±¤ºXr‹UÄ‹MÈ…ö‰T$‹•ÿÿÿ”öûƒé‰|$‰ $èó­ÿÿ‹}à‹ŸH‹4@b%k‰·Hé_úÿÿ‹Uà‹…ÿÿÿ‹$ÿÿÿ4B‹Œš8‰ø·–D%Áè ‰µìþÿÿ1ö‰M€¯Â‹ÿÿÿ‰ÃYq )Ç‹Eà‰Y‹ìþÿÿ‰q ‰ÑÁ鉸¨º)Êÿÿÿÿf‰“D%‡!‹…ÿÿÿÁç‰8‹xÿÿÿÿþv…ö„W‹ÿÿÿ‹S¶Cë-‹µÿÿÿ°ÿ‹N‹^ƒÁÿƒÓÿ‰ß Ï„‹‹µÿÿÿ‰N‰^‹v ‰ó؈‹…ÿÿÿB9P‰Pu¾‹x0…ÿu·‰Á‹@ ‰Ó‹Q$)É\$‰D$‰$ÿ9Øt ‹µÿÿÿÇF0 ‰Ø‹ÿÿÿ1Ò‹µÿÿÿ‹{ ‹NC(°ÿ‰{S,‹^ƒÁÿ‰úƒÓÿ‰ß Ï…uÿÿÿ‹~‰úÁêˆV‹u艵$ÿÿÿ‹µÿÿÿƒÁƒÓÁç‰~‹}à‰N‹Mà‰^‹ŸH‹¹¨ºÇF ‰ÿÿÿƒ½$ÿÿÿ„ ‹…ÿÿÿ‹Uà‹ÿÿÿ4B‰øÁè ·–\%‰µìþÿÿ1ö¯Â‰ÃYq )Ç‹Eà‰Y‹ìþÿÿ‰q ‰ÑÁ鉸¨º)Êÿÿÿÿf‰“\%‡!‹ÿÿÿÁç‰9‹yÿÿÿÿþv…ö„ú‹•ÿÿÿ¶B‹Rë-‹µÿÿÿ°ÿ‹N‹^ƒÁÿƒÓÿ‰ß Ï„‹‹µÿÿÿ‰N‰^‹v ‰ó؈‹…ÿÿÿB9P‰Pu¾‹x0…ÿu·‰Á‹@ ‰Ó‹Q$)É\$‰D$‰$ÿ9Øt ‹µÿÿÿÇF0 ‰Ø‹ÿÿÿ1Ò‹µÿÿÿ‹{ ‹NC(°ÿ‰{S,‹^ƒÁÿ‰úƒÓÿ‰ß Ï…uÿÿÿ‹~‰úÁêˆV‹u艵$ÿÿÿ‹µÿÿÿƒÁƒÓÁç‰~‹}à‰N‹Mà‰^‹ŸH‹¹¨ºÇF ‰ÿÿÿ‹ÿÿÿ‹MàY·˜t%‰ùÁé t%‰•Ìþÿÿ¯Ëƒ½$ÿÿÿ… ‹uà¿)ßÁï;‰Ž¨º‹Ìþÿÿf‰‹ÿÿÿ‹=ÿÿÿ‡ù‹QÁà‰úÿÿÿþ†<‹y ‹Y …ÿ„‹ÿÿÿ‹Q¶Aë)‹µÿÿÿ°ÿ‹N‹^ƒÁÿƒÓÿ‰ß Ït{‹½ÿÿÿ‰_‹_ ‰O؈‹½ÿÿÿB9W‰WuÄ‹_0…Ûu½‹G ‰Ó‹W$‰D$)É\$‰$ÿ9ØtÇG0 ‹µÿÿÿ1ɰÿ^(‹~ N,‰ú‰~‹µÿÿÿ‹N‹^ƒÁÿƒÓÿ‰ß Ïu…‹V‰ÐÁèˆF‹E艅$ÿÿÿ‹½ÿÿÿƒÁƒÓÁâ‰O‰_‰WÇG ƒ½$ÿÿÿ„ý ‹Uà‹‚<‰‚@‹}à‹u€‹Ÿ8‰·8‰Ÿ<éuíÿÿ‹]àÃŒ(‰xÿÿÿéFñÿÿ¹ÿÿ‹}à)ÁÁé÷Ùƒá ƒÁÓè¶„œH‰|ÿÿÿéóðÿÿ‹S‰ß1öÇœ‰$ÿS‰ƒ˜‰|$‹K‰ $ÿS…À‰Ã„¡<…‹Eà‹´8”9°0„S‹Mà‹‘˜‰u¼‹Eàÿ€4‰]äéÜåÿÿ1öƒ}¼v]‹Uäƒú‹t“üv7‹L“ðA;M¼u-‰÷Áï;|“ôv"Bþƒø‰Eä‹tƒø‰u¼‹tƒüv ‰Â‹L“ðA;M¼tÓƒ}¼”À1Òƒþ—Â…ÐtÇE¼ƒ}´vK‹M´A;M¼ƒŸ‹}´ƒÇ;}¼“Â1Àþÿ—À…Â…€‹E´ƒÀ;E¼“Á1Òþÿ—Â…Ñ…aƒ}¼º–Àƒ}À–Á Ȩ…Çåÿÿ‹Mà‹}à‹QÇ”‰}¬1ÿ‰$ÿQ‹Uà‰‚˜‰\$‹B‰$ÿR‰E¨…Àt‹UàÁà‰E¤‹¼”9º0„‹Eà‹M¨‹U¬ÿ€4ƒÿ‰ ‰¸vV;}¼‹€”‹Lƒü“Ã1À9ñ’À…Ã…¡ ‹U¼B9ׄˆ 9ׇ _;]¼“Â1Àƒ}¼—À…Ât ‰÷Áï9χj ‹]à‹C‰$ÿS ‹M¼1ÛI¶Pÿxÿ‰ÿÿÿˆ•ÿÿÿ‹Mà‰ú‹„™8¶ÿÿÿ)ÂBÿ‰Eœ:Jÿ„Í CƒûvÖ‹E¼~‰}èƒè„žäÿÿ‹uà†4‰D$‹^‰$ÿV‹U¼éƒäÿÿ‹E´‹]¸H‰]èu‹U´éoäÿÿ‹uà†4‰D$‹~‰<$ÿV‹U´éQäÿÿ‹•ÿÿÿ‹Z éñÿÿ‹µÿÿÿƒê‹dÿÿÿ‰•Hÿÿÿ‹~‹F Áë‰Lÿÿÿ‰½àþÿÿ‰…äþÿÿt&¼'ÿHÿÿÿ1ö‹…ÿÿÿ‹•Lÿÿÿ¶Hÿÿÿ‹8ÓêƒâÑï÷Ú!ú‰Óàþÿÿµäþÿÿÿÿÿÿ‰àþÿÿ‰µäþÿÿ‡!‹•ÿÿÿÁç‰Z‰:‹z‰r ÿÿÿÿþv…ö„拽ÿÿÿ‹w¶Gë<‹•ÿÿÿ°ÿ‹J‹ZƒÁÿƒÓÿ‰ß Ï„œ‹½ÿÿÿ‹W‰O‹O ‰_‰•àþÿÿ‰äþÿÿ‹äþÿÿȈ‹ÿÿÿF9q‰qu«‹A0…Àu¤‹y ‰ó‹q$‰|$)û‰\$‰4$ÿ9Øt ‹•ÿÿÿÇB0 ‰Ø‹ÿÿÿ1ö‹•ÿÿÿ‹K C(°ÿ‰Ks,‰Î‹J‹ZƒÁÿƒÓÿ‰ß Ï…dÿÿÿ‹z‰øÁèˆB‹…ÿÿÿƒÁƒÓÁç‰H1ɉΉX‰û‰½àþÿÿ‰äþÿÿë‹•ÿÿÿ‰:‹½Hÿÿÿ…ÿ…{þÿÿ‹•ÿÿÿ¹‹Eà‰@ÿÿÿ‰r ‹µdÿÿÿ‰Zð)»‰…(ÿÿÿƒæ‰µDÿÿÿ‰ÿÿÿ‹(ÿÿÿ‹ÿÿÿ‹•@ÿÿÿ‹µDÿÿÿ‹ÿÿ…Àº„tÿÿÿ‰^‰t$‰$è£`ÿÿƒÄ,1Ò‰Ð[^_]ô&‰<$¹‰L$ÿº…À‰C „4ÿÿÿ‰Cénþÿÿt&U1À‰åWV1öS‹]‰³H1ɉŒƒ8@ƒøvñƒ¨º¿ÿÿÿÿ‹P Ç@1öÇ@ ‰»¨ºÇ@Ç@Æ@‰PÇ@(Ç@,Ç@0‰ñ1ÒÁá‰ö¼'¿Bf‰¼C¬#ƒú¿f‰¼CŒ%vÝ¿¸ºf‰¼s,%¹f‰„sD%f‰”s\%f‰Œst%Fƒþ v“‹»˜#1À‹³”#‰ùñ¾Óæ9ðs‹“¨#fÇB@9ðrõ1É“ '1Àt&¼'fÇB@ƒø?vôAƒê€ƒùvÞ1À‰ö¼'ºf‰”C )@ƒøqví¸“*f‰ƒ*1ÀfÇBvfÇDB@ƒøvó1À¹f‰ŒB@ƒøví1Àt&¼'¾f‰´B@=ÿv븓Xrf‰ƒXr1ÀfÇBfÇDB@ƒøvó1À¹f‰ŒB@ƒøví1Àt&¼'¾f‰´B@=ÿvë1Àºf‰”Cð)@ƒøví‹‹œ#1À1Ò‰ƒ4¸1ö‰“ˆ‰ÂÓ≳Œ‰ù‰ÖÓàNH‰³¤#‰ƒ #[^_]öU‰åWVSƒì‹Uœ ‰Uè‹U‹‚¤º…À„‰‹U¾1Û‹Š0‰×Ç*I‰Š\º‰Šr‹Šœ#Óæ9ór9‹}¾1ÛÓæÇXr9ósv‹Uè‰ø‰$‰ÚCèÀÿÿ9órìƒÄ[^_]Ãt&‹Eè‰ÚC‰$‰øè ÿÿ9órì‹u‹Žœ#먉ÐèêÀÿÿÇEð‹]‹MÃð)Áœ ‰]ä‰Mèt&¼'ÇEì‹]𾿶¿‹Eä‰ÙƒáÑë·p‰Èö÷Ø Î%ÿ1‹EèÁú‹EìOuÔ‹uð‹}ì‹M‰¼±L#Fƒþ‰uðv›1Û‰™Œ#éÔþÿÿ´&¼'U‰åWV¾Sƒì‹] ‹M‹E‹U‰™»‹˜»1Éë ¶Aƒùw‰÷Óç9ûwò‹u 1ÿ‹M1Û‰†#‰¾ôº‰žüº‰L$‹E‰$‰ðèúÿÿ…ÀtƒÄ[^_]ËM‰ $è«ûÿÿ‹M‹u‹‘¤ºÆœ ‰uè…Ò„‹U¾1Û‹Š0‰×Ç*I‰Š\º‰Šr‹Šœ#Óæ9órM‹}¾1ÛÓæÇXr9ós‹Uè‰ø‰$‰ÚCèç‹ÿÿ9órì‹]1ÿ1É1À‰‹èº‰»ìºƒÄ[^_]ö‹Eè‰ÚC‰$‰øè°‹ÿÿ9órì‹u‹Žœ#딉Èèú¾ÿÿÇEð‹}‹]Çð)Ü ‰}ä‰]èt&¼'ÇEì‹]𾿶¿‹Eä‰ÙƒáÑë·p‰Èö÷Ø Î%ÿ1‹EèÁú‹EìOuÔ‹uð‹]ì‹M‰œ±L#Fƒþ‰uðv›1ÿ‰¹Œ#éÀþÿÿ´&¼'U¹ ®$k‰åWVSƒì‹E‹u‹} ‹U‰ˆ »‹M‹E‰±»‰Ëà »‰™»‹˜»¾‰¹»1ÉëAƒùw‰÷Óç9ûwò‹]4 1ÿ‹E1ɉ³#‰»ôº‰‹üº‰D$‹u‰Ø‰4$èò÷ÿÿ…ÀtƒÄ[^_]ËE‰$è›ùÿÿ‹M‹]‹‘¤ºÜ ‰]ä…Ò„‹U¾1Û‹Š0‰×Ç*I‰Š\º‰Šr‹Šœ#Óæ9órM‹}¾1ÛÓæÇXr9ós‹U䉸‰$‰ÚCè׉ÿÿ9órì‹]1ÿ1É1À‰‹èº‰»ìºƒÄ[^_]ö‹Eä‰ÚC‰$‰øè ‰ÿÿ9órì‹u‹Žœ#딉Èèê¼ÿÿÇEð‹}‹MÇð)Áœ ‰}è‰Mät&¼'ÇEì‹]𾿶¿‹Eè‰ÙƒáÑë·p‰Èö÷Ø Î%ÿ1‹EäÁú‹EìOuÔ‹uð‹]ì‹M‰œ±L#Fƒþ‰uðv›1ÿ‰¹Œ#éÀþÿÿ´&¼'U‰å]Ãt&¼'U‰åƒì‰uü‹u‰]ø‹]‹F9Øs ÇF ‰Ã‹V‰\$‹E ‰$‰D$èÈ)^‰Ø^‹]ø‹uü‰ì]öU‰å‹E‹P‹H‰U]ÿá´&¼'U‰åSƒì‹]‹C‰$ÿS ‹“4[)Ð[]ÃU1Ò‰åWV1öSƒì<1ÛÇEØ/%k‹}‹E‹‰EÜ‹E ‰Mà‹M…ÀÇE䉱ຉ™ôº‰‘üº…÷‹Uœ ‰UÌ‹U‹š¤º…Û„<‹U¾1Û‹Š0‰×Ç*I‰Š\º‰Šr‹Šœ#Óæ9ó‚å‹}¾1ÛÓæÇXr9ós!¶¼'‹Ủø‰$‰ÚCèp‡ÿÿ9órì‹}¾ÿÿÿÿM؉·¨º‰ø‹Ÿèº‰Ìº¨º‹P Æ@‹uÇ@0‰P‹UÇ@Ç@ Ç@Ç@Ç@(Ç@,‹‰$º‰D$‰øè2Åÿÿ‹M‰Â‹}‹±èº)Þ‰7‹u‹Eà‹)Á¸‰‹]ä…Ûu‰ÐƒÄ<[^_]ËẺÚC‰$‰øè®†ÿÿ9órì‹}‹œ#éùþÿÿ‰Ðèõ¹ÿÿÇEÔ‹M‹uÁð)Æœ ‰Mȉu̶ÇEЋ]Ô¾¿¶¿‹EȉكáÑë·p‰Èö÷Ø Î%ÿ1‹EÌÁú‹EÐOuÔ‹}Ô‹]ЋM‰œ¹L#Gƒÿ‰}Ôv›1ö‰±Œ#é&þÿÿ‰ $èFõÿÿéüýÿÿU‰åWVSƒì,‹U‹]‹M ‰š»»‰ŠÌº‹’»1Éë vAƒùw‰ÞÓæ9òwò‹U4 1Û‹E1ɉ²#‰šôº‰Šüº1Ò‰D$‹}‰<$‹Eèóÿÿ…ÀtƒÄ,[^_]ËU‰$è¸ôÿÿ‹U‹E‹º¤ºœ ‰Eè…ÿ„x‹U¾1Û‹Š0‰×Ç*I‰Š\º‰Šr‹Šœ#Óæ9ó‚í‹}¾1ÛÓæÇXr9ós‹Uè‰ø‰$‰ÚCèñ„ÿÿ9órì‹U1ÿ1ö‹E…Ò‰¸èº‰°ìº„Øë Ç$1À1Ò‰D$‹EèéÂÿÿ…À…&ÿÿÿ‹M‹™ôº…Û…ÿÿÿ‹}‹M‹‡Àº‹·Èº)ð™к‘Ôº¸º‘¼º‰D$ ‰T$‹™èº‹¹ìº‰\$‰|$‹U‰$ÿ…À„wÿÿÿ¸ ƒÄ,[^_]ËEè‰ÚC‰$‰øè„ÿÿ9órì‹u‹Žœ#éñþÿÿ‹M‹™ôº…Û…|þÿÿÇ$1ÿ1Ò‰|$‹Eè Âÿÿ…ÀtÔƒÄ,[^_]ÉÐè-·ÿÿÇEð‹]‹MÃð)Áœ ‰]ä‰Mè´&¼'ÇEì‹]𾿶¿‹Eä‰ÙƒáÑë·p‰Èö÷Ø Î%ÿ1‹EèÁú‹EìOuÔ‹uð‹}ì‹M‰¼±L#Fƒþ‰uðv›1Û‰™Œ#éâýÿÿ´&¼'U¸‰åW‹M‹UV‹} S‹š»ƒ9vhÇ‹‚œ#‹Š˜#4€Îö‚”#¹ ¾ºˆ‰ðÓà9Øs4‰ÐÓà9Øs,Aƒù~ê1Ò´& Õ‰ØÓèˆDBƒú~ë1À[^_]ÉÃëÖU¸ ®$k‰åWVSƒìL‹uÇEØ/%k‹]‹M‰† »‹u‹}‹U ‰ž»‹‰¾»‹MÇEä‹]‰UÜU؉Eà‹E‰‘̺‹}à »‰™»‹»1ɉ¾àº»ëfAƒùw‰ßÓç9úwò‹]1À< ‹U(1ö‹M$‰ƒôº‹E‰»#‰³üº‰T$1Ò‰ $è_ïÿÿ…À‰Ât"‹]‹uà‹)ð‰‹}丅ÿu‰ÐƒÄL[^_]Ë]‰$èìðÿÿ‹Uœ ‰UÈ‹U‹Š¤º…É„`‹U¾1Û‹Š0‰×Ç*I‰Š\º‰Šr‹Šœ#Óæ9ó‚Ú‹}¾1ÛÓæÇXr9ós‹Uȉø‰$‰ÚCè$ÿÿ9órì‹U 1ÿ1É‹E…Ò‰¸èº‰ˆìºuléÀ‹u‹žôº…Ûux‹}‹u‹‡Àº‹Èº‹} )È™†Ðº–Ôº†¸º–¼º‰D$ ‰T$‹†èº‹žìº‰<$‰D$‰\$ÿ…À…Ç$‹E1Ò‰T$1Òèþÿÿ…À„{ÿÿÿ‰Âé«þÿÿt&‹EȉÚC‰$‰øè`€ÿÿ9órì‹}‹œ#éÿÿÿ‹M‹±ôº…öuÆÇ$‹E1Û‰\$1Òèj¾ÿÿ…Àt؉ÂéVþÿÿ‰Ðèx³ÿÿÇEÔ‹E‹uð)Æœ ‰ẺuÈv¼'ÇEЋ]Ô¾¿¶¿‹ẺكáÑë·p‰Èö÷Ø Î%ÿ1‹EÈÁú‹EÐOuÔ‹}Ô‹]ЋM‰œ¹L#Gƒÿ‰}Ôv›1ö‰±Œ#éÿýÿÿ¸ ‰Âé©ýÿÿfU‰åWVSì¼»(R‰\$‹E,‰$ÿ‰…tÿÿÿ…À„}¨ºu¸Ç@$Ç@ ‹…tÿÿÿƒÀ‰$è®+ÿÿÇE¸Uˆ¹ ÇE܉×ÇE¼ÇEäÿÿÿÿÇEØÿÿÿÿÇEÔÿÿÿÿÇEÐÿÿÿÿÇEÌÿÿÿÿÇEÈÿÿÿÿÇEÄÿÿÿÿÇEÀÿÿÿÿÇEàüó¥‰×‹Uˆ…Òˆ{‰Uˆ‹]Œ…Û„.‹w…öˆE‹G …ÀˆL‹_…ÛˆS‹_…ÛˆZ‹O…Ɉe‹W…Òˆw‹w …öˆ‹_$…ÛuÑù…ÒAuÑø‰G$‹W,…Òˆ„ƒ} ƒ}”Žm‹µtÿÿÿº»‹½tÿÿÿÆœƇœ¿ÆF‰Ù‰øÑùIÓà‰Á1Àëˆ2@B9Èr÷Cƒû~⋵tÿÿÿ»¿°Æœ ‰Ø1ɺ¶¿¯ÀÉëÑèA=ÿÿwöJyì‰ø‰Ú)ȃÃÁêƒè‰–ûÿv½‹½tÿÿÿ1Û1ö‰Ÿ¨#…ÿ‰·»„œü¹ ‹uUˆ‰×ó¥‰×‹Uˆ…Òˆ‰Uˆ‹EŒ…Àuƒú_L¸Óà‰G‹_…ۈЋw …öˆ¹‹G…Àˆ¢‹_…Ûˆ‡‹O…Ɉe‹W…ÒˆK‹_ …Ûˆ4‹w$…öuÑù…ÒAuÑø‰G$‹W,…Òˆüƒ}!ƒ}”ƒ}˜‹EŒ=w =@†g¸…À‰Æ…|‹} ¸‹tÿÿÿƒ?‹™»vw‹E ‹•tÿÿÿÇ‹²œ#‹Š˜#<¶Ï‹uÿ¹ ‚”#ºˆ¾‰ÐÓà9؃–‰ðÓà9؃ŠAƒù~â1Ò‹} Õ‰ØÓèˆDBƒú~è1À…À‰Æ…â‹tÿÿÿ¹ ®$k¾/%k‰µxÿÿÿ‹}‹E‰‹ »‹M ‰Þ‰»»‹UÆ »‰ƒ»‹}$‹‰•|ÿÿÿ•xÿÿÿ1ɉE€ÇE„‰“̺‹“»‰»àº‰³»»ëAƒùw‰ÞÓæ9òwò‹tÿÿÿ1À4 ‹}01ɉƒüº‰Ø‰³#‰‹ôº‰|$‹U,‰$1Òè½èÿÿ…À‰Â„Ÿ‹} ‹u€‹)ð‰‹]„¸…Ûu‰Ð‰Æ‹E0‰D$‹tÿÿÿƒÁ‰ $èÿ'ÿÿ‹•tÿÿÿ‹š¨#‰\$‹},1Û‰<$ÿW‹½tÿÿÿ‹‡»‰D$‹M,‰ $ÿQ‰Ÿ¨#‰û躋C 1Ò‰—»‰D$‹M,‰ $ÿQÇC ‰|$‹U,‰$ÿRļ‰ð[^_]Ãú{L¸Óà‰G‹w…ö‰»ûÿÿÇG‹G …À‰´ûÿÿÇG ‹_…Û‰­ûÿÿÇG‹_…Û‰¦ûÿÿ‹O1ÛƒúŸÃ…ɉ_‰›ûÿÿ1ÀƒúŸÀ‹WHƒààH@…Ò‰O‰‰ûÿÿ‹w 1Ò…Û•Â…ö‰W‰ûÿÿÇG ésûÿÿļ¸[^_]Ã}˜‰ûÿÿ‹EŒ=‡{ûÿÿ=@‡pûÿÿ‹½tÿÿÿ‰‡»‹M¬‰»‹E ƒø‡t¸‹µtÿÿÿ1Ò‰†0‹E‰†”#‹M”‰Ž˜#‹}˜‰¾œ#ƒ}œ”‰–¤º‹]¤º‰^l‹E¤…Àt‹E¨ƒøŽ:ƒø‰Â‹µtÿÿÿ‰Vd‹U¬‰VH‹]°‰žàºéÒúÿÿ´&1Àƒú•ÀH%þ‰Géxþÿÿ1Àƒú•ÀH%þé”ûÿÿÇG,éøûÿÿÇG,épúÿÿÇG éÀûÿÿ1Ò…Û•‰Wé¦ûÿÿ1ÀƒúŸÀHƒààH@‰Oé„ûÿÿ1ÛƒúŸÃ‰_éiûÿÿÇGéRûÿÿÇG é;ûÿÿÇGé$ûÿÿºéîúÿÿºé{ùÿÿ‹½tÿÿÿ‰‡»‹M¬‰»‹E ƒø‡ñ¸‹tÿÿÿ1Ò‰ƒ0‹E‰ƒ”#‹M”‰‹˜#‹}˜‰»œ#ƒ}œ”‰“¤º‹u¤º‰sl‹E¤…Àt‹E¨ƒøŽÆƒø‰Â‹tÿÿÿ1À‰Sd‹U¬‰SH‹u°‰³àºéþúÿÿ‰Ãéuûÿÿ‹½tÿÿÿ‰<$èÆæÿÿ‹½tÿÿÿ‹•tÿÿÿ‹Ÿ¤ºœ ‰•dÿÿÿ…Û„‘‹•tÿÿÿ¾1Û‹Š0‰×Ç*I‰Š\º‰Šr‹Šœ#Óæ9ó‚ꋽtÿÿÿ¾1ÛÓæÇXr9ós‹•dÿÿÿ‰ø‰$‰ÚCèìvÿÿ9óré‹U(1ÿ1ö‹…tÿÿÿ…Ò‰¸èº‰°ìºutéÖ¶‹tÿÿÿ‹™ôº…Ûu{‹µtÿÿÿ‹¾Èº‹†Àº)ø™†Ðº–Ôº†¸º–¼º‰D$ ‰T$‹–躋žìº‰T$‰\$‹}(‰<$ÿ…À…ŒÇ$1ö1Ò‰t$‹…tÿÿÿè}´ÿÿ…À„uÿÿÿ‰Âé ûÿÿ‹…dÿÿÿ‰ÚC‰$‰øèvÿÿ9óré‹tÿÿÿ‹‹œ#éîþÿÿ¶‹tÿÿÿ‹±ôº…öu»Ç$1ÿ1Ò‰|$‹…tÿÿÿè´ÿÿ…ÀtÒ‰Âé¨úÿÿ¸ ‰Âéœúÿÿ‰ø1öè©ÿÿ‰µpÿÿÿœ ‡ð)‰dÿÿÿ‰…hÿÿÿ‹pÿÿÿ1Ò¾‰•lÿÿÿ¿‹…hÿÿÿ‰ÙƒáÑë·p‰Èö÷Ø Î%ÿ1‹…dÿÿÿÁú‹…lÿÿÿOuË‹pÿÿÿ‹½lÿÿÿ‹tÿÿÿ‰¼™L#Cƒû‰pÿÿÿvŽ1ö‰±Œ#éÉýÿÿ=† ýÿÿ¸éÿüÿÿt&=††ûÿÿ¸é|ûÿÿºé7ýÿÿºéÃûÿÿU‰å‹E ‰E]éáÿÿU‰å‹E ‰E]éñÿÿU‰åSƒìd]ȉ$èngÿÿ‰\$‹U ‹E$‹M(‹]‰UÈ‹U,‰EÌ‹E0‰UÔ‹U8‰EØ‹E<‰MЋM4‰UôºP%k‰EÜ1À‰T$$‹U‰D$ ‹E‰Mà¹P%k‰L$(1ɉL$‹M‰T$‹U ‰D$‹E‰\$ ‰L$‰T$‰$è®ôÿÿƒÄd[]ô&U¹P%k‰åUüƒì(1À‰L$ ‹M‰T$‹U‰D$‹E‰L$‹M‰T$‹U ‰D$ ‹E‰L$‰T$‰$èFdÿÿÉùd%kUùd%k‰ås‹Q‹ƒÁ‚$kùd%krê]ÃU‰åƒì¡P%k‹…ÀtÿЋP%kB£P%k‹B…ÀuéÉöU‰åVSƒì‹5`J%kƒþÿt-…ötµ`J%kfÿƒëƒîuöÇ$PD%kèzËþÿƒÄ[^]Ãv1Òë‰ÂB‹ …`J%k…Éuð‰Öë»´&¡ p%kU‰å…Àt]Ãf]Ç p%këƒU¸‰å] U¡p%k‰å]‹Hÿá‰öUºB‰åS·Àƒìd‰T$U¨1Û‰T$‰$ÿ¸%kº¹ƒì …Àuë=ÉJx€|*¨Auô ËÉJyòƒ;Tu‰Ø‹]üÉÃÇ$$c%kº÷¸Tc%k‰T$‰D$èƒÇ$ˆc%k»ñ¹Tc%k‰\$‰L$èe¶¼'U‰åWVS켋=p%k…ÿteô[^_]ÃÇE˜AAAA¡c%k}˜ÇEœAAAAÇE AAAA‰E¸¡c%kÇE¤AAAAÇE¨AAAA‰E¼¡c%kÇE¬AAAAÇE°AAAA‰EÀ¡ c%kÇE´AAAA‰EÄ¡c%k‰EÈ¡c%k‰EÌ¡c%k‰EСc%k‰EÔ· c%kf‰E؉<$ÿ´%k·Àƒì…À…qÇ$Tè …À‰Ã„‰$1ɾT‰L$‰t$èHÇC J%k¹ÇCE%k¡@p%kÇT‹Dp%kÇC(‰C¡ P%k‰S‹$P%k‰C¡Pp%kÇC,ÿÿÿÿ‰S ‰C0¡(P%k‹,P%k‰C4¡`p%k‰S8‹dp%k‰C<¡pp%kÇCDÿÿÿÿ‰S@‰CH‹4P%k¡0P%k‰SPº‰CL‰Ø!ȃøÀ$ ÉAˆ„*HÿÿÿJyç¡c%k‰…hÿÿÿ¡c%k‰…lÿÿÿ¡c%k‰…pÿÿÿ¡ c%k‰…tÿÿÿ¡c%k‰…xÿÿÿ¡c%k‰…|ÿÿÿ¡c%k‰E€¡c%k‰E„· c%kf‰Eˆ…Hÿÿÿ‰$ÿ°%k·ðƒì…öuB1Ò…Òu‰$èÉ<$ÿ´%kƒì·Àè/ýÿÿ‰Ã‰p%kC£€p%kC£ p%keô[^_]Éðèýÿÿ9؉òu±ë±èûÙD$Ùå›ßàÝØ%EÃÙD$Ùÿßà©uÃÙëØÀÙÉÙõßà©uõÝÙÙÿÃÙD$Ùþßà©uÃÙëØÀÙÉÙõßà©uõÝÙÙþÃÙD$ÙD$ÙÉÙóÃÙD$ÙÀØÈÙèÞáÙúÙÉÙóÃì ÙD$ÙîÝéßàžwƒÄ ÙúÃÝØè«ÙÀc%kÇ!ƒÄ ÃÙD$ƒì›Ù|$º T$âÿ÷‰$Ù,$ÙüÙl$ƒÄÃÙD$ƒì›Ù|$º T$âÿû‰$Ù,$ÙüÙl$ƒÄÃÛl$Ùÿßà©uÃÙëØÀÙÉÙõßà©uõÝÙÙÿÃÙÀc%kÃÿ%ô%kÿ%Ô%kÿ%ì%kÿ%à%kÿ%Ì%kÿ%ð%kÿ%Ü%kÿ%ä%kÿ%è%kÿ%‘%kÿ%‘%kÿ% ‘%kÿ%‘%kÿ%‘%kÿ%‘%kÿ%ü%kÿ%ø%kÿ%Ð%kÿ%Ø%kÿ%À%kÿ%¼%kÿ%¸%kÿ%´%kÿ%°%kU‰å]é'ÇþÿÿÿÿÿPJ%kÿÿÿÿC%k C%kpJ%kÿÿÿÿÿÿÿÿÿÿÿÿUnknown error codeCTM_UNSUPPORTED_FORMAT_VERSIONCTM_INTERNAL_ERRORCTM_LZMA_ERRORCTM_BAD_FORMATCTM_FILE_ERRORCTM_OUT_OF_MEMORYCTM_INVALID_MESHCTM_INVALID_OPERATIONCTM_INVALID_ARGUMENTCTM_INVALID_CONTEXT2$kŒ$kƒ$kz$kq$kh$k_$kV$kM$kD$k;$kö$kï$kâ$kÛ$kÔ$kÀ$kÀ$kÍ$krbOCTMRAWMG1MG2wbINDXVERTTEXCATTRNORMINDXVERTTEXCATTRNORMÿæÛ.MG2HVERTGIDXINDXTEXCATTRNORM`B¢ €?ÈB?ÿæÛ.å<ÛÉ?ƒù"?ÛÉ@ÛI@ÛÉ?ÛÉ@ÛI@å<   -LIBGCCW32-EH-3-SJLJ-GTHR-MINGW32w32_sharedptr->size == sizeof(W32_EH_SHARED)../../gcc-3.4.5/gcc/config/i386/w32-shared-ptr.cGetAtomNameA (atom, s, sizeof(s)) != 0Àÿ€ÿ€™PK(€4€¬€$openctm.dll ÀÀð°ðpÀÀ`p @ 0€ à#° `À0&$0€`p|£¸ÆÕäó‚‚*‚6‚G‚U‚h‚}‚Ž‚›‚¬‚¾‚ƂԂâ‚õ‚ý‚ ƒƒ2ƒ ctmAddAttribMapctmAddUVMapctmAttribPrecisionctmCompressionLevelctmCompressionMethodctmDefineMeshctmErrorStringctmFileCommentctmFreeContextctmGetAttribMapFloatctmGetAttribMapStringctmGetErrorctmGetFloatctmGetFloatArrayctmGetIntegerctmGetIntegerArrayctmGetNamedAttribMapctmGetNamedUVMapctmGetStringctmGetUVMapFloatctmGetUVMapStringctmLoadctmLoadCustomctmNewContextctmNormalPrecisionctmSavectmSaveCustomctmUVCoordPrecisionctmVertexPrecisionctmVertexPrecisionRel™PKT(€ € ÀÀð°ð pÀÀ`p @ 0€à#° `À0&$0€`s‚˜®ÅÖçø ‚!‚:‚H‚V‚i‚y‚Ž‚¥‚¸‚ǂۂð‚ú‚ ƒƒ0ƒ:ƒKƒbƒwƒ openctm.dllctmAddAttribMap@12ctmAddUVMap@16ctmAttribPrecision@12ctmCompressionLevel@8ctmCompressionMethod@8ctmDefineMesh@24ctmErrorString@4ctmFileComment@8ctmFreeContext@4ctmGetAttribMapFloat@12ctmGetAttribMapString@12ctmGetError@4ctmGetFloat@8ctmGetFloatArray@8ctmGetInteger@8ctmGetIntegerArray@8ctmGetNamedAttribMap@8ctmGetNamedUVMap@8ctmGetString@8ctmGetUVMapFloat@12ctmGetUVMapString@12ctmLoad@8ctmLoadCustom@12ctmNewContext@4ctmNormalPrecision@8ctmSave@8ctmSaveCustom@12ctmUVCoordPrecision@12ctmVertexPrecision@8ctmVertexPrecisionRel@8@,’°\ˆ’Ì‘(‘4‘D‘T‘b‘p‘z‘„‘Œ‘–‘ ‘¨‘°‘¸‘‘֑̑à‘ê‘ð‘ø‘’ ’‘(‘4‘D‘T‘b‘p‘z‘„‘Œ‘–‘ ‘¨‘°‘¸‘‘֑̑à‘ê‘ð‘ø‘’ ’AddAtomA°FindAtomAÝGetAtomNameAVirtualAllocVirtualFree$__dllonexito_assert˜_errnoabort-fclose0fflush8fopen>fread?freeGfwritermallocxmemcpyymemmovezmemset~pow…qsort™strcmp›strcpyŸstrlenKERNEL32.dllmsvcrt.dll™PK€™PK0€™PK HX øø4VS_VERSION_INFO½ïþVStringFileInfo2040904e44ProductVersion1.0.3.00FileVersion1.0.3.0^FileDescriptionOpenCTM API shared library0ProductNameOpenCTM@ OriginalFilenameopenctm.dll\LegalCopyright© 2009-2010 Marcus GeelnardŠ9LicenseThis software is released under the zlib/libpng license.DVarFileInfo$Translation ä8 00=0E0i0r0Š0Ÿ0ð01$1.545=5F5O5X5a5j5s5|5…5Ž5¼5 4.4ñ4?5ß56d6~60 B5¦5 6‰6ú6ê9V:±:;–;<“?@(È0j2‚2¸2X3.5s6å637¡7:9?<ä<>…>‚?P,‰0•0ê01l1õ1<2…23:4ƒ4÷4Ž5#6ü=6>J>H?€$ž7¥7®7µ7¾7Å7à7ç7ó7ú78 8 :Àfh>à µ5ð þ= A1©; ±9 Ì2ò<²?0R5d5þ;<@¸t33Ò3!4(4:4@4W4e4m4Š4š4­4Ì4á4ó45A5z5„5˜5¢5Î5æ5ÿ56+6:6B6J6R6\6i6«6·6¼6È6×6à6è6ú67777,717Z7e7p7{7†7‘7œ7¤7®7Á7â7õ7ý78ï8‚9’9š9¢9ª9²9º9Â9Ê9Ò9Ú9â9ê9ò9ú9: :::":*:2:::B:J:d:P000`0Ø0Ü0à0ä0è0ì0ð0ô0ø0ü0111 11111 18 00=0E0i0r0Š0Ÿ0ð01$1.545=5F5O5X5a5j5s5|5…5Ž5¼5 4.4ñ4?5ß56d6~60 B5¦5 6‰6ú6ê9V:±:;–;<“?@(È0j2‚2¸2X3.5s6å637¡7:9?<ä<>…>‚?P,‰0•0ê01l1õ1<2…23:4ƒ4÷4Ž5#6ü=6>J>H?€$ž7¥7®7µ7¾7Å7à7ç7ó7ú78 8 :Àfh>à µ5ð þ= A1©; ±9 Ì2ò<²?0R5d5þ;<@¸t33Ò3!4(4:4@4W4e4m4Š4š4­4Ì4á4ó45A5z5„5˜5¢5Î5æ5ÿ56+6:6B6J6R6\6i6«6·6¼6È6×6à6è6ú67777,717Z7e7p7{7†7‘7œ7¤7®7Á7â7õ7ý78ï8‚9’9š9¢9ª9²9º9Â9Ê9Ò9Ú9â9ê9ò9ú9: :::":*:2:::B:J:d:P000`0Ø0Ü0à0ä0è0ì0ð0ô0ø0ü0111 11111 1three.js-r73/utils/converters/fbx/0000755000175500017550000000000012610076566017065 5ustar debacledebaclethree.js-r73/utils/converters/fbx/README.md0000755000175500017550000000334012610076566020347 0ustar debacledebacle## convert-to-threejs Utility for converting model files to the Three.js JSON format ## Supported Formats * Fbx (.fbx) * Collada (.dae) * Wavefront/Alias (.obj) * 3D Studio Max (.3ds) ## Usage ``` convert_to_threejs.py [source_file] [output_file] [options] Options: -t, --triangulate force non-triangle geometry into triangles -x, --ignore-textures don't include texture references in output file -u, --force-prefix prefix all object names in output file to ensure uniqueness -f, --flatten-scene merge all geometries and apply node transforms -c, --add-camera include default camera in output scene -l, --add-light include default light in output scene -p, --pretty-print prefix all object names in output file ``` ## Current Limitations * No animation support * Only Lambert and Phong materials are supported * Some camera properties are not converted correctly * Some light properties are not converted correctly * Some material properties are not converted correctly * Textures must be put in asset's folder, and use relative path in the material ## Dependencies ### FBX SDK * Requires Autodesk FBX SDK Python 2013.3 bindings. ``` You can download the python bindings from the Autodesk website: http://usa.autodesk.com/fbx/ ``` ``` Don't forget the visit the FBX SDK documentation website: http://docs.autodesk.com/FBX/2013/ENU/FBX-SDK-Documentation/cpp_ref/index.html ``` ### Python * Requires Python 2.6 or 3.1 (The FBX SDK requires one of these versions) ``` bash sudo apt-get install build-essential wget http://www.python.org/ftp/python/2.6.8/Python-2.6.8.tar.bz2 tar jxf ./Python-2.6.8.tar.bz2 cd ./Python-2.6.8 ./configure --prefix=/opt/python2.6.8 && make && make install ``` three.js-r73/utils/converters/fbx/LICENSE0000755000175500017550000000210112610076566020067 0ustar debacledebacleThe MIT License Copyright (c) 2012 convert-to-three.py authors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. three.js-r73/utils/converters/fbx/convert_to_threejs.py0000755000175500017550000022756412610076566023370 0ustar debacledebacle# @author zfedoran / http://github.com/zfedoran import os import sys import math import operator import re import json import types import shutil # ##################################################### # Globals # ##################################################### option_triangulate = True option_textures = True option_copy_textures = True option_prefix = True option_geometry = False option_forced_y_up = False option_default_camera = False option_default_light = False option_pretty_print = False converter = None inputFolder = "" outputFolder = "" # ##################################################### # Pretty Printing Hacks # ##################################################### # Force an array to be printed fully on a single line class NoIndent(object): def __init__(self, value, separator = ','): self.separator = separator self.value = value def encode(self): if not self.value: return None return '[ %s ]' % self.separator.join(str(f) for f in self.value) # Force an array into chunks rather than printing each element on a new line class ChunkedIndent(object): def __init__(self, value, chunk_size = 15, force_rounding = False): self.value = value self.size = chunk_size self.force_rounding = force_rounding def encode(self): # Turn the flat array into an array of arrays where each subarray is of # length chunk_size. Then string concat the values in the chunked # arrays, delimited with a ', ' and round the values finally append # '{CHUNK}' so that we can find the strings with regex later if not self.value: return None if self.force_rounding: return ['{CHUNK}%s' % ', '.join(str(round(f, 6)) for f in self.value[i:i+self.size]) for i in range(0, len(self.value), self.size)] else: return ['{CHUNK}%s' % ', '.join(str(f) for f in self.value[i:i+self.size]) for i in range(0, len(self.value), self.size)] # This custom encoder looks for instances of NoIndent or ChunkedIndent. # When it finds class CustomEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, NoIndent) or isinstance(obj, ChunkedIndent): return obj.encode() else: return json.JSONEncoder.default(self, obj) def executeRegexHacks(output_string): # turn strings of arrays into arrays (remove the double quotes) output_string = re.sub(':\s*\"(\[.*\])\"', r': \1', output_string) output_string = re.sub('(\n\s*)\"(\[.*\])\"', r'\1\2', output_string) output_string = re.sub('(\n\s*)\"{CHUNK}(.*)\"', r'\1\2', output_string) # replace '0metadata' with metadata output_string = re.sub('0metadata', r'metadata', output_string) # replace 'zchildren' with children output_string = re.sub('zchildren', r'children', output_string) # add an extra newline after '"children": {' output_string = re.sub('(children.*{\s*\n)', r'\1\n', output_string) # add an extra newline after '},' output_string = re.sub('},\s*\n', r'},\n\n', output_string) # add an extra newline after '\n\s*],' output_string = re.sub('(\n\s*)],\s*\n', r'\1],\n\n', output_string) return output_string # ##################################################### # Object Serializers # ##################################################### # FbxVector2 is not JSON serializable def serializeVector2(v, round_vector = False): # JSON does not support NaN or Inf if math.isnan(v[0]) or math.isinf(v[0]): v[0] = 0 if math.isnan(v[1]) or math.isinf(v[1]): v[1] = 0 if round_vector or option_pretty_print: v = (round(v[0], 5), round(v[1], 5)) if option_pretty_print: return NoIndent([v[0], v[1]], ', ') else: return [v[0], v[1]] # FbxVector3 is not JSON serializable def serializeVector3(v, round_vector = False): # JSON does not support NaN or Inf if math.isnan(v[0]) or math.isinf(v[0]): v[0] = 0 if math.isnan(v[1]) or math.isinf(v[1]): v[1] = 0 if math.isnan(v[2]) or math.isinf(v[2]): v[2] = 0 if round_vector or option_pretty_print: v = (round(v[0], 5), round(v[1], 5), round(v[2], 5)) if option_pretty_print: return NoIndent([v[0], v[1], v[2]], ', ') else: return [v[0], v[1], v[2]] # FbxVector4 is not JSON serializable def serializeVector4(v, round_vector = False): # JSON does not support NaN or Inf if math.isnan(v[0]) or math.isinf(v[0]): v[0] = 0 if math.isnan(v[1]) or math.isinf(v[1]): v[1] = 0 if math.isnan(v[2]) or math.isinf(v[2]): v[2] = 0 if math.isnan(v[3]) or math.isinf(v[3]): v[3] = 0 if round_vector or option_pretty_print: v = (round(v[0], 5), round(v[1], 5), round(v[2], 5), round(v[3], 5)) if option_pretty_print: return NoIndent([v[0], v[1], v[2], v[3]], ', ') else: return [v[0], v[1], v[2], v[3]] # ##################################################### # Helpers # ##################################################### def getRadians(v): return ((v[0]*math.pi)/180, (v[1]*math.pi)/180, (v[2]*math.pi)/180) def getHex(c): color = (int(c[0]*255) << 16) + (int(c[1]*255) << 8) + int(c[2]*255) return int(color) def setBit(value, position, on): if on: mask = 1 << position return (value | mask) else: mask = ~(1 << position) return (value & mask) def generate_uvs(uv_layers): layers = [] for uvs in uv_layers: tmp = [] for uv in uvs: tmp.append(uv[0]) tmp.append(uv[1]) if option_pretty_print: layer = ChunkedIndent(tmp) else: layer = tmp layers.append(layer) return layers # ##################################################### # Object Name Helpers # ##################################################### def hasUniqueName(o, class_id): scene = o.GetScene() object_name = o.GetName() object_id = o.GetUniqueID() object_count = scene.GetSrcObjectCount(class_id) for i in range(object_count): other = scene.GetSrcObject(class_id, i) other_id = other.GetUniqueID() other_name = other.GetName() if other_id == object_id: continue if other_name == object_name: return False return True def getObjectName(o, force_prefix = False): if not o: return "" object_name = o.GetName() object_id = o.GetUniqueID() if not force_prefix: force_prefix = not hasUniqueName(o, FbxNode.ClassId) prefix = "" if option_prefix or force_prefix: prefix = "Object_%s_" % object_id return prefix + object_name def getMaterialName(o, force_prefix = False): object_name = o.GetName() object_id = o.GetUniqueID() if not force_prefix: force_prefix = not hasUniqueName(o, FbxSurfaceMaterial.ClassId) prefix = "" if option_prefix or force_prefix: prefix = "Material_%s_" % object_id return prefix + object_name def getTextureName(t, force_prefix = False): if type(t) is FbxFileTexture: texture_file = t.GetFileName() texture_id = os.path.splitext(os.path.basename(texture_file))[0] else: texture_id = t.GetName() if texture_id == "_empty_": texture_id = "" prefix = "" if option_prefix or force_prefix: prefix = "Texture_%s_" % t.GetUniqueID() if len(texture_id) == 0: prefix = prefix[0:len(prefix)-1] return prefix + texture_id def getMtlTextureName(texture_name, texture_id, force_prefix = False): texture_name = os.path.splitext(texture_name)[0] prefix = "" if option_prefix or force_prefix: prefix = "Texture_%s_" % texture_id return prefix + texture_name def getPrefixedName(o, prefix): return (prefix + '_%s_') % o.GetUniqueID() + o.GetName() # ##################################################### # Triangulation # ##################################################### def triangulate_node_hierarchy(node): node_attribute = node.GetNodeAttribute(); if node_attribute: if node_attribute.GetAttributeType() == FbxNodeAttribute.eMesh or \ node_attribute.GetAttributeType() == FbxNodeAttribute.eNurbs or \ node_attribute.GetAttributeType() == FbxNodeAttribute.eNurbsSurface or \ node_attribute.GetAttributeType() == FbxNodeAttribute.ePatch: converter.TriangulateInPlace(node); child_count = node.GetChildCount() for i in range(child_count): triangulate_node_hierarchy(node.GetChild(i)) def triangulate_scene(scene): node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): triangulate_node_hierarchy(node.GetChild(i)) # ##################################################### # Generate Material Object # ##################################################### def generate_texture_bindings(material_property, material_params): # FBX to Three.js texture types binding_types = { "DiffuseColor": "map", "DiffuseFactor": "diffuseFactor", "EmissiveColor": "emissiveMap", "EmissiveFactor": "emissiveFactor", "AmbientColor": "lightMap", # "ambientMap", "AmbientFactor": "ambientFactor", "SpecularColor": "specularMap", "SpecularFactor": "specularFactor", "ShininessExponent": "shininessExponent", "NormalMap": "normalMap", "Bump": "bumpMap", "TransparentColor": "transparentMap", "TransparencyFactor": "transparentFactor", "ReflectionColor": "reflectionMap", "ReflectionFactor": "reflectionFactor", "DisplacementColor": "displacementMap", "VectorDisplacementColor": "vectorDisplacementMap" } if material_property.IsValid(): #Here we have to check if it's layeredtextures, or just textures: layered_texture_count = material_property.GetSrcObjectCount(FbxLayeredTexture.ClassId) if layered_texture_count > 0: for j in range(layered_texture_count): layered_texture = material_property.GetSrcObject(FbxLayeredTexture.ClassId, j) texture_count = layered_texture.GetSrcObjectCount(FbxTexture.ClassId) for k in range(texture_count): texture = layered_texture.GetSrcObject(FbxTexture.ClassId,k) if texture: texture_id = getTextureName(texture, True) material_params[binding_types[str(material_property.GetName())]] = texture_id else: # no layered texture simply get on the property texture_count = material_property.GetSrcObjectCount(FbxTexture.ClassId) for j in range(texture_count): texture = material_property.GetSrcObject(FbxTexture.ClassId,j) if texture: texture_id = getTextureName(texture, True) material_params[binding_types[str(material_property.GetName())]] = texture_id def generate_material_object(material): #Get the implementation to see if it's a hardware shader. implementation = GetImplementation(material, "ImplementationHLSL") implementation_type = "HLSL" if not implementation: implementation = GetImplementation(material, "ImplementationCGFX") implementation_type = "CGFX" output = None material_params = None material_type = None if implementation: print("Shader materials are not supported") elif material.GetClassId().Is(FbxSurfaceLambert.ClassId): ambient = getHex(material.Ambient.Get()) diffuse = getHex(material.Diffuse.Get()) emissive = getHex(material.Emissive.Get()) opacity = 1.0 - material.TransparencyFactor.Get() opacity = 1.0 if opacity == 0 else opacity opacity = opacity transparent = False reflectivity = 1 material_type = 'MeshBasicMaterial' # material_type = 'MeshLambertMaterial' material_params = { 'color' : diffuse, 'ambient' : ambient, 'emissive' : emissive, 'reflectivity' : reflectivity, 'transparent' : transparent, 'opacity' : opacity } elif material.GetClassId().Is(FbxSurfacePhong.ClassId): ambient = getHex(material.Ambient.Get()) diffuse = getHex(material.Diffuse.Get()) emissive = getHex(material.Emissive.Get()) specular = getHex(material.Specular.Get()) opacity = 1.0 - material.TransparencyFactor.Get() opacity = 1.0 if opacity == 0 else opacity opacity = opacity shininess = material.Shininess.Get() transparent = False reflectivity = 1 bumpScale = 1 material_type = 'MeshPhongMaterial' material_params = { 'color' : diffuse, 'ambient' : ambient, 'emissive' : emissive, 'specular' : specular, 'shininess' : shininess, 'bumpScale' : bumpScale, 'reflectivity' : reflectivity, 'transparent' : transparent, 'opacity' : opacity } else: print "Unknown type of Material", getMaterialName(material) # default to Lambert Material if the current Material type cannot be handeled if not material_type: ambient = getHex((0,0,0)) diffuse = getHex((0.5,0.5,0.5)) emissive = getHex((0,0,0)) opacity = 1 transparent = False reflectivity = 1 material_type = 'MeshLambertMaterial' material_params = { 'color' : diffuse, 'ambient' : ambient, 'emissive' : emissive, 'reflectivity' : reflectivity, 'transparent' : transparent, 'opacity' : opacity } if option_textures: texture_count = FbxLayerElement.sTypeTextureCount() for texture_index in range(texture_count): material_property = material.FindProperty(FbxLayerElement.sTextureChannelNames(texture_index)) generate_texture_bindings(material_property, material_params) material_params['wireframe'] = False material_params['wireframeLinewidth'] = 1 output = { 'type' : material_type, 'parameters' : material_params } return output def generate_proxy_material_object(node, material_names): material_type = 'MeshFaceMaterial' material_params = { 'materials' : material_names } output = { 'type' : material_type, 'parameters' : material_params } return output # ##################################################### # Find Scene Materials # ##################################################### def extract_materials_from_node(node, material_dict): name = node.GetName() mesh = node.GetNodeAttribute() node = None if mesh: node = mesh.GetNode() if node: material_count = node.GetMaterialCount() material_names = [] for l in range(mesh.GetLayerCount()): materials = mesh.GetLayer(l).GetMaterials() if materials: if materials.GetReferenceMode() == FbxLayerElement.eIndex: #Materials are in an undefined external table continue for i in range(material_count): material = node.GetMaterial(i) material_names.append(getMaterialName(material)) if material_count > 1: proxy_material = generate_proxy_material_object(node, material_names) proxy_name = getMaterialName(node, True) material_dict[proxy_name] = proxy_material def generate_materials_from_hierarchy(node, material_dict): if node.GetNodeAttribute() == None: pass else: attribute_type = (node.GetNodeAttribute().GetAttributeType()) if attribute_type == FbxNodeAttribute.eMesh: extract_materials_from_node(node, material_dict) for i in range(node.GetChildCount()): generate_materials_from_hierarchy(node.GetChild(i), material_dict) def generate_material_dict(scene): material_dict = {} # generate all materials for this scene material_count = scene.GetSrcObjectCount(FbxSurfaceMaterial.ClassId) for i in range(material_count): material = scene.GetSrcObject(FbxSurfaceMaterial.ClassId, i) material_object = generate_material_object(material) material_name = getMaterialName(material) material_dict[material_name] = material_object # generate material porxies # Three.js does not support meshs with multiple materials, however it does # support materials with multiple submaterials node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): generate_materials_from_hierarchy(node.GetChild(i), material_dict) return material_dict # ##################################################### # Generate Texture Object # ##################################################### def generate_texture_object(texture): #TODO: extract more texture properties wrap_u = texture.GetWrapModeU() wrap_v = texture.GetWrapModeV() offset = texture.GetUVTranslation() if type(texture) is FbxFileTexture: url = texture.GetFileName() else: url = getTextureName( texture ) #url = replace_inFolder2OutFolder( url ) #print( url ) index = url.rfind( '/' ) if index == -1: index = url.rfind( '\\' ) filename = url[ index+1 : len(url) ] output = { 'url': filename, 'fullpath': url, 'repeat': serializeVector2( (1,1) ), 'offset': serializeVector2( texture.GetUVTranslation() ), 'magFilter': 'LinearFilter', 'minFilter': 'LinearMipMapLinearFilter', 'anisotropy': True } return output # ##################################################### # Replace Texture input path to output # ##################################################### def replace_inFolder2OutFolder(url): folderIndex = url.find(inputFolder) if folderIndex != -1: url = url[ folderIndex+len(inputFolder): ] url = outputFolder + url return url # ##################################################### # Replace Texture output path to input # ##################################################### def replace_OutFolder2inFolder(url): folderIndex = url.find(outputFolder) if folderIndex != -1: url = url[ folderIndex+len(outputFolder): ] url = inputFolder + url return url # ##################################################### # Find Scene Textures # ##################################################### def extract_material_textures(material_property, texture_dict): if material_property.IsValid(): #Here we have to check if it's layeredtextures, or just textures: layered_texture_count = material_property.GetSrcObjectCount(FbxLayeredTexture.ClassId) if layered_texture_count > 0: for j in range(layered_texture_count): layered_texture = material_property.GetSrcObject(FbxLayeredTexture.ClassId, j) texture_count = layered_texture.GetSrcObjectCount(FbxTexture.ClassId) for k in range(texture_count): texture = layered_texture.GetSrcObject(FbxTexture.ClassId,k) if texture: texture_object = generate_texture_object(texture) texture_name = getTextureName( texture, True ) texture_dict[texture_name] = texture_object else: # no layered texture simply get on the property texture_count = material_property.GetSrcObjectCount(FbxTexture.ClassId) for j in range(texture_count): texture = material_property.GetSrcObject(FbxTexture.ClassId,j) if texture: texture_object = generate_texture_object(texture) texture_name = getTextureName( texture, True ) texture_dict[texture_name] = texture_object def extract_textures_from_node(node, texture_dict): name = node.GetName() mesh = node.GetNodeAttribute() #for all materials attached to this mesh material_count = mesh.GetNode().GetSrcObjectCount(FbxSurfaceMaterial.ClassId) for material_index in range(material_count): material = mesh.GetNode().GetSrcObject(FbxSurfaceMaterial.ClassId, material_index) #go through all the possible textures types if material: texture_count = FbxLayerElement.sTypeTextureCount() for texture_index in range(texture_count): material_property = material.FindProperty(FbxLayerElement.sTextureChannelNames(texture_index)) extract_material_textures(material_property, texture_dict) def generate_textures_from_hierarchy(node, texture_dict): if node.GetNodeAttribute() == None: pass else: attribute_type = (node.GetNodeAttribute().GetAttributeType()) if attribute_type == FbxNodeAttribute.eMesh: extract_textures_from_node(node, texture_dict) for i in range(node.GetChildCount()): generate_textures_from_hierarchy(node.GetChild(i), texture_dict) def generate_texture_dict(scene): if not option_textures: return {} texture_dict = {} node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): generate_textures_from_hierarchy(node.GetChild(i), texture_dict) return texture_dict # ##################################################### # Extract Fbx SDK Mesh Data # ##################################################### def extract_fbx_vertex_positions(mesh): control_points_count = mesh.GetControlPointsCount() control_points = mesh.GetControlPoints() positions = [] for i in range(control_points_count): tmp = control_points[i] tmp = [tmp[0], tmp[1], tmp[2]] positions.append(tmp) node = mesh.GetNode() if node: t = node.GeometricTranslation.Get() t = FbxVector4(t[0], t[1], t[2], 1) r = node.GeometricRotation.Get() r = FbxVector4(r[0], r[1], r[2], 1) s = node.GeometricScaling.Get() s = FbxVector4(s[0], s[1], s[2], 1) hasGeometricTransform = False if t[0] != 0 or t[1] != 0 or t[2] != 0 or \ r[0] != 0 or r[1] != 0 or r[2] != 0 or \ s[0] != 1 or s[1] != 1 or s[2] != 1: hasGeometricTransform = True if hasGeometricTransform: geo_transform = FbxMatrix(t,r,s) else: geo_transform = FbxMatrix() transform = None if option_geometry: # FbxMeshes are local to their node, we need the vertices in global space # when scene nodes are not exported transform = node.EvaluateGlobalTransform() transform = FbxMatrix(transform) * geo_transform elif hasGeometricTransform: transform = geo_transform if transform: for i in range(len(positions)): v = positions[i] position = FbxVector4(v[0], v[1], v[2]) position = transform.MultNormalize(position) positions[i] = [position[0], position[1], position[2]] return positions def extract_fbx_vertex_normals(mesh): # eNone The mapping is undetermined. # eByControlPoint There will be one mapping coordinate for each surface control point/vertex. # eByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. # eByPolygon There can be only one mapping coordinate for the whole polygon. # eByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. # eAllSame There can be only one mapping coordinate for the whole surface. layered_normal_indices = [] layered_normal_values = [] poly_count = mesh.GetPolygonCount() control_points = mesh.GetControlPoints() for l in range(mesh.GetLayerCount()): mesh_normals = mesh.GetLayer(l).GetNormals() if not mesh_normals: continue normals_array = mesh_normals.GetDirectArray() normals_count = normals_array.GetCount() if normals_count == 0: continue normal_indices = [] normal_values = [] # values for i in range(normals_count): normal = normals_array.GetAt(i) normal = [normal[0], normal[1], normal[2]] normal_values.append(normal) node = mesh.GetNode() if node: t = node.GeometricTranslation.Get() t = FbxVector4(t[0], t[1], t[2], 1) r = node.GeometricRotation.Get() r = FbxVector4(r[0], r[1], r[2], 1) s = node.GeometricScaling.Get() s = FbxVector4(s[0], s[1], s[2], 1) hasGeometricTransform = False if t[0] != 0 or t[1] != 0 or t[2] != 0 or \ r[0] != 0 or r[1] != 0 or r[2] != 0 or \ s[0] != 1 or s[1] != 1 or s[2] != 1: hasGeometricTransform = True if hasGeometricTransform: geo_transform = FbxMatrix(t,r,s) else: geo_transform = FbxMatrix() transform = None if option_geometry: # FbxMeshes are local to their node, we need the vertices in global space # when scene nodes are not exported transform = node.EvaluateGlobalTransform() transform = FbxMatrix(transform) * geo_transform elif hasGeometricTransform: transform = geo_transform if transform: t = FbxVector4(0,0,0,1) transform.SetRow(3, t) for i in range(len(normal_values)): n = normal_values[i] normal = FbxVector4(n[0], n[1], n[2]) normal = transform.MultNormalize(normal) normal.Normalize() normal = [normal[0], normal[1], normal[2]] normal_values[i] = normal # indices vertexId = 0 for p in range(poly_count): poly_size = mesh.GetPolygonSize(p) poly_normals = [] for v in range(poly_size): control_point_index = mesh.GetPolygonVertex(p, v) # mapping mode is by control points. The mesh should be smooth and soft. # we can get normals by retrieving each control point if mesh_normals.GetMappingMode() == FbxLayerElement.eByControlPoint: # reference mode is direct, the normal index is same as vertex index. # get normals by the index of control vertex if mesh_normals.GetReferenceMode() == FbxLayerElement.eDirect: poly_normals.append(control_point_index) elif mesh_normals.GetReferenceMode() == FbxLayerElement.eIndexToDirect: index = mesh_normals.GetIndexArray().GetAt(control_point_index) poly_normals.append(index) # mapping mode is by polygon-vertex. # we can get normals by retrieving polygon-vertex. elif mesh_normals.GetMappingMode() == FbxLayerElement.eByPolygonVertex: if mesh_normals.GetReferenceMode() == FbxLayerElement.eDirect: poly_normals.append(vertexId) elif mesh_normals.GetReferenceMode() == FbxLayerElement.eIndexToDirect: index = mesh_normals.GetIndexArray().GetAt(vertexId) poly_normals.append(index) elif mesh_normals.GetMappingMode() == FbxLayerElement.eByPolygon or \ mesh_normals.GetMappingMode() == FbxLayerElement.eAllSame or \ mesh_normals.GetMappingMode() == FbxLayerElement.eNone: print("unsupported normal mapping mode for polygon vertex") vertexId += 1 normal_indices.append(poly_normals) layered_normal_values.append(normal_values) layered_normal_indices.append(normal_indices) normal_values = [] normal_indices = [] # Three.js only supports one layer of normals if len(layered_normal_values) > 0: normal_values = layered_normal_values[0] normal_indices = layered_normal_indices[0] return normal_values, normal_indices def extract_fbx_vertex_colors(mesh): # eNone The mapping is undetermined. # eByControlPoint There will be one mapping coordinate for each surface control point/vertex. # eByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. # eByPolygon There can be only one mapping coordinate for the whole polygon. # eByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. # eAllSame There can be only one mapping coordinate for the whole surface. layered_color_indices = [] layered_color_values = [] poly_count = mesh.GetPolygonCount() control_points = mesh.GetControlPoints() for l in range(mesh.GetLayerCount()): mesh_colors = mesh.GetLayer(l).GetVertexColors() if not mesh_colors: continue colors_array = mesh_colors.GetDirectArray() colors_count = colors_array.GetCount() if colors_count == 0: continue color_indices = [] color_values = [] # values for i in range(colors_count): color = colors_array.GetAt(i) color = [color.mRed, color.mGreen, color.mBlue, color.mAlpha] color_values.append(color) # indices vertexId = 0 for p in range(poly_count): poly_size = mesh.GetPolygonSize(p) poly_colors = [] for v in range(poly_size): control_point_index = mesh.GetPolygonVertex(p, v) if mesh_colors.GetMappingMode() == FbxLayerElement.eByControlPoint: if mesh_colors.GetReferenceMode() == FbxLayerElement.eDirect: poly_colors.append(control_point_index) elif mesh_colors.GetReferenceMode() == FbxLayerElement.eIndexToDirect: index = mesh_colors.GetIndexArray().GetAt(control_point_index) poly_colors.append(index) elif mesh_colors.GetMappingMode() == FbxLayerElement.eByPolygonVertex: if mesh_colors.GetReferenceMode() == FbxLayerElement.eDirect: poly_colors.append(vertexId) elif mesh_colors.GetReferenceMode() == FbxLayerElement.eIndexToDirect: index = mesh_colors.GetIndexArray().GetAt(vertexId) poly_colors.append(index) elif mesh_colors.GetMappingMode() == FbxLayerElement.eByPolygon or \ mesh_colors.GetMappingMode() == FbxLayerElement.eAllSame or \ mesh_colors.GetMappingMode() == FbxLayerElement.eNone: print("unsupported color mapping mode for polygon vertex") vertexId += 1 color_indices.append(poly_colors) layered_color_indices.append( color_indices ) layered_color_values.append( color_values ) color_values = [] color_indices = [] # Three.js only supports one layer of colors if len(layered_color_values) > 0: color_values = layered_color_values[0] color_indices = layered_color_indices[0] ''' # The Fbx SDK defaults mesh.Color to (0.8, 0.8, 0.8) # This causes most models to receive incorrect vertex colors if len(color_values) == 0: color = mesh.Color.Get() color_values = [[color[0], color[1], color[2]]] color_indices = [] for p in range(poly_count): poly_size = mesh.GetPolygonSize(p) color_indices.append([0] * poly_size) ''' return color_values, color_indices def extract_fbx_vertex_uvs(mesh): # eNone The mapping is undetermined. # eByControlPoint There will be one mapping coordinate for each surface control point/vertex. # eByPolygonVertex There will be one mapping coordinate for each vertex, for every polygon of which it is a part. This means that a vertex will have as many mapping coordinates as polygons of which it is a part. # eByPolygon There can be only one mapping coordinate for the whole polygon. # eByEdge There will be one mapping coordinate for each unique edge in the mesh. This is meant to be used with smoothing layer elements. # eAllSame There can be only one mapping coordinate for the whole surface. layered_uv_indices = [] layered_uv_values = [] poly_count = mesh.GetPolygonCount() control_points = mesh.GetControlPoints() for l in range(mesh.GetLayerCount()): mesh_uvs = mesh.GetLayer(l).GetUVs() if not mesh_uvs: continue uvs_array = mesh_uvs.GetDirectArray() uvs_count = uvs_array.GetCount() if uvs_count == 0: continue uv_indices = [] uv_values = [] # values for i in range(uvs_count): uv = uvs_array.GetAt(i) uv = [uv[0], uv[1]] uv_values.append(uv) # indices vertexId = 0 for p in range(poly_count): poly_size = mesh.GetPolygonSize(p) poly_uvs = [] for v in range(poly_size): control_point_index = mesh.GetPolygonVertex(p, v) if mesh_uvs.GetMappingMode() == FbxLayerElement.eByControlPoint: if mesh_uvs.GetReferenceMode() == FbxLayerElement.eDirect: poly_uvs.append(control_point_index) elif mesh_uvs.GetReferenceMode() == FbxLayerElement.eIndexToDirect: index = mesh_uvs.GetIndexArray().GetAt(control_point_index) poly_uvs.append(index) elif mesh_uvs.GetMappingMode() == FbxLayerElement.eByPolygonVertex: uv_texture_index = mesh_uvs.GetIndexArray().GetAt(vertexId) if mesh_uvs.GetReferenceMode() == FbxLayerElement.eDirect or \ mesh_uvs.GetReferenceMode() == FbxLayerElement.eIndexToDirect: poly_uvs.append(uv_texture_index) elif mesh_uvs.GetMappingMode() == FbxLayerElement.eByPolygon or \ mesh_uvs.GetMappingMode() == FbxLayerElement.eAllSame or \ mesh_uvs.GetMappingMode() == FbxLayerElement.eNone: print("unsupported uv mapping mode for polygon vertex") vertexId += 1 uv_indices.append(poly_uvs) layered_uv_values.append(uv_values) layered_uv_indices.append(uv_indices) return layered_uv_values, layered_uv_indices # ##################################################### # Process Mesh Geometry # ##################################################### def generate_normal_key(normal): return (round(normal[0], 6), round(normal[1], 6), round(normal[2], 6)) def generate_color_key(color): return getHex(color) def generate_uv_key(uv): return (round(uv[0], 6), round(uv[1], 6)) def append_non_duplicate_uvs(source_uvs, dest_uvs, counts): source_layer_count = len(source_uvs) for layer_index in range(source_layer_count): dest_layer_count = len(dest_uvs) if dest_layer_count <= layer_index: dest_uv_layer = {} count = 0 dest_uvs.append(dest_uv_layer) counts.append(count) else: dest_uv_layer = dest_uvs[layer_index] count = counts[layer_index] source_uv_layer = source_uvs[layer_index] for uv in source_uv_layer: key = generate_uv_key(uv) if key not in dest_uv_layer: dest_uv_layer[key] = count count += 1 counts[layer_index] = count return counts def generate_unique_normals_dictionary(mesh_list): normals_dictionary = {} nnormals = 0 # Merge meshes, remove duplicate data for mesh in mesh_list: node = mesh.GetNode() normal_values, normal_indices = extract_fbx_vertex_normals(mesh) if len(normal_values) > 0: for normal in normal_values: key = generate_normal_key(normal) if key not in normals_dictionary: normals_dictionary[key] = nnormals nnormals += 1 return normals_dictionary def generate_unique_colors_dictionary(mesh_list): colors_dictionary = {} ncolors = 0 # Merge meshes, remove duplicate data for mesh in mesh_list: color_values, color_indices = extract_fbx_vertex_colors(mesh) if len(color_values) > 0: for color in color_values: key = generate_color_key(color) if key not in colors_dictionary: colors_dictionary[key] = ncolors ncolors += 1 return colors_dictionary def generate_unique_uvs_dictionary_layers(mesh_list): uvs_dictionary_layers = [] nuvs_list = [] # Merge meshes, remove duplicate data for mesh in mesh_list: uv_values, uv_indices = extract_fbx_vertex_uvs(mesh) if len(uv_values) > 0: nuvs_list = append_non_duplicate_uvs(uv_values, uvs_dictionary_layers, nuvs_list) return uvs_dictionary_layers def generate_normals_from_dictionary(normals_dictionary): normal_values = [] for key, index in sorted(normals_dictionary.items(), key = operator.itemgetter(1)): normal_values.append(key) return normal_values def generate_colors_from_dictionary(colors_dictionary): color_values = [] for key, index in sorted(colors_dictionary.items(), key = operator.itemgetter(1)): color_values.append(key) return color_values def generate_uvs_from_dictionary_layers(uvs_dictionary_layers): uv_values = [] for uvs_dictionary in uvs_dictionary_layers: uv_values_layer = [] for key, index in sorted(uvs_dictionary.items(), key = operator.itemgetter(1)): uv_values_layer.append(key) uv_values.append(uv_values_layer) return uv_values def generate_normal_indices_for_poly(poly_index, mesh_normal_values, mesh_normal_indices, normals_to_indices): if len(mesh_normal_indices) <= 0: return [] poly_normal_indices = mesh_normal_indices[poly_index] poly_size = len(poly_normal_indices) output_poly_normal_indices = [] for v in range(poly_size): normal_index = poly_normal_indices[v] normal_value = mesh_normal_values[normal_index] key = generate_normal_key(normal_value) output_index = normals_to_indices[key] output_poly_normal_indices.append(output_index) return output_poly_normal_indices def generate_color_indices_for_poly(poly_index, mesh_color_values, mesh_color_indices, colors_to_indices): if len(mesh_color_indices) <= 0: return [] poly_color_indices = mesh_color_indices[poly_index] poly_size = len(poly_color_indices) output_poly_color_indices = [] for v in range(poly_size): color_index = poly_color_indices[v] color_value = mesh_color_values[color_index] key = generate_color_key(color_value) output_index = colors_to_indices[key] output_poly_color_indices.append(output_index) return output_poly_color_indices def generate_uv_indices_for_poly(poly_index, mesh_uv_values, mesh_uv_indices, uvs_to_indices): if len(mesh_uv_indices) <= 0: return [] poly_uv_indices = mesh_uv_indices[poly_index] poly_size = len(poly_uv_indices) output_poly_uv_indices = [] for v in range(poly_size): uv_index = poly_uv_indices[v] uv_value = mesh_uv_values[uv_index] key = generate_uv_key(uv_value) output_index = uvs_to_indices[key] output_poly_uv_indices.append(output_index) return output_poly_uv_indices def process_mesh_vertices(mesh_list): vertex_offset = 0 vertex_offset_list = [0] vertices = [] for mesh in mesh_list: node = mesh.GetNode() mesh_vertices = extract_fbx_vertex_positions(mesh) vertices.extend(mesh_vertices[:]) vertex_offset += len(mesh_vertices) vertex_offset_list.append(vertex_offset) return vertices, vertex_offset_list def process_mesh_materials(mesh_list): material_offset = 0 material_offset_list = [0] materials_list = [] #TODO: remove duplicate mesh references for mesh in mesh_list: node = mesh.GetNode() material_count = node.GetMaterialCount() if material_count > 0: for l in range(mesh.GetLayerCount()): materials = mesh.GetLayer(l).GetMaterials() if materials: if materials.GetReferenceMode() == FbxLayerElement.eIndex: #Materials are in an undefined external table continue for i in range(material_count): material = node.GetMaterial(i) materials_list.append( material ) material_offset += material_count material_offset_list.append(material_offset) return materials_list, material_offset_list def process_mesh_polygons(mesh_list, normals_to_indices, colors_to_indices, uvs_to_indices_list, vertex_offset_list, material_offset_list): faces = [] for mesh_index in range(len(mesh_list)): mesh = mesh_list[mesh_index] flipWindingOrder = False node = mesh.GetNode() if node: local_scale = node.EvaluateLocalScaling() if local_scale[0] < 0 or local_scale[1] < 0 or local_scale[2] < 0: flipWindingOrder = True poly_count = mesh.GetPolygonCount() control_points = mesh.GetControlPoints() normal_values, normal_indices = extract_fbx_vertex_normals(mesh) color_values, color_indices = extract_fbx_vertex_colors(mesh) uv_values_layers, uv_indices_layers = extract_fbx_vertex_uvs(mesh) for poly_index in range(poly_count): poly_size = mesh.GetPolygonSize(poly_index) face_normals = generate_normal_indices_for_poly(poly_index, normal_values, normal_indices, normals_to_indices) face_colors = generate_color_indices_for_poly(poly_index, color_values, color_indices, colors_to_indices) face_uv_layers = [] for l in range(len(uv_indices_layers)): uv_values = uv_values_layers[l] uv_indices = uv_indices_layers[l] face_uv_indices = generate_uv_indices_for_poly(poly_index, uv_values, uv_indices, uvs_to_indices_list[l]) face_uv_layers.append(face_uv_indices) face_vertices = [] for vertex_index in range(poly_size): control_point_index = mesh.GetPolygonVertex(poly_index, vertex_index) face_vertices.append(control_point_index) #TODO: assign a default material to any mesh without one if len(material_offset_list) <= mesh_index: material_offset = 0 else: material_offset = material_offset_list[mesh_index] vertex_offset = vertex_offset_list[mesh_index] if poly_size > 4: new_face_normals = [] new_face_colors = [] new_face_uv_layers = [] for i in range(poly_size - 2): new_face_vertices = [face_vertices[0], face_vertices[i+1], face_vertices[i+2]] if len(face_normals): new_face_normals = [face_normals[0], face_normals[i+1], face_normals[i+2]] if len(face_colors): new_face_colors = [face_colors[0], face_colors[i+1], face_colors[i+2]] if len(face_uv_layers): new_face_uv_layers = [] for layer in face_uv_layers: new_face_uv_layers.append([layer[0], layer[i+1], layer[i+2]]) face = generate_mesh_face(mesh, poly_index, new_face_vertices, new_face_normals, new_face_colors, new_face_uv_layers, vertex_offset, material_offset, flipWindingOrder) faces.append(face) else: face = generate_mesh_face(mesh, poly_index, face_vertices, face_normals, face_colors, face_uv_layers, vertex_offset, material_offset, flipWindingOrder) faces.append(face) return faces def generate_mesh_face(mesh, polygon_index, vertex_indices, normals, colors, uv_layers, vertex_offset, material_offset, flipOrder): isTriangle = ( len(vertex_indices) == 3 ) nVertices = 3 if isTriangle else 4 hasMaterial = False for l in range(mesh.GetLayerCount()): materials = mesh.GetLayer(l).GetMaterials() if materials: hasMaterial = True break hasFaceUvs = False hasFaceVertexUvs = len(uv_layers) > 0 hasFaceNormals = False hasFaceVertexNormals = len(normals) > 0 hasFaceColors = False hasFaceVertexColors = len(colors) > 0 faceType = 0 faceType = setBit(faceType, 0, not isTriangle) faceType = setBit(faceType, 1, hasMaterial) faceType = setBit(faceType, 2, hasFaceUvs) faceType = setBit(faceType, 3, hasFaceVertexUvs) faceType = setBit(faceType, 4, hasFaceNormals) faceType = setBit(faceType, 5, hasFaceVertexNormals) faceType = setBit(faceType, 6, hasFaceColors) faceType = setBit(faceType, 7, hasFaceVertexColors) faceData = [] # order is important, must match order in JSONLoader # face type # vertex indices # material index # face uvs index # face vertex uvs indices # face color index # face vertex colors indices faceData.append(faceType) if flipOrder: if nVertices == 3: vertex_indices = [vertex_indices[0], vertex_indices[2], vertex_indices[1]] if hasFaceVertexNormals: normals = [normals[0], normals[2], normals[1]] if hasFaceVertexColors: colors = [colors[0], colors[2], colors[1]] if hasFaceVertexUvs: tmp = [] for polygon_uvs in uv_layers: tmp.append([polygon_uvs[0], polygon_uvs[2], polygon_uvs[1]]) uv_layers = tmp else: vertex_indices = [vertex_indices[0], vertex_indices[3], vertex_indices[2], vertex_indices[1]] if hasFaceVertexNormals: normals = [normals[0], normals[3], normals[2], normals[1]] if hasFaceVertexColors: colors = [colors[0], colors[3], colors[2], colors[1]] if hasFaceVertexUvs: tmp = [] for polygon_uvs in uv_layers: tmp.append([polygon_uvs[0], polygon_uvs[3], polygon_uvs[2], polygon_uvs[3]]) uv_layers = tmp for i in range(nVertices): index = vertex_indices[i] + vertex_offset faceData.append(index) if hasMaterial: material_id = 0 for l in range(mesh.GetLayerCount()): materials = mesh.GetLayer(l).GetMaterials() if materials: material_id = materials.GetIndexArray().GetAt(polygon_index) break material_id += material_offset faceData.append( material_id ) if hasFaceVertexUvs: for polygon_uvs in uv_layers: for i in range(nVertices): index = polygon_uvs[i] faceData.append(index) if hasFaceVertexNormals: for i in range(nVertices): index = normals[i] faceData.append(index) if hasFaceVertexColors: for i in range(nVertices): index = colors[i] faceData.append(index) return faceData # ##################################################### # Generate Mesh Object (for scene output format) # ##################################################### def generate_scene_output(node): mesh = node.GetNodeAttribute() # This is done in order to keep the scene output and non-scene output code DRY mesh_list = [ mesh ] # Extract the mesh data into arrays vertices, vertex_offsets = process_mesh_vertices(mesh_list) materials, material_offsets = process_mesh_materials(mesh_list) normals_to_indices = generate_unique_normals_dictionary(mesh_list) colors_to_indices = generate_unique_colors_dictionary(mesh_list) uvs_to_indices_list = generate_unique_uvs_dictionary_layers(mesh_list) normal_values = generate_normals_from_dictionary(normals_to_indices) color_values = generate_colors_from_dictionary(colors_to_indices) uv_values = generate_uvs_from_dictionary_layers(uvs_to_indices_list) # Generate mesh faces for the Three.js file format faces = process_mesh_polygons(mesh_list, normals_to_indices, colors_to_indices, uvs_to_indices_list, vertex_offsets, material_offsets) # Generate counts for uvs, vertices, normals, colors, and faces nuvs = [] for layer_index, uvs in enumerate(uv_values): nuvs.append(str(len(uvs))) nvertices = len(vertices) nnormals = len(normal_values) ncolors = len(color_values) nfaces = len(faces) # Flatten the arrays, currently they are in the form of [[0, 1, 2], [3, 4, 5], ...] vertices = [val for v in vertices for val in v] normal_values = [val for n in normal_values for val in n] color_values = [c for c in color_values] faces = [val for f in faces for val in f] uv_values = generate_uvs(uv_values) # Disable automatic json indenting when pretty printing for the arrays if option_pretty_print: nuvs = NoIndent(nuvs) vertices = ChunkedIndent(vertices, 15, True) normal_values = ChunkedIndent(normal_values, 15, True) color_values = ChunkedIndent(color_values, 15) faces = ChunkedIndent(faces, 30) metadata = { 'vertices' : nvertices, 'normals' : nnormals, 'colors' : ncolors, 'faces' : nfaces, 'uvs' : nuvs } output = { 'scale' : 1, 'materials' : [], 'vertices' : vertices, 'normals' : [] if nnormals <= 0 else normal_values, 'colors' : [] if ncolors <= 0 else color_values, 'uvs' : uv_values, 'faces' : faces } if option_pretty_print: output['0metadata'] = metadata else: output['metadata'] = metadata return output # ##################################################### # Generate Mesh Object (for non-scene output) # ##################################################### def generate_non_scene_output(scene): mesh_list = generate_mesh_list(scene) # Extract the mesh data into arrays vertices, vertex_offsets = process_mesh_vertices(mesh_list) materials, material_offsets = process_mesh_materials(mesh_list) normals_to_indices = generate_unique_normals_dictionary(mesh_list) colors_to_indices = generate_unique_colors_dictionary(mesh_list) uvs_to_indices_list = generate_unique_uvs_dictionary_layers(mesh_list) normal_values = generate_normals_from_dictionary(normals_to_indices) color_values = generate_colors_from_dictionary(colors_to_indices) uv_values = generate_uvs_from_dictionary_layers(uvs_to_indices_list) # Generate mesh faces for the Three.js file format faces = process_mesh_polygons(mesh_list, normals_to_indices, colors_to_indices, uvs_to_indices_list, vertex_offsets, material_offsets) # Generate counts for uvs, vertices, normals, colors, and faces nuvs = [] for layer_index, uvs in enumerate(uv_values): nuvs.append(str(len(uvs))) nvertices = len(vertices) nnormals = len(normal_values) ncolors = len(color_values) nfaces = len(faces) # Flatten the arrays, currently they are in the form of [[0, 1, 2], [3, 4, 5], ...] vertices = [val for v in vertices for val in v] normal_values = [val for n in normal_values for val in n] color_values = [c for c in color_values] faces = [val for f in faces for val in f] uv_values = generate_uvs(uv_values) # Disable json indenting when pretty printing for the arrays if option_pretty_print: nuvs = NoIndent(nuvs) vertices = NoIndent(vertices) normal_values = NoIndent(normal_values) color_values = NoIndent(color_values) faces = NoIndent(faces) metadata = { 'formatVersion' : 3, 'type' : 'geometry', 'generatedBy' : 'convert-to-threejs.py', 'vertices' : nvertices, 'normals' : nnormals, 'colors' : ncolors, 'faces' : nfaces, 'uvs' : nuvs } output = { 'scale' : 1, 'materials' : [], 'vertices' : vertices, 'normals' : [] if nnormals <= 0 else normal_values, 'colors' : [] if ncolors <= 0 else color_values, 'uvs' : uv_values, 'faces' : faces } if option_pretty_print: output['0metadata'] = metadata else: output['metadata'] = metadata return output def generate_mesh_list_from_hierarchy(node, mesh_list): if node.GetNodeAttribute() == None: pass else: attribute_type = (node.GetNodeAttribute().GetAttributeType()) if attribute_type == FbxNodeAttribute.eMesh or \ attribute_type == FbxNodeAttribute.eNurbs or \ attribute_type == FbxNodeAttribute.eNurbsSurface or \ attribute_type == FbxNodeAttribute.ePatch: if attribute_type != FbxNodeAttribute.eMesh: converter.TriangulateInPlace(node); mesh_list.append(node.GetNodeAttribute()) for i in range(node.GetChildCount()): generate_mesh_list_from_hierarchy(node.GetChild(i), mesh_list) def generate_mesh_list(scene): mesh_list = [] node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): generate_mesh_list_from_hierarchy(node.GetChild(i), mesh_list) return mesh_list # ##################################################### # Generate Embed Objects # ##################################################### def generate_embed_dict_from_hierarchy(node, embed_dict): if node.GetNodeAttribute() == None: pass else: attribute_type = (node.GetNodeAttribute().GetAttributeType()) if attribute_type == FbxNodeAttribute.eMesh or \ attribute_type == FbxNodeAttribute.eNurbs or \ attribute_type == FbxNodeAttribute.eNurbsSurface or \ attribute_type == FbxNodeAttribute.ePatch: if attribute_type != FbxNodeAttribute.eMesh: converter.TriangulateInPlace(node); embed_object = generate_scene_output(node) embed_name = getPrefixedName(node, 'Embed') embed_dict[embed_name] = embed_object for i in range(node.GetChildCount()): generate_embed_dict_from_hierarchy(node.GetChild(i), embed_dict) def generate_embed_dict(scene): embed_dict = {} node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): generate_embed_dict_from_hierarchy(node.GetChild(i), embed_dict) return embed_dict # ##################################################### # Generate Geometry Objects # ##################################################### def generate_geometry_object(node): output = { 'type' : 'embedded', 'id' : getPrefixedName( node, 'Embed' ) } return output def generate_geometry_dict_from_hierarchy(node, geometry_dict): if node.GetNodeAttribute() == None: pass else: attribute_type = (node.GetNodeAttribute().GetAttributeType()) if attribute_type == FbxNodeAttribute.eMesh: geometry_object = generate_geometry_object(node) geometry_name = getPrefixedName( node, 'Geometry' ) geometry_dict[geometry_name] = geometry_object for i in range(node.GetChildCount()): generate_geometry_dict_from_hierarchy(node.GetChild(i), geometry_dict) def generate_geometry_dict(scene): geometry_dict = {} node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): generate_geometry_dict_from_hierarchy(node.GetChild(i), geometry_dict) return geometry_dict # ##################################################### # Generate Light Node Objects # ##################################################### def generate_default_light(): direction = (1,1,1) color = (1,1,1) intensity = 80.0 output = { 'type': 'DirectionalLight', 'color': getHex(color), 'intensity': intensity/100.00, 'direction': serializeVector3( direction ), 'target': getObjectName( None ) } return output def generate_light_object(node): light = node.GetNodeAttribute() light_types = ["point", "directional", "spot", "area", "volume"] light_type = light_types[light.LightType.Get()] transform = node.EvaluateLocalTransform() position = transform.GetT() output = None if light_type == "directional": # Three.js directional lights emit light from a point in 3d space to a target node or the origin. # When there is no target, we need to take a point, one unit away from the origin, and move it # into the right location so that the origin acts like the target if node.GetTarget(): direction = position else: translation = FbxVector4(0,0,0,0) scale = FbxVector4(1,1,1,1) rotation = transform.GetR() matrix = FbxMatrix(translation, rotation, scale) direction = matrix.MultNormalize(FbxVector4(0,1,0,1)) output = { 'type': 'DirectionalLight', 'color': getHex(light.Color.Get()), 'intensity': light.Intensity.Get()/100.0, 'direction': serializeVector3( direction ), 'target': getObjectName( node.GetTarget() ) } elif light_type == "point": output = { 'type': 'PointLight', 'color': getHex(light.Color.Get()), 'intensity': light.Intensity.Get()/100.0, 'position': serializeVector3( position ), 'distance': light.FarAttenuationEnd.Get() } elif light_type == "spot": output = { 'type': 'SpotLight', 'color': getHex(light.Color.Get()), 'intensity': light.Intensity.Get()/100.0, 'position': serializeVector3( position ), 'distance': light.FarAttenuationEnd.Get(), 'angle': light.OuterAngle.Get()*math.pi/180, 'exponent': light.DecayType.Get(), 'target': getObjectName( node.GetTarget() ) } return output def generate_ambient_light(scene): scene_settings = scene.GetGlobalSettings() ambient_color = scene_settings.GetAmbientColor() ambient_color = (ambient_color.mRed, ambient_color.mGreen, ambient_color.mBlue) if ambient_color[0] == 0 and ambient_color[1] == 0 and ambient_color[2] == 0: return None output = { 'type': 'AmbientLight', 'color': getHex(ambient_color) } return output # ##################################################### # Generate Camera Node Objects # ##################################################### def generate_default_camera(): position = (100, 100, 100) near = 0.1 far = 1000 fov = 75 output = { 'type': 'PerspectiveCamera', 'fov': fov, 'near': near, 'far': far, 'position': serializeVector3( position ) } return output def generate_camera_object(node): camera = node.GetNodeAttribute() position = camera.Position.Get() projection_types = [ "perspective", "orthogonal" ] projection = projection_types[camera.ProjectionType.Get()] near = camera.NearPlane.Get() far = camera.FarPlane.Get() name = getObjectName( node ) output = {} if projection == "perspective": aspect = camera.PixelAspectRatio.Get() fov = camera.FieldOfView.Get() output = { 'type': 'PerspectiveCamera', 'fov': fov, 'aspect': aspect, 'near': near, 'far': far, 'position': serializeVector3( position ) } elif projection == "orthogonal": left = "" right = "" top = "" bottom = "" output = { 'type': 'PerspectiveCamera', 'left': left, 'right': right, 'top': top, 'bottom': bottom, 'near': near, 'far': far, 'position': serializeVector3( position ) } return output # ##################################################### # Generate Camera Names # ##################################################### def generate_camera_name_list_from_hierarchy(node, camera_list): if node.GetNodeAttribute() == None: pass else: attribute_type = (node.GetNodeAttribute().GetAttributeType()) if attribute_type == FbxNodeAttribute.eCamera: camera_string = getObjectName(node) camera_list.append(camera_string) for i in range(node.GetChildCount()): generate_camera_name_list_from_hierarchy(node.GetChild(i), camera_list) def generate_camera_name_list(scene): camera_list = [] node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): generate_camera_name_list_from_hierarchy(node.GetChild(i), camera_list) return camera_list # ##################################################### # Generate Mesh Node Object # ##################################################### def generate_mesh_object(node): mesh = node.GetNodeAttribute() transform = node.EvaluateLocalTransform() position = transform.GetT() scale = transform.GetS() rotation = getRadians(transform.GetR()) quaternion = transform.GetQ() material_count = node.GetMaterialCount() material_name = "" if material_count > 0: material_names = [] for l in range(mesh.GetLayerCount()): materials = mesh.GetLayer(l).GetMaterials() if materials: if materials.GetReferenceMode() == FbxLayerElement.eIndex: #Materials are in an undefined external table continue for i in range(material_count): material = node.GetMaterial(i) material_names.append( getMaterialName(material) ) if not material_count > 1 and not len(material_names) > 0: material_names.append('') #If this mesh has more than one material, use a proxy material material_name = getMaterialName( node, True) if material_count > 1 else material_names[0] output = { 'geometry': getPrefixedName( node, 'Geometry' ), 'material': material_name, 'position': serializeVector3( position ), 'quaternion': serializeVector4( quaternion ), 'scale': serializeVector3( scale ), 'visible': True, } return output # ##################################################### # Generate Node Object # ##################################################### def generate_object(node): node_types = ["Unknown", "Null", "Marker", "Skeleton", "Mesh", "Nurbs", "Patch", "Camera", "CameraStereo", "CameraSwitcher", "Light", "OpticalReference", "OpticalMarker", "NurbsCurve", "TrimNurbsSurface", "Boundary", "NurbsSurface", "Shape", "LODGroup", "SubDiv", "CachedEffect", "Line"] transform = node.EvaluateLocalTransform() position = transform.GetT() scale = transform.GetS() rotation = getRadians(transform.GetR()) quaternion = transform.GetQ() node_type = "" if node.GetNodeAttribute() == None: node_type = "Null" else: node_type = node_types[node.GetNodeAttribute().GetAttributeType()] name = getObjectName( node ) output = { 'fbx_type': node_type, 'position': serializeVector3( position ), 'quaternion': serializeVector4( quaternion ), 'scale': serializeVector3( scale ), 'visible': True } return output # ##################################################### # Parse Scene Node Objects # ##################################################### def generate_object_hierarchy(node, object_dict): object_count = 0 if node.GetNodeAttribute() == None: object_data = generate_object(node) else: attribute_type = (node.GetNodeAttribute().GetAttributeType()) if attribute_type == FbxNodeAttribute.eMesh: object_data = generate_mesh_object(node) elif attribute_type == FbxNodeAttribute.eLight: object_data = generate_light_object(node) elif attribute_type == FbxNodeAttribute.eCamera: object_data = generate_camera_object(node) else: object_data = generate_object(node) object_count += 1 object_name = getObjectName(node) object_children = {} for i in range(node.GetChildCount()): object_count += generate_object_hierarchy(node.GetChild(i), object_children) if node.GetChildCount() > 0: # Having 'children' above other attributes is hard to read. # We can send it to the bottom using the last letter of the alphabet 'z'. # This letter is removed from the final output. if option_pretty_print: object_data['zchildren'] = object_children else: object_data['children'] = object_children object_dict[object_name] = object_data return object_count def generate_scene_objects(scene): object_count = 0 object_dict = {} ambient_light = generate_ambient_light(scene) if ambient_light: object_dict['AmbientLight'] = ambient_light object_count += 1 if option_default_light: default_light = generate_default_light() object_dict['DefaultLight'] = default_light object_count += 1 if option_default_camera: default_camera = generate_default_camera() object_dict['DefaultCamera'] = default_camera object_count += 1 node = scene.GetRootNode() if node: for i in range(node.GetChildCount()): object_count += generate_object_hierarchy(node.GetChild(i), object_dict) return object_dict, object_count # ##################################################### # Generate Scene Output # ##################################################### def extract_scene(scene, filename): global_settings = scene.GetGlobalSettings() objects, nobjects = generate_scene_objects(scene) textures = generate_texture_dict(scene) materials = generate_material_dict(scene) geometries = generate_geometry_dict(scene) embeds = generate_embed_dict(scene) ntextures = len(textures) nmaterials = len(materials) ngeometries = len(geometries) position = serializeVector3( (0,0,0) ) rotation = serializeVector3( (0,0,0) ) scale = serializeVector3( (1,1,1) ) camera_names = generate_camera_name_list(scene) scene_settings = scene.GetGlobalSettings() # This does not seem to be any help here # global_settings.GetDefaultCamera() defcamera = camera_names[0] if len(camera_names) > 0 else "" if option_default_camera: defcamera = 'default_camera' metadata = { 'formatVersion': 3.2, 'type': 'scene', 'generatedBy': 'convert-to-threejs.py', 'objects': nobjects, 'geometries': ngeometries, 'materials': nmaterials, 'textures': ntextures } transform = { 'position' : position, 'rotation' : rotation, 'scale' : scale } defaults = { 'bgcolor' : 0, 'camera' : defcamera, 'fog' : '' } output = { 'objects': objects, 'geometries': geometries, 'materials': materials, 'textures': textures, 'embeds': embeds, 'transform': transform, 'defaults': defaults, } if option_pretty_print: output['0metadata'] = metadata else: output['metadata'] = metadata return output # ##################################################### # Generate Non-Scene Output # ##################################################### def extract_geometry(scene, filename): output = generate_non_scene_output(scene) return output # ##################################################### # File Helpers # ##################################################### def write_file(filepath, content): index = filepath.rfind('/') dir = filepath[0:index] #if not os.path.exists(dir): #os.makedirs(dir) out = open(filepath, "w") out.write(content.encode('utf8', 'replace')) out.close() def read_file(filepath): f = open(filepath) content = f.readlines() f.close() return content def copy_textures(textures): texture_dict = {} for key in textures: url = textures[key]['fullpath'] #src = replace_OutFolder2inFolder(url) #print( src ) #print( url ) if url in texture_dict: # texture has been copied continue if not os.path.exists(url): print("copy_texture error: we can't find this texture at " + url) continue try: index = url.rfind('/') if index == -1: index = url.rfind( '\\' ) filename = url[index+1:len(url)] saveFolder = "maps" saveFilename = saveFolder + "/" + filename #print( src ) #print( url ) #print( saveFilename ) if not os.path.exists(saveFolder): os.makedirs(saveFolder) shutil.copyfile(url, saveFilename) texture_dict[url] = True except IOError as e: print "I/O error({0}): {1} {2}".format(e.errno, e.strerror, url) def findFilesWithExt(directory, ext, include_path = True): ext = ext.lower() found = [] for root, dirs, files in os.walk(directory): for filename in files: current_ext = os.path.splitext(filename)[1].lower() if current_ext == ext: if include_path: found.append(os.path.join(root, filename)) else: found.append(filename) return found # ##################################################### # main # ##################################################### if __name__ == "__main__": from optparse import OptionParser try: from FbxCommon import * except ImportError: import platform msg = 'Could not locate the python FBX SDK!\n' msg += 'You need to copy the FBX SDK into your python install folder such as ' if platform.system() == 'Windows' or platform.system() == 'Microsoft': msg += '"Python26/Lib/site-packages"' elif platform.system() == 'Linux': msg += '"/usr/local/lib/python2.6/site-packages"' elif platform.system() == 'Darwin': msg += '"/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages"' msg += ' folder.' print(msg) sys.exit(1) usage = "Usage: %prog [source_file.fbx] [output_file.js] [options]" parser = OptionParser(usage=usage) parser.add_option('-t', '--triangulate', action='store_true', dest='triangulate', help="force quad geometry into triangles", default=False) parser.add_option('-x', '--ignore-textures', action='store_true', dest='notextures', help="don't include texture references in output file", default=False) parser.add_option('-n', '--no-texture-copy', action='store_true', dest='notexturecopy', help="don't copy texture files", default=False) parser.add_option('-u', '--force-prefix', action='store_true', dest='prefix', help="prefix all object names in output file to ensure uniqueness", default=False) parser.add_option('-f', '--flatten-scene', action='store_true', dest='geometry', help="merge all geometries and apply node transforms", default=False) parser.add_option('-y', '--force-y-up', action='store_true', dest='forceyup', help="ensure that the y axis shows up", default=False) parser.add_option('-c', '--add-camera', action='store_true', dest='defcamera', help="include default camera in output scene", default=False) parser.add_option('-l', '--add-light', action='store_true', dest='deflight', help="include default light in output scene", default=False) parser.add_option('-p', '--pretty-print', action='store_true', dest='pretty', help="prefix all object names in output file", default=False) (options, args) = parser.parse_args() option_triangulate = options.triangulate option_textures = True if not options.notextures else False option_copy_textures = True if not options.notexturecopy else False option_prefix = options.prefix option_geometry = options.geometry option_forced_y_up = options.forceyup option_default_camera = options.defcamera option_default_light = options.deflight option_pretty_print = options.pretty # Prepare the FBX SDK. sdk_manager, scene = InitializeSdkObjects() converter = FbxGeometryConverter(sdk_manager) # The converter takes an FBX file as an argument. if len(args) > 1: print("\nLoading file: %s" % args[0]) result = LoadScene(sdk_manager, scene, args[0]) else: result = False print("\nUsage: convert_fbx_to_threejs [source_file.fbx] [output_file.js]\n") if not result: print("\nAn error occurred while loading the file...") else: if option_triangulate: print("\nForcing geometry to triangles") triangulate_scene(scene) axis_system = FbxAxisSystem.MayaYUp if not option_forced_y_up: # According to asset's coordinate to convert scene upVector = scene.GetGlobalSettings().GetAxisSystem().GetUpVector(); if upVector[0] == 3: axis_system = FbxAxisSystem.MayaZUp axis_system.ConvertScene(scene) inputFolder = args[0].replace( "\\", "/" ); index = args[0].rfind( "/" ); inputFolder = inputFolder[:index] outputFolder = args[1].replace( "\\", "/" ); index = args[1].rfind( "/" ); outputFolder = outputFolder[:index] if option_geometry: output_content = extract_geometry(scene, os.path.basename(args[0])) else: output_content = extract_scene(scene, os.path.basename(args[0])) if option_pretty_print: output_string = json.dumps(output_content, indent=4, cls=CustomEncoder, separators=(',', ': '), sort_keys=True) output_string = executeRegexHacks(output_string) else: output_string = json.dumps(output_content, separators=(',', ': '), sort_keys=True) output_path = os.path.join(os.getcwd(), args[1]) write_file(output_path, output_string) if option_copy_textures: copy_textures( output_content['textures'] ) print("\nExported Three.js file to:\n%s\n" % output_path) # Destroy all objects created by the FBX SDK. sdk_manager.Destroy() sys.exit(0)three.js-r73/utils/build/0000755000175500017550000000000012640551725015211 5ustar debacledebaclethree.js-r73/utils/build/build_all.sh0000755000175500017550000000116112610076566017500 0ustar debacledebacle#!/bin/sh cd "$(dirname "$0")" python build.py --include common --include extras --output ../../build/three.js python build.py --include common --include extras --minify --output ../../build/three.min.js python build.py --include canvas --minify --output ../../build/three-canvas.min.js python build.py --include css3d --minify --output ../../build/three-css3d.min.js python build.py --include extras --externs externs/extras.js --minify --output ../../build/three-extras.min.js python build.py --include math --output ../../build/three-math.js python build.py --include math --minify --output ../../build/three-math.min.js three.js-r73/utils/build/build.py0000644000175500017550000000662612610076566016676 0ustar debacledebacle#!/usr/bin/env python import sys if sys.version_info < (2, 7): print("This script requires at least Python 2.7.") print("Please, update to a newer version: http://www.python.org/download/releases/") # exit() import argparse import json import os import re import shutil import tempfile from io import open def main(argv=None): parser = argparse.ArgumentParser() parser.add_argument('--include', action='append', required=True) parser.add_argument('--externs', action='append', default=['externs/common.js']) parser.add_argument('--amd', action='store_true', default=False) parser.add_argument('--minify', action='store_true', default=False) parser.add_argument('--output', default='../../build/three.js') parser.add_argument('--sourcemaps', action='store_true', default=False) args = parser.parse_args() output = args.output # merge print(' * Building ' + output) # enable sourcemaps support if args.sourcemaps: sourcemap = output + '.map' sourcemapping = '\n//@ sourceMappingURL=' + sourcemap sourcemapargs = ' --create_source_map ' + sourcemap + ' --source_map_format=V3' else: sourcemap = sourcemapping = sourcemapargs = '' fd, path = tempfile.mkstemp() tmp = open(path, 'w', encoding='utf-8') sources = [] if args.amd: tmp.write(u'( function ( root, factory ) {\n\n\tif ( typeof define === \'function\' && define.amd ) {\n\n\t\tdefine( [ \'exports\' ], factory );\n\n\t} else if ( typeof exports === \'object\' ) {\n\n\t\tfactory( exports );\n\n\t} else {\n\n\t\tfactory( root );\n\n\t}\n\n}( this, function ( exports ) {\n\n') for include in args.include: with open('includes/' + include + '.json','r', encoding='utf-8') as f: files = json.load(f) for filename in files: tmp.write(u'// File:' + filename) tmp.write(u'\n\n') filename = '../../' + filename sources.append(filename) with open(filename, 'r', encoding='utf-8') as f: if filename.endswith(".glsl"): tmp.write(u'THREE.ShaderChunk[ \'' + os.path.splitext(os.path.basename(filename))[0] + u'\'] = "') text = f.read() text = re.sub(r"\t*//.*\n", "", text) # strip comments text = text.replace('\n','\\n') # line breaks to \n tmp.write(text) tmp.write(u'";\n\n') else: tmp.write(f.read()) tmp.write(u'\n') if args.amd: tmp.write(u'exports.THREE = THREE;\n\n} ) );') tmp.close() # save if args.minify is False: shutil.copy(path, output) os.chmod(output, 0o664) # temp files would usually get 0600 else: backup = '' if os.path.exists(output): with open(output, 'r', encoding='utf-8') as f: backup = f.read() os.remove(output) externs = ' --externs '.join(args.externs) source = ' '.join(sources) cmd = 'java -jar compiler/compiler.jar --warning_level=VERBOSE --jscomp_off=globalThis --externs %s --jscomp_off=checkTypes --language_in=ECMASCRIPT5_STRICT --js %s --js_output_file %s %s' % (externs, path, output, sourcemapargs) os.system(cmd) # header if os.path.exists(output): with open(output, 'r', encoding='utf-8') as f: text = f.read() with open(output, 'w', encoding='utf-8') as f: f.write('// threejs.org/license\n' + text + sourcemapping) else: print("Minification with Closure compiler failed. Check your Java runtime version.") with open(output, 'w', encoding='utf-8') as f: f.write(backup) os.close(fd) os.remove(path) if __name__ == "__main__": script_dir = os.path.dirname(os.path.abspath(__file__)) os.chdir(script_dir) main() three.js-r73/utils/build/externs/0000755000175500017550000000000012610076566016703 5ustar debacledebaclethree.js-r73/utils/build/externs/examples.js0000644000175500017550000000004212610076566021053 0ustar debacledebaclevar webkitAudioContext; var TWEEN;three.js-r73/utils/build/externs/extras.js0000644000175500017550000000001212610076566020540 0ustar debacledebaclevar THREE;three.js-r73/utils/build/externs/common.js0000644000175500017550000000011612610076566020527 0ustar debacledebaclevar AudioContext; var console; var define; var module; var exports; var JSON; three.js-r73/utils/build/includes/0000755000175500017550000000000012610076566017021 5ustar debacledebaclethree.js-r73/utils/build/includes/math.json0000644000175500017550000000066112610076566020650 0ustar debacledebacle[ "src/Three.js", "src/math/Color.js", "src/math/Quaternion.js", "src/math/Vector2.js", "src/math/Vector3.js", "src/math/Vector4.js", "src/math/Euler.js", "src/math/Line3.js", "src/math/Box2.js", "src/math/Box3.js", "src/math/Matrix3.js", "src/math/Matrix4.js", "src/math/Ray.js", "src/math/Sphere.js", "src/math/Frustum.js", "src/math/Plane.js", "src/math/Math.js", "src/math/Spline.js", "src/math/Triangle.js" ] three.js-r73/utils/build/includes/css3d.json0000644000175500017550000000110612610076566020731 0ustar debacledebacle[ "src/Three.js", "src/math/Color.js", "src/math/Quaternion.js", "src/math/Vector2.js", "src/math/Vector3.js", "src/math/Vector4.js", "src/math/Euler.js", "src/math/Math.js", "src/math/Matrix3.js", "src/math/Matrix4.js", "src/math/Box3.js", "src/math/Sphere.js", "src/math/Frustum.js", "src/math/Plane.js", "src/core/EventDispatcher.js", "src/core/Object3D.js", "src/cameras/Camera.js", "src/cameras/PerspectiveCamera.js", "src/lights/Light.js", "src/objects/Group.js", "src/objects/Bone.js", "src/scenes/Scene.js", "examples/js/renderers/CSS3DRenderer.js" ] three.js-r73/utils/build/includes/canvas.json0000644000175500017550000000340612610076566021172 0ustar debacledebacle[ "src/Three.js", "src/math/Color.js", "src/math/Quaternion.js", "src/math/Vector2.js", "src/math/Vector3.js", "src/math/Vector4.js", "src/math/Euler.js", "src/math/Matrix3.js", "src/math/Matrix4.js", "src/math/Ray.js", "src/math/Box2.js", "src/math/Box3.js", "src/math/Sphere.js", "src/math/Plane.js", "src/math/Frustum.js", "src/math/Math.js", "src/math/Triangle.js", "src/core/EventDispatcher.js", "src/core/Raycaster.js", "src/core/Object3D.js", "src/core/Face3.js", "src/core/Face4.js", "src/core/BufferAttribute.js", "src/core/Geometry.js", "src/core/BufferGeometry.js", "src/cameras/Camera.js", "src/cameras/OrthographicCamera.js", "src/cameras/PerspectiveCamera.js", "src/lights/Light.js", "src/lights/AmbientLight.js", "src/lights/DirectionalLight.js", "src/lights/PointLight.js", "src/loaders/Cache.js", "src/loaders/Loader.js", "src/loaders/ImageLoader.js", "src/loaders/JSONLoader.js", "src/loaders/LoadingManager.js", "src/loaders/MaterialLoader.js", "src/loaders/TextureLoader.js", "src/materials/Material.js", "src/materials/LineBasicMaterial.js", "src/materials/MeshBasicMaterial.js", "src/materials/MeshLambertMaterial.js", "src/materials/MeshPhongMaterial.js", "src/materials/MeshDepthMaterial.js", "src/materials/MeshNormalMaterial.js", "src/materials/MeshFaceMaterial.js", "src/materials/SpriteMaterial.js", "src/textures/Texture.js", "src/textures/CompressedTexture.js", "src/textures/DataTexture.js", "src/textures/VideoTexture.js", "src/objects/Group.js", "src/objects/Line.js", "src/objects/LineSegments.js", "src/objects/Mesh.js", "src/objects/Bone.js", "src/objects/Skeleton.js", "src/objects/Sprite.js", "src/scenes/Scene.js", "examples/js/renderers/Projector.js", "examples/js/renderers/CanvasRenderer.js" ] three.js-r73/utils/build/includes/extras.json0000644000175500017550000000503312610076566021223 0ustar debacledebacle[ "src/extras/CurveUtils.js", "src/extras/GeometryUtils.js", "src/extras/ImageUtils.js", "src/extras/SceneUtils.js", "src/extras/ShapeUtils.js", "src/extras/audio/Audio.js", "src/extras/audio/AudioListener.js", "src/extras/core/Curve.js", "src/extras/core/CurvePath.js", "src/extras/core/Path.js", "src/extras/core/Shape.js", "src/extras/curves/LineCurve.js", "src/extras/curves/QuadraticBezierCurve.js", "src/extras/curves/CubicBezierCurve.js", "src/extras/curves/SplineCurve.js", "src/extras/curves/EllipseCurve.js", "src/extras/curves/ArcCurve.js", "src/extras/curves/LineCurve3.js", "src/extras/curves/QuadraticBezierCurve3.js", "src/extras/curves/CubicBezierCurve3.js", "src/extras/curves/SplineCurve3.js", "src/extras/curves/CatmullRomCurve3.js", "src/extras/curves/ClosedSplineCurve3.js", "src/extras/geometries/BoxGeometry.js", "src/extras/geometries/CircleGeometry.js", "src/extras/geometries/CircleBufferGeometry.js", "src/extras/geometries/CylinderGeometry.js", "src/extras/geometries/EdgesGeometry.js", "src/extras/geometries/ExtrudeGeometry.js", "src/extras/geometries/ShapeGeometry.js", "src/extras/geometries/LatheGeometry.js", "src/extras/geometries/PlaneGeometry.js", "src/extras/geometries/PlaneBufferGeometry.js", "src/extras/geometries/RingGeometry.js", "src/extras/geometries/SphereGeometry.js", "src/extras/geometries/SphereBufferGeometry.js", "src/extras/geometries/TorusGeometry.js", "src/extras/geometries/TorusKnotGeometry.js", "src/extras/geometries/TubeGeometry.js", "src/extras/geometries/PolyhedronGeometry.js", "src/extras/geometries/DodecahedronGeometry.js", "src/extras/geometries/IcosahedronGeometry.js", "src/extras/geometries/OctahedronGeometry.js", "src/extras/geometries/TetrahedronGeometry.js", "src/extras/geometries/ParametricGeometry.js", "src/extras/geometries/WireframeGeometry.js", "src/extras/helpers/AxisHelper.js", "src/extras/helpers/ArrowHelper.js", "src/extras/helpers/BoxHelper.js", "src/extras/helpers/BoundingBoxHelper.js", "src/extras/helpers/CameraHelper.js", "src/extras/helpers/DirectionalLightHelper.js", "src/extras/helpers/EdgesHelper.js", "src/extras/helpers/FaceNormalsHelper.js", "src/extras/helpers/GridHelper.js", "src/extras/helpers/HemisphereLightHelper.js", "src/extras/helpers/PointLightHelper.js", "src/extras/helpers/SkeletonHelper.js", "src/extras/helpers/SpotLightHelper.js", "src/extras/helpers/VertexNormalsHelper.js", "src/extras/helpers/WireframeHelper.js", "src/extras/objects/ImmediateRenderObject.js", "src/extras/objects/MorphBlendMesh.js" ] three.js-r73/utils/build/includes/common.json0000644000175500017550000001775312610076566021221 0ustar debacledebacle[ "src/Three.js", "src/math/Color.js", "src/math/Quaternion.js", "src/math/Vector2.js", "src/math/Vector3.js", "src/math/Vector4.js", "src/math/Euler.js", "src/math/Line3.js", "src/math/Box2.js", "src/math/Box3.js", "src/math/Matrix3.js", "src/math/Matrix4.js", "src/math/Ray.js", "src/math/Sphere.js", "src/math/Frustum.js", "src/math/Plane.js", "src/math/Math.js", "src/math/Spline.js", "src/math/Triangle.js", "src/core/Channels.js", "src/core/Clock.js", "src/core/EventDispatcher.js", "src/core/Raycaster.js", "src/core/Object3D.js", "src/core/Face3.js", "src/core/Face4.js", "src/core/BufferAttribute.js", "src/core/InstancedBufferAttribute.js", "src/core/InterleavedBuffer.js", "src/core/InstancedInterleavedBuffer.js", "src/core/InterleavedBufferAttribute.js", "src/core/Geometry.js", "src/core/DirectGeometry.js", "src/core/BufferGeometry.js", "src/core/InstancedBufferGeometry.js", "src/animation/AnimationAction.js", "src/animation/AnimationClip.js", "src/animation/AnimationMixer.js", "src/animation/AnimationUtils.js", "src/animation/KeyframeTrack.js", "src/animation/PropertyBinding.js", "src/animation/tracks/VectorKeyframeTrack.js", "src/animation/tracks/QuaternionKeyframeTrack.js", "src/animation/tracks/StringKeyframeTrack.js", "src/animation/tracks/BooleanKeyframeTrack.js", "src/animation/tracks/NumberKeyframeTrack.js", "src/cameras/Camera.js", "src/cameras/CubeCamera.js", "src/cameras/OrthographicCamera.js", "src/cameras/PerspectiveCamera.js", "src/lights/Light.js", "src/lights/LightShadow.js", "src/lights/AmbientLight.js", "src/lights/DirectionalLight.js", "src/lights/HemisphereLight.js", "src/lights/PointLight.js", "src/lights/SpotLight.js", "src/loaders/Cache.js", "src/loaders/Loader.js", "src/loaders/XHRLoader.js", "src/loaders/ImageLoader.js", "src/loaders/JSONLoader.js", "src/loaders/LoadingManager.js", "src/loaders/BufferGeometryLoader.js", "src/loaders/MaterialLoader.js", "src/loaders/ObjectLoader.js", "src/loaders/TextureLoader.js", "src/loaders/CubeTextureLoader.js", "src/loaders/BinaryTextureLoader.js", "src/loaders/CompressedTextureLoader.js", "src/materials/Material.js", "src/materials/LineBasicMaterial.js", "src/materials/LineDashedMaterial.js", "src/materials/MeshBasicMaterial.js", "src/materials/MeshLambertMaterial.js", "src/materials/MeshPhongMaterial.js", "src/materials/MeshDepthMaterial.js", "src/materials/MeshNormalMaterial.js", "src/materials/MultiMaterial.js", "src/materials/PointsMaterial.js", "src/materials/ShaderMaterial.js", "src/materials/RawShaderMaterial.js", "src/materials/SpriteMaterial.js", "src/textures/Texture.js", "src/textures/CanvasTexture.js", "src/textures/CubeTexture.js", "src/textures/CompressedTexture.js", "src/textures/DataTexture.js", "src/textures/VideoTexture.js", "src/objects/Group.js", "src/objects/Points.js", "src/objects/Line.js", "src/objects/LineSegments.js", "src/objects/Mesh.js", "src/objects/Bone.js", "src/objects/Skeleton.js", "src/objects/SkinnedMesh.js", "src/objects/LOD.js", "src/objects/Sprite.js", "src/objects/LensFlare.js", "src/scenes/Scene.js", "src/scenes/Fog.js", "src/scenes/FogExp2.js", "src/renderers/shaders/ShaderChunk.js", "src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl", "src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl", "src/renderers/shaders/ShaderChunk/aomap_fragment.glsl", "src/renderers/shaders/ShaderChunk/aomap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/begin_vertex.glsl", "src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl", "src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/color_fragment.glsl", "src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/color_vertex.glsl", "src/renderers/shaders/ShaderChunk/common.glsl", "src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl", "src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl", "src/renderers/shaders/ShaderChunk/displacementmap_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl", "src/renderers/shaders/ShaderChunk/emissivemap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/envmap_fragment.glsl", "src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/envmap_vertex.glsl", "src/renderers/shaders/ShaderChunk/fog_fragment.glsl", "src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/hemilight_fragment.glsl", "src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl", "src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl", "src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl", "src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl", "src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl", "src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl", "src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl", "src/renderers/shaders/ShaderChunk/map_fragment.glsl", "src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl", "src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl", "src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl", "src/renderers/shaders/ShaderChunk/normal_phong_fragment.glsl", "src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/project_vertex.glsl", "src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl", "src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl", "src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl", "src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/skinning_vertex.glsl", "src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl", "src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl", "src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/uv2_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/uv2_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/uv2_vertex.glsl", "src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl", "src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl", "src/renderers/shaders/ShaderChunk/uv_vertex.glsl", "src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl", "src/renderers/shaders/UniformsUtils.js", "src/renderers/shaders/UniformsLib.js", "src/renderers/shaders/ShaderLib.js", "src/renderers/WebGLRenderer.js", "src/renderers/WebGLRenderTarget.js", "src/renderers/WebGLRenderTargetCube.js", "src/renderers/webgl/WebGLBufferRenderer.js", "src/renderers/webgl/WebGLIndexedBufferRenderer.js", "src/renderers/webgl/WebGLExtensions.js", "src/renderers/webgl/WebGLCapabilities.js", "src/renderers/webgl/WebGLGeometries.js", "src/renderers/webgl/WebGLObjects.js", "src/renderers/webgl/WebGLProgram.js", "src/renderers/webgl/WebGLPrograms.js", "src/renderers/webgl/WebGLProperties.js", "src/renderers/webgl/WebGLShader.js", "src/renderers/webgl/WebGLShadowMap.js", "src/renderers/webgl/WebGLState.js", "src/renderers/webgl/plugins/LensFlarePlugin.js", "src/renderers/webgl/plugins/SpritePlugin.js" ] three.js-r73/utils/build/compiler/0000755000175500017550000000000012640541336017020 5ustar debacledebaclethree.js-r73/utils/build/compiler/README.md0000644000175500017550000003136512610076566020314 0ustar debacledebacle# [Google Closure Compiler](https://developers.google.com/closure/compiler/) [![Build Status](https://travis-ci.org/google/closure-compiler.svg?branch=master)](https://travis-ci.org/google/closure-compiler) The [Closure Compiler](https://developers.google.com/closure/compiler/) is a tool for making JavaScript download and run faster. It is a true compiler for JavaScript. Instead of compiling from a source language to machine code, it compiles from JavaScript to better JavaScript. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls. ## Getting Started * [Download the latest version](http://dl.google.com/closure-compiler/compiler-latest.zip) * See the [Google Developers Site](https://developers.google.com/closure/compiler/docs/gettingstarted_app) for documentation including instructions for running the compiler from the command line. ## Options for Getting Help 1. Post in the [Closure Compiler Discuss Group](https://groups.google.com/forum/#!forum/closure-compiler-discuss) 2. Ask a question on [Stack Overflow](http://stackoverflow.com/questions/tagged/google-closure-compiler) 3. Consult the [FAQ](https://github.com/google/closure-compiler/wiki/FAQ) ## Building it Yourself Note: The Closure Compiler requires [Java 7 or higher](http://www.java.com/). ### Using [Ant](http://ant.apache.org/) 1. Download the [Ant build tool](http://ant.apache.org/bindownload.cgi). 2. At the root of the source tree, there is an Ant file named ```build.xml```. To use it, navigate to the same directory and type the command ``` ant jar ``` This will produce a jar file called ```build/compiler.jar```. ### Using [Eclipse](http://www.eclipse.org/) 1. Download and open the [Eclipse IDE](http://www.eclipse.org/). 2. Navigate to ```File > New > Project ...``` and create a Java Project. Give the project a name. 3. Select ```Create project from existing source``` and choose the root of the checked-out source tree as the existing directory. 3. Navigate to the ```build.xml``` file. You will see all the build rules in the Outline pane. Run the ```jar``` rule to build the compiler in ```build/compiler.jar```. ## Running On the command line, at the root of this project, type ``` java -jar build/compiler.jar ``` This starts the compiler in interactive mode. Type ```javascript var x = 17 + 25; ``` then hit "Enter", then hit "Ctrl-Z" (on Windows) or "Ctrl-D" (on Mac or Linux) and "Enter" again. The Compiler will respond: ```javascript var x=42; ``` The Closure Compiler has many options for reading input from a file, writing output to a file, checking your code, and running optimizations. To learn more, type ``` java -jar compiler.jar --help ``` More detailed information about running the Closure Compiler is available in the [documentation](http://code.google.com/closure/compiler/docs/gettingstarted_app.html). ## Compiling Multiple Scripts If you have multiple scripts, you should compile them all together with one compile command. ```bash java -jar compiler.jar --js_output_file=out.js in1.js in2.js in3.js ... ``` You can also use minimatch-style globs. ```bash # Recursively include all js files in subdirs java -jar compiler.jar --js_output_file=out.js 'src/**.js' # Recursively include all js files in subdirs, exclusing test files. # Use single-quotes, so that bash doesn't try to expand the '!' java -jar compiler.jar --js_output_file=out.js 'src/**.js' '!**_test.js' ``` The Closure Compiler will concatenate the files in the order they're passed at the command line. If you're using globs or many files, you may start to run into problems with managing dependencies between scripts. In this case, you should use the [Closure Library](https://developers.google.com/closure/library/). It contains functions for enforcing dependencies between scripts, and Closure Compiler will re-order the inputs automatically. ## How to Contribute ### Reporting a bug 1. First make sure that it is really a bug and not simply the way that Closure Compiler works (especially true for ADVANCED_OPTIMIZATIONS). * Check the [official documentation](https://developers.google.com/closure/compiler/) * Consult the [FAQ](https://github.com/google/closure-compiler/wiki/FAQ) * Search on [Stack Overflow](http://stackoverflow.com/questions/tagged/google-closure-compiler) and in the [Closure Compiler Discuss Group](https://groups.google.com/forum/#!forum/closure-compiler-discuss) 2. If you still think you have found a bug, make sure someone hasn't already reported it. See the list of [known issues](https://github.com/google/closure-compiler/issues). 3. If it hasn't been reported yet, post a new issue. Make sure to add enough detail so that the bug can be recreated. The smaller the reproduction code, the better. ### Suggesting a Feature 1. Consult the [FAQ](https://github.com/google/closure-compiler/wiki/FAQ) to make sure that the behaviour you would like isn't specifically excluded (such as string inlining). 2. Make sure someone hasn't requested the same thing. See the list of [known issues](https://github.com/google/closure-compiler/issues). 3. Read up on [what type of feature requests are accepted](https://github.com/google/closure-compiler/wiki/FAQ#how-do-i-submit-a-feature-request-for-a-new-type-of-optimization). 4. Submit your reqest as an issue. ### Submitting patches 1. All contributors must sign a contributor license agreement. See the [CONTRIBUTORS](https://raw.githubusercontent.com/google/closure-compiler/master/CONTRIBUTORS) file for details. 2. To make sure your changes are of the type that will be accepted, ask about your patch on the [Closure Compiler Discuss Group](https://groups.google.com/forum/#!forum/closure-compiler-discuss) 3. Fork the repository. 4. Make your changes. 5. Submit a pull request for your changes. A project developer will review your work and then merge your request into the project. ## Closure Compiler License Copyright 2009 The Closure Compiler Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## Dependency Licenses ### Rhino
Code Path src/com/google/javascript/rhino, test/com/google/javascript/rhino
URL http://www.mozilla.org/rhino
Version 1.5R3, with heavy modifications
License Netscape Public License and MPL / GPL dual license
Description A partial copy of Mozilla Rhino. Mozilla Rhino is an implementation of JavaScript for the JVM. The JavaScript parse tree data structures were extracted and modified significantly for use by Google's JavaScript compiler.
Local Modifications The packages have been renamespaced. All code not relevant to the parse tree has been removed. A JsDoc parser and static typing system have been added.
### Args4j
Code Path lib/args4j.jar
URL https://args4j.dev.java.net/
Version 2.0.26
License MIT
Description args4j is a small Java class library that makes it easy to parse command line options/arguments in your CUI application.
Local Modifications None
### Guava Libraries
Code Path lib/guava.jar
URL http://code.google.com/p/guava-libraries/
Version 18.0
License Apache License 2.0
Description Google's core Java libraries.
Local Modifications None
### JSR 305
Code Path lib/jsr305.jar
URL http://code.google.com/p/jsr-305/
Version svn revision 47
License BSD License
Description Annotations for software defect detection.
Local Modifications None
### JUnit
Code Path lib/junit.jar
URL http://sourceforge.net/projects/junit/
Version 4.11
License Common Public License 1.0
Description A framework for writing and running automated tests in Java.
Local Modifications None
### Protocol Buffers
Code Path lib/protobuf-java.jar
URL http://code.google.com/p/protobuf/
Version 2.5.0
License New BSD License
Description Supporting libraries for protocol buffers, an encoding of structured data.
Local Modifications None
### Ant
Code Path lib/ant.jar, lib/ant-launcher.jar
URL http://ant.apache.org/bindownload.cgi
Version 1.8.1
License Apache License 2.0
Description Ant is a Java based build tool. In theory it is kind of like "make" without make's wrinkles and with the full portability of pure java code.
Local Modifications None
### JSON
Code Path lib/json.jar
URL http://json.org/java/index.html
Version JSON version 20090211
License MIT license
Description JSON is a set of java files for use in transmitting data in JSON format.
Local Modifications None
### Mockito
Code Path lib/mockito-core.jar
URL https://code.google.com/p/mockito
Version 1.9.5
License MIT license
Description Mockito is an open source testing framework for Java. The framework allows the creation of Test Double objects (called "Mock Objects") in automated unit tests for the purpose of Test-driven Development (TDD) or Behavior Driven Development (BDD).
Local Modifications None
### Objenesis
Code Path lib/objenesis.jar
URL http://objenesis.org
Version 1.2
License Apache 2.0 license
Description Depended by lib/mockito-core.jar, not used directly.
Local Modifications None
### Node.js Closure Compiler Externs
Code Path contrib/nodejs
URL https://github.com/dcodeIO/node.js-closure-compiler-externs
Version e891b4fbcf5f466cc4307b0fa842a7d8163a073a
License Apache 2.0 license
Description Type contracts for NodeJS APIs
Local Modifications Substantial changes to make them compatible with NpmCommandLineRunner.
three.js-r73/utils/build/compiler/COPYING0000644000175500017550000002613612610076566020070 0ustar debacledebacle Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. three.js-r73/utils/build/build.xml0000644000175500017550000000246512610076566017043 0ustar debacledebacle three.js-r73/utils/build/build.sh0000755000175500017550000000031512610076566016650 0ustar debacledebacle#!/bin/sh cd "$(dirname "$0")" python build.py --include common --include extras --output ../../build/three.js python build.py --include common --include extras --minify --output ../../build/three.min.js three.js-r73/utils/build/package.json0000644000175500017550000000112712610076566017502 0ustar debacledebacle{ "name": "three.js", "description": "JavaScript 3D library", "version": "0.0.0", "homepage" : "http://threejs.org/", "author": "three.js contributors", "help": { "web": "http://stackoverflow.com/questions/tagged/three.js" }, "devDependencies": { "uglify-js": "^2.4.17", "argparse" : "*" }, "repository" : { "type" : "git", "url" : "git://github.com/mrdoob/three.js.git" }, "licenses": [{ "type": "The MIT License", "url": "https://raw.github.com/mrdoob/three.js/master/LICENSE" }] } three.js-r73/utils/build/build_max.bat0000644000175500017550000000021612610076566017646 0ustar debacledebaclepython build.py --include common --include extras --include examples --externs externs/examples.js --minify --output ../../build/three.max.js three.js-r73/utils/build/build.bat0000644000175500017550000000025512610076566017004 0ustar debacledebaclepython build.py --include common --include extras --output ../../build/three.js python build.py --include common --include extras --minify --output ../../build/three.min.js three.js-r73/utils/build/build_debug.bat0000644000175500017550000000012412610076566020145 0ustar debacledebaclepython build.py --include common --include extras --output ../../build/three.min.js three.js-r73/utils/build/build_debug.sh0000755000175500017550000000016412610076566020020 0ustar debacledebacle#!/bin/sh cd "$(dirname "$0")" python build.py --include common --include extras --output ../../build/three.min.js three.js-r73/utils/build/build_all.bat0000644000175500017550000000112112610076566017625 0ustar debacledebaclepython build.py --include common --include extras --output ../../build/three.js python build.py --include common --include extras --minify --output ../../build/three.min.js python build.py --include canvas --minify --output ../../build/three-canvas.min.js python build.py --include css3d --minify --output ../../build/three-css3d.min.js python build.py --include extras --externs externs/extras.js --minify --output ../../build/three-extras.min.js python build.py --include math --output ../../build/three-math.js python build.py --include math --minify --output ../../build/three-math.min.js three.js-r73/utils/build/build.js0000644000175500017550000000645212610076566016657 0ustar debacledebaclevar fs = require("fs"); var path = require("path"); var argparse = require( "argparse" ); var uglify = require("uglify-js"); var spawn = require('child_process').spawn; function main() { "use strict"; var parser = new argparse.ArgumentParser(); parser.addArgument( ['--include'], { action: 'append', required: true } ); parser.addArgument( ['--externs'], { action: 'append', defaultValue: ['./externs/common.js'] } ); parser.addArgument( ['--amd'], { action: 'storeTrue', defaultValue: false } ); parser.addArgument( ['--minify'], { action: 'storeTrue', defaultValue: false } ); parser.addArgument( ['--output'], { defaultValue: '../../build/three.js' } ); parser.addArgument( ['--sourcemaps'], { action: 'storeTrue', defaultValue: true } ); var args = parser.parseArgs(); var output = args.output; console.log(' * Building ' + output); var sourcemap = ''; var sourcemapping = ''; if ( args.sourcemaps ){ sourcemap = output + '.map'; sourcemapping = '\n//# sourceMappingURL=three.min.js.map'; } var buffer = []; var sources = []; // used for source maps with minification if ( args.amd ){ buffer.push('function ( root, factory ) {\n\n\tif ( typeof define === \'function\' && define.amd ) {\n\n\t\tdefine( [ \'exports\' ], factory );\n\n\t} else if ( typeof exports === \'object\' ) {\n\n\t\tfactory( exports );\n\n\t} else {\n\n\t\tfactory( root );\n\n\t}\n\n}( this, function ( exports ) {\n\n'); }; for ( var i = 0; i < args.include.length; i ++ ){ var contents = fs.readFileSync( './includes/' + args.include[i] + '.json', 'utf8' ); var files = JSON.parse( contents ); for ( var j = 0; j < files.length; j ++ ){ var file = '../../' + files[ j ]; buffer.push('// File:' + files[ j ]); buffer.push('\n\n'); contents = fs.readFileSync( file, 'utf8' ); if( file.indexOf( '.glsl') >= 0 ) { contents = 'THREE.ShaderChunk[ \'' + path.basename( file, '.glsl' ) + '\' ] =' + JSON.stringify( contents ) + ';\n'; } sources.push( { file: file, contents: contents } ); buffer.push( contents ); buffer.push( '\n' ); } } if ( args.amd ){ buffer.push('exports.THREE = THREE;\n\n} ) );'); }; var temp = buffer.join( '' ); if ( !args.minify ){ fs.writeFileSync( output, temp, 'utf8' ); } else { var LICENSE = "threejs.org/license"; // Parsing var toplevel = null; toplevel = uglify.parse( '// ' + LICENSE + '\n' ); sources.forEach( function( source ) { toplevel = uglify.parse( source.contents, { filename: source.file, toplevel: toplevel } ); } ); // Compression toplevel.figure_out_scope(); var compressor = uglify.Compressor( {} ); var compressed_ast = toplevel.transform( compressor ); // Mangling compressed_ast.figure_out_scope(); compressed_ast.compute_char_frequency(); compressed_ast.mangle_names(); // Output var source_map_options = { file: 'three.min.js', root: 'src' }; var source_map = uglify.SourceMap( source_map_options ) var stream = uglify.OutputStream( { source_map: source_map, comments: new RegExp( LICENSE ) } ); compressed_ast.print( stream ); var code = stream.toString(); fs.writeFileSync( output, code + sourcemapping, 'utf8' ); if ( args.sourcemaps ) { fs.writeFileSync( sourcemap, source_map.toString(), 'utf8' ); } } } main(); three.js-r73/utils/npm/0000755000175500017550000000000012610076566014706 5ustar debacledebaclethree.js-r73/utils/npm/README.md0000644000175500017550000000313212610076566016164 0ustar debacledebacle#### Dependencies 1. To build the npm modules you will need both `node` and `npm` installed. 2. We can then use `npm` to resolve our remaining Javascript build dependences. These dependencies are specified in `utils/build/package.json`. 3. Note that there are other dependences - in particular, the [closure compiler](https://developers.google.com/closure/compiler/) is invoked, so you will need to ensure that `java` points to a suitably up-to-date version of the JVM. #### Specifying the version To invoke the build script (which will build both the both the `three` and `three-math` node modules) we need to run a command like ``` > node build.js 0.54.3-dev ``` in this directory. Note how we have to provide the build script with the version number. The version number is of the form `major.minor.fix[-dev]`. The major/minor version numbers of the build should be taken from the `REVISION` parameter in `src/Three.js` (e.g. if `REVISION: '68'` choose `0.68`). Note that the following rules should be followed to determine the full version identifier: - Increment the fix number by `1` if you are re-publishing an existing Three.js version. If this is a new release the fix number should be `0`. - Add `-dev` to the version number if this is a development branch. As an example, to build r68, checkout the `r68` tag, follow the above, and then run ``` > node build.js 0.68.0 ``` #### Publishing The built modules will be left in `node_modules` in this directory. To upload both `three` and `three-math` to `npm`, run ``` > npm publish node_modules/three > npm publish node_modules/three-math ``` in this directory. three.js-r73/utils/npm/footer.js0000644000175500017550000000065112610076566016544 0ustar debacledebacle // Export the THREE object for **Node.js**, with // backwards-compatibility for the old `require()` API. If we're in // the browser, add `_` as a global object via a string identifier, // for Closure Compiler "advanced" mode. if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { exports = module.exports = THREE; } exports.THREE = THREE; } else { this['THREE'] = THREE; } three.js-r73/utils/npm/header.js0000644000175500017550000000002612610076566016472 0ustar debacledebaclevar self = self || {};three.js-r73/utils/npm/three-math.package.json0000644000175500017550000000155312610076566021235 0ustar debacledebacle{ "name" : "three-math", "version" : "%VERSION%", "description" : "JavaScript 3D Math library", "keywords" : [ "3D", "WebGL", "Three", "ThreeJS", "CSS", "engine", "rendering", "geometry", "math" ], "homepage" : "http://threejs.org/", "bugs" : { "url" : "https://github.com/mrdoob/three.js/issues" }, "author" : "three.js contributors", "main" : "./three-math.js", "repository" : { "type" : "git", "url" : "git://github.com/mrdoob/three.js.git" }, "license" : { "type" : "The MIT License", "url" : "https://raw.github.com/mrdoob/three.js/master/LICENSE" }, "engines" : { "node" : "*" }, "help" : { "web" : "http://stackoverflow.com/questions/tagged/three.js" } } three.js-r73/utils/npm/three.package.json0000644000175500017550000000135612610076566020307 0ustar debacledebacle{ "name" : "three", "version" : "%VERSION%", "description" : "JavaScript 3D library", "keywords" : [ "3D", "WebGL", "Three", "ThreeJS", "CSS", "engine", "rendering", "geometry", "math" ], "homepage" : "http://threejs.org/", "bugs" : { "url" : "https://github.com/mrdoob/three.js/issues" }, "author" : "three.js contributors", "main" : "./three.js", "repository" : { "type" : "git", "url" : "git://github.com/mrdoob/three.js.git" }, "license" : "MIT", "engines" : { "node" : "*" }, "help" : { "web" : "http://stackoverflow.com/questions/tagged/three.js" } } three.js-r73/utils/npm/test.js0000644000175500017550000000133612610076566016226 0ustar debacledebacle/** * For testing whether the node modules for three and three-math work properly. * * To test the node modules: * 1. First build them, but don't submit them to npm, see README.md for instructions * 2. Run "node test.js" * 3. You should see a list of all of the types exposed by the two THREE modules. * * @author bhouston / http://exocortex.com */ var threemath = function () { var THREE = require( "three-math" ); var a = new THREE.Vector3( 1, 1, 1 ); console.log( a ); for( var i in THREE ) { console.log( i ); } }; var three = function () { var THREE = require( "three" ); var a = new THREE.Vector3( 1, 1, 1 ); console.log( a ); for( var i in THREE ) { console.log( i ); } }; threemath(); three();three.js-r73/utils/npm/build.js0000644000175500017550000000617012610076566016347 0ustar debacledebacle/** * Builds node_modules three and three-math * * Expects a single command line argument that is the build version in the format 0.54.4-dev * * @author bhouston / http://exocortex.com */ var fs = require( "fs" ); var cp = require('child_process'); var commandLineArguments = process.argv.splice(2); var outputRootDir = "./node_modules"; var inputDir = "../../build"; var readmeFileName = "../../README.md"; var headerFileName = "./header.js"; var footerFileName = "./footer.js"; if( commandLineArguments.length == 0 ) { throw new Error( "build version must be specified as a command line argument (e.g. 0.54.3-dev)"); } var buildVersion = commandLineArguments[0]; var concateFiles = function ( inputFileNames, outputFileName ) { var buffer = []; for ( var i = 0; i < inputFileNames.length; i++ ) { buffer.push( fs.readFileSync( inputFileNames[i], 'utf8' ) ); } var combinedContents = buffer.join(""); fs.writeFileSync( outputFileName, combinedContents, 'utf8' ); } var createTemplatedFile = function ( templateFileName, replaceSet, outputFileName ) { var templateContents = fs.readFileSync( templateFileName, 'utf8' ); for( var token in replaceSet ) { templateContents = templateContents.replace( "%"+token+"%", replaceSet[token] ); } fs.writeFileSync( outputFileName, templateContents, 'utf8' ); } var copyFile = function( sourceFileName, destinationFileName ) { var contents = fs.readFileSync( sourceFileName, 'utf8' ); fs.writeFileSync( destinationFileName, contents, 'utf8' ); } var buildModule = function ( name, version ) { if( ! fs.existsSync( outputRootDir ) ) { fs.mkdirSync( outputRootDir ); } var outputModuleDir = outputRootDir + "/" + name; if( ! fs.existsSync( outputModuleDir ) ) { fs.mkdirSync( outputModuleDir ); } // make directory moduleDir var inputRawFileName = inputDir + "/" + name + ".js"; var outputRawFileName = outputModuleDir + "/" + name + ".js"; concateFiles( [ headerFileName, inputRawFileName, footerFileName ], outputRawFileName ); var inputMinifiedFileName = inputDir + "/" + name + ".min.js"; var outputMinifiedFileName = outputModuleDir + "/" + name + ".min.js"; concateFiles( [ headerFileName, inputMinifiedFileName, footerFileName ], outputMinifiedFileName ); var templatePackageFileName = "./" + name + ".package.json"; var replaceSet = { "VERSION": buildVersion }; var outputPackageFileName = outputModuleDir + "/package.json"; createTemplatedFile( templatePackageFileName, replaceSet, outputPackageFileName ); var outputReadmeFileName = outputModuleDir + "/README.md"; copyFile( readmeFileName, outputReadmeFileName ); } var cmdExe, args; if (process.platform === 'win32' || process.platform === 'win64') { cmdExe = "cmd.exe"; args = [ "/c", "build.bat" ]; } else { cmdExe = './build.sh'; args = []; } var opts = { "cwd": "../build" }; var buildAll = cp.spawn( cmdExe, args, opts ); buildAll.stdout.on('data', function (data) { console.log('stdout: ' + data); }); buildAll.stderr.on('data', function (data) { console.log('stderr: ' + data); }); buildAll.on( 'exit', function ( exitCode ) { console.log( "exitCode: " + exitCode ); buildModule( "three" ); }); three.js-r73/utils/servers/0000755000175500017550000000000012610076566015605 5ustar debacledebaclethree.js-r73/utils/servers/simplehttpserver.js0000644000175500017550000000463212610076566021570 0ustar debacledebacle/** * a barebones HTTP server in JS * to serve three.js easily * * @author zz85 https://github.com/zz85 * * Usage: node simplehttpserver.js * * do not use in production servers * and try * npm install http-server -g * instead. */ var port = 8000, http = require('http'), urlParser = require('url'), fs = require('fs'), path = require('path'), currentDir = process.cwd(); port = process.argv[2] ? parseInt(process.argv[2], 0) : port; function handleRequest(request, response) { var urlObject = urlParser.parse(request.url, true); var pathname = decodeURIComponent(urlObject.pathname); console.log('[' + (new Date()).toUTCString() + '] ' + '"' + request.method + ' ' + pathname + '"'); var filePath = path.join(currentDir, pathname); fs.stat(filePath, function(err, stats) { if (err) { response.writeHead(404, {}); response.end('File not found!'); return; } if (stats.isFile()) { fs.readFile(filePath, function(err, data) { if (err) { response.writeHead(404, {}); response.end('Opps. Resource not found'); return; } response.writeHead(200, {}); response.write(data); response.end(); }); } else if (stats.isDirectory()) { fs.readdir(filePath, function(error, files) { if (error) { response.writeHead(500, {}); response.end(); return; } var l = pathname.length; if (pathname.substring(l-1)!='/') pathname += '/'; response.writeHead(200, {'Content-Type': 'text/html'}); response.write('\n' + filePath + ''); response.write('

' + filePath + '

'); response.write('
    '); files.unshift('.', '..'); files.forEach(function(item) { var urlpath = pathname + item, itemStats = fs.statSync(currentDir + urlpath); if (itemStats.isDirectory()) { urlpath += '/'; item += '/'; } response.write('
  • ' + item + '
  • '); }); response.end('
'); }); } }); } http.createServer(handleRequest).listen(port); require('dns').lookup(require('os').hostname(), function (err, addr, fam) { console.log('Running at http://' + addr + ((port === 80) ? '' : ':') + port + '/'); }) console.log('Three.js server has started...'); console.log('Base directory at ' + currentDir);three.js-r73/utils/servers/nodejs_server.sh0000755000175500017550000000011012610076566021004 0ustar debacledebacle#!/bin/sh cd `dirname $0`/../../ node utils/servers/simplehttpserver.jsthree.js-r73/utils/servers/perl_server.sh0000644000175500017550000000022012610076566020463 0ustar debacledebacle#!/bin/sh cd `dirname $0`/../../ perl -MIO::All -e 'io(":8080")->fork->accept->(sub { $_[0] < io(-x $1 +? "./$1 |" : $1) if /^GET \/(.*) / })'three.js-r73/utils/servers/ruby_server.sh0000644000175500017550000000024012610076566020504 0ustar debacledebacle#!/bin/sh cd `dirname $0`/../../ ruby -r webrick -e "s = WEBrick::HTTPServer.new(:Port => 8000, :DocumentRoot => Dir.pwd); trap('INT') { s.shutdown }; s.start"three.js-r73/utils/servers/readme.txt0000644000175500017550000000017112610076566017602 0ustar debacledebacleFor more information about running files locally, visit https://github.com/mrdoob/three.js/wiki/How-to-run-things-locallythree.js-r73/utils/servers/python_server.sh0000644000175500017550000000031712610076566021051 0ustar debacledebacle#!/bin/sh cd `dirname $0`/../../ ret=`python -c 'import sys; print("%i" % (sys.version_info[0]))'` if [ $ret -eq 2 ]; then python -m SimpleHTTPServer # Python 2 else python -m http.server # Python 3 fi three.js-r73/utils/codestyle/0000755000175500017550000000000012610076566016107 5ustar debacledebaclethree.js-r73/utils/codestyle/config.json0000644000175500017550000000177412610076566020260 0ustar debacledebacle{ "preset": "mdcs", "disallowSpaceAfterPrefixUnaryOperators": ["+", "-"], "disallowNewlineBeforeBlockStatements": true, "requireSpaceAfterBinaryOperators": [","], "disallowKeywordsOnNewLine": ["else"], "excludeFiles": [ "../../.c9/", "../../.c9version/", "../../.git/", "../../build/", "../../docs/", "../../editor/", "../../node_modules/", "../../test/", "../../utils/", "../../examples/files/", "../../examples/fonts/", "../../examples/models/", "../../examples/obj/", "../../examples/scenes/", "../../examples/sounds/", "../../examples/textures/", "../../examples/js/libs/", "../../examples/js/loaders/ctm/", "../../examples/js/loaders/gltf/", "../../examples/js/loaders/sea3d/", "../../examples/js/ImprovedNoise.js", "../../examples/js/SimplexNoise.js", "../../examples/js/loaders/UTF8Loader.js" ] } three.js-r73/utils/codestyle/codestyle.sh0000755000175500017550000000010012610076566020430 0ustar debacledebaclejscs "../.." --fix --config=./config.json --max-errors=1000000 three.js-r73/.npmignore0000644000175500017550000000005212610076566014750 0ustar debacledebacleexamples/ src/ test/ utils/ docs/ editor/ three.js-r73/examples/0000755000175500017550000000000012640541127014563 5ustar debacledebaclethree.js-r73/examples/js/0000755000175500017550000000000012610076566015206 5ustar debacledebaclethree.js-r73/examples/js/utils/0000755000175500017550000000000012610076566016346 5ustar debacledebaclethree.js-r73/examples/js/utils/FontUtils.js0000644000175500017550000001267512610076566020646 0ustar debacledebacle/** * @author zz85 / http://www.lab4games.net/zz85/blog * @author alteredq / http://alteredqualia.com/ * * For Text operations in three.js (See TextGeometry) * * It uses techniques used in: * * Triangulation ported from AS3 * Simple Polygon Triangulation * http://actionsnippet.com/?p=1462 * * A Method to triangulate shapes with holes * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ * */ THREE.FontUtils = { faces: {}, // Just for now. face[weight][style] face: 'helvetiker', weight: 'normal', style: 'normal', size: 150, divisions: 10, getFace: function () { try { return this.faces[ this.face.toLowerCase() ][ this.weight ][ this.style ]; } catch ( e ) { throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing." } }, loadFace: function ( data ) { var family = data.familyName.toLowerCase(); var ThreeFont = this; ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; return data; }, drawText: function ( text ) { // RenderText var i, face = this.getFace(), scale = this.size / face.resolution, offset = 0, chars = String( text ).split( '' ), length = chars.length; var fontPaths = []; for ( i = 0; i < length; i ++ ) { var path = new THREE.Path(); var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); offset += ret.offset; fontPaths.push( ret.path ); } // get the width var width = offset / 2; // // for ( p = 0; p < allPts.length; p++ ) { // // allPts[ p ].x -= width; // // } //var extract = this.extractPoints( allPts, characterPts ); //extract.contour = allPts; //extract.paths = fontPaths; //extract.offset = width; return { paths: fontPaths, offset: width }; }, extractGlyphPoints: function ( c, face, scale, offset, path ) { var pts = []; var b2 = THREE.ShapeUtils.b2; var b3 = THREE.ShapeUtils.b3; var i, i2, divisions, outline, action, length, scaleX, scaleY, x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste, glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; if ( ! glyph ) return; if ( glyph.o ) { outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); length = outline.length; scaleX = scale; scaleY = scale; for ( i = 0; i < length; ) { action = outline[ i ++ ]; //console.log( action ); switch ( action ) { case 'm': // Move To x = outline[ i ++ ] * scaleX + offset; y = outline[ i ++ ] * scaleY; path.moveTo( x, y ); break; case 'l': // Line To x = outline[ i ++ ] * scaleX + offset; y = outline[ i ++ ] * scaleY; path.lineTo( x, y ); break; case 'q': // QuadraticCurveTo cpx = outline[ i ++ ] * scaleX + offset; cpy = outline[ i ++ ] * scaleY; cpx1 = outline[ i ++ ] * scaleX + offset; cpy1 = outline[ i ++ ] * scaleY; path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); laste = pts[ pts.length - 1 ]; if ( laste ) { cpx0 = laste.x; cpy0 = laste.y; for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { var t = i2 / divisions; b2( t, cpx0, cpx1, cpx ); b2( t, cpy0, cpy1, cpy ); } } break; case 'b': // Cubic Bezier Curve cpx = outline[ i ++ ] * scaleX + offset; cpy = outline[ i ++ ] * scaleY; cpx1 = outline[ i ++ ] * scaleX + offset; cpy1 = outline[ i ++ ] * scaleY; cpx2 = outline[ i ++ ] * scaleX + offset; cpy2 = outline[ i ++ ] * scaleY; path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); laste = pts[ pts.length - 1 ]; if ( laste ) { cpx0 = laste.x; cpy0 = laste.y; for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { var t = i2 / divisions; b3( t, cpx0, cpx1, cpx2, cpx ); b3( t, cpy0, cpy1, cpy2, cpy ); } } break; } } } return { offset: glyph.ha * scale, path: path }; } }; THREE.FontUtils.generateShapes = function ( text, parameters ) { // Parameters parameters = parameters || {}; var size = parameters.size !== undefined ? parameters.size : 100; var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4; var font = parameters.font !== undefined ? parameters.font : 'helvetiker'; var weight = parameters.weight !== undefined ? parameters.weight : 'normal'; var style = parameters.style !== undefined ? parameters.style : 'normal'; THREE.FontUtils.size = size; THREE.FontUtils.divisions = curveSegments; THREE.FontUtils.face = font; THREE.FontUtils.weight = weight; THREE.FontUtils.style = style; // Get a Font data json object var data = THREE.FontUtils.drawText( text ); var paths = data.paths; var shapes = []; for ( var p = 0, pl = paths.length; p < pl; p ++ ) { Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); } return shapes; }; // To use the typeface.js face files, hook up the API THREE.typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; if ( typeof self !== 'undefined' ) self._typeface_js = THREE.typeface_js; three.js-r73/examples/js/utils/UVsDebug.js0000644000175500017550000000443112610076566020372 0ustar debacledebacle/* * @author zz85 / http://github.com/zz85 * @author WestLangley / http://github.com/WestLangley * * tool for "unwrapping" and debugging three.js * geometries UV mapping * * Sample usage: * document.body.appendChild( THREE.UVsDebug( new THREE.SphereGeometry( 10, 10, 10, 10 ) ); * */ THREE.UVsDebug = function( geometry, size ) { // handles wrapping of uv.x > 1 only var abc = 'abc'; var uv, u, ax, ay; var i, il, j, jl; var vnum; var a = new THREE.Vector2(); var b = new THREE.Vector2(); var geo = ( geometry instanceof THREE.BufferGeometry ) ? new THREE.Geometry().fromBufferGeometry( geometry ) : geometry; var faces = geo.faces; var uvs = geo.faceVertexUvs[ 0 ]; var canvas = document.createElement( 'canvas' ); var width = size || 1024; // power of 2 required for wrapping var height = size || 1024; canvas.width = width; canvas.height = height; var ctx = canvas.getContext( '2d' ); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba( 0, 0, 0, 1.0 )'; ctx.textAlign = 'center'; // paint background white ctx.fillStyle = 'rgba( 255, 255, 255, 1.0 )'; ctx.fillRect( 0, 0, width, height ); for ( i = 0, il = uvs.length; i < il; i ++ ) { uv = uvs[ i ]; // draw lines ctx.beginPath(); a.set( 0, 0 ); for ( j = 0, jl = uv.length; j < jl; j ++ ) { u = uv[ j ]; a.x += u.x; a.y += u.y; if ( j == 0 ) { ctx.moveTo( u.x * width, ( 1 - u.y ) * height ); } else { ctx.lineTo( u.x * width, ( 1 - u.y ) * height ); } } ctx.closePath(); ctx.stroke(); a.divideScalar( jl ); // label the face number ctx.font = "12pt Arial bold"; ctx.fillStyle = 'rgba( 0, 0, 0, 1.0 )'; ctx.fillText( i, a.x * width, ( 1 - a.y ) * height ); if ( a.x > 0.95 ) { // wrap x // 0.95 is arbitrary ctx.fillText( i, ( a.x % 1 ) * width, ( 1 - a.y ) * height ); } ctx.font = "8pt Arial bold"; ctx.fillStyle = 'rgba( 0, 0, 0, 1.0 )'; // label uv edge orders for ( j = 0, jl = uv.length; j < jl; j ++ ) { u = uv[ j ]; b.addVectors( a, u ).divideScalar( 2 ); vnum = faces[ i ][ abc[ j ] ]; ctx.fillText( abc[ j ] + vnum, b.x * width, ( 1 - b.y ) * height ); if ( b.x > 0.95 ) { // wrap x ctx.fillText( abc[ j ] + vnum, ( b.x % 1 ) * width, ( 1 - b.y ) * height ); } } } return canvas; }; three.js-r73/examples/js/utils/ImageUtils.js0000644000175500017550000000672512610076566020761 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author Daosheng Mu / https://github.com/DaoshengMu/ */ THREE.ImageUtils = { getNormalMap: function ( image, depth ) { // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ function cross( a, b ) { return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; } function subtract( a, b ) { return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; } function normalize( a ) { var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; } depth = depth | 1; var width = image.width; var height = image.height; var canvas = document.createElement( 'canvas' ); canvas.width = width; canvas.height = height; var context = canvas.getContext( '2d' ); context.drawImage( image, 0, 0 ); var data = context.getImageData( 0, 0, width, height ).data; var imageData = context.createImageData( width, height ); var output = imageData.data; for ( var x = 0; x < width; x ++ ) { for ( var y = 0; y < height; y ++ ) { var ly = y - 1 < 0 ? 0 : y - 1; var uy = y + 1 > height - 1 ? height - 1 : y + 1; var lx = x - 1 < 0 ? 0 : x - 1; var ux = x + 1 > width - 1 ? width - 1 : x + 1; var points = []; var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); var normals = []; var num_points = points.length; for ( var i = 0; i < num_points; i ++ ) { var v1 = points[ i ]; var v2 = points[ ( i + 1 ) % num_points ]; v1 = subtract( v1, origin ); v2 = subtract( v2, origin ); normals.push( normalize( cross( v1, v2 ) ) ); } var normal = [ 0, 0, 0 ]; for ( var i = 0; i < normals.length; i ++ ) { normal[ 0 ] += normals[ i ][ 0 ]; normal[ 1 ] += normals[ i ][ 1 ]; normal[ 2 ] += normals[ i ][ 2 ]; } normal[ 0 ] /= normals.length; normal[ 1 ] /= normals.length; normal[ 2 ] /= normals.length; var idx = ( y * width + x ) * 4; output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; output[ idx + 3 ] = 255; } } context.putImageData( imageData, 0, 0 ); return canvas; }, generateDataTexture: function ( width, height, color ) { var size = width * height; var data = new Uint8Array( 3 * size ); var r = Math.floor( color.r * 255 ); var g = Math.floor( color.g * 255 ); var b = Math.floor( color.b * 255 ); for ( var i = 0; i < size; i ++ ) { data[ i * 3 ] = r; data[ i * 3 + 1 ] = g; data[ i * 3 + 2 ] = b; } var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); texture.needsUpdate = true; return texture; } }; three.js-r73/examples/js/utils/GeometryUtils.js0000644000175500017550000001403612610076566021524 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.GeometryUtils = { // Merge two geometries or geometry and geometry from object (using object's transform) merge: function ( geometry1, geometry2, materialIndexOffset ) { console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); var matrix; if ( geometry2 instanceof THREE.Mesh ) { geometry2.matrixAutoUpdate && geometry2.updateMatrix(); matrix = geometry2.matrix; geometry2 = geometry2.geometry; } geometry1.merge( geometry2, matrix, materialIndexOffset ); }, // Get random point in triangle (via barycentric coordinates) // (uniform distribution) // http://www.cgafaq.info/wiki/Random_Point_In_Triangle randomPointInTriangle: function () { var vector = new THREE.Vector3(); return function ( vectorA, vectorB, vectorC ) { var point = new THREE.Vector3(); var a = THREE.Math.random16(); var b = THREE.Math.random16(); if ( ( a + b ) > 1 ) { a = 1 - a; b = 1 - b; } var c = 1 - a - b; point.copy( vectorA ); point.multiplyScalar( a ); vector.copy( vectorB ); vector.multiplyScalar( b ); point.add( vector ); vector.copy( vectorC ); vector.multiplyScalar( c ); point.add( vector ); return point; }; }(), // Get random point in face (triangle) // (uniform distribution) randomPointInFace: function ( face, geometry ) { var vA, vB, vC; vA = geometry.vertices[ face.a ]; vB = geometry.vertices[ face.b ]; vC = geometry.vertices[ face.c ]; return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); }, // Get uniformly distributed random points in mesh // - create array with cumulative sums of face areas // - pick random number from 0 to total area // - find corresponding place in area array by binary search // - get random point in face randomPointsInGeometry: function ( geometry, n ) { var face, i, faces = geometry.faces, vertices = geometry.vertices, il = faces.length, totalArea = 0, cumulativeAreas = [], vA, vB, vC; // precompute face areas for ( i = 0; i < il; i ++ ) { face = faces[ i ]; vA = vertices[ face.a ]; vB = vertices[ face.b ]; vC = vertices[ face.c ]; face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); totalArea += face._area; cumulativeAreas[ i ] = totalArea; } // binary search cumulative areas array function binarySearchIndices( value ) { function binarySearch( start, end ) { // return closest larger index // if exact number is not found if ( end < start ) return start; var mid = start + Math.floor( ( end - start ) / 2 ); if ( cumulativeAreas[ mid ] > value ) { return binarySearch( start, mid - 1 ); } else if ( cumulativeAreas[ mid ] < value ) { return binarySearch( mid + 1, end ); } else { return mid; } } var result = binarySearch( 0, cumulativeAreas.length - 1 ); return result; } // pick random face weighted by face area var r, index, result = []; var stats = {}; for ( i = 0; i < n; i ++ ) { r = THREE.Math.random16() * totalArea; index = binarySearchIndices( r ); result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry ); if ( ! stats[ index ] ) { stats[ index ] = 1; } else { stats[ index ] += 1; } } return result; }, randomPointsInBufferGeometry: function ( geometry, n ) { var i, vertices = geometry.attributes.position.array, totalArea = 0, cumulativeAreas = [], vA, vB, vC; // precompute face areas vA = new THREE.Vector3(); vB = new THREE.Vector3(); vC = new THREE.Vector3(); // geometry._areas = []; var il = vertices.length / 9; for ( i = 0; i < il; i ++ ) { vA.set( vertices[ i * 9 + 0 ], vertices[ i * 9 + 1 ], vertices[ i * 9 + 2 ] ); vB.set( vertices[ i * 9 + 3 ], vertices[ i * 9 + 4 ], vertices[ i * 9 + 5 ] ); vC.set( vertices[ i * 9 + 6 ], vertices[ i * 9 + 7 ], vertices[ i * 9 + 8 ] ); area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); totalArea += area; cumulativeAreas.push( totalArea ); } // binary search cumulative areas array function binarySearchIndices( value ) { function binarySearch( start, end ) { // return closest larger index // if exact number is not found if ( end < start ) return start; var mid = start + Math.floor( ( end - start ) / 2 ); if ( cumulativeAreas[ mid ] > value ) { return binarySearch( start, mid - 1 ); } else if ( cumulativeAreas[ mid ] < value ) { return binarySearch( mid + 1, end ); } else { return mid; } } var result = binarySearch( 0, cumulativeAreas.length - 1 ); return result; } // pick random face weighted by face area var r, index, result = []; for ( i = 0; i < n; i ++ ) { r = THREE.Math.random16() * totalArea; index = binarySearchIndices( r ); // result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); vA.set( vertices[ index * 9 + 0 ], vertices[ index * 9 + 1 ], vertices[ index * 9 + 2 ] ); vB.set( vertices[ index * 9 + 3 ], vertices[ index * 9 + 4 ], vertices[ index * 9 + 5 ] ); vC.set( vertices[ index * 9 + 6 ], vertices[ index * 9 + 7 ], vertices[ index * 9 + 8 ] ); result[ i ] = THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); } return result; }, // Get triangle area (half of parallelogram) // http://mathworld.wolfram.com/TriangleArea.html triangleArea: function () { var vector1 = new THREE.Vector3(); var vector2 = new THREE.Vector3(); return function ( vectorA, vectorB, vectorC ) { vector1.subVectors( vectorB, vectorA ); vector2.subVectors( vectorC, vectorA ); vector1.cross( vector2 ); return 0.5 * vector1.length(); }; }(), center: function ( geometry ) { console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); return geometry.center(); } }; three.js-r73/examples/js/utils/ShadowMapViewer.js0000644000175500017550000001242612610076566021756 0ustar debacledebacle/** * @author arya-s / https://github.com/arya-s * * This is a helper for visualising a given light's shadow map. * It works for shadow casting lights: THREE.DirectionalLight and THREE.SpotLight. * It renders out the shadow map and displays it on a HUD. * * Example usage: * 1) Include ``` This code creates a scene, a camera, and a geometric cube, and it adds the cube to the scene. It then creates a `WebGL` renderer for the scene and camera, and it adds that viewport to the document.body element. Finally it animates the cube within the scene for the camera. ```html ``` If everything went well you should see [this](http://jsfiddle.net/f17Lz5ux/). ### Change log ### [releases](https://github.com/mrdoob/three.js/releases) three.js-r73/test/0000755000175500017550000000000012610076566013733 5ustar debacledebaclethree.js-r73/test/benchmark/0000755000175500017550000000000012610076566015665 5ustar debacledebaclethree.js-r73/test/benchmark/benchmarking_float32array.html0000644000175500017550000000223612610076566023577 0ustar debacledebacle ThreeJS Benchmark Tests - Using Files in /src During this Benchmarking test the browser will be unresponsive.

Benchmark output is written to the JavaScript console. To access the JavaScript console presss Ctrl-Shift-J. three.js-r73/test/benchmark/benchmarking_vector3components.html0000644000175500017550000000074512610076566024764 0ustar debacledebacle ThreeJS Benchmark Tests - Using Files in /src During this Benchmarking test the browser will be unresponsive.

Benchmark output is written to the JavaScript console. To access the JavaScript console presss Ctrl-Shift-J. three.js-r73/test/benchmark/core/0000755000175500017550000000000012610076566016615 5ustar debacledebaclethree.js-r73/test/benchmark/core/Float32Array.js0000644000175500017550000000506112610076566021366 0ustar debacledebacle var input = new Float32Array( 10000 * 3 ); var output = new Float32Array( 10000 * 3 ); for( var j = 0, jl = input.length; j < jl; j ++ ) { input[j] = j; } var inputVectors = []; var outputVectors = []; for( var j = 0, jl = input.length/3; j < jl; j ++ ) { inputVectors.push( new THREE.Vector3( j*3, j*3+1, j*3+2 ) ); outputVectors.push( new THREE.Vector3() ); } var suite = new Benchmark.Suite; suite.add('Float32Array-Float32Array', function() { var value3 = new Float32Array( 3 ); for (var i = 0, il = input.length / 3; i < il; i += 3) { value3[0] = input[i + 0]; value3[1] = input[i + 1]; value3[2] = input[i + 2]; value3[0] *= 1.01; value3[1] *= 1.03; value3[2] *= 0.98; output[i + 0] = value3[0]; output[i + 1] = value3[1]; output[i + 2] = value3[2]; } }); suite.add('Float32Array-Array', function() { var value2 = [0,0,0]; for (var i = 0, il = input.length / 3; i < il; i += 3) { value2[0] = input[i + 0]; value2[1] = input[i + 1]; value2[2] = input[i + 2]; value2[0] *= 1.01; value2[1] *= 1.03; value2[2] *= 0.98; output[i + 0] = value2[0]; output[i + 1] = value2[1]; output[i + 2] = value2[2]; } }); suite.add('Float32Array-Literal', function() { var x, y, z; for (var i = 0, il = input.length / 3; i < il; i += 3) { x = input[i + 0]; y = input[i + 1]; z = input[i + 2]; x *= 1.01; y *= 1.03; z *= 0.98; output[i + 0] = x; output[i + 1] = y; output[i + 2] = z; } }); suite.add('Float32Array-Vector3', function() { var value = new THREE.Vector3(); for (var i = 0, il = input.length / 3; i < il; i += 3) { value.x = input[i + 0]; value.y = input[i + 1]; value.z = input[i + 2]; value.x *= 1.01; value.y *= 1.03; value.z *= 0.98; output[i + 0] = value.x; output[i + 1] = value.y; output[i + 2] = value.z; } }); suite.add('Vector3Array-Direct', function() { for (var i = 0, il = inputVectors.length; i < il; i ++ ) { outputVectors[i].copy( inputVectors[i] ); outputVectors[i].x *= 1.01; outputVectors[i].y *= 1.03; outputVectors[i].z *= 0.98; } }); suite.add('Vector3Array-Vector3', function() { var value = new THREE.Vector3(); for (var i = 0, il = inputVectors.length; i < il; i ++ ) { value.copy( inputVectors[i] ); value.x *= 1.01; value.y *= 1.03; value.z *= 0.98; outputVectors[i].copy( value ); } }); suite.on('cycle', function(event, bench) { console.log(String(event.target)); }); suite.on('complete', function() { console.log('Fastest is ' + this.filter('fastest').pluck('name')); console.log( "Done" ); }); suite.run(true);three.js-r73/test/benchmark/core/Vector3Length.js0000644000175500017550000000261312610076566021644 0ustar debacledebacleTHREE = {}; THREE.Vector3 = function ( x, y, z ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; THREE.Vector3.prototype = { constructor: THREE.Vector3, lengthSq: function () { return this.x * this.x + this.y * this.y + this.z * this.z; }, length: function () { return Math.sqrt( this.lengthSq() ); }, length2: function () { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); } }; var a = []; for ( var i = 0; i < 100000; i ++ ) { a[ i ] = new THREE.Vector3( i * 0.01, i * 2, i * -1.3 ); } var suite = new Benchmark.Suite; suite.add('NoCallTest', function() { var result = 0; for ( var i = 0; i < 100000; i ++ ) { var v = a[i]; result += Math.sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); } }); suite.add('InlineCallTest', function() { var result = 0; for ( var i = 0; i < 100000; i ++ ) { result += a[ i ].length2(); } }); suite.add('FunctionCallTest', function() { var result = 0; for ( var i = 0; i < 100000; i ++ ) { result += a[ i ].length(); } }); suite.on('cycle', function(event, bench) { console.log(String(event.target)); }); suite.on('complete', function() { console.log('Fastest is ' + this.filter('fastest').pluck('name')); console.log( "Done" ); }); suite.run(true);three.js-r73/test/benchmark/core/Vector3Components.js0000644000175500017550000000506712610076566022556 0ustar debacledebacleTHREE = {}; THREE.Vector3 = function ( x, y, z ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; THREE.Vector3.prototype = { constructor: THREE.Vector3, setComponent: function ( index, value ) { this[ THREE.Vector3.__indexToName[ index ] ] = value; }, getComponent: function ( index ) { return this[ THREE.Vector3.__indexToName[ index ] ]; }, setComponent2: function ( index, value ) { switch( index ) { case 0: this.x = value; break; case 1: this.y = value; break; case 2: this.z = value; break; default: throw new Error( "index is out of range: " + index ); } }, getComponent2: function ( index ) { switch( index ) { case 0: return this.x; case 1: return this.y; case 2: return this.z; default: throw new Error( "index is out of range: " + index ); } }, getComponent3: function ( index ) { if ( index === 0 ) return this.x; if ( index === 1 ) return this.y; if ( index === 2 ) return this.z; throw new Error( "index is out of range: " + index ); }, getComponent4: function ( index ) { if ( index === 0 ) return this.x; else if ( index === 1 ) return this.y; else if ( index === 2 ) return this.z; else throw new Error( "index is out of range: " + index ); } }; THREE.Vector3.__indexToName = { 0: 'x', 1: 'y', 2: 'z' }; var a = []; for ( var i = 0; i < 100000; i ++ ) { a[ i ] = new THREE.Vector3( i * 0.01, i * 2, i * -1.3 ); } var suite = new Benchmark.Suite; suite.add('IndexToName', function() { var result = 0; for ( var i = 0; i < 100000; i ++ ) { result += a[i].getComponent( i % 3 ); } }); suite.add('SwitchStatement', function() { var result = 0; for ( var i = 0; i < 100000; i ++ ) { result += a[i].getComponent2( i % 3 ); } }); suite.add('IfAndReturnSeries', function() { var result = 0; for ( var i = 0; i < 100000; i ++ ) { result += a[i].getComponent3( i % 3 ); } }); suite.add('IfReturnElseSeries', function() { var result = 0; for ( var i = 0; i < 100000; i ++ ) { result += a[i].getComponent4( i % 3 ); } }); suite.on('cycle', function(event, bench) { console.log(String(event.target)); }); suite.on('complete', function() { console.log('Fastest is ' + this.filter('fastest').pluck('name')); console.log( "Done" ); }); suite.run(true);three.js-r73/test/benchmark/core/Vector3Storage.js0000644000175500017550000000441212610076566022026 0ustar debacledebacleTHREE = {}; THREE.Vector3 = function ( x, y, z ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; THREE.Vector3.prototype = { constructor: THREE.Vector3, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); } }; THREE.Vector3X = function ( x, y, z ) { var elements = this.elements = new Float32Array( 3 ); elements[0] = x || 0; elements[1] = y || 1; elements[2] = z || 2; }; THREE.Vector3X.prototype = { constructor: THREE.Vector3X, length: function () { return Math.sqrt( this.elements[0] * this.elements[0] + this.elements[1] * this.elements[1] + this.elements[2] * this.elements[2] ); } }; THREE.Vector3Y = function ( x, y, z ) { this.elements = [ x || 0, y || 1, z || 2 ]; }; THREE.Vector3Y.prototype = { constructor: THREE.Vector3Y, length: function () { return Math.sqrt( this.elements[0] * this.elements[0] + this.elements[1] * this.elements[1] + this.elements[2] * this.elements[2] ); } }; var suite = new Benchmark.Suite; suite.add('Vector3-Set', function() { var array = []; for ( var i = 0; i < 100000; i ++ ) { var v = new THREE.Vector3( i, i, i ); array.push( v ); } var result = 0; for ( var i = 0; i < 100000; i ++ ) { var v = array[i]; result += v.length(); } }); suite.add('Vector3-Float32Array', function() { var array = []; for ( var i = 0; i < 100000; i ++ ) { var v = new THREE.Vector3X( i, i, i ); array.push( v ); } var result = 0; for ( var i = 0; i < 100000; i ++ ) { var v = array[i]; result += v.length(); } }); suite.add('Vector3-Array', function() { var array = []; for ( var i = 0; i < 100000; i ++ ) { var v = new THREE.Vector3Y( i, i, i ); array.push( v ); } var result = 0; for ( var i = 0; i < 100000; i ++ ) { var v = array[i]; result += v.length(); } }); suite.on('cycle', function(event, bench) { console.log(String(event.target)); }); suite.on('complete', function() { console.log('Fastest is ' + this.filter('fastest').pluck('name')); console.log( "Done" ); }); suite.run(true);three.js-r73/test/benchmark/benchmarking_vector3storage.html0000644000175500017550000000074212610076566024240 0ustar debacledebacle ThreeJS Benchmark Tests - Using Files in /src During this Benchmarking test the browser will be unresponsive.

Benchmark output is written to the JavaScript console. To access the JavaScript console presss Ctrl-Shift-J. three.js-r73/test/benchmark/benchmarking_vector3length.html0000644000175500017550000000074112610076566024054 0ustar debacledebacle ThreeJS Benchmark Tests - Using Files in /src During this Benchmarking test the browser will be unresponsive.

Benchmark output is written to the JavaScript console. To access the JavaScript console presss Ctrl-Shift-J. three.js-r73/test/benchmark/benchmark-1.0.0.js0000644000175500017550000033626212610076566020623 0ustar debacledebacle/*! * Benchmark.js v1.0.0 * Copyright 2010-2012 Mathias Bynens * Based on JSLitmus.js, copyright Robert Kieffer * Modified by John-David Dalton * Available under MIT license */ ;(function(window, undefined) { 'use strict'; /** Used to assign each benchmark an incrimented id */ var counter = 0; /** Detect DOM document object */ var doc = isHostType(window, 'document') && document; /** Detect free variable `define` */ var freeDefine = typeof define == 'function' && typeof define.amd == 'object' && define.amd && define; /** Detect free variable `exports` */ var freeExports = typeof exports == 'object' && exports && (typeof global == 'object' && global && global == global.global && (window = global), exports); /** Detect free variable `require` */ var freeRequire = typeof require == 'function' && require; /** Used to crawl all properties regardless of enumerability */ var getAllKeys = Object.getOwnPropertyNames; /** Used to get property descriptors */ var getDescriptor = Object.getOwnPropertyDescriptor; /** Used in case an object doesn't have its own method */ var hasOwnProperty = {}.hasOwnProperty; /** Used to check if an object is extensible */ var isExtensible = Object.isExtensible || function() { return true; }; /** Used to access Wade Simmons' Node microtime module */ var microtimeObject = req('microtime'); /** Used to access the browser's high resolution timer */ var perfObject = isHostType(window, 'performance') && performance; /** Used to call the browser's high resolution timer */ var perfName = perfObject && ( perfObject.now && 'now' || perfObject.webkitNow && 'webkitNow' ); /** Used to access Node's high resolution timer */ var processObject = isHostType(window, 'process') && process; /** Used to check if an own property is enumerable */ var propertyIsEnumerable = {}.propertyIsEnumerable; /** Used to set property descriptors */ var setDescriptor = Object.defineProperty; /** Used to resolve a value's internal [[Class]] */ var toString = {}.toString; /** Used to prevent a `removeChild` memory leak in IE < 9 */ var trash = doc && doc.createElement('div'); /** Used to integrity check compiled tests */ var uid = 'uid' + (+new Date); /** Used to avoid infinite recursion when methods call each other */ var calledBy = {}; /** Used to avoid hz of Infinity */ var divisors = { '1': 4096, '2': 512, '3': 64, '4': 8, '5': 0 }; /** * T-Distribution two-tailed critical values for 95% confidence * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm */ var tTable = { '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064, '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042, 'infinity': 1.96 }; /** * Critical Mann-Whitney U-values for 95% confidence * http://www.saburchill.com/IBbiology/stats/003.html */ var uTable = { '5': [0, 1, 2], '6': [1, 2, 3, 5], '7': [1, 3, 5, 6, 8], '8': [2, 4, 6, 8, 10, 13], '9': [2, 4, 7, 10, 12, 15, 17], '10': [3, 5, 8, 11, 14, 17, 20, 23], '11': [3, 6, 9, 13, 16, 19, 23, 26, 30], '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127], '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142], '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158], '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175], '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192], '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211], '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230], '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250], '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272], '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294], '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317] }; /** * An object used to flag environments/features. * * @static * @memberOf Benchmark * @type Object */ var support = {}; (function() { /** * Detect Adobe AIR. * * @memberOf Benchmark.support * @type Boolean */ support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject'); /** * Detect if `arguments` objects have the correct internal [[Class]] value. * * @memberOf Benchmark.support * @type Boolean */ support.argumentsClass = isClassOf(arguments, 'Arguments'); /** * Detect if in a browser environment. * * @memberOf Benchmark.support * @type Boolean */ support.browser = doc && isHostType(window, 'navigator'); /** * Detect if strings support accessing characters by index. * * @memberOf Benchmark.support * @type Boolean */ support.charByIndex = // IE 8 supports indexes on string literals but not string objects ('x'[0] + Object('x')[0]) == 'xx'; /** * Detect if strings have indexes as own properties. * * @memberOf Benchmark.support * @type Boolean */ support.charByOwnIndex = // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on // strings but don't detect them as own properties support.charByIndex && hasKey('x', '0'); /** * Detect if Java is enabled/exposed. * * @memberOf Benchmark.support * @type Boolean */ support.java = isClassOf(window.java, 'JavaPackage'); /** * Detect if the Timers API exists. * * @memberOf Benchmark.support * @type Boolean */ support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout'); /** * Detect if functions support decompilation. * * @name decompilation * @memberOf Benchmark.support * @type Boolean */ try { // Safari 2.x removes commas in object literals // from Function#toString results // http://webk.it/11609 // Firefox 3.6 and Opera 9.25 strip grouping // parentheses from Function#toString results // http://bugzil.la/559438 support.decompilation = Function( 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')' )()(0).x === '1'; } catch(e) { support.decompilation = false; } /** * Detect ES5+ property descriptor API. * * @name descriptors * @memberOf Benchmark.support * @type Boolean */ try { var o = {}; support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o)); } catch(e) { support.descriptors = false; } /** * Detect ES5+ Object.getOwnPropertyNames(). * * @name getAllKeys * @memberOf Benchmark.support * @type Boolean */ try { support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype)); } catch(e) { support.getAllKeys = false; } /** * Detect if own properties are iterated before inherited properties (all but IE < 9). * * @name iteratesOwnLast * @memberOf Benchmark.support * @type Boolean */ support.iteratesOwnFirst = (function() { var props = []; function ctor() { this.x = 1; } ctor.prototype = { 'y': 1 }; for (var prop in new ctor) { props.push(prop); } return props[0] == 'x'; }()); /** * Detect if a node's [[Class]] is resolvable (all but IE < 9) * and that the JS engine errors when attempting to coerce an object to a * string without a `toString` property value of `typeof` "function". * * @name nodeClass * @memberOf Benchmark.support * @type Boolean */ try { support.nodeClass = ({ 'toString': 0 } + '', toString.call(doc || 0) != '[object Object]'); } catch(e) { support.nodeClass = true; } }()); /** * Timer object used by `clock()` and `Deferred#resolve`. * * @private * @type Object */ var timer = { /** * The timer namespace object or constructor. * * @private * @memberOf timer * @type Function|Object */ 'ns': Date, /** * Starts the deferred timer. * * @private * @memberOf timer * @param {Object} deferred The deferred instance. */ 'start': null, // lazy defined in `clock()` /** * Stops the deferred timer. * * @private * @memberOf timer * @param {Object} deferred The deferred instance. */ 'stop': null // lazy defined in `clock()` }; /** Shortcut for inverse results */ var noArgumentsClass = !support.argumentsClass, noCharByIndex = !support.charByIndex, noCharByOwnIndex = !support.charByOwnIndex; /** Math shortcuts */ var abs = Math.abs, floor = Math.floor, max = Math.max, min = Math.min, pow = Math.pow, sqrt = Math.sqrt; /*--------------------------------------------------------------------------*/ /** * The Benchmark constructor. * * @constructor * @param {String} name A name to identify the benchmark. * @param {Function|String} fn The test to benchmark. * @param {Object} [options={}] Options object. * @example * * // basic usage (the `new` operator is optional) * var bench = new Benchmark(fn); * * // or using a name first * var bench = new Benchmark('foo', fn); * * // or with options * var bench = new Benchmark('foo', fn, { * * // displayed by Benchmark#toString if `name` is not available * 'id': 'xyz', * * // called when the benchmark starts running * 'onStart': onStart, * * // called after each run cycle * 'onCycle': onCycle, * * // called when aborted * 'onAbort': onAbort, * * // called when a test errors * 'onError': onError, * * // called when reset * 'onReset': onReset, * * // called when the benchmark completes running * 'onComplete': onComplete, * * // compiled/called before the test loop * 'setup': setup, * * // compiled/called after the test loop * 'teardown': teardown * }); * * // or name and options * var bench = new Benchmark('foo', { * * // a flag to indicate the benchmark is deferred * 'defer': true, * * // benchmark test function * 'fn': function(deferred) { * // call resolve() when the deferred test is finished * deferred.resolve(); * } * }); * * // or options only * var bench = new Benchmark({ * * // benchmark name * 'name': 'foo', * * // benchmark test as a string * 'fn': '[1,2,3,4].sort()' * }); * * // a test's `this` binding is set to the benchmark instance * var bench = new Benchmark('foo', function() { * 'My name is '.concat(this.name); // My name is foo * }); */ function Benchmark(name, fn, options) { var me = this; // allow instance creation without the `new` operator if (me == null || me.constructor != Benchmark) { return new Benchmark(name, fn, options); } // juggle arguments if (isClassOf(name, 'Object')) { // 1 argument (options) options = name; } else if (isClassOf(name, 'Function')) { // 2 arguments (fn, options) options = fn; fn = name; } else if (isClassOf(fn, 'Object')) { // 2 arguments (name, options) options = fn; fn = null; me.name = name; } else { // 3 arguments (name, fn [, options]) me.name = name; } setOptions(me, options); me.id || (me.id = ++counter); me.fn == null && (me.fn = fn); me.stats = deepClone(me.stats); me.times = deepClone(me.times); } /** * The Deferred constructor. * * @constructor * @memberOf Benchmark * @param {Object} clone The cloned benchmark instance. */ function Deferred(clone) { var me = this; if (me == null || me.constructor != Deferred) { return new Deferred(clone); } me.benchmark = clone; clock(me); } /** * The Event constructor. * * @constructor * @memberOf Benchmark * @param {String|Object} type The event type. */ function Event(type) { var me = this; return (me == null || me.constructor != Event) ? new Event(type) : (type instanceof Event) ? type : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type); } /** * The Suite constructor. * * @constructor * @memberOf Benchmark * @param {String} name A name to identify the suite. * @param {Object} [options={}] Options object. * @example * * // basic usage (the `new` operator is optional) * var suite = new Benchmark.Suite; * * // or using a name first * var suite = new Benchmark.Suite('foo'); * * // or with options * var suite = new Benchmark.Suite('foo', { * * // called when the suite starts running * 'onStart': onStart, * * // called between running benchmarks * 'onCycle': onCycle, * * // called when aborted * 'onAbort': onAbort, * * // called when a test errors * 'onError': onError, * * // called when reset * 'onReset': onReset, * * // called when the suite completes running * 'onComplete': onComplete * }); */ function Suite(name, options) { var me = this; // allow instance creation without the `new` operator if (me == null || me.constructor != Suite) { return new Suite(name, options); } // juggle arguments if (isClassOf(name, 'Object')) { // 1 argument (options) options = name; } else { // 2 arguments (name [, options]) me.name = name; } setOptions(me, options); } /*--------------------------------------------------------------------------*/ /** * Note: Some array methods have been implemented in plain JavaScript to avoid * bugs in IE, Opera, Rhino, and Mobile Safari. * * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()` * functions that fail to remove the last element, `object[0]`, of * array-like-objects even though the `length` property is set to `0`. * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. * * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()` * generically to augment the `arguments` object will pave the value at index 0 * without incrimenting the other values's indexes. * https://github.com/documentcloud/underscore/issues/9 * * Rhino and environments it powers, like Narwhal and RingoJS, may have * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and * `unshift()` functions that make sparse arrays non-sparse by assigning the * undefined indexes a value of undefined. * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd */ /** * Creates an array containing the elements of the host array followed by the * elements of each argument in order. * * @memberOf Benchmark.Suite * @returns {Array} The new array. */ function concat() { var value, j = -1, length = arguments.length, result = slice.call(this), index = result.length; while (++j < length) { value = arguments[j]; if (isClassOf(value, 'Array')) { for (var k = 0, l = value.length; k < l; k++, index++) { if (k in value) { result[index] = value[k]; } } } else { result[index++] = value; } } return result; } /** * Utility function used by `shift()`, `splice()`, and `unshift()`. * * @private * @param {Number} start The index to start inserting elements. * @param {Number} deleteCount The number of elements to delete from the insert point. * @param {Array} elements The elements to insert. * @returns {Array} An array of deleted elements. */ function insert(start, deleteCount, elements) { // `result` should have its length set to the `deleteCount` // see https://bugs.ecmascript.org/show_bug.cgi?id=332 var deleteEnd = start + deleteCount, elementCount = elements ? elements.length : 0, index = start - 1, length = start + elementCount, object = this, result = Array(deleteCount), tail = slice.call(object, deleteEnd); // delete elements from the array while (++index < deleteEnd) { if (index in object) { result[index - start] = object[index]; delete object[index]; } } // insert elements index = start - 1; while (++index < length) { object[index] = elements[index - start]; } // append tail elements start = index--; length = max(0, (object.length >>> 0) - deleteCount + elementCount); while (++index < length) { if ((index - start) in tail) { object[index] = tail[index - start]; } else if (index in object) { delete object[index]; } } // delete excess elements deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0; while (deleteCount--) { index = length + deleteCount; if (index in object) { delete object[index]; } } object.length = length; return result; } /** * Rearrange the host array's elements in reverse order. * * @memberOf Benchmark.Suite * @returns {Array} The reversed array. */ function reverse() { var upperIndex, value, index = -1, object = Object(this), length = object.length >>> 0, middle = floor(length / 2); if (length > 1) { while (++index < middle) { upperIndex = length - index - 1; value = upperIndex in object ? object[upperIndex] : uid; if (index in object) { object[upperIndex] = object[index]; } else { delete object[upperIndex]; } if (value != uid) { object[index] = value; } else { delete object[index]; } } } return object; } /** * Removes the first element of the host array and returns it. * * @memberOf Benchmark.Suite * @returns {Mixed} The first element of the array. */ function shift() { return insert.call(this, 0, 1)[0]; } /** * Creates an array of the host array's elements from the start index up to, * but not including, the end index. * * @memberOf Benchmark.Suite * @param {Number} start The starting index. * @param {Number} end The end index. * @returns {Array} The new array. */ function slice(start, end) { var index = -1, object = Object(this), length = object.length >>> 0, result = []; start = toInteger(start); start = start < 0 ? max(length + start, 0) : min(start, length); start--; end = end == null ? length : toInteger(end); end = end < 0 ? max(length + end, 0) : min(end, length); while ((++index, ++start) < end) { if (start in object) { result[index] = object[start]; } } return result; } /** * Allows removing a range of elements and/or inserting elements into the * host array. * * @memberOf Benchmark.Suite * @param {Number} start The start index. * @param {Number} deleteCount The number of elements to delete. * @param {Mixed} [val1, val2, ...] values to insert at the `start` index. * @returns {Array} An array of removed elements. */ function splice(start, deleteCount) { var object = Object(this), length = object.length >>> 0; start = toInteger(start); start = start < 0 ? max(length + start, 0) : min(start, length); // support the de-facto SpiderMonkey extension // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice#Parameters // https://bugs.ecmascript.org/show_bug.cgi?id=429 deleteCount = arguments.length == 1 ? length - start : min(max(toInteger(deleteCount), 0), length - start); return insert.call(object, start, deleteCount, slice.call(arguments, 2)); } /** * Converts the specified `value` to an integer. * * @private * @param {Mixed} value The value to convert. * @returns {Number} The resulting integer. */ function toInteger(value) { value = +value; return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1); } /** * Appends arguments to the host array. * * @memberOf Benchmark.Suite * @returns {Number} The new length. */ function unshift() { var object = Object(this); insert.call(object, 0, 0, arguments); return object.length; } /*--------------------------------------------------------------------------*/ /** * A generic `Function#bind` like method. * * @private * @param {Function} fn The function to be bound to `thisArg`. * @param {Mixed} thisArg The `this` binding for the given function. * @returns {Function} The bound function. */ function bind(fn, thisArg) { return function() { fn.apply(thisArg, arguments); }; } /** * Creates a function from the given arguments string and body. * * @private * @param {String} args The comma separated function arguments. * @param {String} body The function body. * @returns {Function} The new function. */ function createFunction() { // lazy define createFunction = function(args, body) { var result, anchor = freeDefine ? define.amd : Benchmark, prop = uid + 'createFunction'; runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}'); result = anchor[prop]; delete anchor[prop]; return result; }; // fix JaegerMonkey bug // http://bugzil.la/639720 createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function; return createFunction.apply(null, arguments); } /** * Delay the execution of a function based on the benchmark's `delay` property. * * @private * @param {Object} bench The benchmark instance. * @param {Object} fn The function to execute. */ function delay(bench, fn) { bench._timerId = setTimeout(fn, bench.delay * 1e3); } /** * Destroys the given element. * * @private * @param {Element} element The element to destroy. */ function destroyElement(element) { trash.appendChild(element); trash.innerHTML = ''; } /** * Iterates over an object's properties, executing the `callback` for each. * Callbacks may terminate the loop by explicitly returning `false`. * * @private * @param {Object} object The object to iterate over. * @param {Function} callback The function executed per own property. * @param {Object} options The options object. * @returns {Object} Returns the object iterated over. */ function forProps() { var forShadowed, skipSeen, forArgs = true, shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']; (function(enumFlag, key) { // must use a non-native constructor to catch the Safari 2 issue function Klass() { this.valueOf = 0; }; Klass.prototype.valueOf = 0; // check various for-in bugs for (key in new Klass) { enumFlag += key == 'valueOf' ? 1 : 0; } // check if `arguments` objects have non-enumerable indexes for (key in arguments) { key == '0' && (forArgs = false); } // Safari 2 iterates over shadowed properties twice // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/ skipSeen = enumFlag == 2; // IE < 9 incorrectly makes an object's properties non-enumerable if they have // the same name as other non-enumerable properties in its prototype chain. forShadowed = !enumFlag; }(0)); // lazy define forProps = function(object, callback, options) { options || (options = {}); var result = object; object = Object(object); var ctor, key, keys, skipCtor, done = !result, which = options.which, allFlag = which == 'all', index = -1, iteratee = object, length = object.length, ownFlag = allFlag || which == 'own', seen = {}, skipProto = isClassOf(object, 'Function'), thisArg = options.bind; if (thisArg !== undefined) { callback = bind(callback, thisArg); } // iterate all properties if (allFlag && support.getAllKeys) { for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) { key = keys[index]; if (callback(object[key], key, object) === false) { break; } } } // else iterate only enumerable properties else { for (key in object) { // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 // (if the prototype or a property on the prototype has been set) // incorrectly set a function's `prototype` property [[Enumerable]] value // to `true`. Because of this we standardize on skipping the `prototype` // property of functions regardless of their [[Enumerable]] value. if ((done = !(skipProto && key == 'prototype') && !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) && (!ownFlag || ownFlag && hasKey(object, key)) && callback(object[key], key, object) === false)) { break; } } // in IE < 9 strings don't support accessing characters by index if (!done && (forArgs && isArguments(object) || ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') && (iteratee = noCharByIndex ? object.split('') : object)))) { while (++index < length) { if ((done = callback(iteratee[index], String(index), object) === false)) { break; } } } if (!done && forShadowed) { // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing // property and the `constructor` property of a prototype defaults to // non-enumerable, we manually skip the `constructor` property when we // think we are iterating over a `prototype` object. ctor = object.constructor; skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor; for (index = 0; index < 7; index++) { key = shadowed[index]; if (!(skipCtor && key == 'constructor') && hasKey(object, key) && callback(object[key], key, object) === false) { break; } } } } return result; }; return forProps.apply(null, arguments); } /** * Gets the name of the first argument from a function's source. * * @private * @param {Function} fn The function. * @returns {String} The argument name. */ function getFirstArgument(fn) { return (!hasKey(fn, 'toString') && (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || ''; } /** * Computes the arithmetic mean of a sample. * * @private * @param {Array} sample The sample. * @returns {Number} The mean. */ function getMean(sample) { return reduce(sample, function(sum, x) { return sum + x; }) / sample.length || 0; } /** * Gets the source code of a function. * * @private * @param {Function} fn The function. * @param {String} altSource A string used when a function's source code is unretrievable. * @returns {String} The function's source code. */ function getSource(fn, altSource) { var result = altSource; if (isStringable(fn)) { result = String(fn); } else if (support.decompilation) { // escape the `{` for Firefox 1 result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1]; } // trim string result = (result || '').replace(/^\s+|\s+$/g, ''); // detect strings containing only the "use strict" directive return /^(?:\/\*+[\w|\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result) ? '' : result; } /** * Checks if a value is an `arguments` object. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`. */ function isArguments() { // lazy define isArguments = function(value) { return toString.call(value) == '[object Arguments]'; }; if (noArgumentsClass) { isArguments = function(value) { return hasKey(value, 'callee') && !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee')); }; } return isArguments(arguments[0]); } /** * Checks if an object is of the specified class. * * @private * @param {Mixed} value The value to check. * @param {String} name The name of the class. * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`. */ function isClassOf(value, name) { return value != null && toString.call(value) == '[object ' + name + ']'; } /** * Host objects can return type values that are different from their actual * data type. The objects we are concerned with usually return non-primitive * types of object, function, or unknown. * * @private * @param {Mixed} object The owner of the property. * @param {String} property The property to check. * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. */ function isHostType(object, property) { var type = object != null ? typeof object[property] : 'number'; return !/^(?:boolean|number|string|undefined)$/.test(type) && (type == 'object' ? !!object[property] : true); } /** * Checks if a given `value` is an object created by the `Object` constructor * assuming objects created by the `Object` constructor have no inherited * enumerable properties and that there are no `Object.prototype` extensions. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a plain `Object` object, else `false`. */ function isPlainObject(value) { // avoid non-objects and false positives for `arguments` objects in IE < 9 var result = false; if (!(value && typeof value == 'object') || isArguments(value)) { return result; } // IE < 9 presents DOM nodes as `Object` objects except they have `toString` // methods that are `typeof` "string" and still can coerce nodes to strings. // Also check that the constructor is `Object` (i.e. `Object instanceof Object`) var ctor = value.constructor; if ((support.nodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) && (!isClassOf(ctor, 'Function') || ctor instanceof ctor)) { // In most environments an object's own properties are iterated before // its inherited properties. If the last iterated property is an object's // own property then there are no inherited enumerable properties. if (support.iteratesOwnFirst) { forProps(value, function(subValue, subKey) { result = subKey; }); return result === false || hasKey(value, result); } // IE < 9 iterates inherited properties before own properties. If the first // iterated property is an object's own property then there are no inherited // enumerable properties. forProps(value, function(subValue, subKey) { result = !hasKey(value, subKey); return false; }); return result === false; } return result; } /** * Checks if a value can be safely coerced to a string. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the value can be coerced, else `false`. */ function isStringable(value) { return hasKey(value, 'toString') || isClassOf(value, 'String'); } /** * Wraps a function and passes `this` to the original function as the * first argument. * * @private * @param {Function} fn The function to be wrapped. * @returns {Function} The new function. */ function methodize(fn) { return function() { var args = [this]; args.push.apply(args, arguments); return fn.apply(null, args); }; } /** * A no-operation function. * * @private */ function noop() { // no operation performed } /** * A wrapper around require() to suppress `module missing` errors. * * @private * @param {String} id The module id. * @returns {Mixed} The exported module or `null`. */ function req(id) { try { var result = freeExports && freeRequire(id); } catch(e) { } return result || null; } /** * Runs a snippet of JavaScript via script injection. * * @private * @param {String} code The code to run. */ function runScript(code) { var anchor = freeDefine ? define.amd : Benchmark, script = doc.createElement('script'), sibling = doc.getElementsByTagName('script')[0], parent = sibling.parentNode, prop = uid + 'runScript', prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();'; // Firefox 2.0.0.2 cannot use script injection as intended because it executes // asynchronously, but that's OK because script injection is only used to avoid // the previously commented JaegerMonkey bug. try { // remove the inserted script *before* running the code to avoid differences // in the expected script element count/order of the document. script.appendChild(doc.createTextNode(prefix + code)); anchor[prop] = function() { destroyElement(script); }; } catch(e) { parent = parent.cloneNode(false); sibling = null; script.text = code; } parent.insertBefore(script, sibling); delete anchor[prop]; } /** * A helper function for setting options/event handlers. * * @private * @param {Object} bench The benchmark instance. * @param {Object} [options={}] Options object. */ function setOptions(bench, options) { options = extend({}, bench.constructor.options, options); bench.options = forOwn(options, function(value, key) { if (value != null) { // add event listeners if (/^on[A-Z]/.test(key)) { forEach(key.split(' '), function(key) { bench.on(key.slice(2).toLowerCase(), value); }); } else if (!hasKey(bench, key)) { bench[key] = deepClone(value); } } }); } /*--------------------------------------------------------------------------*/ /** * Handles cycling/completing the deferred benchmark. * * @memberOf Benchmark.Deferred */ function resolve() { var me = this, clone = me.benchmark, bench = clone._original; if (bench.aborted) { // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete me.teardown(); clone.running = false; cycle(me); } else if (++me.cycles < clone.count) { // continue the test loop if (support.timeout) { // use setTimeout to avoid a call stack overflow if called recursively setTimeout(function() { clone.compiled.call(me, timer); }, 0); } else { clone.compiled.call(me, timer); } } else { timer.stop(me); me.teardown(); delay(clone, function() { cycle(me); }); } } /*--------------------------------------------------------------------------*/ /** * A deep clone utility. * * @static * @memberOf Benchmark * @param {Mixed} value The value to clone. * @returns {Mixed} The cloned value. */ function deepClone(value) { var accessor, circular, clone, ctor, descriptor, extensible, key, length, markerKey, parent, result, source, subIndex, data = { 'value': value }, index = 0, marked = [], queue = { 'length': 0 }, unmarked = []; /** * An easily detectable decorator for cloned values. */ function Marker(object) { this.raw = object; } /** * The callback used by `forProps()`. */ function forPropsCallback(subValue, subKey) { // exit early to avoid cloning the marker if (subValue && subValue.constructor == Marker) { return; } // add objects to the queue if (subValue === Object(subValue)) { queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value }; } // assign non-objects else { try { // will throw an error in strict mode if the property is read-only clone[subKey] = subValue; } catch(e) { } } } /** * Gets an available marker key for the given object. */ function getMarkerKey(object) { // avoid collisions with existing keys var result = uid; while (object[result] && object[result].constructor != Marker) { result += 1; } return result; } do { key = data.key; parent = data.parent; source = data.source; clone = value = source ? source[key] : data.value; accessor = circular = descriptor = false; // create a basic clone to filter out functions, DOM elements, and // other non `Object` objects if (value === Object(value)) { // use custom deep clone function if available if (isClassOf(value.deepClone, 'Function')) { clone = value.deepClone(); } else { ctor = value.constructor; switch (toString.call(value)) { case '[object Array]': clone = new ctor(value.length); break; case '[object Boolean]': clone = new ctor(value == true); break; case '[object Date]': clone = new ctor(+value); break; case '[object Object]': isPlainObject(value) && (clone = {}); break; case '[object Number]': case '[object String]': clone = new ctor(value); break; case '[object RegExp]': clone = ctor(value.source, (value.global ? 'g' : '') + (value.ignoreCase ? 'i' : '') + (value.multiline ? 'm' : '')); } } // continue clone if `value` doesn't have an accessor descriptor // http://es5.github.com/#x8.10.1 if (clone && clone != value && !(descriptor = source && support.descriptors && getDescriptor(source, key), accessor = descriptor && (descriptor.get || descriptor.set))) { // use an existing clone (circular reference) if ((extensible = isExtensible(value))) { markerKey = getMarkerKey(value); if (value[markerKey]) { circular = clone = value[markerKey].raw; } } else { // for frozen/sealed objects for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) { data = unmarked[subIndex]; if (data.object === value) { circular = clone = data.clone; break; } } } if (!circular) { // mark object to allow quickly detecting circular references and tie it to its clone if (extensible) { value[markerKey] = new Marker(clone); marked.push({ 'key': markerKey, 'object': value }); } else { // for frozen/sealed objects unmarked.push({ 'clone': clone, 'object': value }); } // iterate over object properties forProps(value, forPropsCallback, { 'which': 'all' }); } } } if (parent) { // for custom property descriptors if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) { if ('value' in descriptor) { descriptor.value = clone; } setDescriptor(parent, key, descriptor); } // for default property descriptors else { parent[key] = clone; } } else { result = clone; } } while ((data = queue[index++])); // remove markers for (index = 0, length = marked.length; index < length; index++) { data = marked[index]; delete data.object[data.key]; } return result; } /** * An iteration utility for arrays and objects. * Callbacks may terminate the loop by explicitly returning `false`. * * @static * @memberOf Benchmark * @param {Array|Object} object The object to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Array|Object} Returns the object iterated over. */ function each(object, callback, thisArg) { var result = object; object = Object(object); var fn = callback, index = -1, length = object.length, isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)), isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'), isConvertable = isSnapshot || isSplittable || 'item' in object, origObject = object; // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists if (length === length >>> 0) { if (isConvertable) { // the third argument of the callback is the original non-array object callback = function(value, index) { return fn.call(this, value, index, origObject); }; // in IE < 9 strings don't support accessing characters by index if (isSplittable) { object = object.split(''); } else { object = []; while (++index < length) { // in Safari 2 `index in object` is always `false` for NodeLists object[index] = isSnapshot ? result.snapshotItem(index) : result[index]; } } } forEach(object, callback, thisArg); } else { forOwn(object, callback, thisArg); } return result; } /** * Copies enumerable properties from the source(s) object to the destination object. * * @static * @memberOf Benchmark * @param {Object} destination The destination object. * @param {Object} [source={}] The source object. * @returns {Object} The destination object. */ function extend(destination, source) { // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]` // http://code.google.com/p/v8/issues/detail?id=839 var result = destination; delete arguments[0]; forEach(arguments, function(source) { forProps(source, function(value, key) { result[key] = value; }); }); return result; } /** * A generic `Array#filter` like method. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {Function|String} callback The function/alias called per iteration. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Array} A new array of values that passed callback filter. * @example * * // get odd numbers * Benchmark.filter([1, 2, 3, 4, 5], function(n) { * return n % 2; * }); // -> [1, 3, 5]; * * // get fastest benchmarks * Benchmark.filter(benches, 'fastest'); * * // get slowest benchmarks * Benchmark.filter(benches, 'slowest'); * * // get benchmarks that completed without erroring * Benchmark.filter(benches, 'successful'); */ function filter(array, callback, thisArg) { var result; if (callback == 'successful') { // callback to exclude those that are errored, unrun, or have hz of Infinity callback = function(bench) { return bench.cycles && isFinite(bench.hz); }; } else if (callback == 'fastest' || callback == 'slowest') { // get successful, sort by period + margin of error, and filter fastest/slowest result = filter(array, 'successful').sort(function(a, b) { a = a.stats; b = b.stats; return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1); }); result = filter(result, function(bench) { return result[0].compare(bench) == 0; }); } return result || reduce(array, function(result, value, index) { return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result; }, []); } /** * A generic `Array#forEach` like method. * Callbacks may terminate the loop by explicitly returning `false`. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Array} Returns the array iterated over. */ function forEach(array, callback, thisArg) { var index = -1, length = (array = Object(array)).length >>> 0; if (thisArg !== undefined) { callback = bind(callback, thisArg); } while (++index < length) { if (index in array && callback(array[index], index, array) === false) { break; } } return array; } /** * Iterates over an object's own properties, executing the `callback` for each. * Callbacks may terminate the loop by explicitly returning `false`. * * @static * @memberOf Benchmark * @param {Object} object The object to iterate over. * @param {Function} callback The function executed per own property. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Object} Returns the object iterated over. */ function forOwn(object, callback, thisArg) { return forProps(object, callback, { 'bind': thisArg, 'which': 'own' }); } /** * Converts a number to a more readable comma-separated string representation. * * @static * @memberOf Benchmark * @param {Number} number The number to convert. * @returns {String} The more readable string representation. */ function formatNumber(number) { number = String(number).split('.'); return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + (number[1] ? '.' + number[1] : ''); } /** * Checks if an object has the specified key as a direct property. * * @static * @memberOf Benchmark * @param {Object} object The object to check. * @param {String} key The key to check for. * @returns {Boolean} Returns `true` if key is a direct property, else `false`. */ function hasKey() { // lazy define for worst case fallback (not as accurate) hasKey = function(object, key) { var parent = object != null && (object.constructor || Object).prototype; return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); }; // for modern browsers if (isClassOf(hasOwnProperty, 'Function')) { hasKey = function(object, key) { return object != null && hasOwnProperty.call(object, key); }; } // for Safari 2 else if ({}.__proto__ == Object.prototype) { hasKey = function(object, key) { var result = false; if (object != null) { object = Object(object); object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0]; } return result; }; } return hasKey.apply(this, arguments); } /** * A generic `Array#indexOf` like method. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {Mixed} value The value to search for. * @param {Number} [fromIndex=0] The index to start searching from. * @returns {Number} The index of the matched value or `-1`. */ function indexOf(array, value, fromIndex) { var index = toInteger(fromIndex), length = (array = Object(array)).length >>> 0; index = (index < 0 ? max(0, length + index) : index) - 1; while (++index < length) { if (index in array && value === array[index]) { return index; } } return -1; } /** * Modify a string by replacing named tokens with matching object property values. * * @static * @memberOf Benchmark * @param {String} string The string to modify. * @param {Object} object The template object. * @returns {String} The modified string. */ function interpolate(string, object) { forOwn(object, function(value, key) { // escape regexp special characters in `key` string = string.replace(RegExp('#\\{' + key.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '\\}', 'g'), value); }); return string; } /** * Invokes a method on all items in an array. * * @static * @memberOf Benchmark * @param {Array} benches Array of benchmarks to iterate over. * @param {String|Object} name The name of the method to invoke OR options object. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. * @returns {Array} A new array of values returned from each method invoked. * @example * * // invoke `reset` on all benchmarks * Benchmark.invoke(benches, 'reset'); * * // invoke `emit` with arguments * Benchmark.invoke(benches, 'emit', 'complete', listener); * * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks * Benchmark.invoke(benches, { * * // invoke the `run` method * 'name': 'run', * * // pass a single argument * 'args': true, * * // treat as queue, removing benchmarks from front of `benches` until empty * 'queued': true, * * // called before any benchmarks have been invoked. * 'onStart': onStart, * * // called between invoking benchmarks * 'onCycle': onCycle, * * // called after all benchmarks have been invoked. * 'onComplete': onComplete * }); */ function invoke(benches, name) { var args, bench, queued, index = -1, eventProps = { 'currentTarget': benches }, options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop }, result = map(benches, function(bench) { return bench; }); /** * Invokes the method of the current object and if synchronous, fetches the next. */ function execute() { var listeners, async = isAsync(bench); if (async) { // use `getNext` as the first listener bench.on('complete', getNext); listeners = bench.events.complete; listeners.splice(0, 0, listeners.pop()); } // execute method result[index] = isClassOf(bench && bench[name], 'Function') ? bench[name].apply(bench, args) : undefined; // if synchronous return true until finished return !async && getNext(); } /** * Fetches the next bench or executes `onComplete` callback. */ function getNext(event) { var cycleEvent, last = bench, async = isAsync(last); if (async) { last.off('complete', getNext); last.emit('complete'); } // emit "cycle" event eventProps.type = 'cycle'; eventProps.target = last; cycleEvent = Event(eventProps); options.onCycle.call(benches, cycleEvent); // choose next benchmark if not exiting early if (!cycleEvent.aborted && raiseIndex() !== false) { bench = queued ? benches[0] : result[index]; if (isAsync(bench)) { delay(bench, execute); } else if (async) { // resume execution if previously asynchronous but now synchronous while (execute()) { } } else { // continue synchronous execution return true; } } else { // emit "complete" event eventProps.type = 'complete'; options.onComplete.call(benches, Event(eventProps)); } // When used as a listener `event.aborted = true` will cancel the rest of // the "complete" listeners because they were already called above and when // used as part of `getNext` the `return false` will exit the execution while-loop. if (event) { event.aborted = true; } else { return false; } } /** * Checks if invoking `Benchmark#run` with asynchronous cycles. */ function isAsync(object) { // avoid using `instanceof` here because of IE memory leak issues with host objects var async = args[0] && args[0].async; return Object(object).constructor == Benchmark && name == 'run' && ((async == null ? object.options.async : async) && support.timeout || object.defer); } /** * Raises `index` to the next defined index or returns `false`. */ function raiseIndex() { var length = result.length; if (queued) { // if queued remove the previous bench and subsequent skipped non-entries do { ++index > 0 && shift.call(benches); } while ((length = benches.length) && !('0' in benches)); } else { while (++index < length && !(index in result)) { } } // if we reached the last index then return `false` return (queued ? length : index < length) ? index : (index = false); } // juggle arguments if (isClassOf(name, 'String')) { // 2 arguments (array, name) args = slice.call(arguments, 2); } else { // 2 arguments (array, options) options = extend(options, name); name = options.name; args = isClassOf(args = 'args' in options ? options.args : [], 'Array') ? args : [args]; queued = options.queued; } // start iterating over the array if (raiseIndex() !== false) { // emit "start" event bench = result[index]; eventProps.type = 'start'; eventProps.target = bench; options.onStart.call(benches, Event(eventProps)); // end early if the suite was aborted in an "onStart" listener if (benches.aborted && benches.constructor == Suite && name == 'run') { // emit "cycle" event eventProps.type = 'cycle'; options.onCycle.call(benches, Event(eventProps)); // emit "complete" event eventProps.type = 'complete'; options.onComplete.call(benches, Event(eventProps)); } // else start else { if (isAsync(bench)) { delay(bench, execute); } else { while (execute()) { } } } } return result; } /** * Creates a string of joined array values or object key-value pairs. * * @static * @memberOf Benchmark * @param {Array|Object} object The object to operate on. * @param {String} [separator1=','] The separator used between key-value pairs. * @param {String} [separator2=': '] The separator used between keys and values. * @returns {String} The joined result. */ function join(object, separator1, separator2) { var result = [], length = (object = Object(object)).length, arrayLike = length === length >>> 0; separator2 || (separator2 = ': '); each(object, function(value, key) { result.push(arrayLike ? value : key + separator2 + value); }); return result.join(separator1 || ','); } /** * A generic `Array#map` like method. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Array} A new array of values returned by the callback. */ function map(array, callback, thisArg) { return reduce(array, function(result, value, index) { result[index] = callback.call(thisArg, value, index, array); return result; }, Array(Object(array).length >>> 0)); } /** * Retrieves the value of a specified property from all items in an array. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {String} property The property to pluck. * @returns {Array} A new array of property values. */ function pluck(array, property) { return map(array, function(object) { return object == null ? undefined : object[property]; }); } /** * A generic `Array#reduce` like method. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} accumulator Initial value of the accumulator. * @returns {Mixed} The accumulator. */ function reduce(array, callback, accumulator) { var noaccum = arguments.length < 3; forEach(array, function(value, index) { accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, array); }); return accumulator; } /*--------------------------------------------------------------------------*/ /** * Aborts all benchmarks in the suite. * * @name abort * @memberOf Benchmark.Suite * @returns {Object} The suite instance. */ function abortSuite() { var event, me = this, resetting = calledBy.resetSuite; if (me.running) { event = Event('abort'); me.emit(event); if (!event.cancelled || resetting) { // avoid infinite recursion calledBy.abortSuite = true; me.reset(); delete calledBy.abortSuite; if (!resetting) { me.aborted = true; invoke(me, 'abort'); } } } return me; } /** * Adds a test to the benchmark suite. * * @memberOf Benchmark.Suite * @param {String} name A name to identify the benchmark. * @param {Function|String} fn The test to benchmark. * @param {Object} [options={}] Options object. * @returns {Object} The benchmark instance. * @example * * // basic usage * suite.add(fn); * * // or using a name first * suite.add('foo', fn); * * // or with options * suite.add('foo', fn, { * 'onCycle': onCycle, * 'onComplete': onComplete * }); * * // or name and options * suite.add('foo', { * 'fn': fn, * 'onCycle': onCycle, * 'onComplete': onComplete * }); * * // or options only * suite.add({ * 'name': 'foo', * 'fn': fn, * 'onCycle': onCycle, * 'onComplete': onComplete * }); */ function add(name, fn, options) { var me = this, bench = Benchmark(name, fn, options), event = Event({ 'type': 'add', 'target': bench }); if (me.emit(event), !event.cancelled) { me.push(bench); } return me; } /** * Creates a new suite with cloned benchmarks. * * @name clone * @memberOf Benchmark.Suite * @param {Object} options Options object to overwrite cloned options. * @returns {Object} The new suite instance. */ function cloneSuite(options) { var me = this, result = new me.constructor(extend({}, me.options, options)); // copy own properties forOwn(me, function(value, key) { if (!hasKey(result, key)) { result[key] = value && isClassOf(value.clone, 'Function') ? value.clone() : deepClone(value); } }); return result; } /** * An `Array#filter` like method. * * @name filter * @memberOf Benchmark.Suite * @param {Function|String} callback The function/alias called per iteration. * @returns {Object} A new suite of benchmarks that passed callback filter. */ function filterSuite(callback) { var me = this, result = new me.constructor; result.push.apply(result, filter(me, callback)); return result; } /** * Resets all benchmarks in the suite. * * @name reset * @memberOf Benchmark.Suite * @returns {Object} The suite instance. */ function resetSuite() { var event, me = this, aborting = calledBy.abortSuite; if (me.running && !aborting) { // no worries, `resetSuite()` is called within `abortSuite()` calledBy.resetSuite = true; me.abort(); delete calledBy.resetSuite; } // reset if the state has changed else if ((me.aborted || me.running) && (me.emit(event = Event('reset')), !event.cancelled)) { me.running = false; if (!aborting) { invoke(me, 'reset'); } } return me; } /** * Runs the suite. * * @name run * @memberOf Benchmark.Suite * @param {Object} [options={}] Options object. * @returns {Object} The suite instance. * @example * * // basic usage * suite.run(); * * // or with options * suite.run({ 'async': true, 'queued': true }); */ function runSuite(options) { var me = this; me.reset(); me.running = true; options || (options = {}); invoke(me, { 'name': 'run', 'args': options, 'queued': options.queued, 'onStart': function(event) { me.emit(event); }, 'onCycle': function(event) { var bench = event.target; if (bench.error) { me.emit({ 'type': 'error', 'target': bench }); } me.emit(event); event.aborted = me.aborted; }, 'onComplete': function(event) { me.running = false; me.emit(event); } }); return me; } /*--------------------------------------------------------------------------*/ /** * Executes all registered listeners of the specified event type. * * @memberOf Benchmark, Benchmark.Suite * @param {String|Object} type The event type or object. * @returns {Mixed} Returns the return value of the last listener executed. */ function emit(type) { var listeners, me = this, event = Event(type), events = me.events, args = (arguments[0] = event, arguments); event.currentTarget || (event.currentTarget = me); event.target || (event.target = me); delete event.result; if (events && (listeners = hasKey(events, event.type) && events[event.type])) { forEach(listeners.slice(), function(listener) { if ((event.result = listener.apply(me, args)) === false) { event.cancelled = true; } return !event.aborted; }); } return event.result; } /** * Returns an array of event listeners for a given type that can be manipulated * to add or remove listeners. * * @memberOf Benchmark, Benchmark.Suite * @param {String} type The event type. * @returns {Array} The listeners array. */ function listeners(type) { var me = this, events = me.events || (me.events = {}); return hasKey(events, type) ? events[type] : (events[type] = []); } /** * Unregisters a listener for the specified event type(s), * or unregisters all listeners for the specified event type(s), * or unregisters all listeners for all event types. * * @memberOf Benchmark, Benchmark.Suite * @param {String} [type] The event type. * @param {Function} [listener] The function to unregister. * @returns {Object} The benchmark instance. * @example * * // unregister a listener for an event type * bench.off('cycle', listener); * * // unregister a listener for multiple event types * bench.off('start cycle', listener); * * // unregister all listeners for an event type * bench.off('cycle'); * * // unregister all listeners for multiple event types * bench.off('start cycle complete'); * * // unregister all listeners for all event types * bench.off(); */ function off(type, listener) { var me = this, events = me.events; events && each(type ? type.split(' ') : events, function(listeners, type) { var index; if (typeof listeners == 'string') { type = listeners; listeners = hasKey(events, type) && events[type]; } if (listeners) { if (listener) { index = indexOf(listeners, listener); if (index > -1) { listeners.splice(index, 1); } } else { listeners.length = 0; } } }); return me; } /** * Registers a listener for the specified event type(s). * * @memberOf Benchmark, Benchmark.Suite * @param {String} type The event type. * @param {Function} listener The function to register. * @returns {Object} The benchmark instance. * @example * * // register a listener for an event type * bench.on('cycle', listener); * * // register a listener for multiple event types * bench.on('start cycle', listener); */ function on(type, listener) { var me = this, events = me.events || (me.events = {}); forEach(type.split(' '), function(type) { (hasKey(events, type) ? events[type] : (events[type] = []) ).push(listener); }); return me; } /*--------------------------------------------------------------------------*/ /** * Aborts the benchmark without recording times. * * @memberOf Benchmark * @returns {Object} The benchmark instance. */ function abort() { var event, me = this, resetting = calledBy.reset; if (me.running) { event = Event('abort'); me.emit(event); if (!event.cancelled || resetting) { // avoid infinite recursion calledBy.abort = true; me.reset(); delete calledBy.abort; if (support.timeout) { clearTimeout(me._timerId); delete me._timerId; } if (!resetting) { me.aborted = true; me.running = false; } } } return me; } /** * Creates a new benchmark using the same test and options. * * @memberOf Benchmark * @param {Object} options Options object to overwrite cloned options. * @returns {Object} The new benchmark instance. * @example * * var bizarro = bench.clone({ * 'name': 'doppelganger' * }); */ function clone(options) { var me = this, result = new me.constructor(extend({}, me, options)); // correct the `options` object result.options = extend({}, me.options, options); // copy own custom properties forOwn(me, function(value, key) { if (!hasKey(result, key)) { result[key] = deepClone(value); } }); return result; } /** * Determines if a benchmark is faster than another. * * @memberOf Benchmark * @param {Object} other The benchmark to compare. * @returns {Number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate. */ function compare(other) { var critical, zStat, me = this, sample1 = me.stats.sample, sample2 = other.stats.sample, size1 = sample1.length, size2 = sample2.length, maxSize = max(size1, size2), minSize = min(size1, size2), u1 = getU(sample1, sample2), u2 = getU(sample2, sample1), u = min(u1, u2); function getScore(xA, sampleB) { return reduce(sampleB, function(total, xB) { return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5); }, 0); } function getU(sampleA, sampleB) { return reduce(sampleA, function(total, xA) { return total + getScore(xA, sampleB); }, 0); } function getZ(u) { return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12); } // exit early if comparing the same benchmark if (me == other) { return 0; } // reject the null hyphothesis the two samples come from the // same population (i.e. have the same median) if... if (size1 + size2 > 30) { // ...the z-stat is greater than 1.96 or less than -1.96 // http://www.statisticslectures.com/topics/mannwhitneyu/ zStat = getZ(u); return abs(zStat) > 1.96 ? (zStat > 0 ? -1 : 1) : 0; } // ...the U value is less than or equal the critical U value // http://www.geoib.com/mann-whitney-u-test.html critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3]; return u <= critical ? (u == u1 ? 1 : -1) : 0; } /** * Reset properties and abort if running. * * @memberOf Benchmark * @returns {Object} The benchmark instance. */ function reset() { var data, event, me = this, index = 0, changes = { 'length': 0 }, queue = { 'length': 0 }; if (me.running && !calledBy.abort) { // no worries, `reset()` is called within `abort()` calledBy.reset = true; me.abort(); delete calledBy.reset; } else { // a non-recursive solution to check if properties have changed // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4 data = { 'destination': me, 'source': extend({}, me.constructor.prototype, me.options) }; do { forOwn(data.source, function(value, key) { var changed, destination = data.destination, currValue = destination[key]; if (value && typeof value == 'object') { if (isClassOf(value, 'Array')) { // check if an array value has changed to a non-array value if (!isClassOf(currValue, 'Array')) { changed = currValue = []; } // or has changed its length if (currValue.length != value.length) { changed = currValue = currValue.slice(0, value.length); currValue.length = value.length; } } // check if an object has changed to a non-object value else if (!currValue || typeof currValue != 'object') { changed = currValue = {}; } // register a changed object if (changed) { changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue }; } queue[queue.length++] = { 'destination': currValue, 'source': value }; } // register a changed primitive else if (value !== currValue && !(value == null || isClassOf(value, 'Function'))) { changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value }; } }); } while ((data = queue[index++])); // if changed emit the `reset` event and if it isn't cancelled reset the benchmark if (changes.length && (me.emit(event = Event('reset')), !event.cancelled)) { forEach(changes, function(data) { data.destination[data.key] = data.value; }); } } return me; } /** * Displays relevant benchmark information when coerced to a string. * * @name toString * @memberOf Benchmark * @returns {String} A string representation of the benchmark instance. */ function toStringBench() { var me = this, error = me.error, hz = me.hz, id = me.id, stats = me.stats, size = stats.sample.length, pm = support.java ? '+/-' : '\xb1', result = me.name || (isNaN(id) ? id : ''); if (error) { result += ': ' + join(error); } else { result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm + stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)'; } return result; } /*--------------------------------------------------------------------------*/ /** * Clocks the time taken to execute a test per cycle (secs). * * @private * @param {Object} bench The benchmark instance. * @returns {Number} The time taken. */ function clock() { var applet, options = Benchmark.options, template = { 'begin': 's$=new n$', 'end': 'r$=(new n$-s$)/1e3', 'uid': uid }, timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }]; // lazy define for hi-res timers clock = function(clone) { var deferred; if (clone instanceof Deferred) { deferred = clone; clone = deferred.benchmark; } var bench = clone._original, fn = bench.fn, fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '', stringable = isStringable(fn); var source = { 'setup': getSource(bench.setup, preprocess('m$.setup()')), 'fn': getSource(fn, preprocess('m$.fn(' + fnArg + ')')), 'fnArg': fnArg, 'teardown': getSource(bench.teardown, preprocess('m$.teardown()')) }; var count = bench.count = clone.count, decompilable = support.decompilation || stringable, id = bench.id, isEmpty = !(source.fn || stringable), name = bench.name || (typeof id == 'number' ? '' : id), ns = timer.ns, result = 0; // init `minTime` if needed clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime); // repair nanosecond timer // (some Chrome builds erase the `ns` variable after millions of executions) if (applet) { try { ns.nanoTime(); } catch(e) { // use non-element to avoid issues with libs that augment them ns = timer.ns = new applet.Packages.nano; } } // Compile in setup/teardown functions and the test loop. // Create a new compiled test, instead of using the cached `bench.compiled`, // to avoid potential engine optimizations enabled over the life of the test. var compiled = bench.compiled = createFunction(preprocess('t$'), interpolate( preprocess(deferred ? 'var d$=this,#{fnArg}=d$,m$=d$.benchmark._original,f$=m$.fn,su$=m$.setup,td$=m$.teardown;' + // when `deferred.cycles` is `0` then... 'if(!d$.cycles){' + // set `deferred.fn` 'd$.fn=function(){var #{fnArg}=d$;if(typeof f$=="function"){try{#{fn}\n}catch(e$){f$(d$)}}else{#{fn}\n}};' + // set `deferred.teardown` 'd$.teardown=function(){d$.cycles=0;if(typeof td$=="function"){try{#{teardown}\n}catch(e$){td$()}}else{#{teardown}\n}};' + // execute the benchmark's `setup` 'if(typeof su$=="function"){try{#{setup}\n}catch(e$){su$()}}else{#{setup}\n};' + // start timer 't$.start(d$);' + // execute `deferred.fn` and return a dummy object '}d$.fn();return{}' : 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count,n$=t$.ns;#{setup}\n#{begin};' + 'while(i$--){#{fn}\n}#{end};#{teardown}\nreturn{elapsed:r$,uid:"#{uid}"}'), source )); try { if (isEmpty) { // Firefox may remove dead code from Function#toString results // http://bugzil.la/536085 throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.'); } else if (!deferred) { // pretest to determine if compiled code is exits early, usually by a // rogue `return` statement, by checking for a return object with the uid bench.count = 1; compiled = (compiled.call(bench, timer) || {}).uid == uid && compiled; bench.count = count; } } catch(e) { compiled = null; clone.error = e || new Error(String(e)); bench.count = count; } // fallback when a test exits early or errors during pretest if (decompilable && !compiled && !deferred && !isEmpty) { compiled = createFunction(preprocess('t$'), interpolate( preprocess( (clone.error && !stringable ? 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count' : 'function f$(){#{fn}\n}var r$,s$,m$=this,i$=m$.count' ) + ',n$=t$.ns;#{setup}\n#{begin};m$.f$=f$;while(i$--){m$.f$()}#{end};' + 'delete m$.f$;#{teardown}\nreturn{elapsed:r$}' ), source )); try { // pretest one more time to check for errors bench.count = 1; compiled.call(bench, timer); bench.compiled = compiled; bench.count = count; delete clone.error; } catch(e) { bench.count = count; if (clone.error) { compiled = null; } else { bench.compiled = compiled; clone.error = e || new Error(String(e)); } } } // assign `compiled` to `clone` before calling in case a deferred benchmark // immediately calls `deferred.resolve()` clone.compiled = compiled; // if no errors run the full test loop if (!clone.error) { result = compiled.call(deferred || bench, timer).elapsed; } return result; }; /*------------------------------------------------------------------------*/ /** * Gets the current timer's minimum resolution (secs). */ function getRes(unit) { var measured, begin, count = 30, divisor = 1e3, ns = timer.ns, sample = []; // get average smallest measurable time while (count--) { if (unit == 'us') { divisor = 1e6; if (ns.stop) { ns.start(); while (!(measured = ns.microseconds())) { } } else if (ns[perfName]) { divisor = 1e3; measured = Function('n', 'var r,s=n.' + perfName + '();while(!(r=n.' + perfName + '()-s)){};return r')(ns); } else { begin = ns(); while (!(measured = ns() - begin)) { } } } else if (unit == 'ns') { divisor = 1e9; if (ns.nanoTime) { begin = ns.nanoTime(); while (!(measured = ns.nanoTime() - begin)) { } } else { begin = (begin = ns())[0] + (begin[1] / divisor); while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) { } divisor = 1; } } else { begin = new ns; while (!(measured = new ns - begin)) { } } // check for broken timers (nanoTime may have issues) // http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/ if (measured > 0) { sample.push(measured); } else { sample.push(Infinity); break; } } // convert to seconds return getMean(sample) / divisor; } /** * Replaces all occurrences of `$` with a unique number and * template tokens with content. */ function preprocess(code) { return interpolate(code, template).replace(/\$/g, /\d+/.exec(uid)); } /*------------------------------------------------------------------------*/ // detect nanosecond support from a Java applet each(doc && doc.applets || [], function(element) { return !(timer.ns = applet = 'nanoTime' in element && element); }); // check type in case Safari returns an object instead of a number try { if (typeof timer.ns.nanoTime() == 'number') { timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); } } catch(e) { } // detect Chrome's microsecond timer: // enable benchmarking via the --enable-benchmarking command // line switch in at least Chrome 7 to use chrome.Interval try { if ((timer.ns = new (window.chrome || window.chromium).Interval)) { timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); } } catch(e) { } // detect `performance.now` microsecond resolution timer if ((timer.ns = perfName && perfObject)) { timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); } // detect Node's nanosecond resolution timer available in Node >= 0.8 if (processObject && typeof (timer.ns = processObject.hrtime) == 'function') { timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); } // detect Wade Simmons' Node microtime module if (microtimeObject && typeof (timer.ns = microtimeObject.now) == 'function') { timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); } // pick timer with highest resolution timer = reduce(timers, function(timer, other) { return other.res < timer.res ? other : timer; }); // remove unused applet if (timer.unit != 'ns' && applet) { applet = destroyElement(applet); } // error if there are no working timers if (timer.res == Infinity) { throw new Error('Benchmark.js was unable to find a working timer.'); } // use API of chosen timer if (timer.unit == 'ns') { if (timer.ns.nanoTime) { extend(template, { 'begin': 's$=n$.nanoTime()', 'end': 'r$=(n$.nanoTime()-s$)/1e9' }); } else { extend(template, { 'begin': 's$=n$()', 'end': 'r$=n$(s$);r$=r$[0]+(r$[1]/1e9)' }); } } else if (timer.unit == 'us') { if (timer.ns.stop) { extend(template, { 'begin': 's$=n$.start()', 'end': 'r$=n$.microseconds()/1e6' }); } else if (perfName) { extend(template, { 'begin': 's$=n$.' + perfName + '()', 'end': 'r$=(n$.' + perfName + '()-s$)/1e3' }); } else { extend(template, { 'begin': 's$=n$()', 'end': 'r$=(n$()-s$)/1e6' }); } } // define `timer` methods timer.start = createFunction(preprocess('o$'), preprocess('var n$=this.ns,#{begin};o$.elapsed=0;o$.timeStamp=s$')); timer.stop = createFunction(preprocess('o$'), preprocess('var n$=this.ns,s$=o$.timeStamp,#{end};o$.elapsed=r$')); // resolve time span required to achieve a percent uncertainty of at most 1% // http://spiff.rit.edu/classes/phys273/uncert/uncert.html options.minTime || (options.minTime = max(timer.res / 2 / 0.01, 0.05)); return clock.apply(null, arguments); } /*--------------------------------------------------------------------------*/ /** * Computes stats on benchmark results. * * @private * @param {Object} bench The benchmark instance. * @param {Object} options The options object. */ function compute(bench, options) { options || (options = {}); var async = options.async, elapsed = 0, initCount = bench.initCount, minSamples = bench.minSamples, queue = [], sample = bench.stats.sample; /** * Adds a clone to the queue. */ function enqueue() { queue.push(bench.clone({ '_original': bench, 'events': { 'abort': [update], 'cycle': [update], 'error': [update], 'start': [update] } })); } /** * Updates the clone/original benchmarks to keep their data in sync. */ function update(event) { var clone = this, type = event.type; if (bench.running) { if (type == 'start') { // Note: `clone.minTime` prop is inited in `clock()` clone.count = bench.initCount; } else { if (type == 'error') { bench.error = clone.error; } if (type == 'abort') { bench.abort(); bench.emit('cycle'); } else { event.currentTarget = event.target = bench; bench.emit(event); } } } else if (bench.aborted) { // clear abort listeners to avoid triggering bench's abort/cycle again clone.events.abort.length = 0; clone.abort(); } } /** * Determines if more clones should be queued or if cycling should stop. */ function evaluate(event) { var critical, df, mean, moe, rme, sd, sem, variance, clone = event.target, done = bench.aborted, now = +new Date, size = sample.push(clone.times.period), maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime, times = bench.times, varOf = function(sum, x) { return sum + pow(x - mean, 2); }; // exit early for aborted or unclockable tests if (done || clone.hz == Infinity) { maxedOut = !(size = sample.length = queue.length = 0); } if (!done) { // sample mean (estimate of the population mean) mean = getMean(sample); // sample variance (estimate of the population variance) variance = reduce(sample, varOf, 0) / (size - 1) || 0; // sample standard deviation (estimate of the population standard deviation) sd = sqrt(variance); // standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean) sem = sd / sqrt(size); // degrees of freedom df = size - 1; // critical value critical = tTable[Math.round(df) || 1] || tTable.infinity; // margin of error moe = sem * critical; // relative margin of error rme = (moe / mean) * 100 || 0; extend(bench.stats, { 'deviation': sd, 'mean': mean, 'moe': moe, 'rme': rme, 'sem': sem, 'variance': variance }); // Abort the cycle loop when the minimum sample size has been collected // and the elapsed time exceeds the maximum time allowed per benchmark. // We don't count cycle delays toward the max time because delays may be // increased by browsers that clamp timeouts for inactive tabs. // https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs if (maxedOut) { // reset the `initCount` in case the benchmark is rerun bench.initCount = initCount; bench.running = false; done = true; times.elapsed = (now - times.timeStamp) / 1e3; } if (bench.hz != Infinity) { bench.hz = 1 / mean; times.cycle = mean * bench.count; times.period = mean; } } // if time permits, increase sample size to reduce the margin of error if (queue.length < 2 && !maxedOut) { enqueue(); } // abort the invoke cycle when done event.aborted = done; } // init queue and begin enqueue(); invoke(queue, { 'name': 'run', 'args': { 'async': async }, 'queued': true, 'onCycle': evaluate, 'onComplete': function() { bench.emit('complete'); } }); } /*--------------------------------------------------------------------------*/ /** * Cycles a benchmark until a run `count` can be established. * * @private * @param {Object} clone The cloned benchmark instance. * @param {Object} options The options object. */ function cycle(clone, options) { options || (options = {}); var deferred; if (clone instanceof Deferred) { deferred = clone; clone = clone.benchmark; } var clocked, cycles, divisor, event, minTime, period, async = options.async, bench = clone._original, count = clone.count, times = clone.times; // continue, if not aborted between cycles if (clone.running) { // `minTime` is set to `Benchmark.options.minTime` in `clock()` cycles = ++clone.cycles; clocked = deferred ? deferred.elapsed : clock(clone); minTime = clone.minTime; if (cycles > bench.cycles) { bench.cycles = cycles; } if (clone.error) { event = Event('error'); event.message = clone.error; clone.emit(event); if (!event.cancelled) { clone.abort(); } } } // continue, if not errored if (clone.running) { // time taken to complete last test cycle bench.times.cycle = times.cycle = clocked; // seconds per operation period = bench.times.period = times.period = clocked / count; // ops per second bench.hz = clone.hz = 1 / period; // avoid working our way up to this next time bench.initCount = clone.initCount = count; // do we need to do another cycle? clone.running = clocked < minTime; if (clone.running) { // tests may clock at `0` when `initCount` is a small number, // to avoid that we set its count to something a bit higher if (!clocked && (divisor = divisors[clone.cycles]) != null) { count = floor(4e6 / divisor); } // calculate how many more iterations it will take to achive the `minTime` if (count <= clone.count) { count += Math.ceil((minTime - clocked) / period); } clone.running = count != Infinity; } } // should we exit early? event = Event('cycle'); clone.emit(event); if (event.aborted) { clone.abort(); } // figure out what to do next if (clone.running) { // start a new cycle clone.count = count; if (deferred) { clone.compiled.call(deferred, timer); } else if (async) { delay(clone, function() { cycle(clone, options); }); } else { cycle(clone); } } else { // fix TraceMonkey bug associated with clock fallbacks // http://bugzil.la/509069 if (support.browser) { runScript(uid + '=1;delete ' + uid); } // done clone.emit('complete'); } } /*--------------------------------------------------------------------------*/ /** * Runs the benchmark. * * @memberOf Benchmark * @param {Object} [options={}] Options object. * @returns {Object} The benchmark instance. * @example * * // basic usage * bench.run(); * * // or with options * bench.run({ 'async': true }); */ function run(options) { var me = this, event = Event('start'); // set `running` to `false` so `reset()` won't call `abort()` me.running = false; me.reset(); me.running = true; me.count = me.initCount; me.times.timeStamp = +new Date; me.emit(event); if (!event.cancelled) { options = { 'async': ((options = options && options.async) == null ? me.async : options) && support.timeout }; // for clones created within `compute()` if (me._original) { if (me.defer) { Deferred(me); } else { cycle(me, options); } } // for original benchmarks else { compute(me, options); } } return me; } /*--------------------------------------------------------------------------*/ // Firefox 1 erroneously defines variable and argument names of functions on // the function itself as non-configurable properties with `undefined` values. // The bugginess continues as the `Benchmark` constructor has an argument // named `options` and Firefox 1 will not assign a value to `Benchmark.options`, // making it non-writable in the process, unless it is the first property // assigned by for-in loop of `extend()`. extend(Benchmark, { /** * The default options copied by benchmark instances. * * @static * @memberOf Benchmark * @type Object */ 'options': { /** * A flag to indicate that benchmark cycles will execute asynchronously * by default. * * @memberOf Benchmark.options * @type Boolean */ 'async': false, /** * A flag to indicate that the benchmark clock is deferred. * * @memberOf Benchmark.options * @type Boolean */ 'defer': false, /** * The delay between test cycles (secs). * @memberOf Benchmark.options * @type Number */ 'delay': 0.005, /** * Displayed by Benchmark#toString when a `name` is not available * (auto-generated if absent). * * @memberOf Benchmark.options * @type String */ 'id': undefined, /** * The default number of times to execute a test on a benchmark's first cycle. * * @memberOf Benchmark.options * @type Number */ 'initCount': 1, /** * The maximum time a benchmark is allowed to run before finishing (secs). * * Note: Cycle delays aren't counted toward the maximum time. * * @memberOf Benchmark.options * @type Number */ 'maxTime': 5, /** * The minimum sample size required to perform statistical analysis. * * @memberOf Benchmark.options * @type Number */ 'minSamples': 5, /** * The time needed to reduce the percent uncertainty of measurement to 1% (secs). * * @memberOf Benchmark.options * @type Number */ 'minTime': 0, /** * The name of the benchmark. * * @memberOf Benchmark.options * @type String */ 'name': undefined, /** * An event listener called when the benchmark is aborted. * * @memberOf Benchmark.options * @type Function */ 'onAbort': undefined, /** * An event listener called when the benchmark completes running. * * @memberOf Benchmark.options * @type Function */ 'onComplete': undefined, /** * An event listener called after each run cycle. * * @memberOf Benchmark.options * @type Function */ 'onCycle': undefined, /** * An event listener called when a test errors. * * @memberOf Benchmark.options * @type Function */ 'onError': undefined, /** * An event listener called when the benchmark is reset. * * @memberOf Benchmark.options * @type Function */ 'onReset': undefined, /** * An event listener called when the benchmark starts running. * * @memberOf Benchmark.options * @type Function */ 'onStart': undefined }, /** * Platform object with properties describing things like browser name, * version, and operating system. * * @static * @memberOf Benchmark * @type Object */ 'platform': req('platform') || window.platform || { /** * The platform description. * * @memberOf Benchmark.platform * @type String */ 'description': window.navigator && navigator.userAgent || null, /** * The name of the browser layout engine. * * @memberOf Benchmark.platform * @type String|Null */ 'layout': null, /** * The name of the product hosting the browser. * * @memberOf Benchmark.platform * @type String|Null */ 'product': null, /** * The name of the browser/environment. * * @memberOf Benchmark.platform * @type String|Null */ 'name': null, /** * The name of the product's manufacturer. * * @memberOf Benchmark.platform * @type String|Null */ 'manufacturer': null, /** * The name of the operating system. * * @memberOf Benchmark.platform * @type String|Null */ 'os': null, /** * The alpha/beta release indicator. * * @memberOf Benchmark.platform * @type String|Null */ 'prerelease': null, /** * The browser/environment version. * * @memberOf Benchmark.platform * @type String|Null */ 'version': null, /** * Return platform description when the platform object is coerced to a string. * * @memberOf Benchmark.platform * @type Function * @returns {String} The platform description. */ 'toString': function() { return this.description || ''; } }, /** * The semantic version number. * * @static * @memberOf Benchmark * @type String */ 'version': '1.0.0', // an object of environment/feature detection flags 'support': support, // clone objects 'deepClone': deepClone, // iteration utility 'each': each, // augment objects 'extend': extend, // generic Array#filter 'filter': filter, // generic Array#forEach 'forEach': forEach, // generic own property iteration utility 'forOwn': forOwn, // converts a number to a comma-separated string 'formatNumber': formatNumber, // generic Object#hasOwnProperty // (trigger hasKey's lazy define before assigning it to Benchmark) 'hasKey': (hasKey(Benchmark, ''), hasKey), // generic Array#indexOf 'indexOf': indexOf, // template utility 'interpolate': interpolate, // invokes a method on each item in an array 'invoke': invoke, // generic Array#join for arrays and objects 'join': join, // generic Array#map 'map': map, // retrieves a property value from each item in an array 'pluck': pluck, // generic Array#reduce 'reduce': reduce }); /*--------------------------------------------------------------------------*/ extend(Benchmark.prototype, { /** * The number of times a test was executed. * * @memberOf Benchmark * @type Number */ 'count': 0, /** * The number of cycles performed while benchmarking. * * @memberOf Benchmark * @type Number */ 'cycles': 0, /** * The number of executions per second. * * @memberOf Benchmark * @type Number */ 'hz': 0, /** * The compiled test function. * * @memberOf Benchmark * @type Function|String */ 'compiled': undefined, /** * The error object if the test failed. * * @memberOf Benchmark * @type Object */ 'error': undefined, /** * The test to benchmark. * * @memberOf Benchmark * @type Function|String */ 'fn': undefined, /** * A flag to indicate if the benchmark is aborted. * * @memberOf Benchmark * @type Boolean */ 'aborted': false, /** * A flag to indicate if the benchmark is running. * * @memberOf Benchmark * @type Boolean */ 'running': false, /** * Compiled into the test and executed immediately **before** the test loop. * * @memberOf Benchmark * @type Function|String * @example * * // basic usage * var bench = Benchmark({ * 'setup': function() { * var c = this.count, * element = document.getElementById('container'); * while (c--) { * element.appendChild(document.createElement('div')); * } * }, * 'fn': function() { * element.removeChild(element.lastChild); * } * }); * * // compiles to something like: * var c = this.count, * element = document.getElementById('container'); * while (c--) { * element.appendChild(document.createElement('div')); * } * var start = new Date; * while (count--) { * element.removeChild(element.lastChild); * } * var end = new Date - start; * * // or using strings * var bench = Benchmark({ * 'setup': '\ * var a = 0;\n\ * (function() {\n\ * (function() {\n\ * (function() {', * 'fn': 'a += 1;', * 'teardown': '\ * }())\n\ * }())\n\ * }())' * }); * * // compiles to something like: * var a = 0; * (function() { * (function() { * (function() { * var start = new Date; * while (count--) { * a += 1; * } * var end = new Date - start; * }()) * }()) * }()) */ 'setup': noop, /** * Compiled into the test and executed immediately **after** the test loop. * * @memberOf Benchmark * @type Function|String */ 'teardown': noop, /** * An object of stats including mean, margin or error, and standard deviation. * * @memberOf Benchmark * @type Object */ 'stats': { /** * The margin of error. * * @memberOf Benchmark#stats * @type Number */ 'moe': 0, /** * The relative margin of error (expressed as a percentage of the mean). * * @memberOf Benchmark#stats * @type Number */ 'rme': 0, /** * The standard error of the mean. * * @memberOf Benchmark#stats * @type Number */ 'sem': 0, /** * The sample standard deviation. * * @memberOf Benchmark#stats * @type Number */ 'deviation': 0, /** * The sample arithmetic mean. * * @memberOf Benchmark#stats * @type Number */ 'mean': 0, /** * The array of sampled periods. * * @memberOf Benchmark#stats * @type Array */ 'sample': [], /** * The sample variance. * * @memberOf Benchmark#stats * @type Number */ 'variance': 0 }, /** * An object of timing data including cycle, elapsed, period, start, and stop. * * @memberOf Benchmark * @type Object */ 'times': { /** * The time taken to complete the last cycle (secs). * * @memberOf Benchmark#times * @type Number */ 'cycle': 0, /** * The time taken to complete the benchmark (secs). * * @memberOf Benchmark#times * @type Number */ 'elapsed': 0, /** * The time taken to execute the test once (secs). * * @memberOf Benchmark#times * @type Number */ 'period': 0, /** * A timestamp of when the benchmark started (ms). * * @memberOf Benchmark#times * @type Number */ 'timeStamp': 0 }, // aborts benchmark (does not record times) 'abort': abort, // creates a new benchmark using the same test and options 'clone': clone, // compares benchmark's hertz with another 'compare': compare, // executes listeners 'emit': emit, // get listeners 'listeners': listeners, // unregister listeners 'off': off, // register listeners 'on': on, // reset benchmark properties 'reset': reset, // runs the benchmark 'run': run, // pretty print benchmark info 'toString': toStringBench }); /*--------------------------------------------------------------------------*/ extend(Deferred.prototype, { /** * The deferred benchmark instance. * * @memberOf Benchmark.Deferred * @type Object */ 'benchmark': null, /** * The number of deferred cycles performed while benchmarking. * * @memberOf Benchmark.Deferred * @type Number */ 'cycles': 0, /** * The time taken to complete the deferred benchmark (secs). * * @memberOf Benchmark.Deferred * @type Number */ 'elapsed': 0, /** * A timestamp of when the deferred benchmark started (ms). * * @memberOf Benchmark.Deferred * @type Number */ 'timeStamp': 0, // cycles/completes the deferred benchmark 'resolve': resolve }); /*--------------------------------------------------------------------------*/ extend(Event.prototype, { /** * A flag to indicate if the emitters listener iteration is aborted. * * @memberOf Benchmark.Event * @type Boolean */ 'aborted': false, /** * A flag to indicate if the default action is cancelled. * * @memberOf Benchmark.Event * @type Boolean */ 'cancelled': false, /** * The object whose listeners are currently being processed. * * @memberOf Benchmark.Event * @type Object */ 'currentTarget': undefined, /** * The return value of the last executed listener. * * @memberOf Benchmark.Event * @type Mixed */ 'result': undefined, /** * The object to which the event was originally emitted. * * @memberOf Benchmark.Event * @type Object */ 'target': undefined, /** * A timestamp of when the event was created (ms). * * @memberOf Benchmark.Event * @type Number */ 'timeStamp': 0, /** * The event type. * * @memberOf Benchmark.Event * @type String */ 'type': '' }); /*--------------------------------------------------------------------------*/ /** * The default options copied by suite instances. * * @static * @memberOf Benchmark.Suite * @type Object */ Suite.options = { /** * The name of the suite. * * @memberOf Benchmark.Suite.options * @type String */ 'name': undefined }; /*--------------------------------------------------------------------------*/ extend(Suite.prototype, { /** * The number of benchmarks in the suite. * * @memberOf Benchmark.Suite * @type Number */ 'length': 0, /** * A flag to indicate if the suite is aborted. * * @memberOf Benchmark.Suite * @type Boolean */ 'aborted': false, /** * A flag to indicate if the suite is running. * * @memberOf Benchmark.Suite * @type Boolean */ 'running': false, /** * An `Array#forEach` like method. * Callbacks may terminate the loop by explicitly returning `false`. * * @memberOf Benchmark.Suite * @param {Function} callback The function called per iteration. * @returns {Object} The suite iterated over. */ 'forEach': methodize(forEach), /** * An `Array#indexOf` like method. * * @memberOf Benchmark.Suite * @param {Mixed} value The value to search for. * @returns {Number} The index of the matched value or `-1`. */ 'indexOf': methodize(indexOf), /** * Invokes a method on all benchmarks in the suite. * * @memberOf Benchmark.Suite * @param {String|Object} name The name of the method to invoke OR options object. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. * @returns {Array} A new array of values returned from each method invoked. */ 'invoke': methodize(invoke), /** * Converts the suite of benchmarks to a string. * * @memberOf Benchmark.Suite * @param {String} [separator=','] A string to separate each element of the array. * @returns {String} The string. */ 'join': [].join, /** * An `Array#map` like method. * * @memberOf Benchmark.Suite * @param {Function} callback The function called per iteration. * @returns {Array} A new array of values returned by the callback. */ 'map': methodize(map), /** * Retrieves the value of a specified property from all benchmarks in the suite. * * @memberOf Benchmark.Suite * @param {String} property The property to pluck. * @returns {Array} A new array of property values. */ 'pluck': methodize(pluck), /** * Removes the last benchmark from the suite and returns it. * * @memberOf Benchmark.Suite * @returns {Mixed} The removed benchmark. */ 'pop': [].pop, /** * Appends benchmarks to the suite. * * @memberOf Benchmark.Suite * @returns {Number} The suite's new length. */ 'push': [].push, /** * Sorts the benchmarks of the suite. * * @memberOf Benchmark.Suite * @param {Function} [compareFn=null] A function that defines the sort order. * @returns {Object} The sorted suite. */ 'sort': [].sort, /** * An `Array#reduce` like method. * * @memberOf Benchmark.Suite * @param {Function} callback The function called per iteration. * @param {Mixed} accumulator Initial value of the accumulator. * @returns {Mixed} The accumulator. */ 'reduce': methodize(reduce), // aborts all benchmarks in the suite 'abort': abortSuite, // adds a benchmark to the suite 'add': add, // creates a new suite with cloned benchmarks 'clone': cloneSuite, // executes listeners of a specified type 'emit': emit, // creates a new suite of filtered benchmarks 'filter': filterSuite, // get listeners 'listeners': listeners, // unregister listeners 'off': off, // register listeners 'on': on, // resets all benchmarks in the suite 'reset': resetSuite, // runs all benchmarks in the suite 'run': runSuite, // array methods 'concat': concat, 'reverse': reverse, 'shift': shift, 'slice': slice, 'splice': splice, 'unshift': unshift }); /*--------------------------------------------------------------------------*/ // expose Deferred, Event and Suite extend(Benchmark, { 'Deferred': Deferred, 'Event': Event, 'Suite': Suite }); // expose Benchmark // some AMD build optimizers, like r.js, check for specific condition patterns like the following: if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { // define as an anonymous module so, through path mapping, it can be aliased define(function() { return Benchmark; }); } // check for `exports` after `define` in case a build optimizer adds an `exports` object else if (freeExports) { // in Node.js or RingoJS v0.8.0+ if (typeof module == 'object' && module && module.exports == freeExports) { (module.exports = Benchmark).Benchmark = Benchmark; } // in Narwhal or RingoJS v0.7.0- else { freeExports.Benchmark = Benchmark; } } // in a browser or Rhino else { // use square bracket notation so Closure Compiler won't munge `Benchmark` // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export window['Benchmark'] = Benchmark; } // trigger clock's lazy define early to avoid a security error if (support.air) { clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } }); } }(this)); three.js-r73/test/perf.html0000644000175500017550000000476612610076566015572 0ustar debacledebacle three.js-r73/test/unit/0000755000175500017550000000000012640542022014676 5ustar debacledebaclethree.js-r73/test/unit/extras/0000755000175500017550000000000012610076566016220 5ustar debacledebaclethree.js-r73/test/unit/extras/geometries/0000755000175500017550000000000012610076566020363 5ustar debacledebaclethree.js-r73/test/unit/extras/geometries/SphereBufferGeometry.tests.js0000644000175500017550000000257412610076566026166 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, widthSegments: 20, heightSegments: 30, phiStart: 0.5, phiLength: 1.0, thetaStart: 0.4, thetaLength: 2.0, }; var geometries; QUnit.module( "Extras - Geometries - SphereBufferGeometry", { beforeEach: function() { geometries = [ new THREE.SphereBufferGeometry(), new THREE.SphereBufferGeometry( parameters.radius ), new THREE.SphereBufferGeometry( parameters.radius, parameters.widthSegments ), new THREE.SphereBufferGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments ), new THREE.SphereBufferGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart ), new THREE.SphereBufferGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength ), new THREE.SphereBufferGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength, parameters.thetaStart ), new THREE.SphereBufferGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength, parameters.thetaStart, parameters.thetaLength ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/BoxGeometry.tests.js0000644000175500017550000000151712610076566024332 0ustar debacledebacle(function () { 'use strict'; var parameters = { width: 10, height: 20, depth: 30, widthSegments: 2, heightSegments: 3, depthSegments: 4, }; var geometries; var box, cube, boxWithSegments; QUnit.module( "Extras - Geometries - BoxGeometry", { beforeEach: function() { box = new THREE.BoxGeometry( parameters.width, parameters.height, parameters.depth ); cube = new THREE.CubeGeometry( parameters.width, parameters.height, parameters.depth ); boxWithSegments = new THREE.BoxGeometry( parameters.width, parameters.height, parameters.depth, parameters.widthSegments, parameters.heightSegments, parameters.depthSegments ); geometries = [ box, cube, boxWithSegments ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/ParametricGeometry.tests.js0000644000175500017550000000000712610076566025662 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/WireframeGeometry.tests.js0000644000175500017550000000000712610076566025514 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/PlaneBufferGeometry.tests.js0000644000175500017550000000142012610076566025764 0ustar debacledebacle(function () { 'use strict'; var parameters = { width: 10, height: 30, widthSegments: 3, heightSegments: 5 }; var geometries; QUnit.module( "Extras - Geometries - PlaneBufferGeometry", { beforeEach: function() { geometries = [ new THREE.PlaneBufferGeometry(), new THREE.PlaneBufferGeometry( parameters.width ), new THREE.PlaneBufferGeometry( parameters.width, parameters.height ), new THREE.PlaneBufferGeometry( parameters.width, parameters.height, parameters.widthSegments ), new THREE.PlaneBufferGeometry( parameters.width, parameters.height, parameters.widthSegments, parameters.heightSegments ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/TubeGeometry.tests.js0000644000175500017550000000000712610076566024472 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/LatheGeometry.tests.js0000644000175500017550000000000712610076566024630 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/TextGeometry.tests.js0000644000175500017550000000000712610076566024517 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/OctahedronGeometry.tests.js0000644000175500017550000000101112610076566025655 0ustar debacledebacle(function() { 'use strict'; var parameters = { radius: 10, detail: undefined }; var geometries; QUnit.module( "Extras - Geometries - OctahedronGeometry", { beforeEach: function() { geometries = [ new THREE.OctahedronGeometry(), new THREE.OctahedronGeometry( parameters.radius ), new THREE.OctahedronGeometry( parameters.radius, parameters.detail ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/ShapeGeometry.tests.js0000644000175500017550000000000712610076566024633 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/CircleGeometry.tests.js0000644000175500017550000000136412610076566025003 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, segments: 20, thetaStart: 0.1, thetaLength: 0.2 }; var geometries; QUnit.module( "Extras - Geometries - CircleGeometry", { beforeEach: function() { geometries = [ new THREE.CircleGeometry(), new THREE.CircleGeometry( parameters.radius ), new THREE.CircleGeometry( parameters.radius, parameters.segments ), new THREE.CircleGeometry( parameters.radius, parameters.segments, parameters.thetaStart ), new THREE.CircleGeometry( parameters.radius, parameters.segments, parameters.thetaStart, parameters.thetaLength ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/TorusKnotGeometry.tests.js0000644000175500017550000000173612610076566025555 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, tube: 20, radialSegments: 30, tubularSegments: 10, p: 3, q: 2, heightScale: 2.0 }; var geometries; QUnit.module( "Extras - Geometries - TorusKnotGeometry", { beforeEach: function() { geometries = [ new THREE.TorusKnotGeometry(), new THREE.TorusKnotGeometry( parameters.radius ), new THREE.TorusKnotGeometry( parameters.radius, parameters.tube ), new THREE.TorusKnotGeometry( parameters.radius, parameters.tube, parameters.radialSegments ), new THREE.TorusKnotGeometry( parameters.radius, parameters.tube, parameters.radialSegments, parameters.tubularSegments ), new THREE.TorusKnotGeometry( parameters.radius, parameters.tube, parameters.radialSegments, parameters.tubularSegments, parameters.p, parameters.q, parameters.heightScale ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/ExtrudeGeometry.tests.js0000644000175500017550000000000712610076566025213 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/TorusGeometry.tests.js0000644000175500017550000000160712610076566024716 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, tube: 20, radialSegments: 30, tubularSegments: 10, arc: 2.0, }; var geometries; QUnit.module( "Extras - Geometries - TorusGeometry", { beforeEach: function() { geometries = [ new THREE.TorusGeometry(), new THREE.TorusGeometry( parameters.radius ), new THREE.TorusGeometry( parameters.radius, parameters.tube ), new THREE.TorusGeometry( parameters.radius, parameters.tube, parameters.radialSegments ), new THREE.TorusGeometry( parameters.radius, parameters.tube, parameters.radialSegments, parameters.tubularSegments ), new THREE.TorusGeometry( parameters.radius, parameters.tube, parameters.radialSegments, parameters.tubularSegments, parameters.arc ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/RingGeometry.tests.js0000644000175500017550000000220112610076566024470 0ustar debacledebacle(function () { 'use strict'; var parameters = { innerRadius: 10, outerRadius: 60, thetaSegments: 12, phiSegments: 14, thetaStart: 0.1, thetaLength: 2.0 }; var geometries; QUnit.module( "Extras - Geometries - RingGeometry", { beforeEach: function() { geometries = [ new THREE.RingGeometry(), new THREE.RingGeometry( parameters.innerRadius ), new THREE.RingGeometry( parameters.innerRadius, parameters.outerRadius ), new THREE.RingGeometry( parameters.innerRadius, parameters.outerRadius, parameters.thetaSegments ), new THREE.RingGeometry( parameters.innerRadius, parameters.outerRadius, parameters.thetaSegments, parameters.phiSegments ), new THREE.RingGeometry( parameters.innerRadius, parameters.outerRadius, parameters.thetaSegments, parameters.phiSegments, parameters.thetaStart ), new THREE.RingGeometry( parameters.innerRadius, parameters.outerRadius, parameters.thetaSegments, parameters.phiSegments, parameters.thetaStart, parameters.thetaLength ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/PolyhedronGeometry.tests.js0000644000175500017550000000000712610076566025716 0ustar debacledebacle// TODOthree.js-r73/test/unit/extras/geometries/PlaneGeometry.tests.js0000644000175500017550000000135412610076566024640 0ustar debacledebacle(function () { 'use strict'; var parameters = { width: 10, height: 30, widthSegments: 3, heightSegments: 5 }; var geometries; QUnit.module( "Extras - Geometries - PlaneGeometry", { beforeEach: function() { geometries = [ new THREE.PlaneGeometry(), new THREE.PlaneGeometry( parameters.width ), new THREE.PlaneGeometry( parameters.width, parameters.height ), new THREE.PlaneGeometry( parameters.width, parameters.height, parameters.widthSegments ), new THREE.PlaneGeometry( parameters.width, parameters.height, parameters.widthSegments, parameters.heightSegments ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/CylinderGeometry.tests.js0000644000175500017550000000313012610076566025344 0ustar debacledebacle(function () { 'use strict'; var parameters = { radiusTop: 10, radiusBottom: 20, height: 30, radialSegments: 20, heightSegments: 30, openEnded: true, thetaStart: 0.1, thetaLength: 2.0, }; var geometries; QUnit.module( "Extras - Geometries - CylinderGeometry", { beforeEach: function() { geometries = [ new THREE.CylinderGeometry(), new THREE.CylinderGeometry( parameters.radiusTop ), new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom ), new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom, parameters.height ), new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments ), new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments, parameters.heightSegments ), new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments, parameters.heightSegments, parameters.openEnded ), new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments, parameters.heightSegments, parameters.openEnded, parameters.thetaStart ), new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments, parameters.heightSegments, parameters.openEnded, parameters.thetaStart, parameters.thetaLength ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/SphereGeometry.tests.js0000644000175500017550000000250612610076566025027 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, widthSegments: 20, heightSegments: 30, phiStart: 0.5, phiLength: 1.0, thetaStart: 0.4, thetaLength: 2.0, }; var geometries; QUnit.module( "Extras - Geometries - SphereGeometry", { beforeEach: function() { geometries = [ new THREE.SphereGeometry(), new THREE.SphereGeometry( parameters.radius ), new THREE.SphereGeometry( parameters.radius, parameters.widthSegments ), new THREE.SphereGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments ), new THREE.SphereGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart ), new THREE.SphereGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength ), new THREE.SphereGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength, parameters.thetaStart ), new THREE.SphereGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength, parameters.thetaStart, parameters.thetaLength ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/CircleBufferGeometry.tests.js0000644000175500017550000000143012610076566026127 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, segments: 20, thetaStart: 0.1, thetaLength: 0.2 }; var geometries; QUnit.module( "Extras - Geometries - CircleBufferGeometry", { beforeEach: function() { geometries = [ new THREE.CircleBufferGeometry(), new THREE.CircleBufferGeometry( parameters.radius ), new THREE.CircleBufferGeometry( parameters.radius, parameters.segments ), new THREE.CircleBufferGeometry( parameters.radius, parameters.segments, parameters.thetaStart ), new THREE.CircleBufferGeometry( parameters.radius, parameters.segments, parameters.thetaStart, parameters.thetaLength ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/IcosahedronGeometry.tests.js0000644000175500017550000000101612610076566026032 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, detail: undefined }; var geometries; QUnit.module( "Extras - Geometries - IcosahedronGeometry", { beforeEach: function() { geometries = [ new THREE.IcosahedronGeometry(), new THREE.IcosahedronGeometry( parameters.radius ), new THREE.IcosahedronGeometry( parameters.radius, parameters.detail ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/DodecahedronGeometry.tests.js0000644000175500017550000000102212610076566026150 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, detail: undefined }; var geometries; QUnit.module( "Extras - Geometries - DodecahedronGeometry", { beforeEach: function() { geometries = [ new THREE.DodecahedronGeometry(), new THREE.DodecahedronGeometry( parameters.radius ), new THREE.DodecahedronGeometry( parameters.radius, parameters.detail ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/geometries/TetrahedronGeometry.tests.js0000644000175500017550000000101612610076566026053 0ustar debacledebacle(function () { 'use strict'; var parameters = { radius: 10, detail: undefined }; var geometries; QUnit.module( "Extras - Geometries - TetrahedronGeometry", { beforeEach: function() { geometries = [ new THREE.TetrahedronGeometry(), new THREE.TetrahedronGeometry( parameters.radius ), new THREE.TetrahedronGeometry( parameters.radius, parameters.detail ), ]; } }); QUnit.test( "standard geometry tests", function( assert ) { runStdGeometryTests( assert, geometries ); }); })(); three.js-r73/test/unit/extras/ImageUtils.test.js0000644000175500017550000000341112610076566021576 0ustar debacledebacleQUnit.module( "ImageLoader", { beforeEach: function() { THREE.Cache.clear(); } }); var good_url = '../../examples/textures/sprite.png'; var bad_url = 'url_not_found'; QUnit.test( "test load handler", function( assert ) { var done = assert.async(); THREE.ImageUtils.loadTexture( good_url, undefined, function ( tex ) { assert.success( "load handler should be called" ); assert.ok( tex, "texture is defined" ); assert.ok( tex.image, "texture.image is defined" ); done(); }, function () { assert.fail( "error handler should not be called" ); done(); }); }); QUnit.test( "test error handler", function( assert ) { var done = assert.async(); THREE.ImageUtils.loadTexture( bad_url, undefined, function () { assert.fail( "load handler should not be called" ); done(); }, function ( event ) { assert.success( "error handler should be called" ); assert.ok( event.type === 'error', "should have error event" ); done(); }); }); QUnit.test( "test cached texture", function( assert ) { var done = assert.async(); var rtex1 = THREE.ImageUtils.loadTexture( good_url, undefined, function ( tex1 ) { assert.ok( rtex1.image !== undefined, "texture 1 image is loaded" ); assert.equal( rtex1, tex1, "texture 1 callback is equal to return" ); var rtex2 = THREE.ImageUtils.loadTexture( good_url, undefined, function ( tex2 ) { assert.ok( rtex2 !== undefined, "cached callback is async" ); assert.ok( rtex2.image !== undefined, "texture 2 image is loaded" ); assert.equal( rtex2, tex2, "texture 2 callback is equal to return" ); done(); }); assert.ok( rtex2, "texture 2 return is defined" ); }); assert.ok( rtex1, "texture 1 return is defined" ); assert.ok( rtex1.image === undefined, "texture 1 image is not loaded" ); }); three.js-r73/test/unit/cameras/0000755000175500017550000000000012610076566016325 5ustar debacledebaclethree.js-r73/test/unit/cameras/PerspectiveCamera.js0000644000175500017550000000257012610076566022271 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "PerspectiveCamera" ); test( "updateProjectionMatrix", function() { var cam = new THREE.PerspectiveCamera( 75, 16 / 9, 0.1, 300.0 ); // updateProjectionMatrix is called in contructor var m = cam.projectionMatrix; // perspective projection is given my the 4x4 Matrix // 2n/r-l 0 l+r/r-l 0 // 0 2n/t-b t+b/t-b 0 // 0 0 -(f+n/f-n) -(2fn/f-n) // 0 0 -1 0 // this matrix was calculated by hand via glMatrix.perspective(75, 16 / 9, 0.1, 300.0, pMatrix) // to get a reference matrix from plain WebGL var reference = new THREE.Matrix4().set( 0.7330642938613892, 0, 0, 0, 0, 1.3032253980636597, 0, 0, 0, 0, -1.000666856765747, -0.2000666856765747, 0, 0, -1, 0 ); ok( reference.equals(m) ); }); test( "clone", function() { var near = 1, far = 3, bottom = -1, top = 1, aspect = 16 / 9, fov = 90; var cam = new THREE.PerspectiveCamera( fov, aspect, near, far ); var clonedCam = cam.clone(); ok( cam.fov === clonedCam.fov , "fov is equal" ); ok( cam.aspect === clonedCam.aspect , "aspect is equal" ); ok( cam.near === clonedCam.near , "near is equal" ); ok( cam.far === clonedCam.far , "far is equal" ); ok( cam.zoom === clonedCam.zoom , "zoom is equal" ); ok( cam.projectionMatrix.equals(clonedCam.projectionMatrix) , "projectionMatrix is equal" ); }); three.js-r73/test/unit/cameras/OrthographicCamera.js0000644000175500017550000000314512610076566022430 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "OrthographicCamera" ); test( "updateProjectionMatrix", function() { var left = -1, right = 1, top = 1, bottom = -1, near = 1, far = 3; cam = new THREE.OrthographicCamera(left, right, top, bottom, near, far); // updateProjectionMatrix is called in contructor var pMatrix = cam.projectionMatrix.elements; // orthographic projection is given my the 4x4 Matrix // 2/r-l 0 0 -(l+r/r-l) // 0 2/t-b 0 -(t+b/t-b) // 0 0 -2/f-n -(f+n/f-n) // 0 0 0 1 ok( pMatrix[0] === 2 / ( right - left ), "m[0,0] === 2 / (r - l)" ); ok( pMatrix[5] === 2 / ( top - bottom ), "m[1,1] === 2 / (t - b)" ); ok( pMatrix[10] === -2 / ( far - near ), "m[2,2] === -2 / (f - n)" ); ok( pMatrix[12] === - ( ( right + left ) / ( right - left ) ), "m[3,0] === -(r+l/r-l)" ); ok( pMatrix[13] === - ( ( top + bottom ) / ( top - bottom ) ), "m[3,1] === -(t+b/b-t)" ); ok( pMatrix[14] === - ( ( far + near ) / ( far - near ) ), "m[3,2] === -(f+n/f-n)" ); }); test( "clone", function() { var left = -1.5, right = 1.5, top = 1, bottom = -1, near = 0.1, far = 42; var cam = new THREE.OrthographicCamera(left, right, top, bottom, near, far); var clonedCam = cam.clone(); ok( cam.left === clonedCam.left , "left is equal" ); ok( cam.right === clonedCam.right , "right is equal" ); ok( cam.top === clonedCam.top , "top is equal" ); ok( cam.bottom === clonedCam.bottom , "bottom is equal" ); ok( cam.near === clonedCam.near , "near is equal" ); ok( cam.far === clonedCam.far , "far is equal" ); ok( cam.zoom === clonedCam.zoom , "zoom is equal" ); }); three.js-r73/test/unit/cameras/Camera.js0000644000175500017550000000143312610076566020054 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "Camera" ); test( "lookAt", function() { var cam = new THREE.Camera(); cam.lookAt(new THREE.Vector3(0, 1, -1)); ok( cam.rotation.x * (180 / Math.PI) === 45 , "x is equal" ); }); test( "clone", function() { var cam = new THREE.Camera(); // fill the matrices with any nonsense values just to see if they get copied cam.matrixWorldInverse.set( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ); cam.projectionMatrix.set( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ); var clonedCam = cam.clone(); ok( cam.matrixWorldInverse.equals(clonedCam.matrixWorldInverse) , "matrixWorldInverse is equal" ); ok( cam.projectionMatrix.equals(clonedCam.projectionMatrix) , "projectionMatrix is equal" ); }); three.js-r73/test/unit/geometry/0000755000175500017550000000000012610076566016545 5ustar debacledebaclethree.js-r73/test/unit/geometry/EdgesGeometry.js0000644000175500017550000001151612610076566021652 0ustar debacledebaclemodule( "EdgesGeometry" ); var DEBUG = false; var vertList = [ new THREE.Vector3(0, 0, 0), new THREE.Vector3(1, 0, 0), new THREE.Vector3(1, 1, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 1, 1), ]; test( "singularity", function() { testEdges( vertList, [1, 1, 1], 0 ); }); test( "needle", function() { testEdges( vertList, [0, 0, 1], 0 ); }); test( "single triangle", function() { testEdges( vertList, [0, 1, 2], 3 ); }); test( "two isolated triangles", function() { var vertList = [ new THREE.Vector3(0, 0, 0), new THREE.Vector3(1, 0, 0), new THREE.Vector3(1, 1, 0), new THREE.Vector3(0, 0, 1), new THREE.Vector3(1, 0, 1), new THREE.Vector3(1, 1, 1), ]; testEdges( vertList, [0, 1, 2, 3, 4, 5], 6 ); }); test( "two flat triangles", function() { testEdges( vertList, [0, 1, 2, 0, 2, 3], 4 ); }); test( "two flat triangles, inverted", function() { testEdges( vertList, [0, 1, 2, 0, 3, 2], 5 ); }); test( "two non-coplanar triangles", function() { testEdges( vertList, [0, 1, 2, 0, 4, 2], 5 ); }); test( "three triangles, coplanar first", function() { testEdges( vertList, [0, 1, 2, 0, 2, 3, 0, 4, 2], 7 ); }); test( "three triangles, coplanar last", function() { testEdges( vertList, [0, 1, 2, 0, 4, 2, 0, 2, 3], 6 ); // Should be 7 }); test( "tetrahedron", function() { testEdges( vertList, [0, 1, 2, 0, 1, 4, 0, 4, 2, 1, 2, 4], 6 ); }); // // HELPERS // function testEdges ( vertList, idxList, numAfter ) { var geoms = createGeometries ( vertList, idxList ); for ( var i = 0 ; i < geoms.length ; i ++ ) { var geom = geoms[i]; var numBefore = idxList.length; equal( countEdges (geom), numBefore, "Edges before!" ); var egeom = new THREE.EdgesGeometry( geom ); equal( countEdges (egeom), numAfter, "Edges after!" ); output( geom, egeom ); } } function createGeometries ( vertList, idxList ) { var geomIB = createIndexedBufferGeometry ( vertList, idxList ); var geom = new THREE.Geometry().fromBufferGeometry( geomIB ); var geomB = new THREE.BufferGeometry().fromGeometry( geom ); var geomDC = addDrawCalls( geomIB.clone() ); return [ geom, geomB, geomIB, geomDC ]; } function createIndexedBufferGeometry ( vertList, idxList ) { var geom = new THREE.BufferGeometry(); var indexTable = []; var numTris = idxList.length / 3; var numVerts = 0; var indices = new Uint32Array( numTris * 3 ); var vertices = new Float32Array( vertList.length * 3 ); for ( var i = 0; i < numTris; i ++ ) { for ( var j = 0; j < 3; j ++ ) { var idx = idxList[ 3 * i + j ]; if ( indexTable[ idx ] === undefined ) { var v = vertList[ idx ]; vertices[ 3 * numVerts ] = v.x; vertices[ 3 * numVerts + 1 ] = v.y; vertices[ 3 * numVerts + 2 ] = v.z; indexTable[ idx ] = numVerts; numVerts ++; } indices[ 3 * i + j ] = indexTable[ idx ] ; } } vertices = vertices.subarray( 0, 3 * numVerts ); geom.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) ); geom.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); geom.computeFaceNormals(); return geom; } function addDrawCalls ( geometry ) { var numTris = geometry.getAttribute( 'index' ).count / 3; var offset = 0; for ( var i = 0 ; i < numTris; i ++ ) { var start = i * 3; var count = 3; geometry.addDrawCall ( start, count, offset ); } return geometry; } function countEdges ( geom ) { if ( geom instanceof THREE.EdgesGeometry ) { return geom.getAttribute( 'position' ).count / 2; } if ( geom.faces !== undefined ) { return geom.faces.length * 3; } var indices = geom.getAttribute( 'index' ); if ( indices !== undefined ) { return indices.count; } return geom.getAttribute( 'position' ).count; } // // DEBUGGING // var renderer; var camera; var scene = new THREE.Scene(); var xoffset = 0; function output ( geom, egeom ) { if ( DEBUG !== true ) return; if ( !renderer ) initDebug(); var mesh = new THREE.Mesh( geom, undefined ); var edges = new THREE.LineSegments( egeom, new THREE.LineBasicMaterial( { color: 'black' } ) ); mesh.position.setX( xoffset ); edges.position.setX( xoffset ++ ); scene.add(mesh); scene.add(edges); if (scene.children.length % 8 === 0) { xoffset += 2; } } function initDebug () { renderer = new THREE.WebGLRenderer({ antialias: true }); var width = 600; var height = 480; renderer.setSize(width, height); renderer.setClearColor( 0xCCCCCC ); camera = new THREE.PerspectiveCamera(45, width / height, 1, 100); camera.position.x = 30; camera.position.z = 40; camera.lookAt(new THREE.Vector3(30, 0, 0)); document.body.appendChild(renderer.domElement); var controls = new THREE.OrbitControls( camera, renderer.domElement ); controls.target = new THREE.Vector3(30, 0, 0); animate(); function animate() { requestAnimationFrame( animate ); controls.update(); renderer.render( scene, camera ); } } three.js-r73/test/unit/unittests_sources.html0000644000175500017550000000376612610076566021421 0ustar debacledebacle ThreeJS Unit Tests - Using Files in /src
three.js-r73/test/unit/qunit-1.18.0.js0000644000175500017550000034207312610076566017144 0ustar debacledebacle/*! * QUnit 1.18.0 * http://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2015-04-03T10:23Z */ (function( window ) { var QUnit, config, onErrorFnPrev, loggingCallbacks = {}, fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ), toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, // Keep a local reference to Date (GH-283) Date = window.Date, now = Date.now || function() { return new Date().getTime(); }, globalStartCalled = false, runStarted = false, setTimeout = window.setTimeout, clearTimeout = window.clearTimeout, defined = { document: window.document !== undefined, setTimeout: window.setTimeout !== undefined, sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); sessionStorage.removeItem( x ); return true; } catch ( e ) { return false; } }()) }, /** * Provides a normalized error string, correcting an issue * with IE 7 (and prior) where Error.prototype.toString is * not properly implemented * * Based on http://es5.github.com/#x15.11.4.4 * * @param {String|Error} error * @return {String} error message */ errorString = function( error ) { var name, message, errorString = error.toString(); if ( errorString.substring( 0, 7 ) === "[object" ) { name = error.name ? error.name.toString() : "Error"; message = error.message ? error.message.toString() : ""; if ( name && message ) { return name + ": " + message; } else if ( name ) { return name; } else if ( message ) { return message; } else { return "Error"; } } else { return errorString; } }, /** * Makes a clone of an object using only Array or Object as base, * and copies over the own enumerable properties. * * @param {Object} obj * @return {Object} New object with only the own properties (recursively). */ objectValues = function( obj ) { var key, val, vals = QUnit.is( "array", obj ) ? [] : {}; for ( key in obj ) { if ( hasOwn.call( obj, key ) ) { val = obj[ key ]; vals[ key ] = val === Object( val ) ? objectValues( val ) : val; } } return vals; }; QUnit = {}; /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ config = { // The queue of tests to run queue: [], // block until document ready blocking: true, // by default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, // by default, modify document.title when suite is done altertitle: true, // by default, scroll to top of the page when suite is done scrolltop: true, // when enabled, all tests must call expect() requireExpects: false, // depth up-to which object will be dumped maxDepth: 0, // add checkboxes that are persisted in the query-string // when enabled, the id is set to `true` as a `QUnit.config` property urlConfig: [ { id: "hidepassed", label: "Hide passed tests", tooltip: "Only show tests and assertions that fail. Stored as query-strings." }, { id: "noglobals", label: "Check for Globals", tooltip: "Enabling this will test if any test introduces new properties on the " + "`window` object. Stored as query-strings." }, { id: "notrycatch", label: "No try-catch", tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + "exceptions in IE reasonable. Stored as query-strings." } ], // Set of all modules. modules: [], // The first unnamed module currentModule: { name: "", tests: [] }, callbacks: {} }; // Push a loose unnamed module to the modules collection config.modules.push( config.currentModule ); // Initialize more QUnit.config and QUnit.urlParams (function() { var i, current, location = window.location || { search: "", protocol: "file:" }, params = location.search.slice( 1 ).split( "&" ), length = params.length, urlParams = {}; if ( params[ 0 ] ) { for ( i = 0; i < length; i++ ) { current = params[ i ].split( "=" ); current[ 0 ] = decodeURIComponent( current[ 0 ] ); // allow just a key to turn on a flag, e.g., test.html?noglobals current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; if ( urlParams[ current[ 0 ] ] ) { urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); } else { urlParams[ current[ 0 ] ] = current[ 1 ]; } } } if ( urlParams.filter === true ) { delete urlParams.filter; } QUnit.urlParams = urlParams; // String search anywhere in moduleName+testName config.filter = urlParams.filter; if ( urlParams.maxDepth ) { config.maxDepth = parseInt( urlParams.maxDepth, 10 ) === -1 ? Number.POSITIVE_INFINITY : urlParams.maxDepth; } config.testId = []; if ( urlParams.testId ) { // Ensure that urlParams.testId is an array urlParams.testId = decodeURIComponent( urlParams.testId ).split( "," ); for ( i = 0; i < urlParams.testId.length; i++ ) { config.testId.push( urlParams.testId[ i ] ); } } // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === "file:"; // Expose the current QUnit version QUnit.version = "1.18.0"; }()); // Root QUnit object. // `QUnit` initialized at top of scope extend( QUnit, { // call on start of module test to prepend name to all tests module: function( name, testEnvironment ) { var currentModule = { name: name, testEnvironment: testEnvironment, tests: [] }; // DEPRECATED: handles setup/teardown functions, // beforeEach and afterEach should be used instead if ( testEnvironment && testEnvironment.setup ) { testEnvironment.beforeEach = testEnvironment.setup; delete testEnvironment.setup; } if ( testEnvironment && testEnvironment.teardown ) { testEnvironment.afterEach = testEnvironment.teardown; delete testEnvironment.teardown; } config.modules.push( currentModule ); config.currentModule = currentModule; }, // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0. asyncTest: function( testName, expected, callback ) { if ( arguments.length === 2 ) { callback = expected; expected = null; } QUnit.test( testName, expected, callback, true ); }, test: function( testName, expected, callback, async ) { var test; if ( arguments.length === 2 ) { callback = expected; expected = null; } test = new Test({ testName: testName, expected: expected, async: async, callback: callback }); test.queue(); }, skip: function( testName ) { var test = new Test({ testName: testName, skip: true }); test.queue(); }, // DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0. // In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior. start: function( count ) { var globalStartAlreadyCalled = globalStartCalled; if ( !config.current ) { globalStartCalled = true; if ( runStarted ) { throw new Error( "Called start() outside of a test context while already started" ); } else if ( globalStartAlreadyCalled || count > 1 ) { throw new Error( "Called start() outside of a test context too many times" ); } else if ( config.autostart ) { throw new Error( "Called start() outside of a test context when " + "QUnit.config.autostart was true" ); } else if ( !config.pageLoaded ) { // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it config.autostart = true; return; } } else { // If a test is running, adjust its semaphore config.current.semaphore -= count || 1; // Don't start until equal number of stop-calls if ( config.current.semaphore > 0 ) { return; } // throw an Error if start is called more often than stop if ( config.current.semaphore < 0 ) { config.current.semaphore = 0; QUnit.pushFailure( "Called start() while already started (test's semaphore was 0 already)", sourceFromStacktrace( 2 ) ); return; } } resumeProcessing(); }, // DEPRECATED: QUnit.stop() will be removed in QUnit 2.0. stop: function( count ) { // If there isn't a test running, don't allow QUnit.stop() to be called if ( !config.current ) { throw new Error( "Called stop() outside of a test context" ); } // If a test is running, adjust its semaphore config.current.semaphore += count || 1; pauseProcessing(); }, config: config, // Safe object type checking is: function( type, obj ) { return QUnit.objectType( obj ) === type; }, objectType: function( obj ) { if ( typeof obj === "undefined" ) { return "undefined"; } // Consider: typeof null === object if ( obj === null ) { return "null"; } var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ), type = match && match[ 1 ] || ""; switch ( type ) { case "Number": if ( isNaN( obj ) ) { return "nan"; } return "number"; case "String": case "Boolean": case "Array": case "Date": case "RegExp": case "Function": return type.toLowerCase(); } if ( typeof obj === "object" ) { return "object"; } return undefined; }, extend: extend, load: function() { config.pageLoaded = true; // Initialize the configuration options extend( config, { stats: { all: 0, bad: 0 }, moduleStats: { all: 0, bad: 0 }, started: 0, updateRate: 1000, autostart: true, filter: "" }, true ); config.blocking = false; if ( config.autostart ) { resumeProcessing(); } } }); // Register logging callbacks (function() { var i, l, key, callbacks = [ "begin", "done", "log", "testStart", "testDone", "moduleStart", "moduleDone" ]; function registerLoggingCallback( key ) { var loggingCallback = function( callback ) { if ( QUnit.objectType( callback ) !== "function" ) { throw new Error( "QUnit logging methods require a callback function as their first parameters." ); } config.callbacks[ key ].push( callback ); }; // DEPRECATED: This will be removed on QUnit 2.0.0+ // Stores the registered functions allowing restoring // at verifyLoggingCallbacks() if modified loggingCallbacks[ key ] = loggingCallback; return loggingCallback; } for ( i = 0, l = callbacks.length; i < l; i++ ) { key = callbacks[ i ]; // Initialize key collection of logging callback if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) { config.callbacks[ key ] = []; } QUnit[ key ] = registerLoggingCallback( key ); } })(); // `onErrorFnPrev` initialized at top of scope // Preserve other handlers onErrorFnPrev = window.onerror; // Cover uncaught exceptions // Returning true will suppress the default browser handler, // returning false will let it run. window.onerror = function( error, filePath, linerNr ) { var ret = false; if ( onErrorFnPrev ) { ret = onErrorFnPrev( error, filePath, linerNr ); } // Treat return value as window.onerror itself does, // Only do our handling if not suppressed. if ( ret !== true ) { if ( QUnit.config.current ) { if ( QUnit.config.current.ignoreGlobalErrors ) { return true; } QUnit.pushFailure( error, filePath + ":" + linerNr ); } else { QUnit.test( "global failure", extend(function() { QUnit.pushFailure( error, filePath + ":" + linerNr ); }, { validTest: true } ) ); } return false; } return ret; }; function done() { var runtime, passed; config.autorun = true; // Log the last module results if ( config.previousModule ) { runLoggingCallbacks( "moduleDone", { name: config.previousModule.name, tests: config.previousModule.tests, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all, runtime: now() - config.moduleStats.started }); } delete config.previousModule; runtime = now() - config.started; passed = config.stats.all - config.stats.bad; runLoggingCallbacks( "done", { failed: config.stats.bad, passed: passed, total: config.stats.all, runtime: runtime }); } // Doesn't support IE6 to IE9, it will return undefined on these browsers // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { offset = offset === undefined ? 4 : offset; var stack, include, i; if ( e.stack ) { stack = e.stack.split( "\n" ); if ( /^error$/i.test( stack[ 0 ] ) ) { stack.shift(); } if ( fileName ) { include = []; for ( i = offset; i < stack.length; i++ ) { if ( stack[ i ].indexOf( fileName ) !== -1 ) { break; } include.push( stack[ i ] ); } if ( include.length ) { return include.join( "\n" ); } } return stack[ offset ]; // Support: Safari <=6 only } else if ( e.sourceURL ) { // exclude useless self-reference for generated Error objects if ( /qunit.js$/.test( e.sourceURL ) ) { return; } // for actual exceptions, this is useful return e.sourceURL + ":" + e.line; } } function sourceFromStacktrace( offset ) { var error = new Error(); // Support: Safari <=7 only, IE <=10 - 11 only // Not all browsers generate the `stack` property for `new Error()`, see also #636 if ( !error.stack ) { try { throw error; } catch ( err ) { error = err; } } return extractStacktrace( error, offset ); } function synchronize( callback, last ) { if ( QUnit.objectType( callback ) === "array" ) { while ( callback.length ) { synchronize( callback.shift() ); } return; } config.queue.push( callback ); if ( config.autorun && !config.blocking ) { process( last ); } } function process( last ) { function next() { process( last ); } var start = now(); config.depth = ( config.depth || 0 ) + 1; while ( config.queue.length && !config.blocking ) { if ( !defined.setTimeout || config.updateRate <= 0 || ( ( now() - start ) < config.updateRate ) ) { if ( config.current ) { // Reset async tracking for each phase of the Test lifecycle config.current.usedAsync = false; } config.queue.shift()(); } else { setTimeout( next, 13 ); break; } } config.depth--; if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { done(); } } function begin() { var i, l, modulesLog = []; // If the test run hasn't officially begun yet if ( !config.started ) { // Record the time of the test run's beginning config.started = now(); verifyLoggingCallbacks(); // Delete the loose unnamed module if unused. if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) { config.modules.shift(); } // Avoid unnecessary information by not logging modules' test environments for ( i = 0, l = config.modules.length; i < l; i++ ) { modulesLog.push({ name: config.modules[ i ].name, tests: config.modules[ i ].tests }); } // The test run is officially beginning now runLoggingCallbacks( "begin", { totalTests: Test.count, modules: modulesLog }); } config.blocking = false; process( true ); } function resumeProcessing() { runStarted = true; // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.) if ( defined.setTimeout ) { setTimeout(function() { if ( config.current && config.current.semaphore > 0 ) { return; } if ( config.timeout ) { clearTimeout( config.timeout ); } begin(); }, 13 ); } else { begin(); } } function pauseProcessing() { config.blocking = true; if ( config.testTimeout && defined.setTimeout ) { clearTimeout( config.timeout ); config.timeout = setTimeout(function() { if ( config.current ) { config.current.semaphore = 0; QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) ); } else { throw new Error( "Test timed out" ); } resumeProcessing(); }, config.testTimeout ); } } function saveGlobal() { config.pollution = []; if ( config.noglobals ) { for ( var key in window ) { if ( hasOwn.call( window, key ) ) { // in Opera sometimes DOM element ids show up here, ignore them if ( /^qunit-test-output/.test( key ) ) { continue; } config.pollution.push( key ); } } } } function checkPollution() { var newGlobals, deletedGlobals, old = config.pollution; saveGlobal(); newGlobals = diff( config.pollution, old ); if ( newGlobals.length > 0 ) { QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) ); } deletedGlobals = diff( old, config.pollution ); if ( deletedGlobals.length > 0 ) { QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) ); } } // returns a new Array with the elements that are in a but not in b function diff( a, b ) { var i, j, result = a.slice(); for ( i = 0; i < result.length; i++ ) { for ( j = 0; j < b.length; j++ ) { if ( result[ i ] === b[ j ] ) { result.splice( i, 1 ); i--; break; } } } return result; } function extend( a, b, undefOnly ) { for ( var prop in b ) { if ( hasOwn.call( b, prop ) ) { // Avoid "Member not found" error in IE8 caused by messing with window.constructor if ( !( prop === "constructor" && a === window ) ) { if ( b[ prop ] === undefined ) { delete a[ prop ]; } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) { a[ prop ] = b[ prop ]; } } } } return a; } function runLoggingCallbacks( key, args ) { var i, l, callbacks; callbacks = config.callbacks[ key ]; for ( i = 0, l = callbacks.length; i < l; i++ ) { callbacks[ i ]( args ); } } // DEPRECATED: This will be removed on 2.0.0+ // This function verifies if the loggingCallbacks were modified by the user // If so, it will restore it, assign the given callback and print a console warning function verifyLoggingCallbacks() { var loggingCallback, userCallback; for ( loggingCallback in loggingCallbacks ) { if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) { userCallback = QUnit[ loggingCallback ]; // Restore the callback function QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ]; // Assign the deprecated given callback QUnit[ loggingCallback ]( userCallback ); if ( window.console && window.console.warn ) { window.console.warn( "QUnit." + loggingCallback + " was replaced with a new value.\n" + "Please, check out the documentation on how to apply logging callbacks.\n" + "Reference: http://api.qunitjs.com/category/callbacks/" ); } } } } // from jquery.js function inArray( elem, array ) { if ( array.indexOf ) { return array.indexOf( elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; } function Test( settings ) { var i, l; ++Test.count; extend( this, settings ); this.assertions = []; this.semaphore = 0; this.usedAsync = false; this.module = config.currentModule; this.stack = sourceFromStacktrace( 3 ); // Register unique strings for ( i = 0, l = this.module.tests; i < l.length; i++ ) { if ( this.module.tests[ i ].name === this.testName ) { this.testName += " "; } } this.testId = generateHash( this.module.name, this.testName ); this.module.tests.push({ name: this.testName, testId: this.testId }); if ( settings.skip ) { // Skipped tests will fully ignore any sent callback this.callback = function() {}; this.async = false; this.expected = 0; } else { this.assert = new Assert( this ); } } Test.count = 0; Test.prototype = { before: function() { if ( // Emit moduleStart when we're switching from one module to another this.module !== config.previousModule || // They could be equal (both undefined) but if the previousModule property doesn't // yet exist it means this is the first test in a suite that isn't wrapped in a // module, in which case we'll just emit a moduleStart event for 'undefined'. // Without this, reporters can get testStart before moduleStart which is a problem. !hasOwn.call( config, "previousModule" ) ) { if ( hasOwn.call( config, "previousModule" ) ) { runLoggingCallbacks( "moduleDone", { name: config.previousModule.name, tests: config.previousModule.tests, failed: config.moduleStats.bad, passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all, runtime: now() - config.moduleStats.started }); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0, started: now() }; runLoggingCallbacks( "moduleStart", { name: this.module.name, tests: this.module.tests }); } config.current = this; this.testEnvironment = extend( {}, this.module.testEnvironment ); delete this.testEnvironment.beforeEach; delete this.testEnvironment.afterEach; this.started = now(); runLoggingCallbacks( "testStart", { name: this.testName, module: this.module.name, testId: this.testId }); if ( !config.pollution ) { saveGlobal(); } }, run: function() { var promise; config.current = this; if ( this.async ) { QUnit.stop(); } this.callbackStarted = now(); if ( config.notrycatch ) { promise = this.callback.call( this.testEnvironment, this.assert ); this.resolvePromise( promise ); return; } try { promise = this.callback.call( this.testEnvironment, this.assert ); this.resolvePromise( promise ); } catch ( e ) { this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); // else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking if ( config.blocking ) { QUnit.start(); } } }, after: function() { checkPollution(); }, queueHook: function( hook, hookName ) { var promise, test = this; return function runHook() { config.current = test; if ( config.notrycatch ) { promise = hook.call( test.testEnvironment, test.assert ); test.resolvePromise( promise, hookName ); return; } try { promise = hook.call( test.testEnvironment, test.assert ); test.resolvePromise( promise, hookName ); } catch ( error ) { test.pushFailure( hookName + " failed on " + test.testName + ": " + ( error.message || error ), extractStacktrace( error, 0 ) ); } }; }, // Currently only used for module level hooks, can be used to add global level ones hooks: function( handler ) { var hooks = []; // Hooks are ignored on skipped tests if ( this.skip ) { return hooks; } if ( this.module.testEnvironment && QUnit.objectType( this.module.testEnvironment[ handler ] ) === "function" ) { hooks.push( this.queueHook( this.module.testEnvironment[ handler ], handler ) ); } return hooks; }, finish: function() { config.current = this; if ( config.requireExpects && this.expected === null ) { this.pushFailure( "Expected number of assertions to be defined, but expect() was " + "not called.", this.stack ); } else if ( this.expected !== null && this.expected !== this.assertions.length ) { this.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); } else if ( this.expected === null && !this.assertions.length ) { this.pushFailure( "Expected at least one assertion, but none were run - call " + "expect(0) to accept zero assertions.", this.stack ); } var i, bad = 0; this.runtime = now() - this.started; config.stats.all += this.assertions.length; config.moduleStats.all += this.assertions.length; for ( i = 0; i < this.assertions.length; i++ ) { if ( !this.assertions[ i ].result ) { bad++; config.stats.bad++; config.moduleStats.bad++; } } runLoggingCallbacks( "testDone", { name: this.testName, module: this.module.name, skipped: !!this.skip, failed: bad, passed: this.assertions.length - bad, total: this.assertions.length, runtime: this.runtime, // HTML Reporter use assertions: this.assertions, testId: this.testId, // DEPRECATED: this property will be removed in 2.0.0, use runtime instead duration: this.runtime }); // QUnit.reset() is deprecated and will be replaced for a new // fixture reset function on QUnit 2.0/2.1. // It's still called here for backwards compatibility handling QUnit.reset(); config.current = undefined; }, queue: function() { var bad, test = this; if ( !this.valid() ) { return; } function run() { // each of these can by async synchronize([ function() { test.before(); }, test.hooks( "beforeEach" ), function() { test.run(); }, test.hooks( "afterEach" ).reverse(), function() { test.after(); }, function() { test.finish(); } ]); } // `bad` initialized at top of scope // defer when previous test run passed, if storage is available bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName ); if ( bad ) { run(); } else { synchronize( run, true ); } }, push: function( result, actual, expected, message ) { var source, details = { module: this.module.name, name: this.testName, result: result, message: message, actual: actual, expected: expected, testId: this.testId, runtime: now() - this.started }; if ( !result ) { source = sourceFromStacktrace(); if ( source ) { details.source = source; } } runLoggingCallbacks( "log", details ); this.assertions.push({ result: !!result, message: message }); }, pushFailure: function( message, source, actual ) { if ( !this instanceof Test ) { throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace( 2 ) ); } var details = { module: this.module.name, name: this.testName, result: false, message: message || "error", actual: actual || null, testId: this.testId, runtime: now() - this.started }; if ( source ) { details.source = source; } runLoggingCallbacks( "log", details ); this.assertions.push({ result: false, message: message }); }, resolvePromise: function( promise, phase ) { var then, message, test = this; if ( promise != null ) { then = promise.then; if ( QUnit.objectType( then ) === "function" ) { QUnit.stop(); then.call( promise, QUnit.start, function( error ) { message = "Promise rejected " + ( !phase ? "during" : phase.replace( /Each$/, "" ) ) + " " + test.testName + ": " + ( error.message || error ); test.pushFailure( message, extractStacktrace( error, 0 ) ); // else next test will carry the responsibility saveGlobal(); // Unblock QUnit.start(); } ); } } }, valid: function() { var include, filter = config.filter && config.filter.toLowerCase(), module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(), fullName = ( this.module.name + ": " + this.testName ).toLowerCase(); // Internally-generated tests are always valid if ( this.callback && this.callback.validTest ) { return true; } if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) { return false; } if ( module && ( !this.module.name || this.module.name.toLowerCase() !== module ) ) { return false; } if ( !filter ) { return true; } include = filter.charAt( 0 ) !== "!"; if ( !include ) { filter = filter.slice( 1 ); } // If the filter matches, we need to honour include if ( fullName.indexOf( filter ) !== -1 ) { return include; } // Otherwise, do the opposite return !include; } }; // Resets the test setup. Useful for tests that modify the DOM. /* DEPRECATED: Use multiple tests instead of resetting inside a test. Use testStart or testDone for custom cleanup. This method will throw an error in 2.0, and will be removed in 2.1 */ QUnit.reset = function() { // Return on non-browser environments // This is necessary to not break on node tests if ( typeof window === "undefined" ) { return; } var fixture = defined.document && document.getElementById && document.getElementById( "qunit-fixture" ); if ( fixture ) { fixture.innerHTML = config.fixture; } }; QUnit.pushFailure = function() { if ( !QUnit.config.current ) { throw new Error( "pushFailure() assertion outside test context, in " + sourceFromStacktrace( 2 ) ); } // Gets current test obj var currentTest = QUnit.config.current; return currentTest.pushFailure.apply( currentTest, arguments ); }; // Based on Java's String.hashCode, a simple but not // rigorously collision resistant hashing function function generateHash( module, testName ) { var hex, i = 0, hash = 0, str = module + "\x1C" + testName, len = str.length; for ( ; i < len; i++ ) { hash = ( ( hash << 5 ) - hash ) + str.charCodeAt( i ); hash |= 0; } // Convert the possibly negative integer hash code into an 8 character hex string, which isn't // strictly necessary but increases user understanding that the id is a SHA-like hash hex = ( 0x100000000 + hash ).toString( 16 ); if ( hex.length < 8 ) { hex = "0000000" + hex; } return hex.slice( -8 ); } function Assert( testContext ) { this.test = testContext; } // Assert helpers QUnit.assert = Assert.prototype = { // Specify the number of expected assertions to guarantee that failed test // (no assertions are run at all) don't slip through. expect: function( asserts ) { if ( arguments.length === 1 ) { this.test.expected = asserts; } else { return this.test.expected; } }, // Increment this Test's semaphore counter, then return a single-use function that // decrements that counter a maximum of once. async: function() { var test = this.test, popped = false; test.semaphore += 1; test.usedAsync = true; pauseProcessing(); return function done() { if ( !popped ) { test.semaphore -= 1; popped = true; resumeProcessing(); } else { test.pushFailure( "Called the callback returned from `assert.async` more than once", sourceFromStacktrace( 2 ) ); } }; }, // Exports test.push() to the user API push: function( /* result, actual, expected, message */ ) { var assert = this, currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current; // Backwards compatibility fix. // Allows the direct use of global exported assertions and QUnit.assert.* // Although, it's use is not recommended as it can leak assertions // to other tests from async tests, because we only get a reference to the current test, // not exactly the test where assertion were intended to be called. if ( !currentTest ) { throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) ); } if ( currentTest.usedAsync === true && currentTest.semaphore === 0 ) { currentTest.pushFailure( "Assertion after the final `assert.async` was resolved", sourceFromStacktrace( 2 ) ); // Allow this assertion to continue running anyway... } if ( !( assert instanceof Assert ) ) { assert = currentTest.assert; } return assert.test.push.apply( assert.test, arguments ); }, ok: function( result, message ) { message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " + QUnit.dump.parse( result ) ); this.push( !!result, result, true, message ); }, notOk: function( result, message ) { message = message || ( !result ? "okay" : "failed, expected argument to be falsy, was: " + QUnit.dump.parse( result ) ); this.push( !result, result, false, message ); }, equal: function( actual, expected, message ) { /*jshint eqeqeq:false */ this.push( expected == actual, actual, expected, message ); }, notEqual: function( actual, expected, message ) { /*jshint eqeqeq:false */ this.push( expected != actual, actual, expected, message ); }, propEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); this.push( QUnit.equiv( actual, expected ), actual, expected, message ); }, notPropEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); }, deepEqual: function( actual, expected, message ) { this.push( QUnit.equiv( actual, expected ), actual, expected, message ); }, notDeepEqual: function( actual, expected, message ) { this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); }, strictEqual: function( actual, expected, message ) { this.push( expected === actual, actual, expected, message ); }, notStrictEqual: function( actual, expected, message ) { this.push( expected !== actual, actual, expected, message ); }, "throws": function( block, expected, message ) { var actual, expectedType, expectedOutput = expected, ok = false, currentTest = ( this instanceof Assert && this.test ) || QUnit.config.current; // 'expected' is optional unless doing string comparison if ( message == null && typeof expected === "string" ) { message = expected; expected = null; } currentTest.ignoreGlobalErrors = true; try { block.call( currentTest.testEnvironment ); } catch (e) { actual = e; } currentTest.ignoreGlobalErrors = false; if ( actual ) { expectedType = QUnit.objectType( expected ); // we don't want to validate thrown error if ( !expected ) { ok = true; expectedOutput = null; // expected is a regexp } else if ( expectedType === "regexp" ) { ok = expected.test( errorString( actual ) ); // expected is a string } else if ( expectedType === "string" ) { ok = expected === errorString( actual ); // expected is a constructor, maybe an Error constructor } else if ( expectedType === "function" && actual instanceof expected ) { ok = true; // expected is an Error object } else if ( expectedType === "object" ) { ok = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message; // expected is a validation function which returns true if validation passed } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) { expectedOutput = null; ok = true; } } currentTest.assert.push( ok, actual, expectedOutput, message ); } }; // Provide an alternative to assert.throws(), for enviroments that consider throws a reserved word // Known to us are: Closure Compiler, Narwhal (function() { /*jshint sub:true */ Assert.prototype.raises = Assert.prototype[ "throws" ]; }()); // Test for equality any JavaScript type. // Author: Philippe Rathé QUnit.equiv = (function() { // Call the o related callback with the given arguments. function bindCallbacks( o, callbacks, args ) { var prop = QUnit.objectType( o ); if ( prop ) { if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { return callbacks[ prop ].apply( callbacks, args ); } else { return callbacks[ prop ]; // or undefined } } } // the real equiv function var innerEquiv, // stack to decide between skip/abort functions callers = [], // stack to avoiding loops from circular referencing parents = [], parentsB = [], getProto = Object.getPrototypeOf || function( obj ) { /* jshint camelcase: false, proto: true */ return obj.__proto__; }, callbacks = (function() { // for string, boolean, number and null function useStrictEquality( b, a ) { /*jshint eqeqeq:false */ if ( b instanceof a.constructor || a instanceof b.constructor ) { // to catch short annotation VS 'new' annotation of a // declaration // e.g. var i = 1; // var j = new Number(1); return a == b; } else { return a === b; } } return { "string": useStrictEquality, "boolean": useStrictEquality, "number": useStrictEquality, "null": useStrictEquality, "undefined": useStrictEquality, "nan": function( b ) { return isNaN( b ); }, "date": function( b, a ) { return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); }, "regexp": function( b, a ) { return QUnit.objectType( b ) === "regexp" && // the regex itself a.source === b.source && // and its modifiers a.global === b.global && // (gmi) ... a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky; }, // - skip when the property is a method of an instance (OOP) // - abort otherwise, // initial === would have catch identical references anyway "function": function() { var caller = callers[ callers.length - 1 ]; return caller !== Object && typeof caller !== "undefined"; }, "array": function( b, a ) { var i, j, len, loop, aCircular, bCircular; // b could be an object literal here if ( QUnit.objectType( b ) !== "array" ) { return false; } len = a.length; if ( len !== b.length ) { // safe and faster return false; } // track reference to avoid circular references parents.push( a ); parentsB.push( b ); for ( i = 0; i < len; i++ ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[ j ] === a[ i ]; bCircular = parentsB[ j ] === b[ i ]; if ( aCircular || bCircular ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) { loop = true; } else { parents.pop(); parentsB.pop(); return false; } } } if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { parents.pop(); parentsB.pop(); return false; } } parents.pop(); parentsB.pop(); return true; }, "object": function( b, a ) { /*jshint forin:false */ var i, j, loop, aCircular, bCircular, // Default to true eq = true, aProperties = [], bProperties = []; // comparing constructors is more strict than using // instanceof if ( a.constructor !== b.constructor ) { // Allow objects with no prototype to be equivalent to // objects with Object as their constructor. if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) || ( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) { return false; } } // stack constructor before traversing properties callers.push( a.constructor ); // track reference to avoid circular references parents.push( a ); parentsB.push( b ); // be strict: don't ensure hasOwnProperty and go deep for ( i in a ) { loop = false; for ( j = 0; j < parents.length; j++ ) { aCircular = parents[ j ] === a[ i ]; bCircular = parentsB[ j ] === b[ i ]; if ( aCircular || bCircular ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) { loop = true; } else { eq = false; break; } } } aProperties.push( i ); if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { eq = false; break; } } parents.pop(); parentsB.pop(); callers.pop(); // unstack, we are done for ( i in b ) { bProperties.push( i ); // collect b's properties } // Ensures identical properties name return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); } }; }()); innerEquiv = function() { // can take multiple arguments var args = [].slice.apply( arguments ); if ( args.length < 2 ) { return true; // end transition } return ( (function( a, b ) { if ( a === b ) { return true; // catch the most you can } else if ( a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType( a ) !== QUnit.objectType( b ) ) { // don't lose time with error prone cases return false; } else { return bindCallbacks( a, callbacks, [ b, a ] ); } // apply transition with (1..n) arguments }( args[ 0 ], args[ 1 ] ) ) && innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) ); }; return innerEquiv; }()); // Based on jsDump by Ariel Flesler // http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html QUnit.dump = (function() { function quote( str ) { return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; } function literal( o ) { return o + ""; } function join( pre, arr, post ) { var s = dump.separator(), base = dump.indent(), inner = dump.indent( 1 ); if ( arr.join ) { arr = arr.join( "," + s + inner ); } if ( !arr ) { return pre + post; } return [ pre, inner + arr, base + post ].join( s ); } function array( arr, stack ) { var i = arr.length, ret = new Array( i ); if ( dump.maxDepth && dump.depth > dump.maxDepth ) { return "[object Array]"; } this.up(); while ( i-- ) { ret[ i ] = this.parse( arr[ i ], undefined, stack ); } this.down(); return join( "[", ret, "]" ); } var reName = /^function (\w+)/, dump = { // objType is used mostly internally, you can fix a (custom) type in advance parse: function( obj, objType, stack ) { stack = stack || []; var res, parser, parserType, inStack = inArray( obj, stack ); if ( inStack !== -1 ) { return "recursion(" + ( inStack - stack.length ) + ")"; } objType = objType || this.typeOf( obj ); parser = this.parsers[ objType ]; parserType = typeof parser; if ( parserType === "function" ) { return; stack.push( obj ); res = parser.call( this, obj, stack ); stack.pop(); return res; } return ( parserType === "string" ) ? parser : this.parsers.error; }, typeOf: function( obj ) { var type; if ( obj === null ) { type = "null"; } else if ( typeof obj === "undefined" ) { type = "undefined"; } else if ( QUnit.is( "regexp", obj ) ) { type = "regexp"; } else if ( QUnit.is( "date", obj ) ) { type = "date"; } else if ( QUnit.is( "function", obj ) ) { type = "function"; } else if ( obj.setInterval !== undefined && obj.document !== undefined && obj.nodeType === undefined ) { type = "window"; } else if ( obj.nodeType === 9 ) { type = "document"; } else if ( obj.nodeType ) { type = "node"; } else if ( // native arrays toString.call( obj ) === "[object Array]" || // NodeList objects ( typeof obj.length === "number" && obj.item !== undefined && ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null && obj[ 0 ] === undefined ) ) ) ) { type = "array"; } else if ( obj.constructor === Error.prototype.constructor ) { type = "error"; } else { type = typeof obj; } return type; }, separator: function() { return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " "; }, // extra can be a number, shortcut for increasing-calling-decreasing indent: function( extra ) { if ( !this.multiline ) { return ""; } var chr = this.indentChar; if ( this.HTML ) { chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); } return new Array( this.depth + ( extra || 0 ) ).join( chr ); }, up: function( a ) { this.depth += a || 1; }, down: function( a ) { this.depth -= a || 1; }, setParser: function( name, parser ) { this.parsers[ name ] = parser; }, // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, // depth: 1, maxDepth: QUnit.config.maxDepth, // This is the list of parsers, to modify them, use dump.setParser parsers: { window: "[Window]", document: "[Document]", error: function( error ) { return "Error(\"" + error.message + "\")"; }, unknown: "[Unknown]", "null": "null", "undefined": "undefined", "function": function( fn ) { var ret = "function", // functions never have name in IE name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ]; if ( name ) { ret += " " + name; } ret += "( "; ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" ); return join( ret, dump.parse( fn, "functionCode" ), "}" ); }, array: array, nodelist: array, "arguments": array, object: function( map, stack ) { var keys, key, val, i, nonEnumerableProperties, ret = []; if ( dump.maxDepth && dump.depth > dump.maxDepth ) { return "[object Object]"; } dump.up(); keys = []; for ( key in map ) { keys.push( key ); } // Some properties are not always enumerable on Error objects. nonEnumerableProperties = [ "message", "name" ]; for ( i in nonEnumerableProperties ) { key = nonEnumerableProperties[ i ]; if ( key in map && inArray( key, keys ) < 0 ) { keys.push( key ); } } keys.sort(); for ( i = 0; i < keys.length; i++ ) { key = keys[ i ]; val = map[ key ]; ret.push( dump.parse( key, "key" ) + ": " + dump.parse( val, undefined, stack ) ); } dump.down(); return join( "{", ret, "}" ); }, node: function( node ) { var len, i, val, open = dump.HTML ? "<" : "<", close = dump.HTML ? ">" : ">", tag = node.nodeName.toLowerCase(), ret = open + tag, attrs = node.attributes; if ( attrs ) { for ( i = 0, len = attrs.length; i < len; i++ ) { val = attrs[ i ].nodeValue; // IE6 includes all attributes in .attributes, even ones not explicitly // set. Those have values like undefined, null, 0, false, "" or // "inherit". if ( val && val !== "inherit" ) { ret += " " + attrs[ i ].nodeName + "=" + dump.parse( val, "attribute" ); } } } ret += close; // Show content of TextNode or CDATASection if ( node.nodeType === 3 || node.nodeType === 4 ) { ret += node.nodeValue; } return ret + open + "/" + tag + close; }, // function calls it internally, it's the arguments part of the function functionArgs: function( fn ) { var args, l = fn.length; if ( !l ) { return ""; } args = new Array( l ); while ( l-- ) { // 97 is 'a' args[ l ] = String.fromCharCode( 97 + l ); } return " " + args.join( ", " ) + " "; }, // object calls it internally, the key part of an item in a map key: quote, // function calls it internally, it's the content of the function functionCode: "[code]", // node calls it internally, it's an html attribute value attribute: quote, string: quote, date: quote, regexp: literal, number: literal, "boolean": literal }, // if true, entities are escaped ( <, >, \t, space and \n ) HTML: false, // indentation unit indentChar: " ", // if true, items in a collection, are separated by a \n, else just a space. multiline: true }; return dump; }()); // back compat QUnit.jsDump = QUnit.dump; // For browser, export only select globals if ( typeof window !== "undefined" ) { // Deprecated // Extend assert methods to QUnit and Global scope through Backwards compatibility (function() { var i, assertions = Assert.prototype; function applyCurrent( current ) { return function() { var assert = new Assert( QUnit.config.current ); current.apply( assert, arguments ); }; } for ( i in assertions ) { QUnit[ i ] = applyCurrent( assertions[ i ] ); } })(); (function() { var i, l, keys = [ "test", "module", "expect", "asyncTest", "start", "stop", "ok", "notOk", "equal", "notEqual", "propEqual", "notPropEqual", "deepEqual", "notDeepEqual", "strictEqual", "notStrictEqual", "throws" ]; for ( i = 0, l = keys.length; i < l; i++ ) { window[ keys[ i ] ] = QUnit[ keys[ i ] ]; } })(); window.QUnit = QUnit; } // For nodejs if ( typeof module !== "undefined" && module && module.exports ) { module.exports = QUnit; // For consistency with CommonJS environments' exports module.exports.QUnit = QUnit; } // For CommonJS with exports, but without module.exports, like Rhino if ( typeof exports !== "undefined" && exports ) { exports.QUnit = QUnit; } if ( typeof define === "function" && define.amd ) { define( function() { return QUnit; } ); QUnit.config.autostart = false; } // Get a reference to the global object, like window in browsers }( (function() { return this; })() )); /*istanbul ignore next */ // jscs:disable maximumLineLength /* * This file is a modified version of google-diff-match-patch's JavaScript implementation * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js), * modifications are licensed as more fully set forth in LICENSE.txt. * * The original source of google-diff-match-patch is attributable and licensed as follows: * * Copyright 2006 Google Inc. * http://code.google.com/p/google-diff-match-patch/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * More Info: * https://code.google.com/p/google-diff-match-patch/ * * Usage: QUnit.diff(expected, actual) * * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) === "the quick brown fox jumpsed} Array of diff tuples. */ DiffMatchPatch.prototype.DiffMain = function( text1, text2, optChecklines, optDeadline ) { var deadline, checklines, commonlength, commonprefix, commonsuffix, diffs; // Set a deadline by which time the diff must be complete. if ( typeof optDeadline === "undefined" ) { if ( this.DiffTimeout <= 0 ) { optDeadline = Number.MAX_VALUE; } else { optDeadline = ( new Date() ).getTime() + this.DiffTimeout * 1000; } } deadline = optDeadline; // Check for null inputs. if ( text1 === null || text2 === null ) { throw new Error( "Null input. (DiffMain)" ); } // Check for equality (speedup). if ( text1 === text2 ) { if ( text1 ) { return [ [ DIFF_EQUAL, text1 ] ]; } return []; } if ( typeof optChecklines === "undefined" ) { optChecklines = true; } checklines = optChecklines; // Trim off common prefix (speedup). commonlength = this.diffCommonPrefix( text1, text2 ); commonprefix = text1.substring( 0, commonlength ); text1 = text1.substring( commonlength ); text2 = text2.substring( commonlength ); // Trim off common suffix (speedup). ///////// commonlength = this.diffCommonSuffix( text1, text2 ); commonsuffix = text1.substring( text1.length - commonlength ); text1 = text1.substring( 0, text1.length - commonlength ); text2 = text2.substring( 0, text2.length - commonlength ); // Compute the diff on the middle block. diffs = this.diffCompute( text1, text2, checklines, deadline ); // Restore the prefix and suffix. if ( commonprefix ) { diffs.unshift( [ DIFF_EQUAL, commonprefix ] ); } if ( commonsuffix ) { diffs.push( [ DIFF_EQUAL, commonsuffix ] ); } this.diffCleanupMerge( diffs ); return diffs; }; /** * Reduce the number of edits by eliminating operationally trivial equalities. * @param {!Array.} diffs Array of diff tuples. */ DiffMatchPatch.prototype.diffCleanupEfficiency = function( diffs ) { var changes, equalities, equalitiesLength, lastequality, pointer, preIns, preDel, postIns, postDel; changes = false; equalities = []; // Stack of indices where equalities are found. equalitiesLength = 0; // Keeping our own length var is faster in JS. /** @type {?string} */ lastequality = null; // Always equal to diffs[equalities[equalitiesLength - 1]][1] pointer = 0; // Index of current position. // Is there an insertion operation before the last equality. preIns = false; // Is there a deletion operation before the last equality. preDel = false; // Is there an insertion operation after the last equality. postIns = false; // Is there a deletion operation after the last equality. postDel = false; while ( pointer < diffs.length ) { if ( diffs[ pointer ][ 0 ] === DIFF_EQUAL ) { // Equality found. if ( diffs[ pointer ][ 1 ].length < this.DiffEditCost && ( postIns || postDel ) ) { // Candidate found. equalities[ equalitiesLength++ ] = pointer; preIns = postIns; preDel = postDel; lastequality = diffs[ pointer ][ 1 ]; } else { // Not a candidate, and can never become one. equalitiesLength = 0; lastequality = null; } postIns = postDel = false; } else { // An insertion or deletion. if ( diffs[ pointer ][ 0 ] === DIFF_DELETE ) { postDel = true; } else { postIns = true; } /* * Five types to be split: * ABXYCD * AXCD * ABXC * AXCD * ABXC */ if ( lastequality && ( ( preIns && preDel && postIns && postDel ) || ( ( lastequality.length < this.DiffEditCost / 2 ) && ( preIns + preDel + postIns + postDel ) === 3 ) ) ) { // Duplicate record. diffs.splice( equalities[equalitiesLength - 1], 0, [ DIFF_DELETE, lastequality ] ); // Change second copy to insert. diffs[ equalities[ equalitiesLength - 1 ] + 1 ][ 0 ] = DIFF_INSERT; equalitiesLength--; // Throw away the equality we just deleted; lastequality = null; if (preIns && preDel) { // No changes made which could affect previous entry, keep going. postIns = postDel = true; equalitiesLength = 0; } else { equalitiesLength--; // Throw away the previous equality. pointer = equalitiesLength > 0 ? equalities[ equalitiesLength - 1 ] : -1; postIns = postDel = false; } changes = true; } } pointer++; } if ( changes ) { this.diffCleanupMerge( diffs ); } }; /** * Convert a diff array into a pretty HTML report. * @param {!Array.} diffs Array of diff tuples. * @param {integer} string to be beautified. * @return {string} HTML representation. */ DiffMatchPatch.prototype.diffPrettyHtml = function( diffs ) { var op, data, x, html = []; for ( x = 0; x < diffs.length; x++ ) { op = diffs[x][0]; // Operation (insert, delete, equal) data = diffs[x][1]; // Text of change. switch ( op ) { case DIFF_INSERT: html[x] = "" + data + ""; break; case DIFF_DELETE: html[x] = "" + data + ""; break; case DIFF_EQUAL: html[x] = "" + data + ""; break; } } return html.join(""); }; /** * Determine the common prefix of two strings. * @param {string} text1 First string. * @param {string} text2 Second string. * @return {number} The number of characters common to the start of each * string. */ DiffMatchPatch.prototype.diffCommonPrefix = function( text1, text2 ) { var pointermid, pointermax, pointermin, pointerstart; // Quick check for common null cases. if ( !text1 || !text2 || text1.charAt(0) !== text2.charAt(0) ) { return 0; } // Binary search. // Performance analysis: http://neil.fraser.name/news/2007/10/09/ pointermin = 0; pointermax = Math.min( text1.length, text2.length ); pointermid = pointermax; pointerstart = 0; while ( pointermin < pointermid ) { if ( text1.substring( pointerstart, pointermid ) === text2.substring( pointerstart, pointermid ) ) { pointermin = pointermid; pointerstart = pointermin; } else { pointermax = pointermid; } pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin ); } return pointermid; }; /** * Determine the common suffix of two strings. * @param {string} text1 First string. * @param {string} text2 Second string. * @return {number} The number of characters common to the end of each string. */ DiffMatchPatch.prototype.diffCommonSuffix = function( text1, text2 ) { var pointermid, pointermax, pointermin, pointerend; // Quick check for common null cases. if (!text1 || !text2 || text1.charAt(text1.length - 1) !== text2.charAt(text2.length - 1)) { return 0; } // Binary search. // Performance analysis: http://neil.fraser.name/news/2007/10/09/ pointermin = 0; pointermax = Math.min(text1.length, text2.length); pointermid = pointermax; pointerend = 0; while ( pointermin < pointermid ) { if (text1.substring( text1.length - pointermid, text1.length - pointerend ) === text2.substring( text2.length - pointermid, text2.length - pointerend ) ) { pointermin = pointermid; pointerend = pointermin; } else { pointermax = pointermid; } pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin ); } return pointermid; }; /** * Find the differences between two texts. Assumes that the texts do not * have any common prefix or suffix. * @param {string} text1 Old string to be diffed. * @param {string} text2 New string to be diffed. * @param {boolean} checklines Speedup flag. If false, then don't run a * line-level diff first to identify the changed areas. * If true, then run a faster, slightly less optimal diff. * @param {number} deadline Time when the diff should be complete by. * @return {!Array.} Array of diff tuples. * @private */ DiffMatchPatch.prototype.diffCompute = function( text1, text2, checklines, deadline ) { var diffs, longtext, shorttext, i, hm, text1A, text2A, text1B, text2B, midCommon, diffsA, diffsB; if ( !text1 ) { // Just add some text (speedup). return [ [ DIFF_INSERT, text2 ] ]; } if (!text2) { // Just delete some text (speedup). return [ [ DIFF_DELETE, text1 ] ]; } longtext = text1.length > text2.length ? text1 : text2; shorttext = text1.length > text2.length ? text2 : text1; i = longtext.indexOf( shorttext ); if ( i !== -1 ) { // Shorter text is inside the longer text (speedup). diffs = [ [ DIFF_INSERT, longtext.substring( 0, i ) ], [ DIFF_EQUAL, shorttext ], [ DIFF_INSERT, longtext.substring( i + shorttext.length ) ] ]; // Swap insertions for deletions if diff is reversed. if ( text1.length > text2.length ) { diffs[0][0] = diffs[2][0] = DIFF_DELETE; } return diffs; } if ( shorttext.length === 1 ) { // Single character string. // After the previous speedup, the character can't be an equality. return [ [ DIFF_DELETE, text1 ], [ DIFF_INSERT, text2 ] ]; } // Check to see if the problem can be split in two. hm = this.diffHalfMatch(text1, text2); if (hm) { // A half-match was found, sort out the return data. text1A = hm[0]; text1B = hm[1]; text2A = hm[2]; text2B = hm[3]; midCommon = hm[4]; // Send both pairs off for separate processing. diffsA = this.DiffMain(text1A, text2A, checklines, deadline); diffsB = this.DiffMain(text1B, text2B, checklines, deadline); // Merge the results. return diffsA.concat([ [ DIFF_EQUAL, midCommon ] ], diffsB); } if (checklines && text1.length > 100 && text2.length > 100) { return this.diffLineMode(text1, text2, deadline); } return this.diffBisect(text1, text2, deadline); }; /** * Do the two texts share a substring which is at least half the length of the * longer text? * This speedup can produce non-minimal diffs. * @param {string} text1 First string. * @param {string} text2 Second string. * @return {Array.} Five element Array, containing the prefix of * text1, the suffix of text1, the prefix of text2, the suffix of * text2 and the common middle. Or null if there was no match. * @private */ DiffMatchPatch.prototype.diffHalfMatch = function(text1, text2) { var longtext, shorttext, dmp, text1A, text2B, text2A, text1B, midCommon, hm1, hm2, hm; if (this.DiffTimeout <= 0) { // Don't risk returning a non-optimal diff if we have unlimited time. return null; } longtext = text1.length > text2.length ? text1 : text2; shorttext = text1.length > text2.length ? text2 : text1; if (longtext.length < 4 || shorttext.length * 2 < longtext.length) { return null; // Pointless. } dmp = this; // 'this' becomes 'window' in a closure. /** * Does a substring of shorttext exist within longtext such that the substring * is at least half the length of longtext? * Closure, but does not reference any external variables. * @param {string} longtext Longer string. * @param {string} shorttext Shorter string. * @param {number} i Start index of quarter length substring within longtext. * @return {Array.} Five element Array, containing the prefix of * longtext, the suffix of longtext, the prefix of shorttext, the suffix * of shorttext and the common middle. Or null if there was no match. * @private */ function diffHalfMatchI(longtext, shorttext, i) { var seed, j, bestCommon, prefixLength, suffixLength, bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB; // Start with a 1/4 length substring at position i as a seed. seed = longtext.substring(i, i + Math.floor(longtext.length / 4)); j = -1; bestCommon = ""; while ((j = shorttext.indexOf(seed, j + 1)) !== -1) { prefixLength = dmp.diffCommonPrefix(longtext.substring(i), shorttext.substring(j)); suffixLength = dmp.diffCommonSuffix(longtext.substring(0, i), shorttext.substring(0, j)); if (bestCommon.length < suffixLength + prefixLength) { bestCommon = shorttext.substring(j - suffixLength, j) + shorttext.substring(j, j + prefixLength); bestLongtextA = longtext.substring(0, i - suffixLength); bestLongtextB = longtext.substring(i + prefixLength); bestShorttextA = shorttext.substring(0, j - suffixLength); bestShorttextB = shorttext.substring(j + prefixLength); } } if (bestCommon.length * 2 >= longtext.length) { return [ bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB, bestCommon ]; } else { return null; } } // First check if the second quarter is the seed for a half-match. hm1 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 4)); // Check again based on the third quarter. hm2 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 2)); if (!hm1 && !hm2) { return null; } else if (!hm2) { hm = hm1; } else if (!hm1) { hm = hm2; } else { // Both matched. Select the longest. hm = hm1[4].length > hm2[4].length ? hm1 : hm2; } // A half-match was found, sort out the return data. text1A, text1B, text2A, text2B; if (text1.length > text2.length) { text1A = hm[0]; text1B = hm[1]; text2A = hm[2]; text2B = hm[3]; } else { text2A = hm[0]; text2B = hm[1]; text1A = hm[2]; text1B = hm[3]; } midCommon = hm[4]; return [ text1A, text1B, text2A, text2B, midCommon ]; }; /** * Do a quick line-level diff on both strings, then rediff the parts for * greater accuracy. * This speedup can produce non-minimal diffs. * @param {string} text1 Old string to be diffed. * @param {string} text2 New string to be diffed. * @param {number} deadline Time when the diff should be complete by. * @return {!Array.} Array of diff tuples. * @private */ DiffMatchPatch.prototype.diffLineMode = function(text1, text2, deadline) { var a, diffs, linearray, pointer, countInsert, countDelete, textInsert, textDelete, j; // Scan the text on a line-by-line basis first. a = this.diffLinesToChars(text1, text2); text1 = a.chars1; text2 = a.chars2; linearray = a.lineArray; diffs = this.DiffMain(text1, text2, false, deadline); // Convert the diff back to original text. this.diffCharsToLines(diffs, linearray); // Eliminate freak matches (e.g. blank lines) this.diffCleanupSemantic(diffs); // Rediff any replacement blocks, this time character-by-character. // Add a dummy entry at the end. diffs.push( [ DIFF_EQUAL, "" ] ); pointer = 0; countDelete = 0; countInsert = 0; textDelete = ""; textInsert = ""; while (pointer < diffs.length) { switch ( diffs[pointer][0] ) { case DIFF_INSERT: countInsert++; textInsert += diffs[pointer][1]; break; case DIFF_DELETE: countDelete++; textDelete += diffs[pointer][1]; break; case DIFF_EQUAL: // Upon reaching an equality, check for prior redundancies. if (countDelete >= 1 && countInsert >= 1) { // Delete the offending records and add the merged ones. diffs.splice(pointer - countDelete - countInsert, countDelete + countInsert); pointer = pointer - countDelete - countInsert; a = this.DiffMain(textDelete, textInsert, false, deadline); for (j = a.length - 1; j >= 0; j--) { diffs.splice( pointer, 0, a[j] ); } pointer = pointer + a.length; } countInsert = 0; countDelete = 0; textDelete = ""; textInsert = ""; break; } pointer++; } diffs.pop(); // Remove the dummy entry at the end. return diffs; }; /** * Find the 'middle snake' of a diff, split the problem in two * and return the recursively constructed diff. * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations. * @param {string} text1 Old string to be diffed. * @param {string} text2 New string to be diffed. * @param {number} deadline Time at which to bail if not yet complete. * @return {!Array.} Array of diff tuples. * @private */ DiffMatchPatch.prototype.diffBisect = function(text1, text2, deadline) { var text1Length, text2Length, maxD, vOffset, vLength, v1, v2, x, delta, front, k1start, k1end, k2start, k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2; // Cache the text lengths to prevent multiple calls. text1Length = text1.length; text2Length = text2.length; maxD = Math.ceil((text1Length + text2Length) / 2); vOffset = maxD; vLength = 2 * maxD; v1 = new Array(vLength); v2 = new Array(vLength); // Setting all elements to -1 is faster in Chrome & Firefox than mixing // integers and undefined. for (x = 0; x < vLength; x++) { v1[x] = -1; v2[x] = -1; } v1[vOffset + 1] = 0; v2[vOffset + 1] = 0; delta = text1Length - text2Length; // If the total number of characters is odd, then the front path will collide // with the reverse path. front = (delta % 2 !== 0); // Offsets for start and end of k loop. // Prevents mapping of space beyond the grid. k1start = 0; k1end = 0; k2start = 0; k2end = 0; for (d = 0; d < maxD; d++) { // Bail out if deadline is reached. if ((new Date()).getTime() > deadline) { break; } // Walk the front path one step. for (k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { k1Offset = vOffset + k1; if ( k1 === -d || ( k1 !== d && v1[ k1Offset - 1 ] < v1[ k1Offset + 1 ] ) ) { x1 = v1[k1Offset + 1]; } else { x1 = v1[k1Offset - 1] + 1; } y1 = x1 - k1; while (x1 < text1Length && y1 < text2Length && text1.charAt(x1) === text2.charAt(y1)) { x1++; y1++; } v1[k1Offset] = x1; if (x1 > text1Length) { // Ran off the right of the graph. k1end += 2; } else if (y1 > text2Length) { // Ran off the bottom of the graph. k1start += 2; } else if (front) { k2Offset = vOffset + delta - k1; if (k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] !== -1) { // Mirror x2 onto top-left coordinate system. x2 = text1Length - v2[k2Offset]; if (x1 >= x2) { // Overlap detected. return this.diffBisectSplit(text1, text2, x1, y1, deadline); } } } } // Walk the reverse path one step. for (k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { k2Offset = vOffset + k2; if ( k2 === -d || (k2 !== d && v2[ k2Offset - 1 ] < v2[ k2Offset + 1 ] ) ) { x2 = v2[k2Offset + 1]; } else { x2 = v2[k2Offset - 1] + 1; } y2 = x2 - k2; while (x2 < text1Length && y2 < text2Length && text1.charAt(text1Length - x2 - 1) === text2.charAt(text2Length - y2 - 1)) { x2++; y2++; } v2[k2Offset] = x2; if (x2 > text1Length) { // Ran off the left of the graph. k2end += 2; } else if (y2 > text2Length) { // Ran off the top of the graph. k2start += 2; } else if (!front) { k1Offset = vOffset + delta - k2; if (k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] !== -1) { x1 = v1[k1Offset]; y1 = vOffset + x1 - k1Offset; // Mirror x2 onto top-left coordinate system. x2 = text1Length - x2; if (x1 >= x2) { // Overlap detected. return this.diffBisectSplit(text1, text2, x1, y1, deadline); } } } } } // Diff took too long and hit the deadline or // number of diffs equals number of characters, no commonality at all. return [ [ DIFF_DELETE, text1 ], [ DIFF_INSERT, text2 ] ]; }; /** * Given the location of the 'middle snake', split the diff in two parts * and recurse. * @param {string} text1 Old string to be diffed. * @param {string} text2 New string to be diffed. * @param {number} x Index of split point in text1. * @param {number} y Index of split point in text2. * @param {number} deadline Time at which to bail if not yet complete. * @return {!Array.} Array of diff tuples. * @private */ DiffMatchPatch.prototype.diffBisectSplit = function( text1, text2, x, y, deadline ) { var text1a, text1b, text2a, text2b, diffs, diffsb; text1a = text1.substring(0, x); text2a = text2.substring(0, y); text1b = text1.substring(x); text2b = text2.substring(y); // Compute both diffs serially. diffs = this.DiffMain(text1a, text2a, false, deadline); diffsb = this.DiffMain(text1b, text2b, false, deadline); return diffs.concat(diffsb); }; /** * Reduce the number of edits by eliminating semantically trivial equalities. * @param {!Array.} diffs Array of diff tuples. */ DiffMatchPatch.prototype.diffCleanupSemantic = function(diffs) { var changes, equalities, equalitiesLength, lastequality, pointer, lengthInsertions2, lengthDeletions2, lengthInsertions1, lengthDeletions1, deletion, insertion, overlapLength1, overlapLength2; changes = false; equalities = []; // Stack of indices where equalities are found. equalitiesLength = 0; // Keeping our own length var is faster in JS. /** @type {?string} */ lastequality = null; // Always equal to diffs[equalities[equalitiesLength - 1]][1] pointer = 0; // Index of current position. // Number of characters that changed prior to the equality. lengthInsertions1 = 0; lengthDeletions1 = 0; // Number of characters that changed after the equality. lengthInsertions2 = 0; lengthDeletions2 = 0; while (pointer < diffs.length) { if (diffs[pointer][0] === DIFF_EQUAL) { // Equality found. equalities[equalitiesLength++] = pointer; lengthInsertions1 = lengthInsertions2; lengthDeletions1 = lengthDeletions2; lengthInsertions2 = 0; lengthDeletions2 = 0; lastequality = diffs[pointer][1]; } else { // An insertion or deletion. if (diffs[pointer][0] === DIFF_INSERT) { lengthInsertions2 += diffs[pointer][1].length; } else { lengthDeletions2 += diffs[pointer][1].length; } // Eliminate an equality that is smaller or equal to the edits on both // sides of it. if (lastequality && (lastequality.length <= Math.max(lengthInsertions1, lengthDeletions1)) && (lastequality.length <= Math.max(lengthInsertions2, lengthDeletions2))) { // Duplicate record. diffs.splice( equalities[ equalitiesLength - 1 ], 0, [ DIFF_DELETE, lastequality ] ); // Change second copy to insert. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; // Throw away the equality we just deleted. equalitiesLength--; // Throw away the previous equality (it needs to be reevaluated). equalitiesLength--; pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; lengthInsertions1 = 0; // Reset the counters. lengthDeletions1 = 0; lengthInsertions2 = 0; lengthDeletions2 = 0; lastequality = null; changes = true; } } pointer++; } // Normalize the diff. if (changes) { this.diffCleanupMerge(diffs); } // Find any overlaps between deletions and insertions. // e.g: abcxxxxxxdef // -> abcxxxdef // e.g: xxxabcdefxxx // -> defxxxabc // Only extract an overlap if it is as big as the edit ahead or behind it. pointer = 1; while (pointer < diffs.length) { if (diffs[pointer - 1][0] === DIFF_DELETE && diffs[pointer][0] === DIFF_INSERT) { deletion = diffs[pointer - 1][1]; insertion = diffs[pointer][1]; overlapLength1 = this.diffCommonOverlap(deletion, insertion); overlapLength2 = this.diffCommonOverlap(insertion, deletion); if (overlapLength1 >= overlapLength2) { if (overlapLength1 >= deletion.length / 2 || overlapLength1 >= insertion.length / 2) { // Overlap found. Insert an equality and trim the surrounding edits. diffs.splice( pointer, 0, [ DIFF_EQUAL, insertion.substring( 0, overlapLength1 ) ] ); diffs[pointer - 1][1] = deletion.substring(0, deletion.length - overlapLength1); diffs[pointer + 1][1] = insertion.substring(overlapLength1); pointer++; } } else { if (overlapLength2 >= deletion.length / 2 || overlapLength2 >= insertion.length / 2) { // Reverse overlap found. // Insert an equality and swap and trim the surrounding edits. diffs.splice( pointer, 0, [ DIFF_EQUAL, deletion.substring( 0, overlapLength2 ) ] ); diffs[pointer - 1][0] = DIFF_INSERT; diffs[pointer - 1][1] = insertion.substring(0, insertion.length - overlapLength2); diffs[pointer + 1][0] = DIFF_DELETE; diffs[pointer + 1][1] = deletion.substring(overlapLength2); pointer++; } } pointer++; } pointer++; } }; /** * Determine if the suffix of one string is the prefix of another. * @param {string} text1 First string. * @param {string} text2 Second string. * @return {number} The number of characters common to the end of the first * string and the start of the second string. * @private */ DiffMatchPatch.prototype.diffCommonOverlap = function(text1, text2) { var text1Length, text2Length, textLength, best, length, pattern, found; // Cache the text lengths to prevent multiple calls. text1Length = text1.length; text2Length = text2.length; // Eliminate the null case. if (text1Length === 0 || text2Length === 0) { return 0; } // Truncate the longer string. if (text1Length > text2Length) { text1 = text1.substring(text1Length - text2Length); } else if (text1Length < text2Length) { text2 = text2.substring(0, text1Length); } textLength = Math.min(text1Length, text2Length); // Quick check for the worst case. if (text1 === text2) { return textLength; } // Start by looking for a single character match // and increase length until no match is found. // Performance analysis: http://neil.fraser.name/news/2010/11/04/ best = 0; length = 1; while (true) { pattern = text1.substring(textLength - length); found = text2.indexOf(pattern); if (found === -1) { return best; } length += found; if (found === 0 || text1.substring(textLength - length) === text2.substring(0, length)) { best = length; length++; } } }; /** * Split two texts into an array of strings. Reduce the texts to a string of * hashes where each Unicode character represents one line. * @param {string} text1 First string. * @param {string} text2 Second string. * @return {{chars1: string, chars2: string, lineArray: !Array.}} * An object containing the encoded text1, the encoded text2 and * the array of unique strings. * The zeroth element of the array of unique strings is intentionally blank. * @private */ DiffMatchPatch.prototype.diffLinesToChars = function(text1, text2) { var lineArray, lineHash, chars1, chars2; lineArray = []; // e.g. lineArray[4] === 'Hello\n' lineHash = {}; // e.g. lineHash['Hello\n'] === 4 // '\x00' is a valid character, but various debuggers don't like it. // So we'll insert a junk entry to avoid generating a null character. lineArray[0] = ""; /** * Split a text into an array of strings. Reduce the texts to a string of * hashes where each Unicode character represents one line. * Modifies linearray and linehash through being a closure. * @param {string} text String to encode. * @return {string} Encoded string. * @private */ function diffLinesToCharsMunge(text) { var chars, lineStart, lineEnd, lineArrayLength, line; chars = ""; // Walk the text, pulling out a substring for each line. // text.split('\n') would would temporarily double our memory footprint. // Modifying text would create many large strings to garbage collect. lineStart = 0; lineEnd = -1; // Keeping our own length variable is faster than looking it up. lineArrayLength = lineArray.length; while (lineEnd < text.length - 1) { lineEnd = text.indexOf("\n", lineStart); if (lineEnd === -1) { lineEnd = text.length - 1; } line = text.substring(lineStart, lineEnd + 1); lineStart = lineEnd + 1; if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) { chars += String.fromCharCode( lineHash[ line ] ); } else { chars += String.fromCharCode(lineArrayLength); lineHash[line] = lineArrayLength; lineArray[lineArrayLength++] = line; } } return chars; } chars1 = diffLinesToCharsMunge(text1); chars2 = diffLinesToCharsMunge(text2); return { chars1: chars1, chars2: chars2, lineArray: lineArray }; }; /** * Rehydrate the text in a diff from a string of line hashes to real lines of * text. * @param {!Array.} diffs Array of diff tuples. * @param {!Array.} lineArray Array of unique strings. * @private */ DiffMatchPatch.prototype.diffCharsToLines = function( diffs, lineArray ) { var x, chars, text, y; for ( x = 0; x < diffs.length; x++ ) { chars = diffs[x][1]; text = []; for ( y = 0; y < chars.length; y++ ) { text[y] = lineArray[chars.charCodeAt(y)]; } diffs[x][1] = text.join(""); } }; /** * Reorder and merge like edit sections. Merge equalities. * Any edit section can move as long as it doesn't cross an equality. * @param {!Array.} diffs Array of diff tuples. */ DiffMatchPatch.prototype.diffCleanupMerge = function(diffs) { var pointer, countDelete, countInsert, textInsert, textDelete, commonlength, changes; diffs.push( [ DIFF_EQUAL, "" ] ); // Add a dummy entry at the end. pointer = 0; countDelete = 0; countInsert = 0; textDelete = ""; textInsert = ""; commonlength; while (pointer < diffs.length) { switch ( diffs[ pointer ][ 0 ] ) { case DIFF_INSERT: countInsert++; textInsert += diffs[pointer][1]; pointer++; break; case DIFF_DELETE: countDelete++; textDelete += diffs[pointer][1]; pointer++; break; case DIFF_EQUAL: // Upon reaching an equality, check for prior redundancies. if (countDelete + countInsert > 1) { if (countDelete !== 0 && countInsert !== 0) { // Factor out any common prefixies. commonlength = this.diffCommonPrefix(textInsert, textDelete); if (commonlength !== 0) { if ((pointer - countDelete - countInsert) > 0 && diffs[pointer - countDelete - countInsert - 1][0] === DIFF_EQUAL) { diffs[pointer - countDelete - countInsert - 1][1] += textInsert.substring(0, commonlength); } else { diffs.splice( 0, 0, [ DIFF_EQUAL, textInsert.substring( 0, commonlength ) ] ); pointer++; } textInsert = textInsert.substring(commonlength); textDelete = textDelete.substring(commonlength); } // Factor out any common suffixies. commonlength = this.diffCommonSuffix(textInsert, textDelete); if (commonlength !== 0) { diffs[pointer][1] = textInsert.substring(textInsert.length - commonlength) + diffs[pointer][1]; textInsert = textInsert.substring(0, textInsert.length - commonlength); textDelete = textDelete.substring(0, textDelete.length - commonlength); } } // Delete the offending records and add the merged ones. if (countDelete === 0) { diffs.splice( pointer - countInsert, countDelete + countInsert, [ DIFF_INSERT, textInsert ] ); } else if (countInsert === 0) { diffs.splice( pointer - countDelete, countDelete + countInsert, [ DIFF_DELETE, textDelete ] ); } else { diffs.splice( pointer - countDelete - countInsert, countDelete + countInsert, [ DIFF_DELETE, textDelete ], [ DIFF_INSERT, textInsert ] ); } pointer = pointer - countDelete - countInsert + (countDelete ? 1 : 0) + (countInsert ? 1 : 0) + 1; } else if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) { // Merge this equality with the previous one. diffs[pointer - 1][1] += diffs[pointer][1]; diffs.splice(pointer, 1); } else { pointer++; } countInsert = 0; countDelete = 0; textDelete = ""; textInsert = ""; break; } } if (diffs[diffs.length - 1][1] === "") { diffs.pop(); // Remove the dummy entry at the end. } // Second pass: look for single edits surrounded on both sides by equalities // which can be shifted sideways to eliminate an equality. // e.g: ABAC -> ABAC changes = false; pointer = 1; // Intentionally ignore the first and last element (don't need checking). while (pointer < diffs.length - 1) { if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) { // This is a single edit surrounded by equalities. if ( diffs[ pointer ][ 1 ].substring( diffs[ pointer ][ 1 ].length - diffs[ pointer - 1 ][ 1 ].length ) === diffs[ pointer - 1 ][ 1 ] ) { // Shift the edit over the previous equality. diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length); diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; diffs.splice(pointer - 1, 1); changes = true; } else if ( diffs[ pointer ][ 1 ].substring( 0, diffs[ pointer + 1 ][ 1 ].length ) === diffs[ pointer + 1 ][ 1 ] ) { // Shift the edit over the next equality. diffs[pointer - 1][1] += diffs[pointer + 1][1]; diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1]; diffs.splice(pointer + 1, 1); changes = true; } } pointer++; } // If shifts were made, the diff needs reordering and another shift sweep. if (changes) { this.diffCleanupMerge(diffs); } }; return function(o, n) { var diff, output, text; diff = new DiffMatchPatch(); output = diff.DiffMain(o, n); //console.log(output); diff.diffCleanupEfficiency(output); text = diff.diffPrettyHtml(output); return text; }; }()); // jscs:enable (function() { // Deprecated QUnit.init - Ref #530 // Re-initialize the configuration options QUnit.init = function() { var tests, banner, result, qunit, config = QUnit.config; config.stats = { all: 0, bad: 0 }; config.moduleStats = { all: 0, bad: 0 }; config.started = 0; config.updateRate = 1000; config.blocking = false; config.autostart = true; config.autorun = false; config.filter = ""; config.queue = []; // Return on non-browser environments // This is necessary to not break on node tests if ( typeof window === "undefined" ) { return; } qunit = id( "qunit" ); if ( qunit ) { qunit.innerHTML = "

" + escapeText( document.title ) + "

" + "

" + "
" + "

" + "
    "; } tests = id( "qunit-tests" ); banner = id( "qunit-banner" ); result = id( "qunit-testresult" ); if ( tests ) { tests.innerHTML = ""; } if ( banner ) { banner.className = ""; } if ( result ) { result.parentNode.removeChild( result ); } if ( tests ) { result = document.createElement( "p" ); result.id = "qunit-testresult"; result.className = "result"; tests.parentNode.insertBefore( result, tests ); result.innerHTML = "Running...
     "; } }; // Don't load the HTML Reporter on non-Browser environments if ( typeof window === "undefined" ) { return; } var config = QUnit.config, hasOwn = Object.prototype.hasOwnProperty, defined = { document: window.document !== undefined, sessionStorage: (function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); sessionStorage.removeItem( x ); return true; } catch ( e ) { return false; } }()) }, modulesList = []; /** * Escape text for attribute or text content. */ function escapeText( s ) { if ( !s ) { return ""; } s = s + ""; // Both single quotes and double quotes (for attributes) return s.replace( /['"<>&]/g, function( s ) { switch ( s ) { case "'": return "'"; case "\"": return """; case "<": return "<"; case ">": return ">"; case "&": return "&"; } }); } /** * @param {HTMLElement} elem * @param {string} type * @param {Function} fn */ function addEvent( elem, type, fn ) { if ( elem.addEventListener ) { // Standards-based browsers elem.addEventListener( type, fn, false ); } else if ( elem.attachEvent ) { // support: IE <9 elem.attachEvent( "on" + type, function() { var event = window.event; if ( !event.target ) { event.target = event.srcElement || document; } fn.call( elem, event ); }); } } /** * @param {Array|NodeList} elems * @param {string} type * @param {Function} fn */ function addEvents( elems, type, fn ) { var i = elems.length; while ( i-- ) { addEvent( elems[ i ], type, fn ); } } function hasClass( elem, name ) { return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0; } function addClass( elem, name ) { if ( !hasClass( elem, name ) ) { elem.className += ( elem.className ? " " : "" ) + name; } } function toggleClass( elem, name ) { if ( hasClass( elem, name ) ) { removeClass( elem, name ); } else { addClass( elem, name ); } } function removeClass( elem, name ) { var set = " " + elem.className + " "; // Class name may appear multiple times while ( set.indexOf( " " + name + " " ) >= 0 ) { set = set.replace( " " + name + " ", " " ); } // trim for prettiness elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" ); } function id( name ) { return defined.document && document.getElementById && document.getElementById( name ); } function getUrlConfigHtml() { var i, j, val, escaped, escapedTooltip, selection = false, len = config.urlConfig.length, urlConfigHtml = ""; for ( i = 0; i < len; i++ ) { val = config.urlConfig[ i ]; if ( typeof val === "string" ) { val = { id: val, label: val }; } escaped = escapeText( val.id ); escapedTooltip = escapeText( val.tooltip ); if ( config[ val.id ] === undefined ) { config[ val.id ] = QUnit.urlParams[ val.id ]; } if ( !val.value || typeof val.value === "string" ) { urlConfigHtml += ""; } else { urlConfigHtml += ""; } } return urlConfigHtml; } // Handle "click" events on toolbar checkboxes and "change" for select menus. // Updates the URL with the new state of `config.urlConfig` values. function toolbarChanged() { var updatedUrl, value, field = this, params = {}; // Detect if field is a select menu or a checkbox if ( "selectedIndex" in field ) { value = field.options[ field.selectedIndex ].value || undefined; } else { value = field.checked ? ( field.defaultValue || true ) : undefined; } params[ field.name ] = value; updatedUrl = setUrl( params ); if ( "hidepassed" === field.name && "replaceState" in window.history ) { config[ field.name ] = value || false; if ( value ) { addClass( id( "qunit-tests" ), "hidepass" ); } else { removeClass( id( "qunit-tests" ), "hidepass" ); } // It is not necessary to refresh the whole page window.history.replaceState( null, "", updatedUrl ); } else { window.location = updatedUrl; } } function setUrl( params ) { var key, querystring = "?"; params = QUnit.extend( QUnit.extend( {}, QUnit.urlParams ), params ); for ( key in params ) { if ( hasOwn.call( params, key ) ) { if ( params[ key ] === undefined ) { continue; } querystring += encodeURIComponent( key ); if ( params[ key ] !== true ) { querystring += "=" + encodeURIComponent( params[ key ] ); } querystring += "&"; } } return location.protocol + "//" + location.host + location.pathname + querystring.slice( 0, -1 ); } function applyUrlParams() { var selectedModule, modulesList = id( "qunit-modulefilter" ), filter = id( "qunit-filter-input" ).value; selectedModule = modulesList ? decodeURIComponent( modulesList.options[ modulesList.selectedIndex ].value ) : undefined; window.location = setUrl({ module: ( selectedModule === "" ) ? undefined : selectedModule, filter: ( filter === "" ) ? undefined : filter, // Remove testId filter testId: undefined }); } function toolbarUrlConfigContainer() { var urlConfigContainer = document.createElement( "span" ); urlConfigContainer.innerHTML = getUrlConfigHtml(); addClass( urlConfigContainer, "qunit-url-config" ); // For oldIE support: // * Add handlers to the individual elements instead of the container // * Use "click" instead of "change" for checkboxes addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged ); addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged ); return urlConfigContainer; } function toolbarLooseFilter() { var filter = document.createElement( "form" ), label = document.createElement( "label" ), input = document.createElement( "input" ), button = document.createElement( "button" ); addClass( filter, "qunit-filter" ); label.innerHTML = "Filter: "; input.type = "text"; input.value = config.filter || ""; input.name = "filter"; input.id = "qunit-filter-input"; button.innerHTML = "Go"; label.appendChild( input ); filter.appendChild( label ); filter.appendChild( button ); addEvent( filter, "submit", function( ev ) { applyUrlParams(); if ( ev && ev.preventDefault ) { ev.preventDefault(); } return false; }); return filter; } function toolbarModuleFilterHtml() { var i, moduleFilterHtml = ""; if ( !modulesList.length ) { return false; } modulesList.sort(function( a, b ) { return a.localeCompare( b ); }); moduleFilterHtml += "" + ""; return moduleFilterHtml; } function toolbarModuleFilter() { var toolbar = id( "qunit-testrunner-toolbar" ), moduleFilter = document.createElement( "span" ), moduleFilterHtml = toolbarModuleFilterHtml(); if ( !toolbar || !moduleFilterHtml ) { return false; } moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); moduleFilter.innerHTML = moduleFilterHtml; addEvent( moduleFilter.lastChild, "change", applyUrlParams ); toolbar.appendChild( moduleFilter ); } function appendToolbar() { var toolbar = id( "qunit-testrunner-toolbar" ); if ( toolbar ) { toolbar.appendChild( toolbarUrlConfigContainer() ); toolbar.appendChild( toolbarLooseFilter() ); } } function appendHeader() { var header = id( "qunit-header" ); if ( header ) { header.innerHTML = "" + header.innerHTML + " "; } } function appendBanner() { var banner = id( "qunit-banner" ); if ( banner ) { banner.className = ""; } } function appendTestResults() { var tests = id( "qunit-tests" ), result = id( "qunit-testresult" ); if ( result ) { result.parentNode.removeChild( result ); } if ( tests ) { tests.innerHTML = ""; result = document.createElement( "p" ); result.id = "qunit-testresult"; result.className = "result"; tests.parentNode.insertBefore( result, tests ); result.innerHTML = "Running...
     "; } } function storeFixture() { var fixture = id( "qunit-fixture" ); if ( fixture ) { config.fixture = fixture.innerHTML; } } function appendUserAgent() { var userAgent = id( "qunit-userAgent" ); if ( userAgent ) { userAgent.innerHTML = ""; userAgent.appendChild( document.createTextNode( "QUnit " + QUnit.version + "; " + navigator.userAgent ) ); } } function appendTestsList( modules ) { var i, l, x, z, test, moduleObj; for ( i = 0, l = modules.length; i < l; i++ ) { moduleObj = modules[ i ]; if ( moduleObj.name ) { modulesList.push( moduleObj.name ); } for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) { test = moduleObj.tests[ x ]; appendTest( test.name, test.testId, moduleObj.name ); } } } function appendTest( name, testId, moduleName ) { var title, rerunTrigger, testBlock, assertList, tests = id( "qunit-tests" ); if ( !tests ) { return; } title = document.createElement( "strong" ); title.innerHTML = getNameHtml( name, moduleName ); rerunTrigger = document.createElement( "a" ); rerunTrigger.innerHTML = "Rerun"; rerunTrigger.href = setUrl({ testId: testId }); testBlock = document.createElement( "li" ); testBlock.appendChild( title ); testBlock.appendChild( rerunTrigger ); testBlock.id = "qunit-test-output-" + testId; assertList = document.createElement( "ol" ); assertList.className = "qunit-assert-list"; testBlock.appendChild( assertList ); tests.appendChild( testBlock ); } // HTML Reporter initialization and load QUnit.begin(function( details ) { var qunit = id( "qunit" ); // Fixture is the only one necessary to run without the #qunit element storeFixture(); if ( qunit ) { qunit.innerHTML = "

    " + escapeText( document.title ) + "

    " + "

    " + "
    " + "

    " + "
      "; } appendHeader(); appendBanner(); appendTestResults(); appendUserAgent(); appendToolbar(); appendTestsList( details.modules ); toolbarModuleFilter(); if ( qunit && config.hidepassed ) { addClass( qunit.lastChild, "hidepass" ); } }); QUnit.done(function( details ) { var i, key, banner = id( "qunit-banner" ), tests = id( "qunit-tests" ), html = [ "Tests completed in ", details.runtime, " milliseconds.
      ", "", details.passed, " assertions of ", details.total, " passed, ", details.failed, " failed." ].join( "" ); if ( banner ) { banner.className = details.failed ? "qunit-fail" : "qunit-pass"; } if ( tests ) { id( "qunit-testresult" ).innerHTML = html; } if ( config.altertitle && defined.document && document.title ) { // show ✖ for good, ✔ for bad suite result in title // use escape sequences in case file gets loaded with non-utf-8-charset document.title = [ ( details.failed ? "\u2716" : "\u2714" ), document.title.replace( /^[\u2714\u2716] /i, "" ) ].join( " " ); } // clear own sessionStorage items if all tests passed if ( config.reorder && defined.sessionStorage && details.failed === 0 ) { for ( i = 0; i < sessionStorage.length; i++ ) { key = sessionStorage.key( i++ ); if ( key.indexOf( "qunit-test-" ) === 0 ) { sessionStorage.removeItem( key ); } } } // scroll back to top to show results if ( config.scrolltop && window.scrollTo ) { window.scrollTo( 0, 0 ); } }); function getNameHtml( name, module ) { var nameHtml = ""; if ( module ) { nameHtml = "" + escapeText( module ) + ": "; } nameHtml += "" + escapeText( name ) + ""; return nameHtml; } QUnit.testStart(function( details ) { var running, testBlock, bad; testBlock = id( "qunit-test-output-" + details.testId ); if ( testBlock ) { testBlock.className = "running"; } else { // Report later registered tests appendTest( details.name, details.testId, details.module ); } running = id( "qunit-testresult" ); if ( running ) { bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem( "qunit-test-" + details.module + "-" + details.name ); running.innerHTML = ( bad ? "Rerunning previously failed test:
      " : "Running:
      " ) + getNameHtml( details.name, details.module ); } }); QUnit.log(function( details ) { var assertList, assertLi, message, expected, actual, testItem = id( "qunit-test-output-" + details.testId ); if ( !testItem ) { return; } message = escapeText( details.message ) || ( details.result ? "okay" : "failed" ); message = "" + message + ""; message += "@ " + details.runtime + " ms"; // pushFailure doesn't provide details.expected // when it calls, it's implicit to also not show expected and diff stuff // Also, we need to check details.expected existence, as it can exist and be undefined if ( !details.result && hasOwn.call( details, "expected" ) ) { expected = escapeText( QUnit.dump.parse( details.expected ) ); actual = escapeText( QUnit.dump.parse( details.actual ) ); message += ""; if ( actual !== expected ) { message += "" + ""; } else { if ( expected.indexOf( "[object Array]" ) !== -1 || expected.indexOf( "[object Object]" ) !== -1 ) { message += ""; } } if ( details.source ) { message += ""; } message += "
      Expected:
      " +
      			expected +
      			"
      Result:
      " +
      				actual + "
      Diff:
      " +
      				QUnit.diff( expected, actual ) + "
      Message: " + "Diff suppressed as the depth of object is more than current max depth (" + QUnit.config.maxDepth + ").

      Hint: Use QUnit.dump.maxDepth to " + " run with a higher max depth or " + "Rerun without max depth.

      Source:
      " +
      				escapeText( details.source ) + "
      "; // this occours when pushFailure is set and we have an extracted stack trace } else if ( !details.result && details.source ) { message += "" + "" + "
      Source:
      " +
      			escapeText( details.source ) + "
      "; } assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; assertLi = document.createElement( "li" ); assertLi.className = details.result ? "pass" : "fail"; assertLi.innerHTML = message; assertList.appendChild( assertLi ); }); QUnit.testDone(function( details ) { var testTitle, time, testItem, assertList, good, bad, testCounts, skipped, tests = id( "qunit-tests" ); if ( !tests ) { return; } testItem = id( "qunit-test-output-" + details.testId ); assertList = testItem.getElementsByTagName( "ol" )[ 0 ]; good = details.passed; bad = details.failed; // store result when possible if ( config.reorder && defined.sessionStorage ) { if ( bad ) { sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad ); } else { sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name ); } } if ( bad === 0 ) { addClass( assertList, "qunit-collapsed" ); } // testItem.firstChild is the test name testTitle = testItem.firstChild; testCounts = bad ? "" + bad + ", " + "" + good + ", " : ""; testTitle.innerHTML += " (" + testCounts + details.assertions.length + ")"; if ( details.skipped ) { testItem.className = "skipped"; skipped = document.createElement( "em" ); skipped.className = "qunit-skipped-label"; skipped.innerHTML = "skipped"; testItem.insertBefore( skipped, testTitle ); } else { addEvent( testTitle, "click", function() { toggleClass( assertList, "qunit-collapsed" ); }); testItem.className = bad ? "fail" : "pass"; time = document.createElement( "span" ); time.className = "runtime"; time.innerHTML = details.runtime + " ms"; testItem.insertBefore( time, assertList ); } }); if ( defined.document ) { if ( document.readyState === "complete" ) { QUnit.load(); } else { addEvent( window, "load", QUnit.load ); } } else { config.pageLoaded = true; config.autorun = true; } })(); three.js-r73/test/unit/lights/0000755000175500017550000000000012610076566016204 5ustar debacledebaclethree.js-r73/test/unit/lights/PointLight.tests.js0000644000175500017550000000045112610076566021764 0ustar debacledebacle(function () { 'use strict'; var lights; QUnit.module( "Lights - PointLight", { beforeEach: function() { lights = [ new THREE.PointLight( 0xaaaaaa ), ]; } }); QUnit.test( "standard light tests", function( assert ) { runStdLightTests( assert, lights ); }); })(); three.js-r73/test/unit/lights/HemisphereLight.tests.js0000644000175500017550000000111112610076566022756 0ustar debacledebacle(function () { 'use strict'; var parameters = { skyColor: 0x123456, groundColor: 0xabc012, intensity: 0.6 }; var lights; QUnit.module( "Lights - HemisphereLight", { beforeEach: function() { lights = [ new THREE.HemisphereLight( parameters.skyColor ), new THREE.HemisphereLight( parameters.skyColor, parameters.groundColor ), new THREE.HemisphereLight( parameters.skyColor, parameters.groundColor, parameters.intensity ), ]; } }); QUnit.test( "standard light tests", function( assert ) { runStdLightTests( assert, lights ); }); })(); three.js-r73/test/unit/lights/DirectionalLight.tests.js0000644000175500017550000000054612610076566023135 0ustar debacledebacle(function () { 'use strict'; var lights; QUnit.module( "Lights - DirectionalLight", { beforeEach: function() { lights = [ new THREE.DirectionalLight( 0xaaaaaa ), new THREE.DirectionalLight( 0xaaaaaa, 0.8 ), ]; } }); QUnit.test( "standard light tests", function( assert ) { runStdLightTests( assert, lights ); }); })(); three.js-r73/test/unit/lights/AmbientLight.tests.js0000644000175500017550000000045512610076566022256 0ustar debacledebacle(function () { 'use strict'; var lights; QUnit.module( "Lights - AmbientLight", { beforeEach: function() { lights = [ new THREE.AmbientLight( 0xaaaaaa ), ]; } }); QUnit.test( "standard light tests", function( assert ) { runStdLightTests( assert, lights ); }); })(); three.js-r73/test/unit/lights/SpotLight.tests.js0000644000175500017550000000167312610076566021627 0ustar debacledebacle(function () { 'use strict'; var parameters = { color: 0xaaaaaa, intensity: 0.5, distance: 100, angle: 0.8, exponent: 8, decay: 2 }; var lights; QUnit.module( "Lights - SpotLight", { beforeEach: function() { lights = [ new THREE.SpotLight( parameters.color ), new THREE.SpotLight( parameters.color, parameters.intensity ), new THREE.SpotLight( parameters.color, parameters.intensity, parameters.distance ), new THREE.SpotLight( parameters.color, parameters.intensity, parameters.distance, parameters.angle ), new THREE.SpotLight( parameters.color, parameters.intensity, parameters.distance, parameters.angle, parameters.exponent ), new THREE.SpotLight( parameters.color, parameters.intensity, parameters.distance, parameters.angle, parameters.exponent, parameters.decay ), ]; } }); QUnit.test( "standard light tests", function( assert ) { runStdLightTests( assert, lights ); }); })(); three.js-r73/test/unit/unittests_three.html0000644000175500017550000000722112610076566021033 0ustar debacledebacle ThreeJS Unit Tests - Using build/Three.js
      three.js-r73/test/unit/core/0000755000175500017550000000000012610076566015642 5ustar debacledebaclethree.js-r73/test/unit/core/Object3D.js0000644000175500017550000000470112610076566017577 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "Object3D" ); var RadToDeg = 180 / Math.PI; test( "rotateX", function() { var obj = new THREE.Object3D(); var angleInRad = 1.562; obj.rotateX(angleInRad); // should calculate the correct rotation on x checkIfFloatsAreEqual(obj.rotation.x, angleInRad); }); test( "rotateY", function() { var obj = new THREE.Object3D(); var angleInRad = -0.346; obj.rotateY(angleInRad); // should calculate the correct rotation on y checkIfFloatsAreEqual(obj.rotation.y, angleInRad); }); test( "rotateZ", function() { var obj = new THREE.Object3D(); var angleInRad = 1; obj.rotateZ(angleInRad); // should calculate the correct rotation on y checkIfFloatsAreEqual(obj.rotation.z, angleInRad); }); test( "translateOnAxis", function() { var obj = new THREE.Object3D(); // get a reference object for comparing var reference = {x: 1, y: 1.23, z: -4.56}; obj.translateOnAxis(new THREE.Vector3(1, 0, 0), 1); obj.translateOnAxis(new THREE.Vector3(0, 1, 0), 1.23); obj.translateOnAxis(new THREE.Vector3(0, 0, 1), -4.56); checkIfPropsAreEqual(reference, obj.position); }); test( "translateX", function() { var obj = new THREE.Object3D(); obj.translateX(1.234); ok( obj.position.x === 1.234 , "x is equal" ); }); test( "translateY", function() { var obj = new THREE.Object3D(); obj.translateY(1.234); ok( obj.position.y === 1.234 , "y is equal" ); }); test( "translateZ", function() { var obj = new THREE.Object3D(); obj.translateZ(1.234); ok( obj.position.z === 1.234 , "z is equal" ); }); test( "lookAt", function() { var obj = new THREE.Object3D(); obj.lookAt(new THREE.Vector3(0, -1, 1)); ok( obj.rotation.x * RadToDeg === 45 , "x is equal" ); }); test( "getWorldRotation", function() { var obj = new THREE.Object3D(); obj.lookAt(new THREE.Vector3(0, -1, 1)); ok( obj.getWorldRotation().x * RadToDeg === 45 , "x is equal" ); obj.lookAt(new THREE.Vector3(1, 0, 0)); ok( obj.getWorldRotation().y * RadToDeg === 90 , "y is equal" ); }); function checkIfPropsAreEqual(reference, obj) { ok( obj.x === reference.x , "x is equal" ); ok( obj.y === reference.y , "y is equal!" ); ok( obj.z === reference.z , "z is equal!" ); } // since float equal checking is a mess in js, one solution is to cut off // decimal places function checkIfFloatsAreEqual(f1, f2) { var f1Rounded = ((f1 * 1000) | 0) / 1000; var f2Rounded = ((f2 * 1000) | 0) / 1000; ok( f1Rounded === f2Rounded, "passed" ); } three.js-r73/test/unit/core/EventDispatcher.js0000644000175500017550000000544212610076566021275 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "EventDispatcher" ); test( "apply", function() { var innocentObject = {}; var eventDispatcher = new THREE.EventDispatcher(); eventDispatcher.apply( innocentObject ); ok( innocentObject.addEventListener !== undefined && innocentObject.hasEventListener !== undefined && innocentObject.removeEventListener !== undefined && innocentObject.dispatchEvent !== undefined, "events where added to object" ); }); test( "addEventListener", function() { var eventDispatcher = new THREE.EventDispatcher(); var listener = {}; eventDispatcher.addEventListener( 'anyType', listener ); ok( eventDispatcher._listeners.anyType.length === 1, "listener with unknown type was added" ); ok( eventDispatcher._listeners.anyType[0] === listener, "listener with unknown type was added" ); eventDispatcher.addEventListener( 'anyType', listener ); ok( eventDispatcher._listeners.anyType.length === 1, "can't add one listener twice to same type" ); ok( eventDispatcher._listeners.anyType[0] === listener, "listener is still there" ); }); test( "hasEventListener", function() { var eventDispatcher = new THREE.EventDispatcher(); var listener = {}; eventDispatcher.addEventListener( 'anyType', listener ); ok( eventDispatcher.hasEventListener( 'anyType', listener ), "listener was found" ); ok( !eventDispatcher.hasEventListener( 'anotherType', listener ), "listener was not found which is good" ); }); test( "removeEventListener", function() { var eventDispatcher = new THREE.EventDispatcher(); var listener = {}; ok ( eventDispatcher._listeners === undefined, "there are no listeners by default" ); eventDispatcher.addEventListener( 'anyType', listener ); ok ( Object.keys( eventDispatcher._listeners ).length === 1 && eventDispatcher._listeners.anyType.length === 1, "if a listener was added, there is a new key" ); eventDispatcher.removeEventListener( 'anyType', listener ); ok ( eventDispatcher._listeners.anyType.length === 0, "listener was deleted" ); eventDispatcher.removeEventListener( 'unknownType', listener ); ok ( eventDispatcher._listeners.unknownType === undefined, "unknown types will be ignored" ); eventDispatcher.removeEventListener( 'anyType', undefined ); ok ( eventDispatcher._listeners.anyType.length === 0, "undefined listeners are ignored" ); }); test( "dispatchEvent", function() { var eventDispatcher = new THREE.EventDispatcher(); var callCount = 0; var listener = function() { callCount++; }; eventDispatcher.addEventListener( 'anyType', listener ); ok( callCount === 0, "no event, no call" ); eventDispatcher.dispatchEvent( { type: 'anyType' } ); ok( callCount === 1, "one event, one call" ); eventDispatcher.dispatchEvent( { type: 'anyType' } ); ok( callCount === 2, "two events, two calls" ); }); // three.js-r73/test/unit/core/BufferGeometry.js0000644000175500017550000002673612610076566021143 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "BufferGeometry" ); var DegToRad = Math.PI / 180; test( "add / delete Attribute", function() { var geometry = new THREE.BufferGeometry(); var attributeName = "position"; ok ( geometry.attributes[attributeName] === undefined , 'no attribute defined' ); geometry.addAttribute( attributeName, new THREE.BufferAttribute( new Float32Array( [1, 2, 3], 1 ) ) ); ok ( geometry.attributes[attributeName] !== undefined , 'attribute is defined' ); geometry.removeAttribute( attributeName ); ok ( geometry.attributes[attributeName] === undefined , 'no attribute defined' ); }); test( "applyMatrix", function() { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(6), 3 ) ); var matrix = new THREE.Matrix4().set( 1, 0, 0, 1.5, 0, 1, 0, -2, 0, 0, 1, 3, 0, 0, 0, 1 ); geometry.applyMatrix(matrix); var position = geometry.attributes.position.array; var m = matrix.elements; ok( position[0] === m[12] && position[1] === m[13] && position[2] === m[14], "position was extracted from matrix" ); ok( position[3] === m[12] && position[4] === m[13] && position[5] === m[14], "position was extracted from matrix twice" ); ok( geometry.attributes.position.version === 1, "version was increased during update" ); }); test( "rotateX/Y/Z", function() { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 4, 5, 6]), 3 ) ); var pos = geometry.attributes.position.array; geometry.rotateX( 180 * DegToRad ); // object was rotated around x so all items should be flipped but the x ones ok( pos[0] === 1 && pos[1] === -2 && pos[2] === -3 && pos[3] === 4 && pos[4] === -5 && pos[5] === -6, "vertices were rotated around x by 180 degrees" ); geometry.rotateY( 180 * DegToRad ); // vertices were rotated around y so all items should be flipped again but the y ones ok( pos[0] === -1 && pos[1] === -2 && pos[2] === 3 && pos[3] === -4 && pos[4] === -5 && pos[5] === 6, "vertices were rotated around y by 180 degrees" ); geometry.rotateZ( 180 * DegToRad ); // vertices were rotated around z so all items should be flipped again but the z ones ok( pos[0] === 1 && pos[1] === 2 && pos[2] === 3 && pos[3] === 4 && pos[4] === 5 && pos[5] === 6, "vertices were rotated around z by 180 degrees" ); }); test( "translate", function() { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 4, 5, 6]), 3 ) ); var pos = geometry.attributes.position.array; geometry.translate( 10, 20, 30 ); ok( pos[0] === 11 && pos[1] === 22 && pos[2] === 33 && pos[3] === 14 && pos[4] === 25 && pos[5] === 36, "vertices were translated" ); }); test( "scale", function() { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([-1, -1, -1, 2, 2, 2]), 3 ) ); var pos = geometry.attributes.position.array; geometry.scale( 1, 2, 3 ); ok( pos[0] === -1 && pos[1] === -2 && pos[2] === -3 && pos[3] === 2 && pos[4] === 4 && pos[5] === 6, "vertices were scaled" ); }); test( "center", function() { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array([ -1, -1, -1, 1, 1, 1, 4, 4, 4 ]), 3 ) ); geometry.center(); var pos = geometry.attributes.position.array; var bb = geometry.boundingBox; // the boundingBox should go from (-1, -1, -1) to (4, 4, 4) so it has a size of (5, 5, 5) // after centering it the vertices should be placed between (-2.5, -2.5, -2.5) and (2.5, 2.5, 2.5) ok( pos[0] === -2.5 && pos[1] === -2.5 && pos[2] === -2.5 && pos[3] === -0.5 && pos[4] === -0.5 && pos[5] === -0.5 && pos[6] === 2.5 && pos[7] === 2.5 && pos[8] === 2.5, "vertices were replaced by boundingBox dimensions" ); }); test( "setFromObject", function() { var lineGeo = new THREE.Geometry(); lineGeo.vertices.push( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( 0, 10, 0 ), new THREE.Vector3( 10, 0, 0 ) ); lineGeo.colors.push( new THREE.Color(1, 0, 0 ), new THREE.Color(0, 1, 0 ), new THREE.Color(0, 0, 1 ) ); var line = new THREE.Line( lineGeo, null ); var geometry = new THREE.BufferGeometry().setFromObject( line ); var pos = geometry.attributes.position.array; var col = geometry.attributes.color.array; var v = lineGeo.vertices; var c = lineGeo.colors; ok( // position exists pos !== undefined && // vertex arrays have the same size v.length * 3 === pos.length && // there are three complete vertices (each vertex contains three values) geometry.attributes.position.count === 3 && // check if both arrays contains the same data pos[0] === v[0].x && pos[1] === v[0].y && pos[2] === v[0].z && pos[3] === v[1].x && pos[4] === v[1].y && pos[5] === v[1].z && pos[6] === v[2].x && pos[7] === v[2].y && pos[8] === v[2].z , "positions are equal" ); ok( // color exists col !== undefined && // color arrays have the same size c.length * 3 === col.length && // there are three complete colors (each color contains three values) geometry.attributes.color.count === 3 && // check if both arrays contains the same data col[0] === c[0].r && col[1] === c[0].g && col[2] === c[0].b && col[3] === c[1].r && col[4] === c[1].g && col[5] === c[1].b && col[6] === c[2].r && col[7] === c[2].g && col[8] === c[2].b , "colors are equal" ); }); test( "computeBoundingBox", function() { var bb = getBBForVertices( [-1, -2, -3, 13, -2, -3.5, -1, -20, 0, -4, 5, 6] ); ok( bb.min.x === -4 && bb.min.y === -20 && bb.min.z === -3.5, "min values are set correctly" ); ok( bb.max.x === 13 && bb.max.y === 5 && bb.max.z === 6, "max values are set correctly" ); bb = getBBForVertices( [] ); ok( bb.min.x === 0 && bb.min.y === 0 && bb.min.z === 0, "since there are no values given, the bb has size = 0" ); ok( bb.max.x === 0 && bb.max.y === 0 && bb.max.z === 0, "since there are no values given, the bb has size = 0" ); bb = getBBForVertices( [-1, -1, -1] ); ok( bb.min.x === bb.max.x && bb.min.y === bb.max.y && bb.min.z === bb.max.z, "since there is only one vertex, max and min are equal" ); ok( bb.min.x === -1 && bb.min.y === -1 && bb.min.z === -1, "since there is only one vertex, min and max are this vertex" ); bb = getBBForVertices( [-1] ); }); test( "computeBoundingSphere", function() { var bs = getBSForVertices( [-10, 0, 0, 10, 0, 0] ); ok( bs.radius === (10 + 10) / 2, "radius is equal to deltaMinMax / 2" ) ok( bs.center.x === 0 && bs.center.y === 0 && bs.center.y === 0, "bounding sphere is at ( 0, 0, 0 )" ) var bs = getBSForVertices( [-5, 11, -3, 5, -11, 3] ); var radius = new THREE.Vector3(5, 11, 3).length(); ok( bs.radius === radius, "radius is equal to directionLength" ) ok( bs.center.x === 0 && bs.center.y === 0 && bs.center.y === 0, "bounding sphere is at ( 0, 0, 0 )" ) }); function getBBForVertices(vertices) { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(vertices), 3 ) ); geometry.computeBoundingBox(); return geometry.boundingBox; } function getBSForVertices(vertices) { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(vertices), 3 ) ); geometry.computeBoundingSphere(); return geometry.boundingSphere; } test( "computeVertexNormals", function() { // get normals for a counter clockwise created triangle var normals = getNormalsForVertices([-1, 0, 0, 1, 0, 0, 0, 1, 0]); ok( normals[0] === 0 && normals[1] === 0 && normals[2] === 1, "first normal is pointing to screen since the the triangle was created counter clockwise" ); ok( normals[3] === 0 && normals[4] === 0 && normals[5] === 1, "second normal is pointing to screen since the the triangle was created counter clockwise" ); ok( normals[6] === 0 && normals[7] === 0 && normals[8] === 1, "third normal is pointing to screen since the the triangle was created counter clockwise" ); // get normals for a clockwise created triangle var normals = getNormalsForVertices([1, 0, 0, -1, 0, 0, 0, 1, 0]); ok( normals[0] === 0 && normals[1] === 0 && normals[2] === -1, "first normal is pointing to screen since the the triangle was created clockwise" ); ok( normals[3] === 0 && normals[4] === 0 && normals[5] === -1, "second normal is pointing to screen since the the triangle was created clockwise" ); ok( normals[6] === 0 && normals[7] === 0 && normals[8] === -1, "third normal is pointing to screen since the the triangle was created clockwise" ); var normals = getNormalsForVertices([0, 0, 1, 0, 0, -1, 1, 1, 0]); // the triangle is rotated by 45 degrees to the right so the normals of the three vertices // should point to (1, -1, 0).normalized(). The simplest solution is to check against a normalized // vector (1, -1, 0) but you will get calculation errors because of floating calculations so another // valid technique is to create a vector which stands in 90 degrees to the normals and calculate the // dot product which is the cos of the angle between them. This should be < floating calculation error // which can be taken from Number.EPSILON var direction = new THREE.Vector3(1, 1, 0).normalize(); // a vector which should have 90 degrees difference to normals var difference = direction.dot( new THREE.Vector3( normals[0], normals[1], normals[2] ) ); ok( difference < Number.EPSILON, "normal is equal to reference vector"); // get normals for a line should be NAN because you need min a triangle to calculate normals var normals = getNormalsForVertices([1, 0, 0, -1, 0, 0]); for (var i = 0; i < normals.length; i++) { ok ( !normals[i], "normals can't be calculated which is good"); } }); function getNormalsForVertices(vertices) { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "position", new THREE.BufferAttribute( new Float32Array(vertices), 3 ) ); geometry.computeVertexNormals(); ok( geometry.attributes.normal !== undefined, "normal attribute was created" ); return geometry.attributes.normal.array; } test( "merge", function() { var geometry1 = new THREE.BufferGeometry(); geometry1.addAttribute( "attrName", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 0, 0, 0]), 3 ) ); var geometry2 = new THREE.BufferGeometry(); geometry2.addAttribute( "attrName", new THREE.BufferAttribute( new Float32Array([4, 5, 6]), 3 ) ); var attr = geometry1.attributes.attrName.array; geometry1.merge(geometry2, 1); // merged array should be 1, 2, 3, 4, 5, 6 for (var i = 0; i < attr.length; i++) { ok( attr[i] === i + 1, ""); } geometry1.merge(geometry2); ok( attr[0] === 4 && attr[1] === 5 && attr[2] === 6, "copied the 3 attributes without offset" ); }); test( "copy", function() { var geometry = new THREE.BufferGeometry(); geometry.addAttribute( "attrName", new THREE.BufferAttribute( new Float32Array([1, 2, 3, 4, 5, 6]), 3 ) ); geometry.addAttribute( "attrName2", new THREE.BufferAttribute( new Float32Array([0, 1, 3, 5, 6]), 1 ) ); var copy = new THREE.BufferGeometry().copy(geometry); ok( copy !== geometry && geometry.id !== copy.id, "new object was created" ); Object.keys(geometry.attributes).forEach(function(key) { var attribute = geometry.attributes[key]; ok( attribute !== undefined, "all attributes where copied"); for (var i = 0; i < attribute.array.length; i++) { ok( attribute.array[i] === copy.attributes[key].array[i], "values of the attribute are equal" ); } }); }); three.js-r73/test/unit/core/Clock.js0000644000175500017550000000175512610076566017243 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "Clock" ); function mockPerformance() { self.performance = { deltaTime: 0, next: function( delta ) { this.deltaTime += delta; }, now: function() { return this.deltaTime; } }; } test( "clock with performance", function() { mockPerformance(); var clock = new THREE.Clock(); clock.start(); self.performance.next(123); ok( clock.getElapsedTime() === 0.123 , "okay"); self.performance.next(100); ok( clock.getElapsedTime() === 0.223 , "okay"); clock.stop(); self.performance.next(1000); ok( clock.getElapsedTime() === 0.223 , "don't update time if the clock was stopped"); }); test( "clock with date", function() { // remove the performance object so that clock takes Date() self.performance = undefined; var clock = new THREE.Clock(); clock.start(); // if a value was calculated, the clock took the alternative Date() object ok( clock.getElapsedTime() >= 0 , "okay"); clock.stop(); }); three.js-r73/test/unit/core/BufferAttribute.js0000644000175500017550000000734012610076566021301 0ustar debacledebacle/** * @author simonThiele / https://github.com/simonThiele */ module( "BufferAttribute" ); test( "count", function() { ok( new THREE.BufferAttribute( new Float32Array( [1, 2, 3, 4, 5, 6] ), 3 ).count === 2, 'count is equal to the number of chunks' ); }); test( "copy", function() { var attr = new THREE.BufferAttribute( new Float32Array( [1, 2, 3, 4, 5, 6] ), 3 ); attr.setDynamic( true ); attr.needsUpdate = true; var attrCopy = new THREE.BufferAttribute().copy( attr ); ok( attr.count === attrCopy.count, 'count is equal' ); ok( attr.itemSize === attrCopy.itemSize, 'itemSize is equal' ); ok( attr.dynamic === attrCopy.dynamic, 'dynamic is equal' ); ok( attr.array.length === attrCopy.array.length, 'array length is equal' ); ok( attr.version === 1 && attrCopy.version === 0, 'version is not copied which is good' ); }); test( "copyAt", function() { var attr = new THREE.BufferAttribute( new Float32Array( [1, 2, 3, 4, 5, 6, 7, 8, 9] ), 3 ); var attr2 = new THREE.BufferAttribute( new Float32Array(9), 3 ); attr2.copyAt( 1, attr, 2 ); attr2.copyAt( 0, attr, 1 ); attr2.copyAt( 2, attr, 0 ); var i = attr.array; var i2 = attr2.array; // should be [4, 5, 6, 7, 8, 9, 1, 2, 3] ok( i2[0] === i[3] && i2[1] === i[4] && i2[2] === i[5], 'chunck copied to correct place' ); ok( i2[3] === i[6] && i2[4] === i[7] && i2[5] === i[8], 'chunck copied to correct place' ); ok( i2[6] === i[0] && i2[7] === i[1] && i2[8] === i[2], 'chunck copied to correct place' ); }); test( "copyColorsArray", function() { var attr = new THREE.BufferAttribute( new Float32Array(6), 3 ); attr.copyColorsArray( [ new THREE.Color( 0, 0.5, 1 ), new THREE.Color( 0.25, 1, 0 ) ]); var i = attr.array; ok( i[0] === 0 && i[1] === 0.5 && i[2] === 1, 'first color was copied correctly' ); ok( i[3] === 0.25 && i[4] === 1 && i[5] === 0, 'second color was copied correctly' ); }); test( "copyIndicesArray", function() { var attr = new THREE.BufferAttribute( new Float32Array(6), 3 ); attr.copyIndicesArray( [ {a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6} ]); var i = attr.array; ok( i[0] === 1 && i[1] === 2 && i[2] === 3, 'first indices were copied correctly' ); ok( i[3] === 4 && i[4] === 5 && i[5] === 6, 'second indices were copied correctly' ); }); test( "copyVector2sArray", function() { var attr = new THREE.BufferAttribute( new Float32Array(4), 2 ); attr.copyVector2sArray( [ new THREE.Vector2(1, 2), new THREE.Vector2(4, 5) ]); var i = attr.array; ok( i[0] === 1 && i[1] === 2, 'first vector was copied correctly' ); ok( i[2] === 4 && i[3] === 5, 'second vector was copied correctly' ); }); test( "copyVector3sArray", function() { var attr = new THREE.BufferAttribute( new Float32Array(6), 2 ); attr.copyVector3sArray( [ new THREE.Vector3(1, 2, 3), new THREE.Vector3(10, 20, 30) ]); var i = attr.array; ok( i[0] === 1 && i[1] === 2 && i[2] === 3, 'first vector was copied correctly' ); ok( i[3] === 10 && i[4] === 20 && i[5] === 30, 'second vector was copied correctly' ); }); test( "copyVector4sArray", function() { var attr = new THREE.BufferAttribute( new Float32Array(8), 2 ); attr.copyVector4sArray( [ new THREE.Vector4(1, 2, 3, 4), new THREE.Vector4(10, 20, 30, 40) ]); var i = attr.array; ok( i[0] === 1 && i[1] === 2 && i[2] === 3 && i[3] === 4, 'first vector was copied correctly' ); ok( i[4] === 10 && i[5] === 20 && i[6] === 30 && i[7] === 40, 'second vector was copied correctly' ); }); test( "clone", function() { var attr = new THREE.BufferAttribute( new Float32Array([1, 2, 3, 4, 0.12, -12]), 2 ); var attrCopy = attr.clone(); ok( attr.array.length === attrCopy.array.length, 'attribute was cloned' ); for ( var i = 0; i < attr.array.length; i++ ) { ok( attr.array[i] === attrCopy.array[i], 'array item is equal' ); } }); three.js-r73/test/unit/qunit-1.18.0.css0000644000175500017550000001203212610076566017305 0ustar debacledebacle/*! * QUnit 1.18.0 * http://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2015-04-03T10:23Z */ /** Font Family and Sizes */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } #qunit-tests { font-size: smaller; } /** Resets */ #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { margin: 0; padding: 0; } /** Header */ #qunit-header { padding: 0.5em 0 0.5em 1em; color: #8699A4; background-color: #0D3349; font-size: 1.5em; line-height: 1em; font-weight: 400; border-radius: 5px 5px 0 0; } #qunit-header a { text-decoration: none; color: #C2CCD1; } #qunit-header a:hover, #qunit-header a:focus { color: #FFF; } #qunit-testrunner-toolbar label { display: inline-block; padding: 0 0.5em 0 0.1em; } #qunit-banner { height: 5px; } #qunit-testrunner-toolbar { padding: 0.5em 1em 0.5em 1em; color: #5E740B; background-color: #EEE; overflow: hidden; } #qunit-userAgent { padding: 0.5em 1em 0.5em 1em; background-color: #2B81AF; color: #FFF; text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; } #qunit-modulefilter-container { float: right; padding: 0.2em; } .qunit-url-config { display: inline-block; padding: 0.1em; } .qunit-filter { display: block; float: right; margin-left: 1em; } /** Tests: Pass/Fail */ #qunit-tests { list-style-position: inside; } #qunit-tests li { padding: 0.4em 1em 0.4em 1em; border-bottom: 1px solid #FFF; list-style-position: inside; } #qunit-tests > li { display: none; } #qunit-tests li.running, #qunit-tests li.pass, #qunit-tests li.fail, #qunit-tests li.skipped { display: list-item; } #qunit-tests.hidepass li.running, #qunit-tests.hidepass li.pass { visibility: hidden; position: absolute; width: 0px; height: 0px; padding: 0; border: 0; margin: 0; } #qunit-tests li strong { cursor: pointer; } #qunit-tests li.skipped strong { cursor: default; } #qunit-tests li a { padding: 0.5em; color: #C2CCD1; text-decoration: none; } #qunit-tests li p a { padding: 0.25em; color: #6B6464; } #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; } #qunit-tests li .runtime { float: right; font-size: smaller; } .qunit-assert-list { margin-top: 0.5em; padding: 0.5em; background-color: #FFF; border-radius: 5px; } .qunit-collapsed { display: none; } #qunit-tests table { border-collapse: collapse; margin-top: 0.2em; } #qunit-tests th { text-align: right; vertical-align: top; padding: 0 0.5em 0 0; } #qunit-tests td { vertical-align: top; } #qunit-tests pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; } #qunit-tests del { background-color: #E0F2BE; color: #374E0C; text-decoration: none; } #qunit-tests ins { background-color: #FFCACA; color: #500; text-decoration: none; } /*** Test Counts */ #qunit-tests b.counts { color: #000; } #qunit-tests b.passed { color: #5E740B; } #qunit-tests b.failed { color: #710909; } #qunit-tests li li { padding: 5px; background-color: #FFF; border-bottom: none; list-style-position: inside; } /*** Passing Styles */ #qunit-tests li li.pass { color: #3C510C; background-color: #FFF; border-left: 10px solid #C6E746; } #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } #qunit-tests .pass .test-name { color: #366097; } #qunit-tests .pass .test-actual, #qunit-tests .pass .test-expected { color: #999; } #qunit-banner.qunit-pass { background-color: #C6E746; } /*** Failing Styles */ #qunit-tests li li.fail { color: #710909; background-color: #FFF; border-left: 10px solid #EE5757; white-space: pre; } #qunit-tests > li:last-child { border-radius: 0 0 5px 5px; } #qunit-tests .fail { color: #000; background-color: #EE5757; } #qunit-tests .fail .test-name, #qunit-tests .fail .module-name { color: #000; } #qunit-tests .fail .test-actual { color: #EE5757; } #qunit-tests .fail .test-expected { color: #008000; } #qunit-banner.qunit-fail { background-color: #EE5757; } /*** Skipped tests */ #qunit-tests .skipped { background-color: #EBECE9; } #qunit-tests .qunit-skipped-label { background-color: #F4FF77; display: inline-block; font-style: normal; color: #366097; line-height: 1.8em; padding: 0 0.5em; margin: -0.4em 0.4em -0.4em 0; } /** Result */ #qunit-testresult { padding: 0.5em 1em 0.5em 1em; color: #2B81AF; background-color: #D2E0E6; border-bottom: 1px solid #FFF; } #qunit-testresult .module-name { font-weight: 700; } /** Fixture */ #qunit-fixture { position: absolute; top: -10000px; left: -10000px; width: 1000px; height: 1000px; } three.js-r73/test/unit/qunit-utils.js0000644000175500017550000001162612610076566017554 0ustar debacledebacle// // Custom QUnit assertions. // QUnit.assert.success = function( message ) { // Equivalent to assert( true, message ); QUnit.assert.push( true, undefined, undefined, message ); }; QUnit.assert.fail = function( message ) { // Equivalent to assert( false, message ); QUnit.assert.push( false, undefined, undefined, message ); }; QUnit.assert.numEqual = function( actual, expected, message ) { var diff = Math.abs(actual - expected); message = message || ( actual + " should be equal to " + expected ); QUnit.assert.push( diff < 0.1, actual, expected, message ); }; QUnit.assert.equalKey = function( obj, ref, key ) { var actual = obj[key]; var expected = ref[key]; var message = actual + ' should be equal to ' + expected + ' for key "' + key + '"'; QUnit.assert.push( actual == expected, actual, expected, message ); }; QUnit.assert.smartEqual = function( actual, expected, message ) { var cmp = new SmartComparer(); var same = cmp.areEqual(actual, expected); var msg = cmp.getDiagnostic() || message; QUnit.assert.push( same, actual, expected, msg ); }; // // GEOMETRY TEST HELPERS // function checkGeometryClone( geom ) { // Clone var copy = geom.clone(); QUnit.assert.notEqual( copy.uuid, geom.uuid, "clone uuid should differ from original" ); QUnit.assert.notEqual( copy.id, geom.id, "clone id should differ from original" ); QUnit.assert.smartEqual( copy, geom, "clone is equal to original" ); // json round trip with clone checkGeometryJsonRoundtrip( copy ); } // Compare json file with its source geometry. function checkGeometryJsonWriting( geom, json ) { QUnit.assert.equal( json.metadata.version, "4.4", "check metadata version" ); QUnit.assert.equalKey( geom, json, 'type' ); QUnit.assert.equalKey( geom, json, 'uuid' ); QUnit.assert.equal( json.id, undefined, "should not persist id" ); // All parameters from geometry should be persisted. _.forOwn( geom.parameters, function ( val, key ) { QUnit.assert.equalKey( geom.parameters, json, key ); }); // All parameters from json should be transfered to the geometry. // json is flat. Ignore first level json properties that are not parameters. var notParameters = [ "metadata", "uuid", "type" ]; _.forOwn( json, function ( val, key ) { if ( notParameters.indexOf( key) === -1 ) QUnit.assert.equalKey( geom.parameters, json, key ); }); } // Check parsing and reconstruction of json geometry function checkGeometryJsonReading( json, geom ) { var wrap = [ json ]; var loader = new THREE.ObjectLoader(); var output = loader.parseGeometries( wrap ); QUnit.assert.ok( output[geom.uuid], 'geometry matching source uuid not in output' ); QUnit.assert.smartEqual( output[geom.uuid], geom, 'Reconstruct geometry from ObjectLoader' ); } // Verify geom -> json -> geom function checkGeometryJsonRoundtrip( geom ) { var json = geom.toJSON(); checkGeometryJsonWriting( geom, json ); checkGeometryJsonReading( json, geom ); } // Look for undefined and NaN values in numerical fieds. function checkFinite( geom ) { var isNotFinite = _.any( geom.vertices, function ( v ) { return ! ( _.isFinite( v.x ) || _.isFinite( v.y ) || _.isFinite( v.z ) ); }); // TODO Buffers, normal, etc. QUnit.assert.ok( isNotFinite === false, "contains non-finite coordinates" ); } // Run common geometry tests. function runStdGeometryTests( assert, geometries ) { _.each( geometries, function( geom ) { checkFinite( geom ); // Clone checkGeometryClone( geom ); // json round trip checkGeometryJsonRoundtrip( geom ); }); } // // LIGHT TEST HELPERS // // Run common light tests. function runStdLightTests( assert, lights ) { _.each( lights, function( light ) { // Clone checkLightClone( light ); // json round trip checkLightJsonRoundtrip( light ); }); } function checkLightClone( light ) { // Clone var copy = light.clone(); QUnit.assert.notEqual( copy.uuid, light.uuid, "clone uuid should differ from original" ); QUnit.assert.notEqual( copy.id, light.id, "clone id should differ from original" ); QUnit.assert.smartEqual( copy, light, "clone is equal to original" ); // json round trip with clone checkLightJsonRoundtrip( copy ); } // Compare json file with its source Light. function checkLightJsonWriting( light, json ) { QUnit.assert.equal( json.metadata.version, "4.4", "check metadata version" ); QUnit.assert.equalKey( light, json, 'type' ); QUnit.assert.equalKey( light, json, 'uuid' ); QUnit.assert.equal( json.id, undefined, "should not persist id" ); } // Check parsing and reconstruction of json Light function checkLightJsonReading( json, light ) { var loader = new THREE.ObjectLoader(); var outputLight = loader.parse( json ); QUnit.assert.smartEqual( outputLight, light, 'Reconstruct Light from ObjectLoader' ); } // Verify light -> json -> light function checkLightJsonRoundtrip( light ) { var json = light.toJSON(); checkLightJsonWriting( light, json.object ); checkLightJsonReading( json, light ); } three.js-r73/test/unit/SmartComparer.js0000644000175500017550000000763412610076566020041 0ustar debacledebacle// Smart comparison of three.js objects. // Identifies significant differences between two objects. // Performs deep comparison. // Comparison stops after the first difference is found. // Provides an explanation for the failure. function SmartComparer() { 'use strict'; // Diagnostic message, when comparison fails. var message; // Keys to skip during object comparison. var omitKeys = [ 'id', 'uuid' ]; return { areEqual: areEqual, getDiagnostic: function() { return message; } }; // val1 - first value to compare (typically the actual value) // val2 - other value to compare (typically the expected value) function areEqual( val1, val2 ) { // Values are strictly equal. if ( val1 === val2 ) return true; // Null or undefined values. /* jshint eqnull:true */ if ( val1 == null || val2 == null ) { if ( val1 != val2 ) { return makeFail( 'One value is undefined or null', val1, val2 ); } // Both null / undefined. return true; } // Don't compare functions. if ( _.isFunction( val1 ) && _.isFunction( val2 ) ) return true; // Array comparison. var arrCmp = compareArrays( val1, val2 ); if ( arrCmp !== undefined ) return arrCmp; // Has custom equality comparer. if ( val1.equals ) { if ( val1.equals( val2 ) ) return true; return makeFail( 'Comparison with .equals method returned false' ); } // Object comparison. var objCmp = compareObjects( val1, val2 ); if ( objCmp !== undefined ) return objCmp; // if (JSON.stringify( val1 ) == JSON.stringify( val2 ) ) return true; // Continue with default comparison. if ( _.isEqual( val1, val2 ) ) return true; // Object differs (unknown reason). return makeFail( 'Values differ', val1, val2 ); } function compareArrays( val1, val2 ) { var isArr1 = Array.isArray( val1 ); var isArr2 = Array.isArray( val2 ); // Compare type. if ( isArr1 !== isArr2 ) return makeFail( 'Values are not both arrays' ); // Not arrays. Continue. if ( !isArr1 ) return undefined; // Compare length. var N1 = val1.length; var N2 = val2.length; if ( N1 !== val2.length ) return makeFail( 'Array length differs', N1, N2 ); // Compare content at each index. for ( var i = 0; i < N1; i ++ ) { var cmp = areEqual( val1[ i ], val2[ i ] ); if ( !cmp ) return addContext( 'array index "' + i + '"' ); } // Arrays are equal. return true; } function compareObjects( val1, val2 ) { var isObj1 = _.isObject( val1 ); var isObj2 = _.isObject( val2 ); // Compare type. if ( isObj1 !== isObj2 ) return makeFail( 'Values are not both objects' ); // Not objects. Continue. if ( !isObj1 ) return undefined; // Compare keys. var keys1 = _( val1 ).keys().difference( omitKeys ).value(); var keys2 = _( val2 ).keys().difference( omitKeys ).value(); var missingActual = _.difference( keys1, keys2 ); if ( missingActual.length !== 0 ) { return makeFail( 'Property "' + missingActual[0] + '" is unexpected.' ); } var missingExpected = _.difference( keys2, keys1 ); if ( missingExpected.length !== 0 ) { return makeFail( 'Property "' + missingExpected[0] + '" is missing.' ); } // Keys are the same. For each key, compare content until a difference is found. var hadDifference = _.any( keys1, function ( key ) { var prop1 = val1[key]; var prop2 = val2[key]; // Compare property content. var eq = areEqual( prop1, prop2 ); // In case of failure, an message should already be set. // Add context to low level message. if ( !eq ) addContext( 'property "' + key + '"' ); return !eq; }); return ! hadDifference; } function makeFail( msg, val1, val2 ) { message = msg; if ( arguments.length > 1) message += " (" + val1 + " vs " + val2 + ")"; return false; } function addContext( msg ) { // There should already be a validation message. Add more context to it. message = message || "Error"; message += ", at " + msg; return false; } } three.js-r73/test/unit/math/0000755000175500017550000000000012610076566015643 5ustar debacledebaclethree.js-r73/test/unit/math/Quaternion.js0000644000175500017550000001412212610076566020326 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Quaternion" ); var orders = [ 'XYZ', 'YXZ', 'ZXY', 'ZYX', 'YZX', 'XZY' ]; var eulerAngles = new THREE.Euler( 0.1, -0.3, 0.25 ); var qSub = function ( a, b ) { var result = new THREE.Quaternion(); result.copy( a ); result.x -= b.x; result.y -= b.y; result.z -= b.z; result.w -= b.w; return result; }; test( "constructor", function() { var a = new THREE.Quaternion(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); ok( a.w == 1, "Passed!" ); a = new THREE.Quaternion( x, y, z, w ); ok( a.x === x, "Passed!" ); ok( a.y === y, "Passed!" ); ok( a.z === z, "Passed!" ); ok( a.w === w, "Passed!" ); }); test( "copy", function() { var a = new THREE.Quaternion( x, y, z, w ); var b = new THREE.Quaternion().copy( a ); ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); ok( b.z == z, "Passed!" ); ok( b.w == w, "Passed!" ); // ensure that it is a true copy a.x = 0; a.y = -1; a.z = 0; a.w = -1; ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); }); test( "set", function() { var a = new THREE.Quaternion(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); ok( a.w == 1, "Passed!" ); a.set( x, y, z, w ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); ok( a.z === z, "Passed!" ); ok( a.w === w, "Passed!" ); }); test( "setFromAxisAngle", function() { // TODO: find cases to validate. ok( true, "Passed!" ); var zero = new THREE.Quaternion(); var a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), 0 ); ok( a.equals( zero ), "Passed!" ); a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), 0 ); ok( a.equals( zero ), "Passed!" ); a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 0, 0, 1 ), 0 ); ok( a.equals( zero ), "Passed!" ); var b1 = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), Math.PI ); ok( ! a.equals( b1 ), "Passed!" ); var b2 = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), -Math.PI ); ok( ! a.equals( b2 ), "Passed!" ); b1.multiply( b2 ); ok( a.equals( b1 ), "Passed!" ); }); test( "setFromEuler/setFromQuaternion", function() { var angles = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ]; // ensure euler conversion to/from Quaternion matches. for( var i = 0; i < orders.length; i ++ ) { for( var j = 0; j < angles.length; j ++ ) { var eulers2 = new THREE.Euler().setFromQuaternion( new THREE.Quaternion().setFromEuler( new THREE.Euler( angles[j].x, angles[j].y, angles[j].z, orders[i] ) ), orders[i] ); var newAngle = new THREE.Vector3( eulers2.x, eulers2.y, eulers2.z ); ok( newAngle.distanceTo( angles[j] ) < 0.001, "Passed!" ); } } }); test( "setFromEuler/setFromRotationMatrix", function() { // ensure euler conversion for Quaternion matches that of Matrix4 for( var i = 0; i < orders.length; i ++ ) { var q = new THREE.Quaternion().setFromEuler( eulerAngles, orders[i] ); var m = new THREE.Matrix4().makeRotationFromEuler( eulerAngles, orders[i] ); var q2 = new THREE.Quaternion().setFromRotationMatrix( m ); ok( qSub( q, q2 ).length() < 0.001, "Passed!" ); } }); test( "normalize/length/lengthSq", function() { var a = new THREE.Quaternion( x, y, z, w ); var b = new THREE.Quaternion( -x, -y, -z, -w ); ok( a.length() != 1, "Passed!"); ok( a.lengthSq() != 1, "Passed!"); a.normalize(); ok( a.length() == 1, "Passed!"); ok( a.lengthSq() == 1, "Passed!"); a.set( 0, 0, 0, 0 ); ok( a.lengthSq() == 0, "Passed!"); ok( a.length() == 0, "Passed!"); a.normalize(); ok( a.lengthSq() == 1, "Passed!"); ok( a.length() == 1, "Passed!"); }); test( "inverse/conjugate", function() { var a = new THREE.Quaternion( x, y, z, w ); // TODO: add better validation here. var b = a.clone().conjugate(); ok( a.x == -b.x, "Passed!" ); ok( a.y == -b.y, "Passed!" ); ok( a.z == -b.z, "Passed!" ); ok( a.w == b.w, "Passed!" ); }); test( "multiplyQuaternions/multiply", function() { var angles = [ new THREE.Euler( 1, 0, 0 ), new THREE.Euler( 0, 1, 0 ), new THREE.Euler( 0, 0, 1 ) ]; var q1 = new THREE.Quaternion().setFromEuler( angles[0], "XYZ" ); var q2 = new THREE.Quaternion().setFromEuler( angles[1], "XYZ" ); var q3 = new THREE.Quaternion().setFromEuler( angles[2], "XYZ" ); var q = new THREE.Quaternion().multiplyQuaternions( q1, q2 ).multiply( q3 ); var m1 = new THREE.Matrix4().makeRotationFromEuler( angles[0], "XYZ" ); var m2 = new THREE.Matrix4().makeRotationFromEuler( angles[1], "XYZ" ); var m3 = new THREE.Matrix4().makeRotationFromEuler( angles[2], "XYZ" ); var m = new THREE.Matrix4().multiplyMatrices( m1, m2 ).multiply( m3 ); var qFromM = new THREE.Quaternion().setFromRotationMatrix( m ); ok( qSub( q, qFromM ).length() < 0.001, "Passed!" ); }); test( "multiplyVector3", function() { var angles = [ new THREE.Euler( 1, 0, 0 ), new THREE.Euler( 0, 1, 0 ), new THREE.Euler( 0, 0, 1 ) ]; // ensure euler conversion for Quaternion matches that of Matrix4 for( var i = 0; i < orders.length; i ++ ) { for( var j = 0; j < angles.length; j ++ ) { var q = new THREE.Quaternion().setFromEuler( angles[j], orders[i] ); var m = new THREE.Matrix4().makeRotationFromEuler( angles[j], orders[i] ); var v0 = new THREE.Vector3(1, 0, 0); var qv = v0.clone().applyQuaternion( q ); var mv = v0.clone().applyMatrix4( m ); ok( qv.distanceTo( mv ) < 0.001, "Passed!" ); } } }); test( "equals", function() { var a = new THREE.Quaternion( x, y, z, w ); var b = new THREE.Quaternion( -x, -y, -z, -w ); ok( a.x != b.x, "Passed!" ); ok( a.y != b.y, "Passed!" ); ok( ! a.equals( b ), "Passed!" ); ok( ! b.equals( a ), "Passed!" ); a.copy( b ); ok( a.x == b.x, "Passed!" ); ok( a.y == b.y, "Passed!" ); ok( a.equals( b ), "Passed!" ); ok( b.equals( a ), "Passed!" ); }); test( "slerp", function() { var a = new THREE.Quaternion( 0.675341, 0.408783, 0.328567, 0.518512 ); var b = new THREE.Quaternion( 0.660279, 0.436474, 0.35119, 0.500187 ); ok( a.slerp( b, 0 ).equals( a ), "Passed!" ); ok( a.slerp( b, 1 ).equals( b ), "Passed!" ); }); three.js-r73/test/unit/math/Constants.js0000644000175500017550000000107112610076566020154 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ var x = 2; var y = 3; var z = 4; var w = 5; var negInf2 = new THREE.Vector2( -Infinity, -Infinity ); var posInf2 = new THREE.Vector2( Infinity, Infinity ); var zero2 = new THREE.Vector2(); var one2 = new THREE.Vector2( 1, 1 ); var two2 = new THREE.Vector2( 2, 2 ); var negInf3 = new THREE.Vector3( -Infinity, -Infinity, -Infinity ); var posInf3 = new THREE.Vector3( Infinity, Infinity, Infinity ); var zero3 = new THREE.Vector3(); var one3 = new THREE.Vector3( 1, 1, 1 ); var two3 = new THREE.Vector3( 2, 2, 2 ); three.js-r73/test/unit/math/Math.js0000644000175500017550000000272012610076566017073 0ustar debacledebacle/** * @author humbletim / https://github.com/humbletim */ module( "Math" ); //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign //http://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.sign /* 20.2.2.29 Math.sign(x) Returns the sign of the x, indicating whether x is positive, negative or zero. If x is NaN, the result is NaN. If x is -0, the result is -0. If x is +0, the result is +0. If x is negative and not -0, the result is -1. If x is positive and not +0, the result is +1. */ test( "Math.sign/polyfill", function() { ok( isNaN( Math.sign(NaN) ) , "If x is NaN, the result is NaN."); ok( isNaN( Math.sign(new THREE.Vector3()) ) , "If x is NaN, the result is NaN."); ok( isNaN( Math.sign() ) , "If x is NaN, the result is NaN."); ok( isNaN( Math.sign('--3') ) , "If x is NaN<'--3'>, the result is NaN."); ok( Math.sign(-0) === -0 , "If x is -0, the result is -0."); ok( Math.sign(+0) === +0 , "If x is +0, the result is +0."); ok( Math.sign(-Infinity) === -1 , "If x is negative<-Infinity> and not -0, the result is -1."); ok( Math.sign('-3') === -1 , "If x is negative<'-3'> and not -0, the result is -1."); ok( Math.sign('-1e-10') === -1 , "If x is negative<'-1e-10'> and not -0, the result is -1."); ok( Math.sign(+Infinity) === +1 , "If x is positive<+Infinity> and not +0, the result is +1."); ok( Math.sign('+3') === +1 , "If x is positive<'+3'> and not +0, the result is +1."); }); three.js-r73/test/unit/math/Line3.js0000644000175500017550000000451612610076566017161 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Line3" ); test( "constructor/equals", function() { var a = new THREE.Line3(); ok( a.start.equals( zero3 ), "Passed!" ); ok( a.end.equals( zero3 ), "Passed!" ); a = new THREE.Line3( two3.clone(), one3.clone() ); ok( a.start.equals( two3 ), "Passed!" ); ok( a.end.equals( one3 ), "Passed!" ); }); test( "copy/equals", function() { var a = new THREE.Line3( zero3.clone(), one3.clone() ); var b = new THREE.Line3().copy( a ); ok( b.start.equals( zero3 ), "Passed!" ); ok( b.end.equals( one3 ), "Passed!" ); // ensure that it is a true copy a.start = zero3; a.end = one3; ok( b.start.equals( zero3 ), "Passed!" ); ok( b.end.equals( one3 ), "Passed!" ); }); test( "set", function() { var a = new THREE.Line3(); a.set( one3, one3 ); ok( a.start.equals( one3 ), "Passed!" ); ok( a.end.equals( one3 ), "Passed!" ); }); test( "at", function() { var a = new THREE.Line3( one3.clone(), new THREE.Vector3( 1, 1, 2 ) ); ok( a.at( -1 ).distanceTo( new THREE.Vector3( 1, 1, 0 ) ) < 0.0001, "Passed!" ); ok( a.at( 0 ).distanceTo( one3.clone() ) < 0.0001, "Passed!" ); ok( a.at( 1 ).distanceTo( new THREE.Vector3( 1, 1, 2 ) ) < 0.0001, "Passed!" ); ok( a.at( 2 ).distanceTo( new THREE.Vector3( 1, 1, 3 ) ) < 0.0001, "Passed!" ); }); test( "closestPointToPoint/closestPointToPointParameter", function() { var a = new THREE.Line3( one3.clone(), new THREE.Vector3( 1, 1, 2 ) ); // nearby the ray ok( a.closestPointToPointParameter( zero3.clone(), true ) == 0, "Passed!" ); var b1 = a.closestPointToPoint( zero3.clone(), true ); ok( b1.distanceTo( new THREE.Vector3( 1, 1, 1 ) ) < 0.0001, "Passed!" ); // nearby the ray ok( a.closestPointToPointParameter( zero3.clone(), false ) == -1, "Passed!" ); var b2 = a.closestPointToPoint( zero3.clone(), false ); ok( b2.distanceTo( new THREE.Vector3( 1, 1, 0 ) ) < 0.0001, "Passed!" ); // nearby the ray ok( a.closestPointToPointParameter( new THREE.Vector3( 1, 1, 5 ), true ) == 1, "Passed!" ); var b = a.closestPointToPoint( new THREE.Vector3( 1, 1, 5 ), true ); ok( b.distanceTo( new THREE.Vector3( 1, 1, 2 ) ) < 0.0001, "Passed!" ); // exactly on the ray ok( a.closestPointToPointParameter( one3.clone(), true ) == 0, "Passed!" ); var c = a.closestPointToPoint( one3.clone(), true ); ok( c.distanceTo( one3.clone() ) < 0.0001, "Passed!" ); });three.js-r73/test/unit/math/Frustum.js0000644000175500017550000001606012610076566017651 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Frustum" ); var unit3 = new THREE.Vector3( 1, 0, 0 ); var planeEquals = function ( a, b, tolerance ) { tolerance = tolerance || 0.0001; if( a.normal.distanceTo( b.normal ) > tolerance ) { return false; } if( Math.abs( a.constant - b.constant ) > tolerance ) { return false; } return true; }; test( "constructor", function() { var a = new THREE.Frustum(); ok( a.planes !== undefined, "Passed!" ); ok( a.planes.length === 6, "Passed!" ); var pDefault = new THREE.Plane(); for( var i = 0; i < 6; i ++ ) { ok( a.planes[i].equals( pDefault ), "Passed!" ); } var p0 = new THREE.Plane( unit3, -1 ); var p1 = new THREE.Plane( unit3, 1 ); var p2 = new THREE.Plane( unit3, 2 ); var p3 = new THREE.Plane( unit3, 3 ); var p4 = new THREE.Plane( unit3, 4 ); var p5 = new THREE.Plane( unit3, 5 ); a = new THREE.Frustum( p0, p1, p2, p3, p4, p5 ); ok( a.planes[0].equals( p0 ), "Passed!" ); ok( a.planes[1].equals( p1 ), "Passed!" ); ok( a.planes[2].equals( p2 ), "Passed!" ); ok( a.planes[3].equals( p3 ), "Passed!" ); ok( a.planes[4].equals( p4 ), "Passed!" ); ok( a.planes[5].equals( p5 ), "Passed!" ); }); test( "copy", function() { var p0 = new THREE.Plane( unit3, -1 ); var p1 = new THREE.Plane( unit3, 1 ); var p2 = new THREE.Plane( unit3, 2 ); var p3 = new THREE.Plane( unit3, 3 ); var p4 = new THREE.Plane( unit3, 4 ); var p5 = new THREE.Plane( unit3, 5 ); var b = new THREE.Frustum( p0, p1, p2, p3, p4, p5 ); var a = new THREE.Frustum().copy( b ); ok( a.planes[0].equals( p0 ), "Passed!" ); ok( a.planes[1].equals( p1 ), "Passed!" ); ok( a.planes[2].equals( p2 ), "Passed!" ); ok( a.planes[3].equals( p3 ), "Passed!" ); ok( a.planes[4].equals( p4 ), "Passed!" ); ok( a.planes[5].equals( p5 ), "Passed!" ); // ensure it is a true copy by modifying source b.planes[0] = p1; ok( a.planes[0].equals( p0 ), "Passed!" ); }); test( "setFromMatrix/makeOrthographic/containsPoint", function() { var m = new THREE.Matrix4().makeOrthographic( -1, 1, -1, 1, 1, 100 ) var a = new THREE.Frustum().setFromMatrix( m ); ok( ! a.containsPoint( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 0, 0, -50 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 0, 0, -1.001 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( -1, -1, -1.001 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( -1.1, -1.1, -1.001 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 1, 1, -1.001 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( 1.1, 1.1, -1.001 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 0, 0, -100 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( -1, -1, -100 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( -1.1, -1.1, -100.1 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 1, 1, -100 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( 1.1, 1.1, -100.1 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( 0, 0, -101 ) ), "Passed!" ); }); test( "setFromMatrix/makeFrustum/containsPoint", function() { var m = new THREE.Matrix4().makeFrustum( -1, 1, -1, 1, 1, 100 ) var a = new THREE.Frustum().setFromMatrix( m ); ok( ! a.containsPoint( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 0, 0, -50 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 0, 0, -1.001 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( -1, -1, -1.001 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( -1.1, -1.1, -1.001 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 1, 1, -1.001 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( 1.1, 1.1, -1.001 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 0, 0, -99.999 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( -99.999, -99.999, -99.999 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( -100.1, -100.1, -100.1 ) ), "Passed!" ); ok( a.containsPoint( new THREE.Vector3( 99.999, 99.999, -99.999 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( 100.1, 100.1, -100.1 ) ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( 0, 0, -101 ) ), "Passed!" ); }); test( "setFromMatrix/makeFrustum/intersectsSphere", function() { var m = new THREE.Matrix4().makeFrustum( -1, 1, -1, 1, 1, 100 ) var a = new THREE.Frustum().setFromMatrix( m ); ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, 0 ), 0 ) ), "Passed!" ); ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, 0 ), 0.9 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, 0 ), 1.1 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -50 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -1.001 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -1, -1, -1.001 ), 0 ) ), "Passed!" ); ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -1.1, -1.1, -1.001 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -1.1, -1.1, -1.001 ), 0.5 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 1, 1, -1.001 ), 0 ) ), "Passed!" ); ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 1.1, 1.1, -1.001 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 1.1, 1.1, -1.001 ), 0.5 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -99.999 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -99.999, -99.999, -99.999 ), 0 ) ), "Passed!" ); ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -100.1, -100.1, -100.1 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -100.1, -100.1, -100.1 ), 0.5 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 99.999, 99.999, -99.999 ), 0 ) ), "Passed!" ); ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 100.1, 100.1, -100.1 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 100.1, 100.1, -100.1 ), 0.2 ) ), "Passed!" ); ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -101 ), 0 ) ), "Passed!" ); ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -101 ), 1.1 ) ), "Passed!" ); }); test( "clone", function() { var p0 = new THREE.Plane( unit3, -1 ); var p1 = new THREE.Plane( unit3, 1 ); var p2 = new THREE.Plane( unit3, 2 ); var p3 = new THREE.Plane( unit3, 3 ); var p4 = new THREE.Plane( unit3, 4 ); var p5 = new THREE.Plane( unit3, 5 ); var b = new THREE.Frustum( p0, p1, p2, p3, p4, p5 ); var a = b.clone(); ok( a.planes[0].equals( p0 ), "Passed!" ); ok( a.planes[1].equals( p1 ), "Passed!" ); ok( a.planes[2].equals( p2 ), "Passed!" ); ok( a.planes[3].equals( p3 ), "Passed!" ); ok( a.planes[4].equals( p4 ), "Passed!" ); ok( a.planes[5].equals( p5 ), "Passed!" ); // ensure it is a true copy by modifying source a.planes[0].copy( p1 ); ok( b.planes[0].equals( p0 ), "Passed!" ); });three.js-r73/test/unit/math/Vector4.js0000644000175500017550000001737712610076566017546 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Vector4" ); test( "constructor", function() { var a = new THREE.Vector4(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); ok( a.w == 1, "Passed!" ); a = new THREE.Vector4( x, y, z, w ); ok( a.x === x, "Passed!" ); ok( a.y === y, "Passed!" ); ok( a.z === z, "Passed!" ); ok( a.w === w, "Passed!" ); }); test( "copy", function() { var a = new THREE.Vector4( x, y, z, w ); var b = new THREE.Vector4().copy( a ); ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); ok( b.z == z, "Passed!" ); ok( b.w == w, "Passed!" ); // ensure that it is a true copy a.x = 0; a.y = -1; a.z = -2; a.w = -3; ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); ok( b.z == z, "Passed!" ); ok( b.w == w, "Passed!" ); }); test( "set", function() { var a = new THREE.Vector4(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); ok( a.w == 1, "Passed!" ); a.set( x, y, z, w ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); ok( a.z == z, "Passed!" ); ok( a.w == w, "Passed!" ); }); test( "setX,setY,setZ,setW", function() { var a = new THREE.Vector4(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); ok( a.w == 1, "Passed!" ); a.setX( x ); a.setY( y ); a.setZ( z ); a.setW( w ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); ok( a.z == z, "Passed!" ); ok( a.w == w, "Passed!" ); }); test( "setComponent,getComponent", function() { var a = new THREE.Vector4(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); ok( a.w == 1, "Passed!" ); a.setComponent( 0, 1 ); a.setComponent( 1, 2 ); a.setComponent( 2, 3 ); a.setComponent( 3, 4 ); ok( a.getComponent( 0 ) == 1, "Passed!" ); ok( a.getComponent( 1 ) == 2, "Passed!" ); ok( a.getComponent( 2 ) == 3, "Passed!" ); ok( a.getComponent( 3 ) == 4, "Passed!" ); }); test( "add", function() { var a = new THREE.Vector4( x, y, z, w ); var b = new THREE.Vector4( -x, -y, -z, -w ); a.add( b ); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); ok( a.w == 0, "Passed!" ); var c = new THREE.Vector4().addVectors( b, b ); ok( c.x == -2*x, "Passed!" ); ok( c.y == -2*y, "Passed!" ); ok( c.z == -2*z, "Passed!" ); ok( c.w == -2*w, "Passed!" ); }); test( "sub", function() { var a = new THREE.Vector4( x, y, z, w ); var b = new THREE.Vector4( -x, -y, -z, -w ); a.sub( b ); ok( a.x == 2*x, "Passed!" ); ok( a.y == 2*y, "Passed!" ); ok( a.z == 2*z, "Passed!" ); ok( a.w == 2*w, "Passed!" ); var c = new THREE.Vector4().subVectors( a, a ); ok( c.x == 0, "Passed!" ); ok( c.y == 0, "Passed!" ); ok( c.z == 0, "Passed!" ); ok( c.w == 0, "Passed!" ); }); test( "multiply/divide", function() { var a = new THREE.Vector4( x, y, z, w ); var b = new THREE.Vector4( -x, -y, -z, -w ); a.multiplyScalar( -2 ); ok( a.x == x*-2, "Passed!" ); ok( a.y == y*-2, "Passed!" ); ok( a.z == z*-2, "Passed!" ); ok( a.w == w*-2, "Passed!" ); b.multiplyScalar( -2 ); ok( b.x == 2*x, "Passed!" ); ok( b.y == 2*y, "Passed!" ); ok( b.z == 2*z, "Passed!" ); ok( b.w == 2*w, "Passed!" ); a.divideScalar( -2 ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); ok( a.z == z, "Passed!" ); ok( a.w == w, "Passed!" ); b.divideScalar( -2 ); ok( b.x == -x, "Passed!" ); ok( b.y == -y, "Passed!" ); ok( b.z == -z, "Passed!" ); ok( b.w == -w, "Passed!" ); }); test( "min/max/clamp", function() { var a = new THREE.Vector4( x, y, z, w ); var b = new THREE.Vector4( -x, -y, -z, -w ); var c = new THREE.Vector4(); c.copy( a ).min( b ); ok( c.x == -x, "Passed!" ); ok( c.y == -y, "Passed!" ); ok( c.z == -z, "Passed!" ); ok( c.w == -w, "Passed!" ); c.copy( a ).max( b ); ok( c.x == x, "Passed!" ); ok( c.y == y, "Passed!" ); ok( c.z == z, "Passed!" ); ok( c.w == w, "Passed!" ); c.set( -2*x, 2*y, -2*z, 2*w ); c.clamp( b, a ); ok( c.x == -x, "Passed!" ); ok( c.y == y, "Passed!" ); ok( c.z == -z, "Passed!" ); ok( c.w == w, "Passed!" ); }); test( "negate", function() { var a = new THREE.Vector4( x, y, z, w ); a.negate(); ok( a.x == -x, "Passed!" ); ok( a.y == -y, "Passed!" ); ok( a.z == -z, "Passed!" ); ok( a.w == -w, "Passed!" ); }); test( "dot", function() { var a = new THREE.Vector4( x, y, z, w ); var b = new THREE.Vector4( -x, -y, -z, -w ); var c = new THREE.Vector4( 0, 0, 0, 0 ); var result = a.dot( b ); ok( result == (-x*x-y*y-z*z-w*w), "Passed!" ); result = a.dot( c ); ok( result == 0, "Passed!" ); }); test( "length/lengthSq", function() { var a = new THREE.Vector4( x, 0, 0, 0 ); var b = new THREE.Vector4( 0, -y, 0, 0 ); var c = new THREE.Vector4( 0, 0, z, 0 ); var d = new THREE.Vector4( 0, 0, 0, w ); var e = new THREE.Vector4( 0, 0, 0, 0 ); ok( a.length() == x, "Passed!" ); ok( a.lengthSq() == x*x, "Passed!" ); ok( b.length() == y, "Passed!" ); ok( b.lengthSq() == y*y, "Passed!" ); ok( c.length() == z, "Passed!" ); ok( c.lengthSq() == z*z, "Passed!" ); ok( d.length() == w, "Passed!" ); ok( d.lengthSq() == w*w, "Passed!" ); ok( e.length() == 0, "Passed!" ); ok( e.lengthSq() == 0, "Passed!" ); a.set( x, y, z, w ); ok( a.length() == Math.sqrt( x*x + y*y + z*z + w*w ), "Passed!" ); ok( a.lengthSq() == ( x*x + y*y + z*z + w*w ), "Passed!" ); }); test( "normalize", function() { var a = new THREE.Vector4( x, 0, 0, 0 ); var b = new THREE.Vector4( 0, -y, 0, 0 ); var c = new THREE.Vector4( 0, 0, z, 0 ); var d = new THREE.Vector4( 0, 0, 0, -w ); a.normalize(); ok( a.length() == 1, "Passed!" ); ok( a.x == 1, "Passed!" ); b.normalize(); ok( b.length() == 1, "Passed!" ); ok( b.y == -1, "Passed!" ); c.normalize(); ok( c.length() == 1, "Passed!" ); ok( c.z == 1, "Passed!" ); d.normalize(); ok( d.length() == 1, "Passed!" ); ok( d.w == -1, "Passed!" ); }); /* test( "distanceTo/distanceToSquared", function() { var a = new THREE.Vector4( x, 0, 0, 0 ); var b = new THREE.Vector4( 0, -y, 0, 0 ); var c = new THREE.Vector4( 0, 0, z, 0 ); var d = new THREE.Vector4( 0, 0, 0, -w ); var e = new THREE.Vector4(); ok( a.distanceTo( e ) == x, "Passed!" ); ok( a.distanceToSquared( e ) == x*x, "Passed!" ); ok( b.distanceTo( e ) == y, "Passed!" ); ok( b.distanceToSquared( e ) == y*y, "Passed!" ); ok( c.distanceTo( e ) == z, "Passed!" ); ok( c.distanceToSquared( e ) == z*z, "Passed!" ); ok( d.distanceTo( e ) == w, "Passed!" ); ok( d.distanceToSquared( e ) == w*w, "Passed!" ); }); */ test( "setLength", function() { var a = new THREE.Vector4( x, 0, 0, 0 ); ok( a.length() == x, "Passed!" ); a.setLength( y ); ok( a.length() == y, "Passed!" ); a = new THREE.Vector4( 0, 0, 0, 0 ); ok( a.length() == 0, "Passed!" ); a.setLength( y ); ok( a.length() == 0, "Passed!" ); }); test( "lerp/clone", function() { var a = new THREE.Vector4( x, 0, z, 0 ); var b = new THREE.Vector4( 0, -y, 0, -w ); ok( a.lerp( a, 0 ).equals( a.lerp( a, 0.5 ) ), "Passed!" ); ok( a.lerp( a, 0 ).equals( a.lerp( a, 1 ) ), "Passed!" ); ok( a.clone().lerp( b, 0 ).equals( a ), "Passed!" ); ok( a.clone().lerp( b, 0.5 ).x == x*0.5, "Passed!" ); ok( a.clone().lerp( b, 0.5 ).y == -y*0.5, "Passed!" ); ok( a.clone().lerp( b, 0.5 ).z == z*0.5, "Passed!" ); ok( a.clone().lerp( b, 0.5 ).w == -w*0.5, "Passed!" ); ok( a.clone().lerp( b, 1 ).equals( b ), "Passed!" ); }); test( "equals", function() { var a = new THREE.Vector4( x, 0, z, 0 ); var b = new THREE.Vector4( 0, -y, 0, -w ); ok( a.x != b.x, "Passed!" ); ok( a.y != b.y, "Passed!" ); ok( a.z != b.z, "Passed!" ); ok( a.w != b.w, "Passed!" ); ok( ! a.equals( b ), "Passed!" ); ok( ! b.equals( a ), "Passed!" ); a.copy( b ); ok( a.x == b.x, "Passed!" ); ok( a.y == b.y, "Passed!" ); ok( a.z == b.z, "Passed!" ); ok( a.w == b.w, "Passed!" ); ok( a.equals( b ), "Passed!" ); ok( b.equals( a ), "Passed!" ); }); three.js-r73/test/unit/math/Plane.js0000644000175500017550000001441212610076566017242 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Plane" ); var comparePlane = function ( a, b, threshold ) { threshold = threshold || 0.0001; return ( a.normal.distanceTo( b.normal ) < threshold && Math.abs( a.constant - b.constant ) < threshold ); }; test( "constructor", function() { var a = new THREE.Plane(); ok( a.normal.x == 1, "Passed!" ); ok( a.normal.y == 0, "Passed!" ); ok( a.normal.z == 0, "Passed!" ); ok( a.constant == 0, "Passed!" ); a = new THREE.Plane( one3.clone(), 0 ); ok( a.normal.x == 1, "Passed!" ); ok( a.normal.y == 1, "Passed!" ); ok( a.normal.z == 1, "Passed!" ); ok( a.constant == 0, "Passed!" ); a = new THREE.Plane( one3.clone(), 1 ); ok( a.normal.x == 1, "Passed!" ); ok( a.normal.y == 1, "Passed!" ); ok( a.normal.z == 1, "Passed!" ); ok( a.constant == 1, "Passed!" ); }); test( "copy", function() { var a = new THREE.Plane( new THREE.Vector3( x, y, z ), w ); var b = new THREE.Plane().copy( a ); ok( b.normal.x == x, "Passed!" ); ok( b.normal.y == y, "Passed!" ); ok( b.normal.z == z, "Passed!" ); ok( b.constant == w, "Passed!" ); // ensure that it is a true copy a.normal.x = 0; a.normal.y = -1; a.normal.z = -2; a.constant = -3; ok( b.normal.x == x, "Passed!" ); ok( b.normal.y == y, "Passed!" ); ok( b.normal.z == z, "Passed!" ); ok( b.constant == w, "Passed!" ); }); test( "set", function() { var a = new THREE.Plane(); ok( a.normal.x == 1, "Passed!" ); ok( a.normal.y == 0, "Passed!" ); ok( a.normal.z == 0, "Passed!" ); ok( a.constant == 0, "Passed!" ); var b = a.clone().set( new THREE.Vector3( x, y, z ), w ); ok( b.normal.x == x, "Passed!" ); ok( b.normal.y == y, "Passed!" ); ok( b.normal.z == z, "Passed!" ); ok( b.constant == w, "Passed!" ); }); test( "setComponents", function() { var a = new THREE.Plane(); ok( a.normal.x == 1, "Passed!" ); ok( a.normal.y == 0, "Passed!" ); ok( a.normal.z == 0, "Passed!" ); ok( a.constant == 0, "Passed!" ); var b = a.clone().setComponents( x, y, z , w ); ok( b.normal.x == x, "Passed!" ); ok( b.normal.y == y, "Passed!" ); ok( b.normal.z == z, "Passed!" ); ok( b.constant == w, "Passed!" ); }); test( "setFromNormalAndCoplanarPoint", function() { var normal = one3.clone().normalize(); var a = new THREE.Plane().setFromNormalAndCoplanarPoint( normal, zero3 ); ok( a.normal.equals( normal ), "Passed!" ); ok( a.constant == 0, "Passed!" ); }); test( "normalize", function() { var a = new THREE.Plane( new THREE.Vector3( 2, 0, 0 ), 2 ); a.normalize(); ok( a.normal.length() == 1, "Passed!" ); ok( a.normal.equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); ok( a.constant == 1, "Passed!" ); }); test( "negate/distanceToPoint", function() { var a = new THREE.Plane( new THREE.Vector3( 2, 0, 0 ), -2 ); a.normalize(); ok( a.distanceToPoint( new THREE.Vector3( 4, 0, 0 ) ) === 3, "Passed!" ); ok( a.distanceToPoint( new THREE.Vector3( 1, 0, 0 ) ) === 0, "Passed!" ); a.negate(); ok( a.distanceToPoint( new THREE.Vector3( 4, 0, 0 ) ) === -3, "Passed!" ); ok( a.distanceToPoint( new THREE.Vector3( 1, 0, 0 ) ) === 0, "Passed!" ); }); test( "distanceToPoint", function() { var a = new THREE.Plane( new THREE.Vector3( 2, 0, 0 ), -2 ); a.normalize(); ok( a.distanceToPoint( a.projectPoint( zero3.clone() ) ) === 0, "Passed!" ); ok( a.distanceToPoint( new THREE.Vector3( 4, 0, 0 ) ) === 3, "Passed!" ); }); test( "distanceToSphere", function() { var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); var b = new THREE.Sphere( new THREE.Vector3( 2, 0, 0 ), 1 ); ok( a.distanceToSphere( b ) === 1, "Passed!" ); a.set( new THREE.Vector3( 1, 0, 0 ), 2 ); ok( a.distanceToSphere( b ) === 3, "Passed!" ); a.set( new THREE.Vector3( 1, 0, 0 ), -2 ); ok( a.distanceToSphere( b ) === -1, "Passed!" ); }); test( "isInterestionLine/intersectLine", function() { var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); var l1 = new THREE.Line3( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( 10, 0, 0 ) ); ok( a.isIntersectionLine( l1 ), "Passed!" ); ok( a.intersectLine( l1 ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), -3 ); ok( a.isIntersectionLine( l1 ), "Passed!" ); ok( a.intersectLine( l1 ).equals( new THREE.Vector3( 3, 0, 0 ) ), "Passed!" ); a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), -11 ); ok( ! a.isIntersectionLine( l1 ), "Passed!" ); ok( a.intersectLine( l1 ) === undefined, "Passed!" ); a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 11 ); ok( ! a.isIntersectionLine( l1 ), "Passed!" ); ok( a.intersectLine( l1 ) === undefined, "Passed!" ); }); test( "projectPoint", function() { var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); ok( a.projectPoint( new THREE.Vector3( 10, 0, 0 ) ).equals( zero3 ), "Passed!" ); ok( a.projectPoint( new THREE.Vector3( -10, 0, 0 ) ).equals( zero3 ), "Passed!" ); a = new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), -1 ); ok( a.projectPoint( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); ok( a.projectPoint( new THREE.Vector3( 0, 1, 0 ) ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); }); test( "orthoPoint", function() { var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); ok( a.orthoPoint( new THREE.Vector3( 10, 0, 0 ) ).equals( new THREE.Vector3( 10, 0, 0 ) ), "Passed!" ); ok( a.orthoPoint( new THREE.Vector3( -10, 0, 0 ) ).equals( new THREE.Vector3( -10, 0, 0 ) ), "Passed!" ); }); test( "coplanarPoint", function() { var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); ok( a.distanceToPoint( a.coplanarPoint() ) === 0, "Passed!" ); a = new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), -1 ); ok( a.distanceToPoint( a.coplanarPoint() ) === 0, "Passed!" ); }); test( "applyMatrix4/translate", function() { var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); var m = new THREE.Matrix4(); m.makeRotationZ( Math.PI * 0.5 ); ok( comparePlane( a.clone().applyMatrix4( m ), new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), 0 ) ), "Passed!" ); a = new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), -1 ); ok( comparePlane( a.clone().applyMatrix4( m ), new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), -1 ) ), "Passed!" ); m.makeTranslation( 1, 1, 1 ); ok( comparePlane( a.clone().applyMatrix4( m ), a.clone().translate( new THREE.Vector3( 1, 1, 1 ) ) ), "Passed!" ); }); three.js-r73/test/unit/math/Box3.js0000644000175500017550000002534312610076566017023 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Box3" ); test( "constructor", function() { var a = new THREE.Box3(); ok( a.min.equals( posInf3 ), "Passed!" ); ok( a.max.equals( negInf3 ), "Passed!" ); a = new THREE.Box3( zero3.clone(), zero3.clone() ); ok( a.min.equals( zero3 ), "Passed!" ); ok( a.max.equals( zero3 ), "Passed!" ); a = new THREE.Box3( zero3.clone(), one3.clone() ); ok( a.min.equals( zero3 ), "Passed!" ); ok( a.max.equals( one3 ), "Passed!" ); }); test( "copy", function() { var a = new THREE.Box3( zero3.clone(), one3.clone() ); var b = new THREE.Box3().copy( a ); ok( b.min.equals( zero3 ), "Passed!" ); ok( b.max.equals( one3 ), "Passed!" ); // ensure that it is a true copy a.min = zero3; a.max = one3; ok( b.min.equals( zero3 ), "Passed!" ); ok( b.max.equals( one3 ), "Passed!" ); }); test( "set", function() { var a = new THREE.Box3(); a.set( zero3, one3 ); ok( a.min.equals( zero3 ), "Passed!" ); ok( a.max.equals( one3 ), "Passed!" ); }); test( "setFromPoints", function() { var a = new THREE.Box3(); a.setFromPoints( [ zero3, one3, two3 ] ); ok( a.min.equals( zero3 ), "Passed!" ); ok( a.max.equals( two3 ), "Passed!" ); a.setFromPoints( [ one3 ] ); ok( a.min.equals( one3 ), "Passed!" ); ok( a.max.equals( one3 ), "Passed!" ); a.setFromPoints( [] ); ok( a.empty(), "Passed!" ); }); test( "empty/makeEmpty", function() { var a = new THREE.Box3(); ok( a.empty(), "Passed!" ); var a = new THREE.Box3( zero3.clone(), one3.clone() ); ok( ! a.empty(), "Passed!" ); a.makeEmpty(); ok( a.empty(), "Passed!" ); }); test( "center", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); ok( a.center().equals( zero3 ), "Passed!" ); a = new THREE.Box3( zero3.clone(), one3.clone() ); var midpoint = one3.clone().multiplyScalar( 0.5 ); ok( a.center().equals( midpoint ), "Passed!" ); }); test( "size", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); ok( a.size().equals( zero3 ), "Passed!" ); a = new THREE.Box3( zero3.clone(), one3.clone() ); ok( a.size().equals( one3 ), "Passed!" ); }); test( "expandByPoint", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); a.expandByPoint( zero3 ); ok( a.size().equals( zero3 ), "Passed!" ); a.expandByPoint( one3 ); ok( a.size().equals( one3 ), "Passed!" ); a.expandByPoint( one3.clone().negate() ); ok( a.size().equals( one3.clone().multiplyScalar( 2 ) ), "Passed!" ); ok( a.center().equals( zero3 ), "Passed!" ); }); test( "expandByVector", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); a.expandByVector( zero3 ); ok( a.size().equals( zero3 ), "Passed!" ); a.expandByVector( one3 ); ok( a.size().equals( one3.clone().multiplyScalar( 2 ) ), "Passed!" ); ok( a.center().equals( zero3 ), "Passed!" ); }); test( "expandByScalar", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); a.expandByScalar( 0 ); ok( a.size().equals( zero3 ), "Passed!" ); a.expandByScalar( 1 ); ok( a.size().equals( one3.clone().multiplyScalar( 2 ) ), "Passed!" ); ok( a.center().equals( zero3 ), "Passed!" ); }); test( "containsPoint", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); ok( a.containsPoint( zero3 ), "Passed!" ); ok( ! a.containsPoint( one3 ), "Passed!" ); a.expandByScalar( 1 ); ok( a.containsPoint( zero3 ), "Passed!" ); ok( a.containsPoint( one3 ), "Passed!" ); ok( a.containsPoint( one3.clone().negate() ), "Passed!" ); }); test( "containsBox", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( zero3.clone(), one3.clone() ); var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.containsBox( a ), "Passed!" ); ok( ! a.containsBox( b ), "Passed!" ); ok( ! a.containsBox( c ), "Passed!" ); ok( b.containsBox( a ), "Passed!" ); ok( c.containsBox( a ), "Passed!" ); ok( ! b.containsBox( c ), "Passed!" ); }); test( "getParameter", function() { var a = new THREE.Box3( zero3.clone(), one3.clone() ); var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.getParameter( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( a.getParameter( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); ok( b.getParameter( new THREE.Vector3( -1, -1, -1 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( b.getParameter( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0.5, 0.5, 0.5 ) ), "Passed!" ); ok( b.getParameter( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); }); test( "clampPoint", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.clampPoint( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( a.clampPoint( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( a.clampPoint( new THREE.Vector3( -1, -1, -1 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector3( 2, 2, 2 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector3( -1, -1, -1 ) ).equals( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector3( -2, -2, -2 ) ).equals( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); }); test( "distanceToPoint", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); ok( a.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == Math.sqrt( 3 ), "Passed!" ); ok( a.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == Math.sqrt( 3 ), "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( 2, 2, 2 ) ) == Math.sqrt( 3 ), "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( -2, -2, -2 ) ) == Math.sqrt( 3 ), "Passed!" ); }); test( "distanceToPoint", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); ok( a.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == Math.sqrt( 3 ), "Passed!" ); ok( a.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == Math.sqrt( 3 ), "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( 2, 2, 2 ) ) == Math.sqrt( 3 ), "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector3( -2, -2, -2 ) ) == Math.sqrt( 3 ), "Passed!" ); }); test( "isIntersectionBox", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( zero3.clone(), one3.clone() ); var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.isIntersectionBox( a ), "Passed!" ); ok( a.isIntersectionBox( b ), "Passed!" ); ok( a.isIntersectionBox( c ), "Passed!" ); ok( b.isIntersectionBox( a ), "Passed!" ); ok( c.isIntersectionBox( a ), "Passed!" ); ok( b.isIntersectionBox( c ), "Passed!" ); b.translate( new THREE.Vector3( 2, 2, 2 ) ); ok( ! a.isIntersectionBox( b ), "Passed!" ); ok( ! b.isIntersectionBox( a ), "Passed!" ); ok( ! b.isIntersectionBox( c ), "Passed!" ); }); test( "getBoundingSphere", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( zero3.clone(), one3.clone() ); var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.getBoundingSphere().equals( new THREE.Sphere( zero3, 0 ) ), "Passed!" ); ok( b.getBoundingSphere().equals( new THREE.Sphere( one3.clone().multiplyScalar( 0.5 ), Math.sqrt( 3 ) * 0.5 ) ), "Passed!" ); ok( c.getBoundingSphere().equals( new THREE.Sphere( zero3, Math.sqrt( 12 ) * 0.5 ) ), "Passed!" ); }); test( "intersect", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( zero3.clone(), one3.clone() ); var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.clone().intersect( a ).equals( a ), "Passed!" ); ok( a.clone().intersect( b ).equals( a ), "Passed!" ); ok( b.clone().intersect( b ).equals( b ), "Passed!" ); ok( a.clone().intersect( c ).equals( a ), "Passed!" ); ok( b.clone().intersect( c ).equals( b ), "Passed!" ); ok( c.clone().intersect( c ).equals( c ), "Passed!" ); }); test( "union", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( zero3.clone(), one3.clone() ); var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); ok( a.clone().union( a ).equals( a ), "Passed!" ); ok( a.clone().union( b ).equals( b ), "Passed!" ); ok( a.clone().union( c ).equals( c ), "Passed!" ); ok( b.clone().union( c ).equals( c ), "Passed!" ); }); var compareBox = function ( a, b, threshold ) { threshold = threshold || 0.0001; return ( a.min.distanceTo( b.min ) < threshold && a.max.distanceTo( b.max ) < threshold ); }; test( "applyMatrix4", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( zero3.clone(), one3.clone() ); var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); var d = new THREE.Box3( one3.clone().negate(), zero3.clone() ); var m = new THREE.Matrix4().makeTranslation( 1, -2, 1 ); var t1 = new THREE.Vector3( 1, -2, 1 ); ok( compareBox( a.clone().applyMatrix4( m ), a.clone().translate( t1 ) ), "Passed!" ); ok( compareBox( b.clone().applyMatrix4( m ), b.clone().translate( t1 ) ), "Passed!" ); ok( compareBox( c.clone().applyMatrix4( m ), c.clone().translate( t1 ) ), "Passed!" ); ok( compareBox( d.clone().applyMatrix4( m ), d.clone().translate( t1 ) ), "Passed!" ); }); test( "translate", function() { var a = new THREE.Box3( zero3.clone(), zero3.clone() ); var b = new THREE.Box3( zero3.clone(), one3.clone() ); var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); var d = new THREE.Box3( one3.clone().negate(), zero3.clone() ); ok( a.clone().translate( one3 ).equals( new THREE.Box3( one3, one3 ) ), "Passed!" ); ok( a.clone().translate( one3 ).translate( one3.clone().negate() ).equals( a ), "Passed!" ); ok( d.clone().translate( one3 ).equals( b ), "Passed!" ); ok( b.clone().translate( one3.clone().negate() ).equals( d ), "Passed!" ); }); three.js-r73/test/unit/math/Box2.js0000644000175500017550000002060712610076566017020 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Box2" ); test( "constructor", function() { var a = new THREE.Box2(); ok( a.min.equals( posInf2 ), "Passed!" ); ok( a.max.equals( negInf2 ), "Passed!" ); a = new THREE.Box2( zero2.clone(), zero2.clone() ); ok( a.min.equals( zero2 ), "Passed!" ); ok( a.max.equals( zero2 ), "Passed!" ); a = new THREE.Box2( zero2.clone(), one2.clone() ); ok( a.min.equals( zero2 ), "Passed!" ); ok( a.max.equals( one2 ), "Passed!" ); }); test( "copy", function() { var a = new THREE.Box2( zero2.clone(), one2.clone() ); var b = new THREE.Box2().copy( a ); ok( b.min.equals( zero2 ), "Passed!" ); ok( b.max.equals( one2 ), "Passed!" ); // ensure that it is a true copy a.min = zero2; a.max = one2; ok( b.min.equals( zero2 ), "Passed!" ); ok( b.max.equals( one2 ), "Passed!" ); }); test( "set", function() { var a = new THREE.Box2(); a.set( zero2, one2 ); ok( a.min.equals( zero2 ), "Passed!" ); ok( a.max.equals( one2 ), "Passed!" ); }); test( "setFromPoints", function() { var a = new THREE.Box2(); a.setFromPoints( [ zero2, one2, two2 ] ); ok( a.min.equals( zero2 ), "Passed!" ); ok( a.max.equals( two2 ), "Passed!" ); a.setFromPoints( [ one2 ] ); ok( a.min.equals( one2 ), "Passed!" ); ok( a.max.equals( one2 ), "Passed!" ); a.setFromPoints( [] ); ok( a.empty(), "Passed!" ); }); test( "empty/makeEmpty", function() { var a = new THREE.Box2(); ok( a.empty(), "Passed!" ); var a = new THREE.Box2( zero2.clone(), one2.clone() ); ok( ! a.empty(), "Passed!" ); a.makeEmpty(); ok( a.empty(), "Passed!" ); }); test( "center", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); ok( a.center().equals( zero2 ), "Passed!" ); a = new THREE.Box2( zero2, one2 ); var midpoint = one2.clone().multiplyScalar( 0.5 ); ok( a.center().equals( midpoint ), "Passed!" ); }); test( "size", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); ok( a.size().equals( zero2 ), "Passed!" ); a = new THREE.Box2( zero2.clone(), one2.clone() ); ok( a.size().equals( one2 ), "Passed!" ); }); test( "expandByPoint", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); a.expandByPoint( zero2 ); ok( a.size().equals( zero2 ), "Passed!" ); a.expandByPoint( one2 ); ok( a.size().equals( one2 ), "Passed!" ); a.expandByPoint( one2.clone().negate() ); ok( a.size().equals( one2.clone().multiplyScalar( 2 ) ), "Passed!" ); ok( a.center().equals( zero2 ), "Passed!" ); }); test( "expandByVector", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); a.expandByVector( zero2 ); ok( a.size().equals( zero2 ), "Passed!" ); a.expandByVector( one2 ); ok( a.size().equals( one2.clone().multiplyScalar( 2 ) ), "Passed!" ); ok( a.center().equals( zero2 ), "Passed!" ); }); test( "expandByScalar", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); a.expandByScalar( 0 ); ok( a.size().equals( zero2 ), "Passed!" ); a.expandByScalar( 1 ); ok( a.size().equals( one2.clone().multiplyScalar( 2 ) ), "Passed!" ); ok( a.center().equals( zero2 ), "Passed!" ); }); test( "containsPoint", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); ok( a.containsPoint( zero2 ), "Passed!" ); ok( ! a.containsPoint( one2 ), "Passed!" ); a.expandByScalar( 1 ); ok( a.containsPoint( zero2 ), "Passed!" ); ok( a.containsPoint( one2 ), "Passed!" ); ok( a.containsPoint( one2.clone().negate() ), "Passed!" ); }); test( "containsBox", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); var b = new THREE.Box2( zero2.clone(), one2.clone() ); var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); ok( a.containsBox( a ), "Passed!" ); ok( ! a.containsBox( b ), "Passed!" ); ok( ! a.containsBox( c ), "Passed!" ); ok( b.containsBox( a ), "Passed!" ); ok( c.containsBox( a ), "Passed!" ); ok( ! b.containsBox( c ), "Passed!" ); }); test( "getParameter", function() { var a = new THREE.Box2( zero2.clone(), one2.clone() ); var b = new THREE.Box2( one2.clone().negate(), one2.clone() ); ok( a.getParameter( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); ok( a.getParameter( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); ok( b.getParameter( new THREE.Vector2( -1, -1 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); ok( b.getParameter( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0.5, 0.5 ) ), "Passed!" ); ok( b.getParameter( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); }); test( "clampPoint", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); var b = new THREE.Box2( one2.clone().negate(), one2.clone() ); ok( a.clampPoint( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); ok( a.clampPoint( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); ok( a.clampPoint( new THREE.Vector2( -1, -1 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector2( 2, 2 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector2( -1, -1 ) ).equals( new THREE.Vector2( -1, -1 ) ), "Passed!" ); ok( b.clampPoint( new THREE.Vector2( -2, -2 ) ).equals( new THREE.Vector2( -1, -1 ) ), "Passed!" ); }); test( "distanceToPoint", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); var b = new THREE.Box2( one2.clone().negate(), one2.clone() ); ok( a.distanceToPoint( new THREE.Vector2( 0, 0 ) ) == 0, "Passed!" ); ok( a.distanceToPoint( new THREE.Vector2( 1, 1 ) ) == Math.sqrt( 2 ), "Passed!" ); ok( a.distanceToPoint( new THREE.Vector2( -1, -1 ) ) == Math.sqrt( 2 ), "Passed!" ); ok( b.distanceToPoint( new THREE.Vector2( 2, 2 ) ) == Math.sqrt( 2 ), "Passed!" ); ok( b.distanceToPoint( new THREE.Vector2( 1, 1 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector2( 0, 0 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector2( -1, -1 ) ) == 0, "Passed!" ); ok( b.distanceToPoint( new THREE.Vector2( -2, -2 ) ) == Math.sqrt( 2 ), "Passed!" ); }); test( "isIntersectionBox", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); var b = new THREE.Box2( zero2.clone(), one2.clone() ); var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); ok( a.isIntersectionBox( a ), "Passed!" ); ok( a.isIntersectionBox( b ), "Passed!" ); ok( a.isIntersectionBox( c ), "Passed!" ); ok( b.isIntersectionBox( a ), "Passed!" ); ok( c.isIntersectionBox( a ), "Passed!" ); ok( b.isIntersectionBox( c ), "Passed!" ); b.translate( new THREE.Vector2( 2, 2 ) ); ok( ! a.isIntersectionBox( b ), "Passed!" ); ok( ! b.isIntersectionBox( a ), "Passed!" ); ok( ! b.isIntersectionBox( c ), "Passed!" ); }); test( "intersect", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); var b = new THREE.Box2( zero2.clone(), one2.clone() ); var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); ok( a.clone().intersect( a ).equals( a ), "Passed!" ); ok( a.clone().intersect( b ).equals( a ), "Passed!" ); ok( b.clone().intersect( b ).equals( b ), "Passed!" ); ok( a.clone().intersect( c ).equals( a ), "Passed!" ); ok( b.clone().intersect( c ).equals( b ), "Passed!" ); ok( c.clone().intersect( c ).equals( c ), "Passed!" ); }); test( "union", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); var b = new THREE.Box2( zero2.clone(), one2.clone() ); var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); ok( a.clone().union( a ).equals( a ), "Passed!" ); ok( a.clone().union( b ).equals( b ), "Passed!" ); ok( a.clone().union( c ).equals( c ), "Passed!" ); ok( b.clone().union( c ).equals( c ), "Passed!" ); }); test( "translate", function() { var a = new THREE.Box2( zero2.clone(), zero2.clone() ); var b = new THREE.Box2( zero2.clone(), one2.clone() ); var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); var d = new THREE.Box2( one2.clone().negate(), zero2.clone() ); ok( a.clone().translate( one2 ).equals( new THREE.Box2( one2, one2 ) ), "Passed!" ); ok( a.clone().translate( one2 ).translate( one2.clone().negate() ).equals( a ), "Passed!" ); ok( d.clone().translate( one2 ).equals( b ), "Passed!" ); ok( b.clone().translate( one2.clone().negate() ).equals( d ), "Passed!" ); }); three.js-r73/test/unit/math/Ray.js0000644000175500017550000003230412610076566016736 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Ray" ); test( "constructor/equals", function() { var a = new THREE.Ray(); ok( a.origin.equals( zero3 ), "Passed!" ); ok( a.direction.equals( zero3 ), "Passed!" ); a = new THREE.Ray( two3.clone(), one3.clone() ); ok( a.origin.equals( two3 ), "Passed!" ); ok( a.direction.equals( one3 ), "Passed!" ); }); test( "copy/equals", function() { var a = new THREE.Ray( zero3.clone(), one3.clone() ); var b = new THREE.Ray().copy( a ); ok( b.origin.equals( zero3 ), "Passed!" ); ok( b.direction.equals( one3 ), "Passed!" ); // ensure that it is a true copy a.origin = zero3; a.direction = one3; ok( b.origin.equals( zero3 ), "Passed!" ); ok( b.direction.equals( one3 ), "Passed!" ); }); test( "set", function() { var a = new THREE.Ray(); a.set( one3, one3 ); ok( a.origin.equals( one3 ), "Passed!" ); ok( a.direction.equals( one3 ), "Passed!" ); }); test( "at", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); ok( a.at( 0 ).equals( one3 ), "Passed!" ); ok( a.at( -1 ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); ok( a.at( 1 ).equals( new THREE.Vector3( 1, 1, 2 ) ), "Passed!" ); }); test( "recast/clone", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); ok( a.recast( 0 ).equals( a ), "Passed!" ); var b = a.clone(); ok( b.recast( -1 ).equals( new THREE.Ray( new THREE.Vector3( 1, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ) ), "Passed!" ); var c = a.clone(); ok( c.recast( 1 ).equals( new THREE.Ray( new THREE.Vector3( 1, 1, 2 ), new THREE.Vector3( 0, 0, 1 ) ) ), "Passed!" ); var d = a.clone(); var e = d.clone().recast( 1 ); ok( d.equals( a ), "Passed!" ); ok( ! e.equals( d ), "Passed!" ); ok( e.equals( c ), "Passed!" ); }); test( "closestPointToPoint", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); // behind the ray var b = a.closestPointToPoint( zero3 ); ok( b.equals( one3 ), "Passed!" ); // front of the ray var c = a.closestPointToPoint( new THREE.Vector3( 0, 0, 50 ) ); ok( c.equals( new THREE.Vector3( 1, 1, 50 ) ), "Passed!" ); // exactly on the ray var d = a.closestPointToPoint( one3 ); ok( d.equals( one3 ), "Passed!" ); }); test( "distanceToPoint", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); // behind the ray var b = a.distanceToPoint( zero3 ); ok( b === Math.sqrt( 3 ), "Passed!" ); // front of the ray var c = a.distanceToPoint( new THREE.Vector3( 0, 0, 50 ) ); ok( c === Math.sqrt( 2 ), "Passed!" ); // exactly on the ray var d = a.distanceToPoint( one3 ); ok( d === 0, "Passed!" ); }); test( "distanceSqToPoint", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); // behind the ray var b = a.distanceSqToPoint( zero3 ); ok( b === 3, "Passed!" ); // front of the ray var c = a.distanceSqToPoint( new THREE.Vector3( 0, 0, 50 ) ); ok( c === 2, "Passed!" ); // exactly on the ray var d = a.distanceSqToPoint( one3 ); ok( d === 0, "Passed!" ); }); test( "isIntersectionSphere", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); var b = new THREE.Sphere( zero3, 0.5 ); var c = new THREE.Sphere( zero3, 1.5 ); var d = new THREE.Sphere( one3, 0.1 ); var e = new THREE.Sphere( two3, 0.1 ); var f = new THREE.Sphere( two3, 1 ); ok( ! a.isIntersectionSphere( b ), "Passed!" ); ok( ! a.isIntersectionSphere( c ), "Passed!" ); ok( a.isIntersectionSphere( d ), "Passed!" ); ok( ! a.isIntersectionSphere( e ), "Passed!" ); ok( ! a.isIntersectionSphere( f ), "Passed!" ); }); test( "intersectSphere", function() { var TOL = 0.0001; // ray a0 origin located at ( 0, 0, 0 ) and points outward in negative-z direction var a0 = new THREE.Ray( zero3.clone(), new THREE.Vector3( 0, 0, -1 ) ); // ray a1 origin located at ( 1, 1, 1 ) and points left in negative-x direction var a1 = new THREE.Ray( one3.clone(), new THREE.Vector3( -1, 0, 0 ) ); // sphere (radius of 2) located behind ray a0, should result in null var b = new THREE.Sphere( new THREE.Vector3( 0, 0, 3 ), 2 ); ok( a0.intersectSphere( b ) === null, "Passed!" ); // sphere (radius of 2) located in front of, but too far right of ray a0, should result in null var b = new THREE.Sphere( new THREE.Vector3( 3, 0, -1 ), 2 ); ok( a0.intersectSphere( b ) === null, "Passed!" ); // sphere (radius of 2) located below ray a1, should result in null var b = new THREE.Sphere( new THREE.Vector3( 1, -2, 1 ), 2 ); ok( a1.intersectSphere( b ) === null, "Passed!" ); // sphere (radius of 1) located to the left of ray a1, should result in intersection at 0, 1, 1 var b = new THREE.Sphere( new THREE.Vector3( -1, 1, 1 ), 1 ); ok( a1.intersectSphere( b ).distanceTo( new THREE.Vector3( 0, 1, 1 ) ) < TOL, "Passed!" ); // sphere (radius of 1) located in front of ray a0, should result in intersection at 0, 0, -1 var b = new THREE.Sphere( new THREE.Vector3( 0, 0, -2 ), 1 ); ok( a0.intersectSphere( b ).distanceTo( new THREE.Vector3( 0, 0, -1 ) ) < TOL, "Passed!" ); // sphere (radius of 2) located in front & right of ray a0, should result in intersection at 0, 0, -1, or left-most edge of sphere var b = new THREE.Sphere( new THREE.Vector3( 2, 0, -1 ), 2 ); ok( a0.intersectSphere( b ).distanceTo( new THREE.Vector3( 0, 0, -1 ) ) < TOL, "Passed!" ); // same situation as above, but move the sphere a fraction more to the right, and ray a0 should now just miss var b = new THREE.Sphere( new THREE.Vector3( 2.01, 0, -1 ), 2 ); ok( a0.intersectSphere( b ) === null, "Passed!" ); // following tests are for situations where the ray origin is inside the sphere // sphere (radius of 1) center located at ray a0 origin / sphere surrounds the ray origin, so the first intersect point 0, 0, 1, // is behind ray a0. Therefore, second exit point on back of sphere will be returned: 0, 0, -1 // thus keeping the intersection point always in front of the ray. var b = new THREE.Sphere( zero3.clone(), 1 ); ok( a0.intersectSphere( b ).distanceTo( new THREE.Vector3( 0, 0, -1 ) ) < TOL, "Passed!" ); // sphere (radius of 4) center located behind ray a0 origin / sphere surrounds the ray origin, so the first intersect point 0, 0, 5, // is behind ray a0. Therefore, second exit point on back of sphere will be returned: 0, 0, -3 // thus keeping the intersection point always in front of the ray. var b = new THREE.Sphere( new THREE.Vector3( 0, 0, 1 ), 4 ); ok( a0.intersectSphere( b ).distanceTo( new THREE.Vector3( 0, 0, -3 ) ) < TOL, "Passed!" ); // sphere (radius of 4) center located in front of ray a0 origin / sphere surrounds the ray origin, so the first intersect point 0, 0, 3, // is behind ray a0. Therefore, second exit point on back of sphere will be returned: 0, 0, -5 // thus keeping the intersection point always in front of the ray. var b = new THREE.Sphere( new THREE.Vector3( 0, 0, -1 ), 4 ); ok( a0.intersectSphere( b ).distanceTo( new THREE.Vector3( 0, 0, -5 ) ) < TOL, "Passed!" ); }); test( "isIntersectionPlane", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); // parallel plane in front of the ray var b = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), one3.clone().sub( new THREE.Vector3( 0, 0, -1 ) ) ); ok( a.isIntersectionPlane( b ), "Passed!" ); // parallel plane coincident with origin var c = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), one3.clone().sub( new THREE.Vector3( 0, 0, 0 ) ) ); ok( a.isIntersectionPlane( c ), "Passed!" ); // parallel plane behind the ray var d = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), one3.clone().sub( new THREE.Vector3( 0, 0, 1 ) ) ); ok( ! a.isIntersectionPlane( d ), "Passed!" ); // perpendical ray that overlaps exactly var e = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), one3 ); ok( a.isIntersectionPlane( e ), "Passed!" ); // perpendical ray that doesn't overlap var f = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), zero3 ); ok( ! a.isIntersectionPlane( f ), "Passed!" ); }); test( "intersectPlane", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); // parallel plane behind var b = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 1, 1, -1 ) ); ok( a.intersectPlane( b ) === null, "Passed!" ); // parallel plane coincident with origin var c = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 1, 1, 0 ) ); ok( a.intersectPlane( c ) === null, "Passed!" ); // parallel plane infront var d = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 1, 1, 1 ) ); ok( a.intersectPlane( d ).equals( a.origin ), "Passed!" ); // perpendical ray that overlaps exactly var e = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), one3 ); ok( a.intersectPlane( e ).equals( a.origin ), "Passed!" ); // perpendical ray that doesn't overlap var f = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), zero3 ); ok( a.intersectPlane( f ) === null, "Passed!" ); }); test( "applyMatrix4", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); var m = new THREE.Matrix4(); ok( a.clone().applyMatrix4( m ).equals( a ), "Passed!" ); a = new THREE.Ray( zero3.clone(), new THREE.Vector3( 0, 0, 1 ) ); m.makeRotationZ( Math.PI ); ok( a.clone().applyMatrix4( m ).equals( a ), "Passed!" ); m.makeRotationX( Math.PI ); var b = a.clone(); b.direction.negate(); var a2 = a.clone().applyMatrix4( m ); ok( a2.origin.distanceTo( b.origin ) < 0.0001, "Passed!" ); ok( a2.direction.distanceTo( b.direction ) < 0.0001, "Passed!" ); a.origin = new THREE.Vector3( 0, 0, 1 ); b.origin = new THREE.Vector3( 0, 0, -1 ); var a2 = a.clone().applyMatrix4( m ); ok( a2.origin.distanceTo( b.origin ) < 0.0001, "Passed!" ); ok( a2.direction.distanceTo( b.direction ) < 0.0001, "Passed!" ); }); test( "distanceSqToSegment", function() { var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); var ptOnLine = new THREE.Vector3(); var ptOnSegment = new THREE.Vector3(); //segment in front of the ray var v0 = new THREE.Vector3( 3, 5, 50 ); var v1 = new THREE.Vector3( 50, 50, 50 ); // just a far away point var distSqr = a.distanceSqToSegment( v0, v1, ptOnLine, ptOnSegment ); ok( ptOnSegment.distanceTo( v0 ) < 0.0001, "Passed!" ); ok( ptOnLine.distanceTo( new THREE.Vector3(1, 1, 50) ) < 0.0001, "Passed!" ); // ((3-1) * (3-1) + (5-1) * (5-1) = 4 + 16 = 20 ok( Math.abs( distSqr - 20 ) < 0.0001, "Passed!" ); //segment behind the ray v0 = new THREE.Vector3( -50, -50, -50 ); // just a far away point v1 = new THREE.Vector3( -3, -5, -4 ); distSqr = a.distanceSqToSegment( v0, v1, ptOnLine, ptOnSegment ); ok( ptOnSegment.distanceTo( v1 ) < 0.0001, "Passed!" ); ok( ptOnLine.distanceTo( one3 ) < 0.0001, "Passed!" ); // ((-3-1) * (-3-1) + (-5-1) * (-5-1) + (-4-1) + (-4-1) = 16 + 36 + 25 = 77 ok( Math.abs( distSqr - 77 ) < 0.0001, "Passed!" ); //exact intersection between the ray and the segment v0 = new THREE.Vector3( -50, -50, -50 ); v1 = new THREE.Vector3( 50, 50, 50 ); distSqr = a.distanceSqToSegment( v0, v1, ptOnLine, ptOnSegment ); ok( ptOnSegment.distanceTo( one3 ) < 0.0001, "Passed!" ); ok( ptOnLine.distanceTo( one3 ) < 0.0001, "Passed!" ); ok( distSqr < 0.0001, "Passed!" ); }); test( "intersectBox", function() { var TOL = 0.0001; var box = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ); var a = new THREE.Ray( new THREE.Vector3( -2, 0, 0 ), new THREE.Vector3( 1, 0, 0) ); //ray should intersect box at -1,0,0 ok( a.isIntersectionBox(box) === true, "Passed!" ); ok( a.intersectBox(box).distanceTo( new THREE.Vector3( -1, 0, 0 ) ) < TOL, "Passed!" ); var b = new THREE.Ray( new THREE.Vector3( -2, 0, 0 ), new THREE.Vector3( -1, 0, 0) ); //ray is point away from box, it should not intersect ok( b.isIntersectionBox(box) === false, "Passed!" ); ok( b.intersectBox(box) === null, "Passed!" ); var c = new THREE.Ray( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0) ); // ray is inside box, should return exit point ok( c.isIntersectionBox(box) === true, "Passed!" ); ok( c.intersectBox(box).distanceTo( new THREE.Vector3( 1, 0, 0 ) ) < TOL, "Passed!" ); var d = new THREE.Ray( new THREE.Vector3( 0, 2, 1 ), new THREE.Vector3( 0, -1, -1).normalize() ); //tilted ray should intersect box at 0,1,0 ok( d.isIntersectionBox(box) === true, "Passed!" ); ok( d.intersectBox(box).distanceTo( new THREE.Vector3( 0, 1, 0 ) ) < TOL, "Passed!" ); var e = new THREE.Ray( new THREE.Vector3( 1, -2, 1 ), new THREE.Vector3( 0, 1, 0).normalize() ); //handle case where ray is coplanar with one of the boxes side - box in front of ray ok( e.isIntersectionBox(box) === true, "Passed!" ); ok( e.intersectBox(box).distanceTo( new THREE.Vector3( 1, -1, 1 ) ) < TOL, "Passed!" ); var f = new THREE.Ray( new THREE.Vector3( 1, -2, 0 ), new THREE.Vector3( 0, -1, 0).normalize() ); //handle case where ray is coplanar with one of the boxes side - box behind ray ok( f.isIntersectionBox(box) === false, "Passed!" ); ok( f.intersectBox(box) == null, "Passed!" ); }); three.js-r73/test/unit/math/Matrix4.js0000644000175500017550000002267012610076566017540 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Matrix4" ); var matrixEquals4 = function( a, b, tolerance ) { tolerance = tolerance || 0.0001; if( a.elements.length != b.elements.length ) { return false; } for( var i = 0, il = a.elements.length; i < il; i ++ ) { var delta = a.elements[i] - b.elements[i]; if( delta > tolerance ) { return false; } } return true; }; test( "constructor", function() { var a = new THREE.Matrix4(); ok( a.determinant() == 1, "Passed!" ); var b = new THREE.Matrix4().set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 4 ); ok( b.elements[2] == 8 ); ok( b.elements[3] == 12 ); ok( b.elements[4] == 1 ); ok( b.elements[5] == 5 ); ok( b.elements[6] == 9 ); ok( b.elements[7] == 13 ); ok( b.elements[8] == 2 ); ok( b.elements[9] == 6 ); ok( b.elements[10] == 10 ); ok( b.elements[11] == 14 ); ok( b.elements[12] == 3 ); ok( b.elements[13] == 7 ); ok( b.elements[14] == 11 ); ok( b.elements[15] == 15 ); ok( ! matrixEquals4( a, b ), "Passed!" ); }); test( "copy", function() { var a = new THREE.Matrix4().set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); var b = new THREE.Matrix4().copy( a ); ok( matrixEquals4( a, b ), "Passed!" ); // ensure that it is a true copy a.elements[0] = 2; ok( ! matrixEquals4( a, b ), "Passed!" ); }); test( "set", function() { var b = new THREE.Matrix4(); ok( b.determinant() == 1, "Passed!" ); b.set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 4 ); ok( b.elements[2] == 8 ); ok( b.elements[3] == 12 ); ok( b.elements[4] == 1 ); ok( b.elements[5] == 5 ); ok( b.elements[6] == 9 ); ok( b.elements[7] == 13 ); ok( b.elements[8] == 2 ); ok( b.elements[9] == 6 ); ok( b.elements[10] == 10 ); ok( b.elements[11] == 14 ); ok( b.elements[12] == 3 ); ok( b.elements[13] == 7 ); ok( b.elements[14] == 11 ); ok( b.elements[15] == 15 ); }); test( "identity", function() { var b = new THREE.Matrix4().set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 4 ); ok( b.elements[2] == 8 ); ok( b.elements[3] == 12 ); ok( b.elements[4] == 1 ); ok( b.elements[5] == 5 ); ok( b.elements[6] == 9 ); ok( b.elements[7] == 13 ); ok( b.elements[8] == 2 ); ok( b.elements[9] == 6 ); ok( b.elements[10] == 10 ); ok( b.elements[11] == 14 ); ok( b.elements[12] == 3 ); ok( b.elements[13] == 7 ); ok( b.elements[14] == 11 ); ok( b.elements[15] == 15 ); var a = new THREE.Matrix4(); ok( ! matrixEquals4( a, b ), "Passed!" ); b.identity(); ok( matrixEquals4( a, b ), "Passed!" ); }); test( "multiplyScalar", function() { var b = new THREE.Matrix4().set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 4 ); ok( b.elements[2] == 8 ); ok( b.elements[3] == 12 ); ok( b.elements[4] == 1 ); ok( b.elements[5] == 5 ); ok( b.elements[6] == 9 ); ok( b.elements[7] == 13 ); ok( b.elements[8] == 2 ); ok( b.elements[9] == 6 ); ok( b.elements[10] == 10 ); ok( b.elements[11] == 14 ); ok( b.elements[12] == 3 ); ok( b.elements[13] == 7 ); ok( b.elements[14] == 11 ); ok( b.elements[15] == 15 ); b.multiplyScalar( 2 ); ok( b.elements[0] == 0*2 ); ok( b.elements[1] == 4*2 ); ok( b.elements[2] == 8*2 ); ok( b.elements[3] == 12*2 ); ok( b.elements[4] == 1*2 ); ok( b.elements[5] == 5*2 ); ok( b.elements[6] == 9*2 ); ok( b.elements[7] == 13*2 ); ok( b.elements[8] == 2*2 ); ok( b.elements[9] == 6*2 ); ok( b.elements[10] == 10*2 ); ok( b.elements[11] == 14*2 ); ok( b.elements[12] == 3*2 ); ok( b.elements[13] == 7*2 ); ok( b.elements[14] == 11*2 ); ok( b.elements[15] == 15*2 ); }); test( "determinant", function() { var a = new THREE.Matrix4(); ok( a.determinant() == 1, "Passed!" ); a.elements[0] = 2; ok( a.determinant() == 2, "Passed!" ); a.elements[0] = 0; ok( a.determinant() == 0, "Passed!" ); // calculated via http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/fourD/index.htm a.set( 2, 3, 4, 5, -1, -21, -3, -4, 6, 7, 8, 10, -8, -9, -10, -12 ); ok( a.determinant() == 76, "Passed!" ); }); test( "getInverse", function() { var identity = new THREE.Matrix4(); var a = new THREE.Matrix4(); var b = new THREE.Matrix4().set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); var c = new THREE.Matrix4().set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); ok( ! matrixEquals4( a, b ), "Passed!" ); b.getInverse( a, false ); ok( matrixEquals4( b, new THREE.Matrix4() ), "Passed!" ); try { b.getInverse( c, true ); ok( false, "Passed!" ); // should never get here. } catch( err ) { ok( true, "Passed!" ); } var testMatrices = [ new THREE.Matrix4().makeRotationX( 0.3 ), new THREE.Matrix4().makeRotationX( -0.3 ), new THREE.Matrix4().makeRotationY( 0.3 ), new THREE.Matrix4().makeRotationY( -0.3 ), new THREE.Matrix4().makeRotationZ( 0.3 ), new THREE.Matrix4().makeRotationZ( -0.3 ), new THREE.Matrix4().makeScale( 1, 2, 3 ), new THREE.Matrix4().makeScale( 1/8, 1/2, 1/3 ), new THREE.Matrix4().makeFrustum( -1, 1, -1, 1, 1, 1000 ), new THREE.Matrix4().makeFrustum( -16, 16, -9, 9, 0.1, 10000 ), new THREE.Matrix4().makeTranslation( 1, 2, 3 ) ]; for( var i = 0, il = testMatrices.length; i < il; i ++ ) { var m = testMatrices[i]; var mInverse = new THREE.Matrix4().getInverse( m ); var mSelfInverse = m.clone(); mSelfInverse.getInverse( mSelfInverse ); // self-inverse should the same as inverse ok( matrixEquals4( mSelfInverse, mInverse ), "Passed!" ); // the determinant of the inverse should be the reciprocal ok( Math.abs( m.determinant() * mInverse.determinant() - 1 ) < 0.0001, "Passed!" ); var mProduct = new THREE.Matrix4().multiplyMatrices( m, mInverse ); // the determinant of the identity matrix is 1 ok( Math.abs( mProduct.determinant() - 1 ) < 0.0001, "Passed!" ); ok( matrixEquals4( mProduct, identity ), "Passed!" ); } }); test( "makeBasis/extractBasis", function() { var identityBasis = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ]; var a = new THREE.Matrix4().makeBasis( identityBasis[0], identityBasis[1], identityBasis[2] ); var identity = new THREE.Matrix4(); ok( matrixEquals4( a, identity ), "Passed!" ); var testBases = [ [ new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( -1, 0, 0 ), new THREE.Vector3( 0, 0, 1 ) ] ] for( var i = 0; i < testBases.length; i ++ ) { var testBasis = testBases[i]; var b = new THREE.Matrix4().makeBasis( testBasis[0], testBasis[1], testBasis[2] ); var outBasis = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; b.extractBasis( outBasis[0], outBasis[1], outBasis[2] ); // check what goes in, is what comes out. for( var j = 0; j < outBasis.length; j ++ ) { console.log( outBasis[j], testBasis[j] ); ok( outBasis[j].equals( testBasis[j] ), "Passed!" ); } // get the basis out the hard war for( var j = 0; j < identityBasis.length; j ++ ) { outBasis[j].copy( identityBasis[j] ); outBasis[j].applyMatrix4( b ); } // did the multiply method of basis extraction work? for( var j = 0; j < outBasis.length; j ++ ) { ok( outBasis[j].equals( testBasis[j] ), "Passed!" ); } } }); test( "transpose", function() { var a = new THREE.Matrix4(); var b = a.clone().transpose(); ok( matrixEquals4( a, b ), "Passed!" ); b = new THREE.Matrix4().set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); var c = b.clone().transpose(); ok( ! matrixEquals4( b, c ), "Passed!" ); c.transpose(); ok( matrixEquals4( b, c ), "Passed!" ); }); test( "clone", function() { var a = new THREE.Matrix4().set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); var b = a.clone(); ok( matrixEquals4( a, b ), "Passed!" ); // ensure that it is a true copy a.elements[0] = 2; ok( ! matrixEquals4( a, b ), "Passed!" ); }); test( "compose/decompose", function() { var tValues = [ new THREE.Vector3(), new THREE.Vector3( 3, 0, 0 ), new THREE.Vector3( 0, 4, 0 ), new THREE.Vector3( 0, 0, 5 ), new THREE.Vector3( -6, 0, 0 ), new THREE.Vector3( 0, -7, 0 ), new THREE.Vector3( 0, 0, -8 ), new THREE.Vector3( -2, 5, -9 ), new THREE.Vector3( -2, -5, -9 ) ]; var sValues = [ new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 2, 2, 2 ), new THREE.Vector3( 1, -1, 1 ), new THREE.Vector3( -1, 1, 1 ), new THREE.Vector3( 1, 1, -1 ), new THREE.Vector3( 2, -2, 1 ), new THREE.Vector3( -1, 2, -2 ), new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( -2, -2, -2 ) ]; var rValues = [ new THREE.Quaternion(), new THREE.Quaternion().setFromEuler( new THREE.Euler( 1, 1, 0 ) ), new THREE.Quaternion().setFromEuler( new THREE.Euler( 1, -1, 1 ) ), new THREE.Quaternion( 0, 0.9238795292366128, 0, 0.38268342717215614 ) ]; for( var ti = 0; ti < tValues.length; ti ++ ) { for( var si = 0; si < sValues.length; si ++ ) { for( var ri = 0; ri < rValues.length; ri ++ ) { var t = tValues[ti]; var s = sValues[si]; var r = rValues[ri]; var m = new THREE.Matrix4().compose( t, r, s ); var t2 = new THREE.Vector3(); var r2 = new THREE.Quaternion(); var s2 = new THREE.Vector3(); m.decompose( t2, r2, s2 ); var m2 = new THREE.Matrix4().compose( t2, r2, s2 ); var matrixIsSame = matrixEquals4( m, m2 ); /* debug code if( ! matrixIsSame ) { console.log( t, s, r ); console.log( t2, s2, r2 ); console.log( m, m2 ); }*/ ok( matrixEquals4( m, m2 ), "Passed!" ); } } } });three.js-r73/test/unit/math/Color.js0000644000175500017550000001671512610076566017271 0ustar debacledebaclemodule( "Color" ); test( "constructor", function(){ var c = new THREE.Color(); ok( c.r, "Red: " + c.r ); ok( c.g, "Green: " + c.g ); ok( c.b, "Blue: " + c.b ); }); test( "rgb constructor", function(){ var c = new THREE.Color( 1, 1, 1 ); ok( c.r == 1, "Passed" ); ok( c.g == 1, "Passed" ); ok( c.b == 1, "Passed" ); }); test( "copyHex", function(){ var c = new THREE.Color(); var c2 = new THREE.Color(0xF5FFFA); c.copy(c2); ok(c.getHex() == c2.getHex(), "Hex c: " + c.getHex() + " Hex c2: " + c2.getHex()); }); test( "copyColorString", function(){ var c = new THREE.Color(); var c2 = new THREE.Color('ivory'); c.copy(c2); ok(c.getHex() == c2.getHex(), "Hex c: " + c.getHex() + " Hex c2: " + c2.getHex()); }); test( "setRGB", function(){ var c = new THREE.Color(); c.setRGB(1, 0.2, 0.1); ok( c.r == 1, "Red: " + c.r ); ok( c.g == 0.2, "Green: " + c.g ); ok( c.b == 0.1, "Blue: " + c.b ); }); test( "copyGammaToLinear", function(){ var c = new THREE.Color(); var c2 = new THREE.Color(); c2.setRGB(0.3, 0.5, 0.9); c.copyGammaToLinear(c2); ok( c.r == 0.09, "Red c: " + c.r + " Red c2: " + c2.r); ok( c.g == 0.25, "Green c: " + c.g + " Green c2: " + c2.g); ok( c.b == 0.81, "Blue c: " + c.b + " Blue c2: " + c2.b); }); test( "copyLinearToGamma", function(){ var c = new THREE.Color(); var c2 = new THREE.Color(); c2.setRGB(0.09, 0.25, 0.81); c.copyLinearToGamma(c2); ok( c.r == 0.3, "Red c: " + c.r + " Red c2: " + c2.r); ok( c.g == 0.5, "Green c: " + c.g + " Green c2: " + c2.g); ok( c.b == 0.9, "Blue c: " + c.b + " Blue c2: " + c2.b); }); test( "convertGammaToLinear", function(){ var c = new THREE.Color(); c.setRGB(0.3, 0.5, 0.9); c.convertGammaToLinear(); ok( c.r == 0.09, "Red: " + c.r ); ok( c.g == 0.25, "Green: " + c.g ); ok( c.b == 0.81, "Blue: " + c.b ); }); test( "convertLinearToGamma", function(){ var c = new THREE.Color(); c.setRGB(4, 9, 16); c.convertLinearToGamma(); ok( c.r == 2, "Red: " + c.r ); ok( c.g == 3, "Green: " + c.g ); ok( c.b == 4, "Blue: " + c.b ); }); test("setWithNum", function(){ var c = new THREE.Color(); c.set(0xFF0000); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setWithString", function(){ var c = new THREE.Color(); c.set('silver'); ok(c.getHex() == 0xC0C0C0, "Hex c: " + c.getHex()); }); test( "clone", function(){ var c = new THREE.Color('teal'); var c2 = c.clone(); ok(c2.getHex() == 0x008080, "Hex c2: " + c2.getHex()); }); test( "lerp", function(){ var c = new THREE.Color(); var c2 = new THREE.Color(); c.setRGB(0, 0, 0); c.lerp(c2, 0.2); ok( c.r == 0.2, "Red: " + c.r ); ok( c.g == 0.2, "Green: " + c.g ); ok( c.b == 0.2, "Blue: " + c.b ); }); test( "setStyleRGBRed", function(){ var c = new THREE.Color(); c.setStyle('rgb(255,0,0)'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleRGBARed", function(){ var c = new THREE.Color(); c.setStyle('rgba(255,0,0,0.5)'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleRGBRedWithSpaces", function(){ var c = new THREE.Color(); c.setStyle('rgb( 255 , 0, 0 )'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleRGBARedWithSpaces", function(){ var c = new THREE.Color(); c.setStyle('rgba( 255, 0, 0 , 1 )'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleRGBPercent", function(){ var c = new THREE.Color(); c.setStyle('rgb(100%,50%,10%)'); ok( c.r == 1, "Red: " + c.r ); ok( c.g == 0.5, "Green: " + c.g ); ok( c.b == 0.1, "Blue: " + c.b ); }); test( "setStyleRGBAPercent", function(){ var c = new THREE.Color(); c.setStyle('rgba(100%,50%,10%, 0.5)'); ok( c.r == 1, "Red: " + c.r ); ok( c.g == 0.5, "Green: " + c.g ); ok( c.b == 0.1, "Blue: " + c.b ); }); test( "setStyleRGBPercentWithSpaces", function(){ var c = new THREE.Color(); c.setStyle('rgb( 100% ,50% , 10% )'); ok( c.r == 1, "Red: " + c.r ); ok( c.g == 0.5, "Green: " + c.g ); ok( c.b == 0.1, "Blue: " + c.b ); }); test( "setStyleRGBAPercentWithSpaces", function(){ var c = new THREE.Color(); c.setStyle('rgba( 100% ,50% , 10%, 0.5 )'); ok( c.r == 1, "Red: " + c.r ); ok( c.g == 0.5, "Green: " + c.g ); ok( c.b == 0.1, "Blue: " + c.b ); }); test( "setStyleHSLRed", function(){ var c = new THREE.Color(); c.setStyle('hsl(360,100%,50%)'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleHSLARed", function(){ var c = new THREE.Color(); c.setStyle('hsla(360,100%,50%,0.5)'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleHSLRedWithSpaces", function(){ var c = new THREE.Color(); c.setStyle('hsl(360, 100% , 50% )'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleHSLARedWithSpaces", function(){ var c = new THREE.Color(); c.setStyle('hsla( 360, 100% , 50%, 0.5 )'); ok( c.r == 1, "Red: " + c.r ); ok( c.g === 0, "Green: " + c.g ); ok( c.b === 0, "Blue: " + c.b ); }); test( "setStyleHexSkyBlue", function(){ var c = new THREE.Color(); c.setStyle('#87CEEB'); ok(c.getHex() == 0x87CEEB, "Hex c: " + c.getHex()); }); test( "setStyleHexSkyBlueMixed", function(){ var c = new THREE.Color(); c.setStyle('#87cEeB'); ok(c.getHex() == 0x87CEEB, "Hex c: " + c.getHex()); }); test( "setStyleHex2Olive", function(){ var c = new THREE.Color(); c.setStyle('#F00'); ok(c.getHex() == 0xFF0000, "Hex c: " + c.getHex()); }); test( "setStyleHex2OliveMixed", function(){ var c = new THREE.Color(); c.setStyle('#f00'); ok(c.getHex() == 0xFF0000, "Hex c: " + c.getHex()); }); test( "setStyleColorName", function(){ var c = new THREE.Color(); c.setStyle('powderblue'); ok(c.getHex() == 0xB0E0E6, "Hex c: " + c.getHex()); }); test( "getHex", function(){ var c = new THREE.Color('red'); var res = c.getHex(); ok( res == 0xFF0000, "Hex: " + res ); }); test( "setHex", function(){ var c = new THREE.Color(); c.setHex(0xFA8072); ok( c.getHex() == 0xFA8072, "Hex: " + c.getHex()); }); test( "getHexString", function(){ var c = new THREE.Color('tomato'); var res = c.getHexString(); ok( res == 'ff6347', "Hex: " + res ); }); test( "getStyle", function(){ var c = new THREE.Color('plum'); var res = c.getStyle(); ok( res == 'rgb(221,160,221)', "style: " + res ); }); test( "getHSL", function () { var c = new THREE.Color( 0x80ffff ); var hsl = c.getHSL(); ok( hsl.h == 0.5, "hue: " + hsl.h ); ok( hsl.s == 1.0, "saturation: " + hsl.s ); ok( (Math.round(parseFloat(hsl.l)*100)/100) == 0.75, "lightness: " + hsl.l ); }); test( "setHSL", function () { var c = new THREE.Color(); c.setHSL(0.75, 1.0, 0.25); var hsl = c.getHSL(); ok( hsl.h == 0.75, "hue: " + hsl.h ); ok( hsl.s == 1.00, "saturation: " + hsl.s ); ok( hsl.l == 0.25, "lightness: " + hsl.l ); }); three.js-r73/test/unit/math/Vector3.js0000644000175500017550000002123712610076566017533 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Vector3" ); test( "constructor", function() { var a = new THREE.Vector3(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); a = new THREE.Vector3( x, y, z ); ok( a.x === x, "Passed!" ); ok( a.y === y, "Passed!" ); ok( a.z === z, "Passed!" ); }); test( "copy", function() { var a = new THREE.Vector3( x, y, z ); var b = new THREE.Vector3().copy( a ); ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); ok( b.z == z, "Passed!" ); // ensure that it is a true copy a.x = 0; a.y = -1; a.z = -2; ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); ok( b.z == z, "Passed!" ); }); test( "set", function() { var a = new THREE.Vector3(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); a.set( x, y, z ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); ok( a.z == z, "Passed!" ); }); test( "setX,setY,setZ", function() { var a = new THREE.Vector3(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); a.setX( x ); a.setY( y ); a.setZ( z ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); ok( a.z == z, "Passed!" ); }); test( "setComponent,getComponent", function() { var a = new THREE.Vector3(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); a.setComponent( 0, 1 ); a.setComponent( 1, 2 ); a.setComponent( 2, 3 ); ok( a.getComponent( 0 ) == 1, "Passed!" ); ok( a.getComponent( 1 ) == 2, "Passed!" ); ok( a.getComponent( 2 ) == 3, "Passed!" ); }); test( "add", function() { var a = new THREE.Vector3( x, y, z ); var b = new THREE.Vector3( -x, -y, -z ); a.add( b ); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); ok( a.z == 0, "Passed!" ); var c = new THREE.Vector3().addVectors( b, b ); ok( c.x == -2*x, "Passed!" ); ok( c.y == -2*y, "Passed!" ); ok( c.z == -2*z, "Passed!" ); }); test( "sub", function() { var a = new THREE.Vector3( x, y, z ); var b = new THREE.Vector3( -x, -y, -z ); a.sub( b ); ok( a.x == 2*x, "Passed!" ); ok( a.y == 2*y, "Passed!" ); ok( a.z == 2*z, "Passed!" ); var c = new THREE.Vector3().subVectors( a, a ); ok( c.x == 0, "Passed!" ); ok( c.y == 0, "Passed!" ); ok( c.z == 0, "Passed!" ); }); test( "multiply/divide", function() { var a = new THREE.Vector3( x, y, z ); var b = new THREE.Vector3( -x, -y, -z ); a.multiplyScalar( -2 ); ok( a.x == x*-2, "Passed!" ); ok( a.y == y*-2, "Passed!" ); ok( a.z == z*-2, "Passed!" ); b.multiplyScalar( -2 ); ok( b.x == 2*x, "Passed!" ); ok( b.y == 2*y, "Passed!" ); ok( b.z == 2*z, "Passed!" ); a.divideScalar( -2 ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); ok( a.z == z, "Passed!" ); b.divideScalar( -2 ); ok( b.x == -x, "Passed!" ); ok( b.y == -y, "Passed!" ); ok( b.z == -z, "Passed!" ); }); test( "min/max/clamp", function() { var a = new THREE.Vector3( x, y, z ); var b = new THREE.Vector3( -x, -y, -z ); var c = new THREE.Vector3(); c.copy( a ).min( b ); ok( c.x == -x, "Passed!" ); ok( c.y == -y, "Passed!" ); ok( c.z == -z, "Passed!" ); c.copy( a ).max( b ); ok( c.x == x, "Passed!" ); ok( c.y == y, "Passed!" ); ok( c.z == z, "Passed!" ); c.set( -2*x, 2*y, -2*z ); c.clamp( b, a ); ok( c.x == -x, "Passed!" ); ok( c.y == y, "Passed!" ); ok( c.z == -z, "Passed!" ); }); test( "negate", function() { var a = new THREE.Vector3( x, y, z ); a.negate(); ok( a.x == -x, "Passed!" ); ok( a.y == -y, "Passed!" ); ok( a.z == -z, "Passed!" ); }); test( "dot", function() { var a = new THREE.Vector3( x, y, z ); var b = new THREE.Vector3( -x, -y, -z ); var c = new THREE.Vector3(); var result = a.dot( b ); ok( result == (-x*x-y*y-z*z), "Passed!" ); result = a.dot( c ); ok( result == 0, "Passed!" ); }); test( "length/lengthSq", function() { var a = new THREE.Vector3( x, 0, 0 ); var b = new THREE.Vector3( 0, -y, 0 ); var c = new THREE.Vector3( 0, 0, z ); var d = new THREE.Vector3(); ok( a.length() == x, "Passed!" ); ok( a.lengthSq() == x*x, "Passed!" ); ok( b.length() == y, "Passed!" ); ok( b.lengthSq() == y*y, "Passed!" ); ok( c.length() == z, "Passed!" ); ok( c.lengthSq() == z*z, "Passed!" ); ok( d.length() == 0, "Passed!" ); ok( d.lengthSq() == 0, "Passed!" ); a.set( x, y, z ); ok( a.length() == Math.sqrt( x*x + y*y + z*z ), "Passed!" ); ok( a.lengthSq() == ( x*x + y*y + z*z ), "Passed!" ); }); test( "normalize", function() { var a = new THREE.Vector3( x, 0, 0 ); var b = new THREE.Vector3( 0, -y, 0 ); var c = new THREE.Vector3( 0, 0, z ); a.normalize(); ok( a.length() == 1, "Passed!" ); ok( a.x == 1, "Passed!" ); b.normalize(); ok( b.length() == 1, "Passed!" ); ok( b.y == -1, "Passed!" ); c.normalize(); ok( c.length() == 1, "Passed!" ); ok( c.z == 1, "Passed!" ); }); test( "distanceTo/distanceToSquared", function() { var a = new THREE.Vector3( x, 0, 0 ); var b = new THREE.Vector3( 0, -y, 0 ); var c = new THREE.Vector3( 0, 0, z ); var d = new THREE.Vector3(); ok( a.distanceTo( d ) == x, "Passed!" ); ok( a.distanceToSquared( d ) == x*x, "Passed!" ); ok( b.distanceTo( d ) == y, "Passed!" ); ok( b.distanceToSquared( d ) == y*y, "Passed!" ); ok( c.distanceTo( d ) == z, "Passed!" ); ok( c.distanceToSquared( d ) == z*z, "Passed!" ); }); test( "setLength", function() { var a = new THREE.Vector3( x, 0, 0 ); ok( a.length() == x, "Passed!" ); a.setLength( y ); ok( a.length() == y, "Passed!" ); a = new THREE.Vector3( 0, 0, 0 ); ok( a.length() == 0, "Passed!" ); a.setLength( y ); ok( a.length() == 0, "Passed!" ); }); test( "projectOnVector", function() { var a = new THREE.Vector3( 1, 0, 0 ); var b = new THREE.Vector3(); var normal = new THREE.Vector3( 10, 0, 0 ); ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); a.set( 0, 1, 0 ); ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); a.set( 0, 0, -1 ); ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); a.set( -1, 0, 0 ); ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( -1, 0, 0 ) ), "Passed!" ); }); test( "projectOnPlane", function() { var a = new THREE.Vector3( 1, 0, 0 ); var b = new THREE.Vector3(); var normal = new THREE.Vector3( 1, 0, 0 ); ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); a.set( 0, 1, 0 ); ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); a.set( 0, 0, -1 ); ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 0, -1 ) ), "Passed!" ); a.set( -1, 0, 0 ); ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); }); test( "reflect", function() { var a = new THREE.Vector3(); var normal = new THREE.Vector3( 0, 1, 0 ); var b = new THREE.Vector3(); a.set( 0, -1, 0 ); ok( b.copy( a ).reflect( normal ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); a.set( 1, -1, 0 ); ok( b.copy( a ).reflect( normal ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); a.set( 1, -1, 0 ); normal.set( 0, -1, 0 ); ok( b.copy( a ).reflect( normal ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); }); test( "angleTo", function() { var a = new THREE.Vector3( 0, -0.18851655680720186, 0.9820700116639124 ); var b = new THREE.Vector3( 0, 0.18851655680720186, -0.9820700116639124 ); equal( a.angleTo( a ), 0 ); equal( a.angleTo( b ), Math.PI ); var x = new THREE.Vector3( 1, 0, 0 ); var y = new THREE.Vector3( 0, 1, 0 ); var z = new THREE.Vector3( 0, 0, 1 ); equal( x.angleTo( y ), Math.PI / 2 ); equal( x.angleTo( z ), Math.PI / 2 ); equal( z.angleTo( x ), Math.PI / 2 ); ok( Math.abs( x.angleTo( new THREE.Vector3( 1, 1, 0 ) ) - ( Math.PI / 4 ) ) < 0.0000001 ); }); test( "lerp/clone", function() { var a = new THREE.Vector3( x, 0, z ); var b = new THREE.Vector3( 0, -y, 0 ); ok( a.lerp( a, 0 ).equals( a.lerp( a, 0.5 ) ), "Passed!" ); ok( a.lerp( a, 0 ).equals( a.lerp( a, 1 ) ), "Passed!" ); ok( a.clone().lerp( b, 0 ).equals( a ), "Passed!" ); ok( a.clone().lerp( b, 0.5 ).x == x*0.5, "Passed!" ); ok( a.clone().lerp( b, 0.5 ).y == -y*0.5, "Passed!" ); ok( a.clone().lerp( b, 0.5 ).z == z*0.5, "Passed!" ); ok( a.clone().lerp( b, 1 ).equals( b ), "Passed!" ); }); test( "equals", function() { var a = new THREE.Vector3( x, 0, z ); var b = new THREE.Vector3( 0, -y, 0 ); ok( a.x != b.x, "Passed!" ); ok( a.y != b.y, "Passed!" ); ok( a.z != b.z, "Passed!" ); ok( ! a.equals( b ), "Passed!" ); ok( ! b.equals( a ), "Passed!" ); a.copy( b ); ok( a.x == b.x, "Passed!" ); ok( a.y == b.y, "Passed!" ); ok( a.z == b.z, "Passed!" ); ok( a.equals( b ), "Passed!" ); ok( b.equals( a ), "Passed!" ); }); three.js-r73/test/unit/math/Sphere.js0000644000175500017550000000521012610076566017425 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Sphere" ); test( "constructor", function() { var a = new THREE.Sphere(); ok( a.center.equals( zero3 ), "Passed!" ); ok( a.radius == 0, "Passed!" ); a = new THREE.Sphere( one3.clone(), 1 ); ok( a.center.equals( one3 ), "Passed!" ); ok( a.radius == 1, "Passed!" ); }); test( "copy", function() { var a = new THREE.Sphere( one3.clone(), 1 ); var b = new THREE.Sphere().copy( a ); ok( b.center.equals( one3 ), "Passed!" ); ok( b.radius == 1, "Passed!" ); // ensure that it is a true copy a.center = zero3; a.radius = 0; ok( b.center.equals( one3 ), "Passed!" ); ok( b.radius == 1, "Passed!" ); }); test( "set", function() { var a = new THREE.Sphere(); ok( a.center.equals( zero3 ), "Passed!" ); ok( a.radius == 0, "Passed!" ); a.set( one3, 1 ); ok( a.center.equals( one3 ), "Passed!" ); ok( a.radius == 1, "Passed!" ); }); test( "empty", function() { var a = new THREE.Sphere(); ok( a.empty(), "Passed!" ); a.set( one3, 1 ); ok( ! a.empty(), "Passed!" ); }); test( "containsPoint", function() { var a = new THREE.Sphere( one3.clone(), 1 ); ok( ! a.containsPoint( zero3 ), "Passed!" ); ok( a.containsPoint( one3 ), "Passed!" ); }); test( "distanceToPoint", function() { var a = new THREE.Sphere( one3.clone(), 1 ); ok( ( a.distanceToPoint( zero3 ) - 0.7320 ) < 0.001, "Passed!" ); ok( a.distanceToPoint( one3 ) === -1, "Passed!" ); }); test( "intersectsSphere", function() { var a = new THREE.Sphere( one3.clone(), 1 ); var b = new THREE.Sphere( zero3.clone(), 1 ); var c = new THREE.Sphere( zero3.clone(), 0.25 ); ok( a.intersectsSphere( b ) , "Passed!" ); ok( ! a.intersectsSphere( c ) , "Passed!" ); }); test( "clampPoint", function() { var a = new THREE.Sphere( one3.clone(), 1 ); ok( a.clampPoint( new THREE.Vector3( 1, 1, 3 ) ).equals( new THREE.Vector3( 1, 1, 2 ) ), "Passed!" ); ok( a.clampPoint( new THREE.Vector3( 1, 1, -3 ) ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); }); test( "getBoundingBox", function() { var a = new THREE.Sphere( one3.clone(), 1 ); ok( a.getBoundingBox().equals( new THREE.Box3( zero3, two3 ) ), "Passed!" ); a.set( zero3, 0 ) ok( a.getBoundingBox().equals( new THREE.Box3( zero3, zero3 ) ), "Passed!" ); }); test( "applyMatrix4", function() { var a = new THREE.Sphere( one3.clone(), 1 ); var m = new THREE.Matrix4().makeTranslation( 1, -2, 1 ); ok( a.clone().applyMatrix4( m ).getBoundingBox().equals( a.getBoundingBox().applyMatrix4( m ) ), "Passed!" ); }); test( "translate", function() { var a = new THREE.Sphere( one3.clone(), 1 ); a.translate( one3.clone().negate() ); ok( a.center.equals( zero3 ), "Passed!" ); }); three.js-r73/test/unit/math/Euler.js0000644000175500017550000001003412610076566017253 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Euler" ); var eulerZero = new THREE.Euler( 0, 0, 0, "XYZ" ); var eulerAxyz = new THREE.Euler( 1, 0, 0, "XYZ" ); var eulerAzyx = new THREE.Euler( 0, 1, 0, "ZYX" ); var matrixEquals4 = function( a, b, tolerance ) { tolerance = tolerance || 0.0001; if( a.elements.length != b.elements.length ) { return false; } for( var i = 0, il = a.elements.length; i < il; i ++ ) { var delta = a.elements[i] - b.elements[i]; if( delta > tolerance ) { return false; } } return true; }; var eulerEquals = function( a, b, tolerance ) { tolerance = tolerance || 0.0001; var diff = Math.abs( a.x - b.x ) + Math.abs( a.y - b.y ) + Math.abs( a.z - b.z ); return ( diff < tolerance ); }; var quatEquals = function( a, b, tolerance ) { tolerance = tolerance || 0.0001; var diff = Math.abs( a.x - b.x ) + Math.abs( a.y - b.y ) + Math.abs( a.z - b.z ) + Math.abs( a.w - b.w ); return ( diff < tolerance ); }; test( "constructor/equals", function() { var a = new THREE.Euler(); ok( a.equals( eulerZero ), "Passed!" ); ok( ! a.equals( eulerAxyz ), "Passed!" ); ok( ! a.equals( eulerAzyx ), "Passed!" ); }); test( "clone/copy/equals", function() { var a = eulerAxyz.clone(); ok( a.equals( eulerAxyz ), "Passed!" ); ok( ! a.equals( eulerZero ), "Passed!" ); ok( ! a.equals( eulerAzyx ), "Passed!" ); a.copy( eulerAzyx ); ok( a.equals( eulerAzyx ), "Passed!" ); ok( ! a.equals( eulerAxyz ), "Passed!" ); ok( ! a.equals( eulerZero ), "Passed!" ); }); test( "set/setFromVector3/toVector3", function() { var a = new THREE.Euler(); a.set( 0, 1, 0, "ZYX" ); ok( a.equals( eulerAzyx ), "Passed!" ); ok( ! a.equals( eulerAxyz ), "Passed!" ); ok( ! a.equals( eulerZero ), "Passed!" ); var vec = new THREE.Vector3( 0, 1, 0 ); var b = new THREE.Euler().setFromVector3( vec, "ZYX" ); console.log( a, b ); ok( a.equals( b ), "Passed!" ); var c = b.toVector3(); console.log( c, vec ); ok( c.equals( vec ), "Passed!" ); }); test( "Quaternion.setFromEuler/Euler.fromQuaternion", function() { var testValues = [ eulerZero, eulerAxyz, eulerAzyx ]; for( var i = 0; i < testValues.length; i ++ ) { var v = testValues[i]; var q = new THREE.Quaternion().setFromEuler( v ); var v2 = new THREE.Euler().setFromQuaternion( q, v.order ); var q2 = new THREE.Quaternion().setFromEuler( v2 ); ok( eulerEquals( q, q2 ), "Passed!" ); } }); test( "Matrix4.setFromEuler/Euler.fromRotationMatrix", function() { var testValues = [ eulerZero, eulerAxyz, eulerAzyx ]; for( var i = 0; i < testValues.length; i ++ ) { var v = testValues[i]; var m = new THREE.Matrix4().makeRotationFromEuler( v ); var v2 = new THREE.Euler().setFromRotationMatrix( m, v.order ); var m2 = new THREE.Matrix4().makeRotationFromEuler( v2 ); ok( matrixEquals4( m, m2, 0.0001 ), "Passed!" ); } }); test( "reorder", function() { var testValues = [ eulerZero, eulerAxyz, eulerAzyx ]; for( var i = 0; i < testValues.length; i ++ ) { var v = testValues[i]; var q = new THREE.Quaternion().setFromEuler( v ); v.reorder( 'YZX' ); var q2 = new THREE.Quaternion().setFromEuler( v ); ok( quatEquals( q, q2 ), "Passed!" ); v.reorder( 'ZXY' ); var q3 = new THREE.Quaternion().setFromEuler( v ); ok( quatEquals( q, q3 ), "Passed!" ); } }); test( "gimbalLocalQuat", function() { // known problematic quaternions var q1 = new THREE.Quaternion( 0.5207769385244341, -0.4783214164122354, 0.520776938524434, 0.47832141641223547 ); var q2 = new THREE.Quaternion( 0.11284905712620674, 0.6980437630368944, -0.11284905712620674, 0.6980437630368944 ); var eulerOrder = "ZYX"; // create Euler directly from a Quaternion var eViaQ1 = new THREE.Euler().setFromQuaternion( q1, eulerOrder ); // there is likely a bug here // create Euler from Quaternion via an intermediate Matrix4 var mViaQ1 = new THREE.Matrix4().makeRotationFromQuaternion( q1 ); var eViaMViaQ1 = new THREE.Euler().setFromRotationMatrix( mViaQ1, eulerOrder ); // the results here are different ok( eulerEquals( eViaQ1, eViaMViaQ1 ), "Passed!" ); // this result is correct });three.js-r73/test/unit/math/Triangle.js0000644000175500017550000001440512610076566017752 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Triangle" ); test( "constructor", function() { var a = new THREE.Triangle(); ok( a.a.equals( zero3 ), "Passed!" ); ok( a.b.equals( zero3 ), "Passed!" ); ok( a.c.equals( zero3 ), "Passed!" ); a = new THREE.Triangle( one3.clone().negate(), one3.clone(), two3.clone() ); ok( a.a.equals( one3.clone().negate() ), "Passed!" ); ok( a.b.equals( one3 ), "Passed!" ); ok( a.c.equals( two3 ), "Passed!" ); }); test( "copy", function() { var a = new THREE.Triangle( one3.clone().negate(), one3.clone(), two3.clone() ); var b = new THREE.Triangle().copy( a ); ok( b.a.equals( one3.clone().negate() ), "Passed!" ); ok( b.b.equals( one3 ), "Passed!" ); ok( b.c.equals( two3 ), "Passed!" ); // ensure that it is a true copy a.a = one3; a.b = zero3; a.c = zero3; ok( b.a.equals( one3.clone().negate() ), "Passed!" ); ok( b.b.equals( one3 ), "Passed!" ); ok( b.c.equals( two3 ), "Passed!" ); }); test( "setFromPointsAndIndices", function() { var a = new THREE.Triangle(); var points = [ one3, one3.clone().negate(), two3 ]; a.setFromPointsAndIndices( points, 1, 0, 2 ); ok( a.a.equals( one3.clone().negate() ), "Passed!" ); ok( a.b.equals( one3 ), "Passed!" ); ok( a.c.equals( two3 ), "Passed!" ); }); test( "set", function() { var a = new THREE.Triangle(); a.set( one3.clone().negate(), one3, two3 ); ok( a.a.equals( one3.clone().negate() ), "Passed!" ); ok( a.b.equals( one3 ), "Passed!" ); ok( a.c.equals( two3 ), "Passed!" ); }); test( "area", function() { var a = new THREE.Triangle(); ok( a.area() == 0, "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); ok( a.area() == 0.5, "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); ok( a.area() == 2, "Passed!" ); // colinear triangle. a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 3, 0, 0 ) ); ok( a.area() == 0, "Passed!" ); }); test( "midpoint", function() { var a = new THREE.Triangle(); ok( a.midpoint().equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); ok( a.midpoint().equals( new THREE.Vector3( 1/3, 1/3, 0 ) ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); ok( a.midpoint().equals( new THREE.Vector3( 2/3, 0, 2/3 ) ), "Passed!" ); }); test( "normal", function() { var a = new THREE.Triangle(); ok( a.normal().equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); ok( a.normal().equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); ok( a.normal().equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); }); test( "plane", function() { var a = new THREE.Triangle(); // artificial normal is created in this case. ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" ); ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" ); ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" ); ok( a.plane().normal.equals( a.normal() ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" ); ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" ); ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" ); ok( a.plane().normal.equals( a.normal() ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" ); ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" ); ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" ); ok( a.plane().normal.clone().normalize().equals( a.normal() ), "Passed!" ); }); test( "barycoordFromPoint", function() { var a = new THREE.Triangle(); var bad = new THREE.Vector3( -2, -1, -1 ); ok( a.barycoordFromPoint( a.a ).equals( bad ), "Passed!" ); ok( a.barycoordFromPoint( a.b ).equals( bad ), "Passed!" ); ok( a.barycoordFromPoint( a.c ).equals( bad ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); ok( a.barycoordFromPoint( a.a ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); ok( a.barycoordFromPoint( a.b ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); ok( a.barycoordFromPoint( a.c ).equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" ); ok( a.barycoordFromPoint( a.midpoint() ).distanceTo( new THREE.Vector3( 1/3, 1/3, 1/3 ) ) < 0.0001, "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); ok( a.barycoordFromPoint( a.a ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); ok( a.barycoordFromPoint( a.b ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); ok( a.barycoordFromPoint( a.c ).equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" ); ok( a.barycoordFromPoint( a.midpoint() ).distanceTo( new THREE.Vector3( 1/3, 1/3, 1/3 ) ) < 0.0001, "Passed!" ); }); test( "containsPoint", function() { var a = new THREE.Triangle(); ok( ! a.containsPoint( a.a ), "Passed!" ); ok( ! a.containsPoint( a.b ), "Passed!" ); ok( ! a.containsPoint( a.c ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); ok( a.containsPoint( a.a ), "Passed!" ); ok( a.containsPoint( a.b ), "Passed!" ); ok( a.containsPoint( a.c ), "Passed!" ); ok( a.containsPoint( a.midpoint() ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); ok( a.containsPoint( a.a ), "Passed!" ); ok( a.containsPoint( a.b ), "Passed!" ); ok( a.containsPoint( a.c ), "Passed!" ); ok( a.containsPoint( a.midpoint() ), "Passed!" ); ok( ! a.containsPoint( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); }); three.js-r73/test/unit/math/Vector2.js0000644000175500017550000001545312610076566017535 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Vector2" ); test( "constructor", function() { var a = new THREE.Vector2(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); a = new THREE.Vector2( x, y ); ok( a.x === x, "Passed!" ); ok( a.y === y, "Passed!" ); }); test( "copy", function() { var a = new THREE.Vector2( x, y ); var b = new THREE.Vector2().copy( a ); ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); // ensure that it is a true copy a.x = 0; a.y = -1; ok( b.x == x, "Passed!" ); ok( b.y == y, "Passed!" ); }); test( "set", function() { var a = new THREE.Vector2(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); a.set( x, y ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); }); test( "setX,setY", function() { var a = new THREE.Vector2(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); a.setX( x ); a.setY( y ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); }); test( "setComponent,getComponent", function() { var a = new THREE.Vector2(); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); a.setComponent( 0, 1 ); a.setComponent( 1, 2 ); ok( a.getComponent( 0 ) == 1, "Passed!" ); ok( a.getComponent( 1 ) == 2, "Passed!" ); }); test( "add", function() { var a = new THREE.Vector2( x, y ); var b = new THREE.Vector2( -x, -y ); a.add( b ); ok( a.x == 0, "Passed!" ); ok( a.y == 0, "Passed!" ); var c = new THREE.Vector2().addVectors( b, b ); ok( c.x == -2*x, "Passed!" ); ok( c.y == -2*y, "Passed!" ); }); test( "sub", function() { var a = new THREE.Vector2( x, y ); var b = new THREE.Vector2( -x, -y ); a.sub( b ); ok( a.x == 2*x, "Passed!" ); ok( a.y == 2*y, "Passed!" ); var c = new THREE.Vector2().subVectors( a, a ); ok( c.x == 0, "Passed!" ); ok( c.y == 0, "Passed!" ); }); test( "multiply/divide", function() { var a = new THREE.Vector2( x, y ); var b = new THREE.Vector2( -x, -y ); a.multiplyScalar( -2 ); ok( a.x == x*-2, "Passed!" ); ok( a.y == y*-2, "Passed!" ); b.multiplyScalar( -2 ); ok( b.x == 2*x, "Passed!" ); ok( b.y == 2*y, "Passed!" ); a.divideScalar( -2 ); ok( a.x == x, "Passed!" ); ok( a.y == y, "Passed!" ); b.divideScalar( -2 ); ok( b.x == -x, "Passed!" ); ok( b.y == -y, "Passed!" ); }); test( "min/max/clamp", function() { var a = new THREE.Vector2( x, y ); var b = new THREE.Vector2( -x, -y ); var c = new THREE.Vector2(); c.copy( a ).min( b ); ok( c.x == -x, "Passed!" ); ok( c.y == -y, "Passed!" ); c.copy( a ).max( b ); ok( c.x == x, "Passed!" ); ok( c.y == y, "Passed!" ); c.set( -2*x, 2*y ); c.clamp( b, a ); ok( c.x == -x, "Passed!" ); ok( c.y == y, "Passed!" ); c.set(-2*x, 2*x); c.clampScalar( -x, x ); equal( c.x, -x, "scalar clamp x" ); equal( c.y, x, "scalar clamp y" ); }); test( "rounding", function() { deepEqual( new THREE.Vector2( -0.1, 0.1 ).floor(), new THREE.Vector2( -1, 0 ), "floor .1" ); deepEqual( new THREE.Vector2( -0.5, 0.5 ).floor(), new THREE.Vector2( -1, 0 ), "floor .5" ); deepEqual( new THREE.Vector2( -0.9, 0.9 ).floor(), new THREE.Vector2( -1, 0 ), "floor .9" ); deepEqual( new THREE.Vector2( -0.1, 0.1 ).ceil(), new THREE.Vector2( 0, 1 ), "ceil .1" ); deepEqual( new THREE.Vector2( -0.5, 0.5 ).ceil(), new THREE.Vector2( 0, 1 ), "ceil .5" ); deepEqual( new THREE.Vector2( -0.9, 0.9 ).ceil(), new THREE.Vector2( 0, 1 ), "ceil .9" ); deepEqual( new THREE.Vector2( -0.1, 0.1 ).round(), new THREE.Vector2( 0, 0 ), "round .1" ); deepEqual( new THREE.Vector2( -0.5, 0.5 ).round(), new THREE.Vector2( 0, 1 ), "round .5" ); deepEqual( new THREE.Vector2( -0.9, 0.9 ).round(), new THREE.Vector2( -1, 1 ), "round .9" ); deepEqual( new THREE.Vector2( -0.1, 0.1 ).roundToZero(), new THREE.Vector2( 0, 0 ), "roundToZero .1" ); deepEqual( new THREE.Vector2( -0.5, 0.5 ).roundToZero(), new THREE.Vector2( 0, 0 ), "roundToZero .5" ); deepEqual( new THREE.Vector2( -0.9, 0.9 ).roundToZero(), new THREE.Vector2( 0, 0 ), "roundToZero .9" ); deepEqual( new THREE.Vector2( -1.1, 1.1 ).roundToZero(), new THREE.Vector2( -1, 1 ), "roundToZero 1.1" ); deepEqual( new THREE.Vector2( -1.5, 1.5 ).roundToZero(), new THREE.Vector2( -1, 1 ), "roundToZero 1.5" ); deepEqual( new THREE.Vector2( -1.9, 1.9 ).roundToZero(), new THREE.Vector2( -1, 1 ), "roundToZero 1.9" ); }); test( "negate", function() { var a = new THREE.Vector2( x, y ); a.negate(); ok( a.x == -x, "Passed!" ); ok( a.y == -y, "Passed!" ); }); test( "dot", function() { var a = new THREE.Vector2( x, y ); var b = new THREE.Vector2( -x, -y ); var c = new THREE.Vector2(); var result = a.dot( b ); ok( result == (-x*x-y*y), "Passed!" ); result = a.dot( c ); ok( result == 0, "Passed!" ); }); test( "length/lengthSq", function() { var a = new THREE.Vector2( x, 0 ); var b = new THREE.Vector2( 0, -y ); var c = new THREE.Vector2(); ok( a.length() == x, "Passed!" ); ok( a.lengthSq() == x*x, "Passed!" ); ok( b.length() == y, "Passed!" ); ok( b.lengthSq() == y*y, "Passed!" ); ok( c.length() == 0, "Passed!" ); ok( c.lengthSq() == 0, "Passed!" ); a.set( x, y ); ok( a.length() == Math.sqrt( x*x + y*y ), "Passed!" ); ok( a.lengthSq() == ( x*x + y*y ), "Passed!" ); }); test( "normalize", function() { var a = new THREE.Vector2( x, 0 ); var b = new THREE.Vector2( 0, -y ); var c = new THREE.Vector2(); a.normalize(); ok( a.length() == 1, "Passed!" ); ok( a.x == 1, "Passed!" ); b.normalize(); ok( b.length() == 1, "Passed!" ); ok( b.y == -1, "Passed!" ); }); test( "distanceTo/distanceToSquared", function() { var a = new THREE.Vector2( x, 0 ); var b = new THREE.Vector2( 0, -y ); var c = new THREE.Vector2(); ok( a.distanceTo( c ) == x, "Passed!" ); ok( a.distanceToSquared( c ) == x*x, "Passed!" ); ok( b.distanceTo( c ) == y, "Passed!" ); ok( b.distanceToSquared( c ) == y*y, "Passed!" ); }); test( "setLength", function() { var a = new THREE.Vector2( x, 0 ); ok( a.length() == x, "Passed!" ); a.setLength( y ); ok( a.length() == y, "Passed!" ); a = new THREE.Vector2( 0, 0 ); ok( a.length() == 0, "Passed!" ); a.setLength( y ); ok( a.length() == 0, "Passed!" ); }); test( "lerp/clone", function() { var a = new THREE.Vector2( x, 0 ); var b = new THREE.Vector2( 0, -y ); ok( a.lerp( a, 0 ).equals( a.lerp( a, 0.5 ) ), "Passed!" ); ok( a.lerp( a, 0 ).equals( a.lerp( a, 1 ) ), "Passed!" ); ok( a.clone().lerp( b, 0 ).equals( a ), "Passed!" ); ok( a.clone().lerp( b, 0.5 ).x == x*0.5, "Passed!" ); ok( a.clone().lerp( b, 0.5 ).y == -y*0.5, "Passed!" ); ok( a.clone().lerp( b, 1 ).equals( b ), "Passed!" ); }); test( "equals", function() { var a = new THREE.Vector2( x, 0 ); var b = new THREE.Vector2( 0, -y ); ok( a.x != b.x, "Passed!" ); ok( a.y != b.y, "Passed!" ); ok( ! a.equals( b ), "Passed!" ); ok( ! b.equals( a ), "Passed!" ); a.copy( b ); ok( a.x == b.x, "Passed!" ); ok( a.y == b.y, "Passed!" ); ok( a.equals( b ), "Passed!" ); ok( b.equals( a ), "Passed!" ); }); three.js-r73/test/unit/math/Matrix3.js0000644000175500017550000001250012610076566017526 0ustar debacledebacle/** * @author bhouston / http://exocortex.com */ module( "Matrix3" ); var matrixEquals3 = function( a, b, tolerance ) { tolerance = tolerance || 0.0001; if( a.elements.length != b.elements.length ) { return false; } for( var i = 0, il = a.elements.length; i < il; i ++ ) { var delta = a.elements[i] - b.elements[i]; if( delta > tolerance ) { return false; } } return true; }; var toMatrix4 = function( m3 ) { var result = new THREE.Matrix4(); var re = result.elements; var me = m3.elements; re[0] = me[0]; re[1] = me[1]; re[2] = me[2]; re[4] = me[3]; re[5] = me[4]; re[6] = me[5]; re[8] = me[6]; re[9] = me[7]; re[10] = me[8]; return result; }; test( "constructor", function() { var a = new THREE.Matrix3(); ok( a.determinant() == 1, "Passed!" ); var b = new THREE.Matrix3().set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 3 ); ok( b.elements[2] == 6 ); ok( b.elements[3] == 1 ); ok( b.elements[4] == 4 ); ok( b.elements[5] == 7 ); ok( b.elements[6] == 2 ); ok( b.elements[7] == 5 ); ok( b.elements[8] == 8 ); ok( ! matrixEquals3( a, b ), "Passed!" ); }); test( "copy", function() { var a = new THREE.Matrix3().set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); var b = new THREE.Matrix3().copy( a ); ok( matrixEquals3( a, b ), "Passed!" ); // ensure that it is a true copy a.elements[0] = 2; ok( ! matrixEquals3( a, b ), "Passed!" ); }); test( "set", function() { var b = new THREE.Matrix3(); ok( b.determinant() == 1, "Passed!" ); b.set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 3 ); ok( b.elements[2] == 6 ); ok( b.elements[3] == 1 ); ok( b.elements[4] == 4 ); ok( b.elements[5] == 7 ); ok( b.elements[6] == 2 ); ok( b.elements[7] == 5 ); ok( b.elements[8] == 8 ); }); test( "identity", function() { var b = new THREE.Matrix3().set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 3 ); ok( b.elements[2] == 6 ); ok( b.elements[3] == 1 ); ok( b.elements[4] == 4 ); ok( b.elements[5] == 7 ); ok( b.elements[6] == 2 ); ok( b.elements[7] == 5 ); ok( b.elements[8] == 8 ); var a = new THREE.Matrix3(); ok( ! matrixEquals3( a, b ), "Passed!" ); b.identity(); ok( matrixEquals3( a, b ), "Passed!" ); }); test( "multiplyScalar", function() { var b = new THREE.Matrix3().set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); ok( b.elements[0] == 0 ); ok( b.elements[1] == 3 ); ok( b.elements[2] == 6 ); ok( b.elements[3] == 1 ); ok( b.elements[4] == 4 ); ok( b.elements[5] == 7 ); ok( b.elements[6] == 2 ); ok( b.elements[7] == 5 ); ok( b.elements[8] == 8 ); b.multiplyScalar( 2 ); ok( b.elements[0] == 0*2 ); ok( b.elements[1] == 3*2 ); ok( b.elements[2] == 6*2 ); ok( b.elements[3] == 1*2 ); ok( b.elements[4] == 4*2 ); ok( b.elements[5] == 7*2 ); ok( b.elements[6] == 2*2 ); ok( b.elements[7] == 5*2 ); ok( b.elements[8] == 8*2 ); }); test( "determinant", function() { var a = new THREE.Matrix3(); ok( a.determinant() == 1, "Passed!" ); a.elements[0] = 2; ok( a.determinant() == 2, "Passed!" ); a.elements[0] = 0; ok( a.determinant() == 0, "Passed!" ); // calculated via http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/threeD/index.htm a.set( 2, 3, 4, 5, 13, 7, 8, 9, 11 ); ok( a.determinant() == -73, "Passed!" ); }); test( "getInverse", function() { var identity = new THREE.Matrix4(); var a = new THREE.Matrix4(); var b = new THREE.Matrix3().set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); var c = new THREE.Matrix4().set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); ok( ! matrixEquals3( a, b ), "Passed!" ); b.getInverse( a, false ); ok( matrixEquals3( b, new THREE.Matrix3() ), "Passed!" ); try { b.getInverse( c, true ); ok( false, "Passed!" ); // should never get here. } catch( err ) { ok( true, "Passed!" ); } var testMatrices = [ new THREE.Matrix4().makeRotationX( 0.3 ), new THREE.Matrix4().makeRotationX( -0.3 ), new THREE.Matrix4().makeRotationY( 0.3 ), new THREE.Matrix4().makeRotationY( -0.3 ), new THREE.Matrix4().makeRotationZ( 0.3 ), new THREE.Matrix4().makeRotationZ( -0.3 ), new THREE.Matrix4().makeScale( 1, 2, 3 ), new THREE.Matrix4().makeScale( 1/8, 1/2, 1/3 ) ]; for( var i = 0, il = testMatrices.length; i < il; i ++ ) { var m = testMatrices[i]; var mInverse3 = new THREE.Matrix3().getInverse( m ); var mInverse = toMatrix4( mInverse3 ); // the determinant of the inverse should be the reciprocal ok( Math.abs( m.determinant() * mInverse3.determinant() - 1 ) < 0.0001, "Passed!" ); ok( Math.abs( m.determinant() * mInverse.determinant() - 1 ) < 0.0001, "Passed!" ); var mProduct = new THREE.Matrix4().multiplyMatrices( m, mInverse ); ok( Math.abs( mProduct.determinant() - 1 ) < 0.0001, "Passed!" ); ok( matrixEquals3( mProduct, identity ), "Passed!" ); } }); test( "transpose", function() { var a = new THREE.Matrix3(); var b = a.clone().transpose(); ok( matrixEquals3( a, b ), "Passed!" ); b = new THREE.Matrix3().set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); var c = b.clone().transpose(); ok( ! matrixEquals3( b, c ), "Passed!" ); c.transpose(); ok( matrixEquals3( b, c ), "Passed!" ); }); test( "clone", function() { var a = new THREE.Matrix3().set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); var b = a.clone(); ok( matrixEquals3( a, b ), "Passed!" ); // ensure that it is a true copy a.elements[0] = 2; ok( ! matrixEquals3( a, b ), "Passed!" ); }); three.js-r73/test/unit/unittests_three.min.html0000644000175500017550000000216712610076566021621 0ustar debacledebacle ThreeJS Unit Tests - Using build/Three.min.js
      three.js-r73/test/unit/unittests_three-math.html0000644000175500017550000000217112610076566021761 0ustar debacledebacle ThreeJS Unit Tests - Using build/Three-math.js
      three.js-r73/editor/0000755000175500017550000000000012610076566014242 5ustar debacledebaclethree.js-r73/editor/examples/0000755000175500017550000000000012610076566016060 5ustar debacledebaclethree.js-r73/editor/examples/pong.app.json0000755000175500017550000001141512610076566020502 0ustar debacledebacle{ "camera": { "metadata": { "version": 4.3, "type": "Object", "generator": "ObjectExporter" }, "object": { "uuid": "8EFB9C06-6312-4975-B04A-C9E4549BE348", "type": "PerspectiveCamera", "name": "Camera", "fov": 50, "aspect": 1.3291139240506329, "near": 0.1, "far": 100000, "matrix": [0.9522120356559753,4.209433246415983e-9,-0.3054378032684326,0,-0.17742955684661865,0.8139731884002686,-0.553142249584198,0,0.24861818552017212,0.5809023976325989,0.7750750780105591,0,186.46363830566406,435.67681884765625,581.3063354492188,1] } }, "scene": { "metadata": { "version": 4.3, "type": "Object", "generator": "ObjectExporter" }, "geometries": [ { "uuid": "77B20ED1-2871-4B14-A652-8F823B2A817E", "type": "PlaneGeometry", "width": 600, "height": 400, "widthSegments": 1, "heightSegments": 1 }, { "uuid": "7ADE0D01-A56A-4D33-869A-6C360E096EF7", "type": "BoxGeometry", "width": 10, "height": 10, "depth": 10, "widthSegments": 1, "heightSegments": 1, "depthSegments": 1 }, { "uuid": "E8C064B6-3454-4739-9E02-3B07B8E70B4C", "type": "BoxGeometry", "width": 20, "height": 20, "depth": 100, "widthSegments": 1, "heightSegments": 1, "depthSegments": 1 }], "materials": [ { "uuid": "7EDF7C08-6325-418A-BBAB-89341C694730", "type": "MeshPhongMaterial", "color": 16777215, "emissive": 0, "specular": 16777215, "shininess": 30 }, { "uuid": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC", "type": "MeshPhongMaterial", "color": 16711680, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "FBDBE66D-B613-4741-802D-5AE1DE07DE46", "type": "MeshPhongMaterial", "color": 2752767, "emissive": 0, "specular": 1118481, "shininess": 30 }], "object": { "uuid": "31517222-A9A7-4EAF-B5F6-60751C0BABA3", "type": "Scene", "name": "Scene", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1], "children": [ { "uuid": "B47D0BFC-D63A-4CBB-985E-9C4DBDF086E4", "type": "Mesh", "name": "Ground", "geometry": "77B20ED1-2871-4B14-A652-8F823B2A817E", "material": "7EDF7C08-6325-418A-BBAB-89341C694730", "matrix": [1,0,0,0,0,0.0007960614748299122,-0.9999997019767761,0,0,0.9999997019767761,0.0007960614748299122,0,0,-10,0,1] }, { "uuid": "CE13E58A-4E8B-4F72-9E2E-7DE57C58F989", "type": "Mesh", "name": "Ball", "geometry": "7ADE0D01-A56A-4D33-869A-6C360E096EF7", "material": "B1CAF098-FE36-45E1-BEBE-8D6AC04821CC", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] }, { "uuid": "2AAEA3AA-EC45-492B-B450-10473D1EC6C5", "type": "Mesh", "name": "Pad 1", "geometry": "E8C064B6-3454-4739-9E02-3B07B8E70B4C", "material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-240,0,0,1] }, { "uuid": "F1DD46A7-6584-4A37-BC76-852C3911077E", "type": "Mesh", "name": "Pad 2", "geometry": "E8C064B6-3454-4739-9E02-3B07B8E70B4C", "material": "FBDBE66D-B613-4741-802D-5AE1DE07DE46", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,240,0,0,1] }, { "uuid": "C62AAE9F-9E51-46A5-BD2B-71BA804FC0B3", "type": "DirectionalLight", "name": "DirectionalLight 3", "color": 16777215, "intensity": 1, "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,100,200,150,1] }] } }, "scripts": { "31517222-A9A7-4EAF-B5F6-60751C0BABA3": [ { "name": "Game logic", "source": "var ball = this.getObjectByName( 'Ball' );\n\nvar position = ball.position;\n\nvar velocity = new THREE.Vector3();\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = Math.random() - 0.5;\ndirection.normalize();\n\nvar pad1 = this.getObjectByName( 'Pad 1' );\nvar pad2 = this.getObjectByName( 'Pad 2' );\n\nvar raycaster = new THREE.Raycaster();\nvar objects = [ pad1, pad2 ];\n\n//\n\nfunction mousemove( event ) {\n\n\tpad1.position.z = ( event.clientX / player.width ) * 300 - 150;\n\tpad2.position.z = - pad1.position.z;\n\n}\n\nfunction update( event ) {\n\t\n\tif ( position.x < -300 || position.x > 300 ) direction.x = - direction.x;\n\tif ( position.z < -200 || position.z > 200 ) direction.z = - direction.z;\n\t\n\tposition.x = Math.max( - 300, Math.min( 300, position.x ) );\n\tposition.z = Math.max( - 200, Math.min( 200, position.z ) );\n\t\n\traycaster.set( position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( objects );\n\t\n\tif ( intersections.length > 0 ) {\n\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 10 ) {\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n\tposition.add( velocity.copy( direction ).multiplyScalar( event.delta / 2 ) );\n\n}" }] } }three.js-r73/editor/examples/camera.app.json0000755000175500017550000001175412610076566020775 0ustar debacledebacle{ "camera": { "metadata": { "version": 4.3, "type": "Object", "generator": "ObjectExporter" }, "object": { "uuid": "C7FB195B-270E-47B4-95C9-1754652A9D11", "type": "PerspectiveCamera", "name": "Camera", "fov": 50, "aspect": 1.2252042007001167, "near": 0.1, "far": 100000, "matrix": [0.9700406789779663,-2.851828329042405e-9,-0.24294254183769226,0,-0.04822639003396034,0.9800989627838135,-0.1925622522830963,0,0.23810774087905884,0.19850945472717285,0.950735867023468,0,154.7735595703125,129.03408813476562,617.992431640625,1] } }, "scene": { "metadata": { "version": 4.3, "type": "Object", "generator": "ObjectExporter" }, "geometries": [ { "uuid": "51BB3E54-D2DF-4576-9953-FB8E940588B5", "type": "PlaneGeometry", "width": 1000, "height": 1000, "widthSegments": 1, "heightSegments": 1 }, { "uuid": "D8E200D3-27BC-49F8-A5C5-7384206E70FE", "type": "BoxGeometry", "width": 100, "height": 100, "depth": 100, "widthSegments": 1, "heightSegments": 1, "depthSegments": 1 }, { "uuid": "25BA32DB-8B02-4ABA-A77C-69868C464A1A", "type": "CylinderGeometry", "radiusTop": 0, "radiusBottom": 40, "height": 75, "radialSegments": 4, "heightSegments": 1, "openEnded": false }, { "uuid": "4DECFAB5-6FD1-4D84-9A29-565807B074EA", "type": "IcosahedronGeometry", "radius": 40, "detail": 2 }], "materials": [ { "uuid": "4AE8130E-B6A8-47BC-ACCF-060973C74044", "type": "MeshPhongMaterial", "color": 16777215, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "B5943856-E404-45D9-A427-4774202C2CD0", "type": "MeshPhongMaterial", "color": 37119, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "3F872310-2067-4BE4-9250-5B3F4E43797E", "type": "MeshPhongMaterial", "color": 15859456, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "E1826901-7922-4584-A25D-6D487E2C9BBD", "type": "MeshPhongMaterial", "color": 16711680, "emissive": 0, "specular": 1118481, "shininess": 30 }], "object": { "uuid": "3741222A-BD8F-401C-A5D2-5A907E891896", "type": "Scene", "name": "Scene", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1], "children": [ { "uuid": "B7CBBC6F-EC26-49B5-8D0D-67D9C535924B", "type": "Group", "name": "Dummy", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,100,400,1], "children": [ { "uuid": "60B69C58-4201-43FD-815E-AD2EDFBBD0CE", "type": "PerspectiveCamera", "name": "PerspectiveCamera", "fov": 50, "aspect": 1, "near": 100, "far": 10000, "matrix": [-1,0,-1.2246468525851679e-16,0,0,1,0,0,1.2246468525851679e-16,0,-1,0,0,0,0,1] }] }, { "uuid": "A460C230-DC88-4A8F-A3FB-AA0FE735F3ED", "type": "Mesh", "name": "Plane", "geometry": "51BB3E54-D2DF-4576-9953-FB8E940588B5", "material": "4AE8130E-B6A8-47BC-ACCF-060973C74044", "matrix": [1,0,0,0,0,0.040785226970911026,-0.9991679191589355,0,0,0.9991679191589355,0.040785226970911026,0,0,-50,0,1] }, { "uuid": "26DAAD69-725D-43B7-AF9D-990A99DEF8C5", "type": "Mesh", "name": "Box", "geometry": "D8E200D3-27BC-49F8-A5C5-7384206E70FE", "material": "B5943856-E404-45D9-A427-4774202C2CD0", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] }, { "uuid": "AAAFF2D6-4725-4AFC-A9FE-26419B11011F", "type": "Mesh", "name": "Cylinder", "geometry": "25BA32DB-8B02-4ABA-A77C-69868C464A1A", "material": "3F872310-2067-4BE4-9250-5B3F4E43797E", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-130,-15,0,1] }, { "uuid": "B855E267-A266-4098-ACD6-6A1FDE7B88BA", "type": "Mesh", "name": "Icosahedron", "geometry": "4DECFAB5-6FD1-4D84-9A29-565807B074EA", "material": "E1826901-7922-4584-A25D-6D487E2C9BBD", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,130,-10,0,1] }, { "uuid": "E2939A7B-5E40-438A-8C1B-32126FBC6892", "type": "PointLight", "name": "PointLight 1", "color": 9474221, "intensity": 0.75, "distance": 0, "decay": 1, "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-93.86000061035156,127.12999725341797,-114.30000305175781,1] }, { "uuid": "3412781E-27CC-43C3-A5DB-54C0C8E42ED6", "type": "PointLight", "name": "PointLight 2", "color": 12773063, "intensity": 1, "distance": 0, "decay": 1, "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,88.12999725341797,8.3100004196167,125.44999694824219,1] }] } }, "scripts": { "60B69C58-4201-43FD-815E-AD2EDFBBD0CE": [ { "name": "Player Camera", "source": "player.setCamera( this );" }], "B7CBBC6F-EC26-49B5-8D0D-67D9C535924B": [ { "name": "Orbit", "source": "function update( event ) {\n\n\tvar time = event.time * 0.001;\n\n\tthis.position.x = Math.sin( time ) * 400;\n\tthis.position.z = Math.cos( time ) * 400;\n\tthis.lookAt( scene.position );\n\n}" }] } }three.js-r73/editor/examples/arkanoid.app.json0000755000175500017550000001706412610076566021335 0ustar debacledebacle{ "project": { "vr": false }, "camera": { "metadata": { "version": 4.4, "type": "Object", "generator": "Object3D.toJSON" }, "object": { "uuid": "E41E9F54-8B31-4D1F-8D09-AF5E802E9A22", "type": "PerspectiveCamera", "name": "Camera", "matrix": [0.9392361044883728,-2.8092810300250903e-9,-0.3432718515396118,0,-0.14778217673301697,0.902585506439209,-0.404351145029068,0,0.3098321855068207,0.43051064014434814,0.847740888595581,0,142.32125854492188,202.75485229492188,389.40936279296875,1], "fov": 50, "aspect": 1.536388140161725, "near": 0.1, "far": 100000 } }, "scene": { "metadata": { "version": 4.4, "type": "Object", "generator": "Object3D.toJSON" }, "geometries": [ { "uuid": "8F05A1F2-3877-478B-8DFC-F572AC61AB3A", "type": "PlaneGeometry", "width": 300, "height": 400, "widthSegments": 1, "heightSegments": 1 }, { "uuid": "EEDF0A9A-D174-44E4-9C2F-A2F5BB8BE7F5", "type": "CylinderGeometry", "radiusTop": 5, "radiusBottom": 5, "height": 20, "radialSegments": 32, "heightSegments": 1, "openEnded": false }, { "uuid": "7149652B-DBD7-4CB7-A600-27A9AC005C95", "type": "BoxGeometry", "width": 20, "height": 10, "depth": 10, "widthSegments": 1, "heightSegments": 1, "depthSegments": 1 }, { "uuid": "CABCC711-1331-4D4C-9FF6-409299F10C68", "type": "SphereGeometry", "radius": 5, "widthSegments": 32, "heightSegments": 16, "phiStart": 0, "phiLength": 6.28, "thetaStart": 0, "thetaLength": 3.14 }, { "uuid": "EFBF641D-F092-462E-B7FB-0BFAD1591EFC", "type": "BoxGeometry", "width": 20, "height": 10, "depth": 10, "widthSegments": 1, "heightSegments": 1, "depthSegments": 1 }], "materials": [ { "uuid": "2F69AF3A-DDF5-4BBA-87B5-80159F90DDBF", "type": "MeshPhongMaterial", "color": 86015, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "3B9DE64D-E1C8-4C24-9F73-3A9E10E3E655", "type": "MeshPhongMaterial", "color": 16777215, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "D98FC4D1-169E-420A-92EA-20E55009A46D", "type": "MeshBasicMaterial", "wireframe": true, "color": 63744 }, { "uuid": "043B208C-1F83-42C6-802C-E0E35621C27C", "type": "MeshPhongMaterial", "color": 16777215, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "40EC9BDA-91C0-4671-937A-2BCB6DA7EEBB", "type": "MeshBasicMaterial", "wireframe": true, "color": 63744 }], "object": { "uuid": "31517222-A9A7-4EAF-B5F6-60751C0BABA3", "type": "Scene", "name": "Scene", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1], "children": [ { "uuid": "EBBB1E63-6318-4752-AE2E-440A4E0B3EF3", "type": "Mesh", "name": "Ground", "matrix": [1,0,0,0,0,0.0007960614748299122,-0.9999997019767761,0,0,0.9999997019767761,0.0007960614748299122,0,0,0,0,1], "geometry": "8F05A1F2-3877-478B-8DFC-F572AC61AB3A", "material": "2F69AF3A-DDF5-4BBA-87B5-80159F90DDBF" }, { "uuid": "6EE2E764-43E0-48E0-85F2-E0C8823C20DC", "type": "DirectionalLight", "name": "DirectionalLight 1", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,100,200,150,1], "color": 16777215, "intensity": 1 }, { "uuid": "38219749-1E67-45F2-AB15-E64BA0940CAD", "type": "Mesh", "name": "Brick", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,5,0,1], "children": [ { "uuid": "711A5955-8F17-4A8B-991A-7604D27E6FA0", "type": "Mesh", "name": "Cylinder", "matrix": [0.0007962009985931218,0.0007962677045725286,0.9999995231628418,0,-0.9999997615814209,3.462185702574061e-7,0.0007962677045725286,0,2.210134084634774e-7,-0.9999997615814209,0.0007962008821777999,0,0,0,0,1], "geometry": "EEDF0A9A-D174-44E4-9C2F-A2F5BB8BE7F5", "material": "3B9DE64D-E1C8-4C24-9F73-3A9E10E3E655" }], "geometry": "7149652B-DBD7-4CB7-A600-27A9AC005C95", "material": "D98FC4D1-169E-420A-92EA-20E55009A46D" }, { "uuid": "18FFA67C-F893-4E7A-8A76-8D996DEBE0C6", "type": "Mesh", "name": "Ball", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,5,35.54999923706055,1], "geometry": "CABCC711-1331-4D4C-9FF6-409299F10C68", "material": "043B208C-1F83-42C6-802C-E0E35621C27C" }, { "uuid": "6D660D49-39B8-40C3-95F6-E4E007AA8D79", "type": "Mesh", "name": "Paddle", "matrix": [2,0,0,0,0,1,0,0,0,0,1,0,0,5,159.5399932861328,1], "children": [ { "uuid": "4F5F884C-9E1B-45E6-8F1E-4D538A46D8CB", "type": "Mesh", "name": "Cylinder", "matrix": [0.0007962009985931218,0.0007962677045725286,0.9999995231628418,0,-0.9999997615814209,3.462185702574061e-7,0.0007962677045725286,0,2.210134084634774e-7,-0.9999997615814209,0.0007962008821777999,0,0,0,0,1], "geometry": "EEDF0A9A-D174-44E4-9C2F-A2F5BB8BE7F5", "material": "3B9DE64D-E1C8-4C24-9F73-3A9E10E3E655" }], "geometry": "EFBF641D-F092-462E-B7FB-0BFAD1591EFC", "material": "40EC9BDA-91C0-4671-937A-2BCB6DA7EEBB" }, { "uuid": "B0BEAF69-8B5D-4D87-ADCA-FDE83A02762D", "type": "PointLight", "name": "PointLight 2", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-116.54356384277344,69.48957061767578,-206.8248291015625,1], "color": 16777215, "intensity": 1, "distance": 0, "decay": 1 }] } }, "scripts": { "6D660D49-39B8-40C3-95F6-E4E007AA8D79": [ { "name": "User", "source": "function mousemove( event ) {\n\n\tthis.position.x = ( event.clientX / player.width ) * 300 - 150;\n\n}\n\n// function update( event ) {}" }], "31517222-A9A7-4EAF-B5F6-60751C0BABA3": [ { "name": "Game Logic", "source": "var ball = this.getObjectByName( 'Ball' );\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = - 0.5;\ndirection.normalize();\n\nvar speed = new THREE.Vector3();\n\n//\n\nvar group = new THREE.Group();\nthis.add( group );\n\nvar paddle = this.getObjectByName( 'Paddle' );\npaddle.material.visible = false;\ngroup.add( paddle );\n\nvar brick = this.getObjectByName( 'Brick' );\n\nfor ( var j = 0; j < 8; j ++ ) {\n\n\tvar material = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );\n\n\tfor ( var i = 0; i < 12; i ++ ) {\n\t\t\n\t\tvar object = brick.clone();\n\t\tobject.position.x = i * 22 - 120;\n\t\tobject.position.z = j * 14 - 120;\n\t\tgroup.add( object );\n\n\t\tvar cylinder = object.getObjectByName( 'Cylinder' );\n\t\tcylinder.material = material;\n\n\t}\n\t\n}\n\nbrick.visible = false;\nbrick.material.visible = false;\n\n//\n\nvar raycaster = new THREE.Raycaster();\n\nfunction update( event ) {\n\t\n\tif ( ball.position.x < - 150 || ball.position.x > 150 ) direction.x = - direction.x;\n\tif ( ball.position.z < - 200 || ball.position.z > 200 ) direction.z = - direction.z;\n\n\tball.position.x = Math.max( - 150, Math.min( 150, ball.position.x ) );\n\tball.position.z = Math.max( - 200, Math.min( 200, ball.position.z ) );\n\t\n\tball.position.add( speed.copy( direction ).multiplyScalar( event.delta / 4 ) );\n\t\n\traycaster.set( ball.position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( group.children );\n\t\n\tif ( intersections.length > 0 ) {\n\t\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 5 ) {\n\t\t\t\n\t\t\tif ( intersection.object !== paddle ) {\n\n\t\t\t\tgroup.remove( intersection.object );\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n}" }] } }three.js-r73/editor/examples/particles.app.json0000644000175500017550000000635112610076566021525 0ustar debacledebacle{ "camera": { "metadata": { "version": 4.3, "type": "Object", "generator": "ObjectExporter" }, "object": { "uuid": "D722B468-8D40-4CAB-82D6-944D2D5A8D35", "type": "PerspectiveCamera", "name": "Camera", "fov": 50, "aspect": 1.2237762237762237, "near": 0.1, "far": 100000, "matrix": [0.7071067690849304,-2.468905080377226e-9,-0.7071068286895752,0,-0.2357022613286972,0.9428090453147888,-0.235702246427536,0,0.6666666865348816,0.3333333134651184,0.6666666269302368,0,500,250,500,1] } }, "scene": { "metadata": { "version": 4.3, "type": "Object", "generator": "ObjectExporter" }, "geometries": [ { "uuid": "5009F17C-E9D3-4D0E-82A6-2E23159128FB", "type": "PlaneGeometry", "width": 600, "height": 600, "widthSegments": 1, "heightSegments": 1 }, { "uuid": "8693E7B2-0009-4C4C-94C5-8E031557AEC2", "type": "BoxGeometry", "width": 4, "height": 4, "depth": 4, "widthSegments": 1, "heightSegments": 1, "depthSegments": 1 }], "materials": [ { "uuid": "6EDB0369-7E11-4B0F-BF98-4BD761846D65", "type": "MeshPhongMaterial", "color": 16777215, "emissive": 0, "specular": 1118481, "shininess": 30 }, { "uuid": "F5361474-F5F1-412F-8D99-3699B868092D", "type": "SpriteMaterial", "color": 16777215 }], "object": { "uuid": "3741222A-BD8F-401C-A5D2-5A907E891896", "type": "Scene", "name": "Scene", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1], "children": [ { "uuid": "05B57416-1BE5-4A96-BB05-9D9CD112D52B", "type": "Mesh", "name": "Ground", "geometry": "5009F17C-E9D3-4D0E-82A6-2E23159128FB", "material": "6EDB0369-7E11-4B0F-BF98-4BD761846D65", "matrix": [1,0,0,0,0,0.0007962886593304574,-0.9999997019767761,0,0,0.9999997019767761,0.0007962886593304574,0,0,-2,0,1] }, { "uuid": "0A3CB873-07E6-4EEB-830B-68192504111B", "type": "Sprite", "name": "Particle", "material": "F5361474-F5F1-412F-8D99-3699B868092D", "matrix": [3,0,0,0,0,3,0,0,0,0,1,0,0,0,0,1] }, { "uuid": "40E5CDA4-0E39-4265-9293-3E9EC3207F61", "type": "PointLight", "name": "PointLight", "color": 16777215, "intensity": 10, "distance": 0, "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] }] } }, "scripts": { "3741222A-BD8F-401C-A5D2-5A907E891896": [ { "name": "Particle Fountain", "source": "var original = this.getObjectByName( 'Particle' );\n\nvar particles = [];\n\nfunction update( event ) {\n\n\tif ( particles.length < 200 ) {\n\n\t\tvar velocity = new THREE.Vector3();\n\t\tvelocity.x = Math.random() * 10 - 5;\n\t\tvelocity.y = Math.random() * 10 + 10;\n\t\tvelocity.z = Math.random() * 10 - 5;\n\n\t\tvar particle = original.clone();\n\t\tparticle.userData.velocity = velocity;\n\t\tparticles.push( particle );\n\n\t\tthis.add( particle );\n\n\t}\n\n\tfor ( var i = 0; i < particles.length; i ++ ) {\n\n\t\tvar particle = particles[ i ];\n\n\t\tvar velocity = particle.userData.velocity;\n\n\t\tvelocity.y -= 0.98;\n\n\t\tparticle.position.add( velocity );\n\n\t\tif ( particle.position.y < 0 ) {\n\n\t\t\tparticle.position.y = 0;\n\n\t\t\tvelocity.y = - velocity.y;\n\t\t\tvelocity.multiplyScalar( 0.6 );\n\n\t\t}\n\n\t}\n\n}" }] } } three.js-r73/editor/index.html0000644000175500017550000002311612610076566016242 0ustar debacledebacle three.js / editor three.js-r73/editor/js/0000755000175500017550000000000012610076566014656 5ustar debacledebaclethree.js-r73/editor/js/Sidebar.Material.js0000644000175500017550000005613212610076566020331 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Material = function ( editor ) { var signals = editor.signals; var currentObject; var container = new UI.CollapsiblePanel(); container.setCollapsed( editor.config.getKey( 'ui/sidebar/material/collapsed' ) ); container.onCollapsedChange( function ( boolean ) { editor.config.setKey( 'ui/sidebar/material/collapsed', boolean ); } ); container.setDisplay( 'none' ); container.dom.classList.add( 'Material' ); container.addStatic( new UI.Text().setValue( 'MATERIAL' ) ); container.add( new UI.Break() ); // uuid var materialUUIDRow = new UI.Panel(); var materialUUID = new UI.Input().setWidth( '115px' ).setFontSize( '12px' ).setDisabled( true ); var materialUUIDRenew = new UI.Button( '⟳' ).setMarginLeft( '7px' ).onClick( function () { materialUUID.setValue( THREE.Math.generateUUID() ); update(); } ); materialUUIDRow.add( new UI.Text( 'UUID' ).setWidth( '90px' ) ); materialUUIDRow.add( materialUUID ); materialUUIDRow.add( materialUUIDRenew ); container.add( materialUUIDRow ); // name var materialNameRow = new UI.Panel(); var materialName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () { editor.setMaterialName( editor.selected.material, materialName.getValue() ); } ); materialNameRow.add( new UI.Text( 'Name' ).setWidth( '90px' ) ); materialNameRow.add( materialName ); container.add( materialNameRow ); // class var materialClassRow = new UI.Panel(); var materialClass = new UI.Select().setOptions( { 'LineBasicMaterial': 'LineBasicMaterial', 'LineDashedMaterial': 'LineDashedMaterial', 'MeshBasicMaterial': 'MeshBasicMaterial', 'MeshDepthMaterial': 'MeshDepthMaterial', 'MeshLambertMaterial': 'MeshLambertMaterial', 'MeshNormalMaterial': 'MeshNormalMaterial', 'MeshPhongMaterial': 'MeshPhongMaterial', 'ShaderMaterial': 'ShaderMaterial', 'SpriteMaterial': 'SpriteMaterial' } ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update ); materialClassRow.add( new UI.Text( 'Type' ).setWidth( '90px' ) ); materialClassRow.add( materialClass ); container.add( materialClassRow ); // program var materialProgramRow = new UI.Panel(); materialProgramRow.add( new UI.Text( 'Program' ).setWidth( '90px' ) ); var materialProgramInfo = new UI.Button( 'Info' ); materialProgramInfo.setMarginLeft( '4px' ); materialProgramInfo.onClick( function () { signals.editScript.dispatch( currentObject.material, 'programInfo' ); } ); materialProgramRow.add( materialProgramInfo ); var materialProgramVertex = new UI.Button( 'Vertex' ); materialProgramVertex.setMarginLeft( '4px' ); materialProgramVertex.onClick( function () { signals.editScript.dispatch( currentObject.material, 'vertexShader' ); } ); materialProgramRow.add( materialProgramVertex ); var materialProgramFragment = new UI.Button( 'Fragment' ); materialProgramFragment.setMarginLeft( '4px' ); materialProgramFragment.onClick( function () { signals.editScript.dispatch( currentObject.material, 'fragmentShader' ); } ); materialProgramRow.add( materialProgramFragment ); container.add( materialProgramRow ); // color var materialColorRow = new UI.Panel(); var materialColor = new UI.Color().onChange( update ); materialColorRow.add( new UI.Text( 'Color' ).setWidth( '90px' ) ); materialColorRow.add( materialColor ); container.add( materialColorRow ); // emissive var materialEmissiveRow = new UI.Panel(); var materialEmissive = new UI.Color().setHexValue( 0x000000 ).onChange( update ); materialEmissiveRow.add( new UI.Text( 'Emissive' ).setWidth( '90px' ) ); materialEmissiveRow.add( materialEmissive ); container.add( materialEmissiveRow ); // specular var materialSpecularRow = new UI.Panel(); var materialSpecular = new UI.Color().setHexValue( 0x111111 ).onChange( update ); materialSpecularRow.add( new UI.Text( 'Specular' ).setWidth( '90px' ) ); materialSpecularRow.add( materialSpecular ); container.add( materialSpecularRow ); // shininess var materialShininessRow = new UI.Panel(); var materialShininess = new UI.Number( 30 ).onChange( update ); materialShininessRow.add( new UI.Text( 'Shininess' ).setWidth( '90px' ) ); materialShininessRow.add( materialShininess ); container.add( materialShininessRow ); // vertex colors var materialVertexColorsRow = new UI.Panel(); var materialVertexColors = new UI.Select().setOptions( { 0: 'No', 1: 'Face', 2: 'Vertex' } ).onChange( update ); materialVertexColorsRow.add( new UI.Text( 'Vertex Colors' ).setWidth( '90px' ) ); materialVertexColorsRow.add( materialVertexColors ); container.add( materialVertexColorsRow ); // skinning var materialSkinningRow = new UI.Panel(); var materialSkinning = new UI.Checkbox( false ).onChange( update ); materialSkinningRow.add( new UI.Text( 'Skinning' ).setWidth( '90px' ) ); materialSkinningRow.add( materialSkinning ); container.add( materialSkinningRow ); // map var materialMapRow = new UI.Panel(); var materialMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialMap = new UI.Texture().onChange( update ); materialMapRow.add( new UI.Text( 'Map' ).setWidth( '90px' ) ); materialMapRow.add( materialMapEnabled ); materialMapRow.add( materialMap ); container.add( materialMapRow ); // alpha map var materialAlphaMapRow = new UI.Panel(); var materialAlphaMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialAlphaMap = new UI.Texture().onChange( update ); materialAlphaMapRow.add( new UI.Text( 'Alpha Map' ).setWidth( '90px' ) ); materialAlphaMapRow.add( materialAlphaMapEnabled ); materialAlphaMapRow.add( materialAlphaMap ); container.add( materialAlphaMapRow ); // bump map var materialBumpMapRow = new UI.Panel(); var materialBumpMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialBumpMap = new UI.Texture().onChange( update ); var materialBumpScale = new UI.Number( 1 ).setWidth( '30px' ).onChange( update ); materialBumpMapRow.add( new UI.Text( 'Bump Map' ).setWidth( '90px' ) ); materialBumpMapRow.add( materialBumpMapEnabled ); materialBumpMapRow.add( materialBumpMap ); materialBumpMapRow.add( materialBumpScale ); container.add( materialBumpMapRow ); // normal map var materialNormalMapRow = new UI.Panel(); var materialNormalMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialNormalMap = new UI.Texture().onChange( update ); materialNormalMapRow.add( new UI.Text( 'Normal Map' ).setWidth( '90px' ) ); materialNormalMapRow.add( materialNormalMapEnabled ); materialNormalMapRow.add( materialNormalMap ); container.add( materialNormalMapRow ); // displacement map var materialDisplacementMapRow = new UI.Panel(); var materialDisplacementMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialDisplacementMap = new UI.Texture().onChange( update ); var materialDisplacementScale = new UI.Number( 1 ).setWidth( '30px' ).onChange( update ); materialDisplacementMapRow.add( new UI.Text( 'Displace Map' ).setWidth( '90px' ) ); materialDisplacementMapRow.add( materialDisplacementMapEnabled ); materialDisplacementMapRow.add( materialDisplacementMap ); materialDisplacementMapRow.add( materialDisplacementScale ); container.add( materialDisplacementMapRow ); // specular map var materialSpecularMapRow = new UI.Panel(); var materialSpecularMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialSpecularMap = new UI.Texture().onChange( update ); materialSpecularMapRow.add( new UI.Text( 'Specular Map' ).setWidth( '90px' ) ); materialSpecularMapRow.add( materialSpecularMapEnabled ); materialSpecularMapRow.add( materialSpecularMap ); container.add( materialSpecularMapRow ); // env map var materialEnvMapRow = new UI.Panel(); var materialEnvMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialEnvMap = new UI.Texture( THREE.SphericalReflectionMapping ).onChange( update ); var materialReflectivity = new UI.Number( 1 ).setWidth( '30px' ).onChange( update ); materialEnvMapRow.add( new UI.Text( 'Env Map' ).setWidth( '90px' ) ); materialEnvMapRow.add( materialEnvMapEnabled ); materialEnvMapRow.add( materialEnvMap ); materialEnvMapRow.add( materialReflectivity ); container.add( materialEnvMapRow ); // light map var materialLightMapRow = new UI.Panel(); var materialLightMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialLightMap = new UI.Texture().onChange( update ); materialLightMapRow.add( new UI.Text( 'Light Map' ).setWidth( '90px' ) ); materialLightMapRow.add( materialLightMapEnabled ); materialLightMapRow.add( materialLightMap ); container.add( materialLightMapRow ); // ambient occlusion map var materialAOMapRow = new UI.Panel(); var materialAOMapEnabled = new UI.Checkbox( false ).onChange( update ); var materialAOMap = new UI.Texture().onChange( update ); var materialAOScale = new UI.Number( 1 ).setRange( 0, 1 ).setWidth( '30px' ).onChange( update ); materialAOMapRow.add( new UI.Text( 'AO Map' ).setWidth( '90px' ) ); materialAOMapRow.add( materialAOMapEnabled ); materialAOMapRow.add( materialAOMap ); materialAOMapRow.add( materialAOScale ); container.add( materialAOMapRow ); // side var materialSideRow = new UI.Panel(); var materialSide = new UI.Select().setOptions( { 0: 'Front', 1: 'Back', 2: 'Double' } ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update ); materialSideRow.add( new UI.Text( 'Side' ).setWidth( '90px' ) ); materialSideRow.add( materialSide ); container.add( materialSideRow ); // shading var materialShadingRow = new UI.Panel(); var materialShading = new UI.Select().setOptions( { 0: 'No', 1: 'Flat', 2: 'Smooth' } ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update ); materialShadingRow.add( new UI.Text( 'Shading' ).setWidth( '90px' ) ); materialShadingRow.add( materialShading ); container.add( materialShadingRow ); // blending var materialBlendingRow = new UI.Panel(); var materialBlending = new UI.Select().setOptions( { 0: 'No', 1: 'Normal', 2: 'Additive', 3: 'Subtractive', 4: 'Multiply', 5: 'Custom' } ).setWidth( '150px' ).setFontSize( '12px' ).onChange( update ); materialBlendingRow.add( new UI.Text( 'Blending' ).setWidth( '90px' ) ); materialBlendingRow.add( materialBlending ); container.add( materialBlendingRow ); // opacity var materialOpacityRow = new UI.Panel(); var materialOpacity = new UI.Number().setWidth( '60px' ).setRange( 0, 1 ).onChange( update ); materialOpacityRow.add( new UI.Text( 'Opacity' ).setWidth( '90px' ) ); materialOpacityRow.add( materialOpacity ); container.add( materialOpacityRow ); // transparent var materialTransparentRow = new UI.Panel(); var materialTransparent = new UI.Checkbox().setLeft( '100px' ).onChange( update ); materialTransparentRow.add( new UI.Text( 'Transparent' ).setWidth( '90px' ) ); materialTransparentRow.add( materialTransparent ); container.add( materialTransparentRow ); // alpha test var materialAlphaTestRow = new UI.Panel(); var materialAlphaTest = new UI.Number().setWidth( '60px' ).setRange( 0, 1 ).onChange( update ); materialAlphaTestRow.add( new UI.Text( 'Alpha Test' ).setWidth( '90px' ) ); materialAlphaTestRow.add( materialAlphaTest ); container.add( materialAlphaTestRow ); // wireframe var materialWireframeRow = new UI.Panel(); var materialWireframe = new UI.Checkbox( false ).onChange( update ); var materialWireframeLinewidth = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, 100 ).onChange( update ); materialWireframeRow.add( new UI.Text( 'Wireframe' ).setWidth( '90px' ) ); materialWireframeRow.add( materialWireframe ); materialWireframeRow.add( materialWireframeLinewidth ); container.add( materialWireframeRow ); // function update() { var object = currentObject; var geometry = object.geometry; var material = object.material; var textureWarning = false; var objectHasUvs = false; if ( object instanceof THREE.Sprite ) objectHasUvs = true; if ( geometry instanceof THREE.Geometry && geometry.faceVertexUvs[ 0 ].length > 0 ) objectHasUvs = true; if ( geometry instanceof THREE.BufferGeometry && geometry.attributes.uv !== undefined ) objectHasUvs = true; if ( material ) { if ( material.uuid !== undefined ) { material.uuid = materialUUID.getValue(); } if ( material instanceof THREE[ materialClass.getValue() ] === false ) { material = new THREE[ materialClass.getValue() ](); object.material = material; // TODO Copy other references in the scene graph // keeping name and UUID then. // Also there should be means to create a unique // copy for the current object explicitly and to // attach the current material to other objects. } if ( material.color !== undefined ) { material.color.setHex( materialColor.getHexValue() ); } if ( material.emissive !== undefined ) { material.emissive.setHex( materialEmissive.getHexValue() ); } if ( material.specular !== undefined ) { material.specular.setHex( materialSpecular.getHexValue() ); } if ( material.shininess !== undefined ) { material.shininess = materialShininess.getValue(); } if ( material.vertexColors !== undefined ) { var vertexColors = parseInt( materialVertexColors.getValue() ); if ( material.vertexColors !== vertexColors ) { material.vertexColors = vertexColors; material.needsUpdate = true; } } if ( material.skinning !== undefined ) { material.skinning = materialSkinning.getValue(); } if ( material.map !== undefined ) { var mapEnabled = materialMapEnabled.getValue() === true; if ( objectHasUvs ) { material.map = mapEnabled ? materialMap.getValue() : null; material.needsUpdate = true; } else { if ( mapEnabled ) textureWarning = true; } } if ( material.alphaMap !== undefined ) { var mapEnabled = materialAlphaMapEnabled.getValue() === true; if ( objectHasUvs ) { material.alphaMap = mapEnabled ? materialAlphaMap.getValue() : null; material.needsUpdate = true; } else { if ( mapEnabled ) textureWarning = true; } } if ( material.bumpMap !== undefined ) { var bumpMapEnabled = materialBumpMapEnabled.getValue() === true; if ( objectHasUvs ) { material.bumpMap = bumpMapEnabled ? materialBumpMap.getValue() : null; material.bumpScale = materialBumpScale.getValue(); material.needsUpdate = true; } else { if ( bumpMapEnabled ) textureWarning = true; } } if ( material.normalMap !== undefined ) { var normalMapEnabled = materialNormalMapEnabled.getValue() === true; if ( objectHasUvs ) { material.normalMap = normalMapEnabled ? materialNormalMap.getValue() : null; material.needsUpdate = true; } else { if ( normalMapEnabled ) textureWarning = true; } } if ( material.displacementMap !== undefined ) { var displacementMapEnabled = materialDisplacementMapEnabled.getValue() === true; if ( objectHasUvs ) { material.displacementMap = displacementMapEnabled ? materialDisplacementMap.getValue() : null; material.displacementScale = materialDisplacementScale.getValue(); material.needsUpdate = true; } else { if ( displacementMapEnabled ) textureWarning = true; } } if ( material.specularMap !== undefined ) { var specularMapEnabled = materialSpecularMapEnabled.getValue() === true; if ( objectHasUvs ) { material.specularMap = specularMapEnabled ? materialSpecularMap.getValue() : null; material.needsUpdate = true; } else { if ( specularMapEnabled ) textureWarning = true; } } if ( material.envMap !== undefined ) { var envMapEnabled = materialEnvMapEnabled.getValue() === true; material.envMap = envMapEnabled ? materialEnvMap.getValue() : null; material.reflectivity = materialReflectivity.getValue(); material.needsUpdate = true; } if ( material.lightMap !== undefined ) { var lightMapEnabled = materialLightMapEnabled.getValue() === true; if ( objectHasUvs ) { material.lightMap = lightMapEnabled ? materialLightMap.getValue() : null; material.needsUpdate = true; } else { if ( lightMapEnabled ) textureWarning = true; } } if ( material.aoMap !== undefined ) { var aoMapEnabled = materialAOMapEnabled.getValue() === true; if ( objectHasUvs ) { material.aoMap = aoMapEnabled ? materialAOMap.getValue() : null; material.aoMapIntensity = materialAOScale.getValue(); material.needsUpdate = true; } else { if ( aoMapEnabled ) textureWarning = true; } } if ( material.side !== undefined ) { material.side = parseInt( materialSide.getValue() ); } if ( material.shading !== undefined ) { material.shading = parseInt( materialShading.getValue() ); } if ( material.blending !== undefined ) { material.blending = parseInt( materialBlending.getValue() ); } if ( material.opacity !== undefined ) { material.opacity = materialOpacity.getValue(); } if ( material.transparent !== undefined ) { material.transparent = materialTransparent.getValue(); } if ( material.alphaTest !== undefined ) { material.alphaTest = materialAlphaTest.getValue(); } if ( material.wireframe !== undefined ) { material.wireframe = materialWireframe.getValue(); } if ( material.wireframeLinewidth !== undefined ) { material.wireframeLinewidth = materialWireframeLinewidth.getValue(); } refreshUi(false); signals.materialChanged.dispatch( material ); } if ( textureWarning ) { console.warn( "Can't set texture, model doesn't have texture coordinates" ); } }; // function setRowVisibility() { var properties = { 'name': materialNameRow, 'color': materialColorRow, 'emissive': materialEmissiveRow, 'specular': materialSpecularRow, 'shininess': materialShininessRow, 'vertexShader': materialProgramRow, 'vertexColors': materialVertexColorsRow, 'skinning': materialSkinningRow, 'map': materialMapRow, 'alphaMap': materialAlphaMapRow, 'bumpMap': materialBumpMapRow, 'normalMap': materialNormalMapRow, 'displacementMap': materialDisplacementMapRow, 'specularMap': materialSpecularMapRow, 'envMap': materialEnvMapRow, 'lightMap': materialLightMapRow, 'aoMap': materialAOMapRow, 'side': materialSideRow, 'shading': materialShadingRow, 'blending': materialBlendingRow, 'opacity': materialOpacityRow, 'transparent': materialTransparentRow, 'alphaTest': materialAlphaTestRow, 'wireframe': materialWireframeRow }; var material = currentObject.material; for ( var property in properties ) { properties[ property ].setDisplay( material[ property ] !== undefined ? '' : 'none' ); } }; function refreshUi( resetTextureSelectors ) { var material = currentObject.material; if ( material.uuid !== undefined ) { materialUUID.setValue( material.uuid ); } if ( material.name !== undefined ) { materialName.setValue( material.name ); } materialClass.setValue( material.type ); if ( material.color !== undefined ) { materialColor.setHexValue( material.color.getHexString() ); } if ( material.emissive !== undefined ) { materialEmissive.setHexValue( material.emissive.getHexString() ); } if ( material.specular !== undefined ) { materialSpecular.setHexValue( material.specular.getHexString() ); } if ( material.shininess !== undefined ) { materialShininess.setValue( material.shininess ); } if ( material.vertexColors !== undefined ) { materialVertexColors.setValue( material.vertexColors ); } if ( material.skinning !== undefined ) { materialSkinning.setValue( material.skinning ); } if ( material.map !== undefined ) { materialMapEnabled.setValue( material.map !== null ); if ( material.map !== null || resetTextureSelectors ) { materialMap.setValue( material.map ); } } if ( material.alphaMap !== undefined ) { materialAlphaMapEnabled.setValue( material.alphaMap !== null ); if ( material.alphaMap !== null || resetTextureSelectors ) { materialAlphaMap.setValue( material.alphaMap ); } } if ( material.bumpMap !== undefined ) { materialBumpMapEnabled.setValue( material.bumpMap !== null ); if ( material.bumpMap !== null || resetTextureSelectors ) { materialBumpMap.setValue( material.bumpMap ); } materialBumpScale.setValue( material.bumpScale ); } if ( material.normalMap !== undefined ) { materialNormalMapEnabled.setValue( material.normalMap !== null ); if ( material.normalMap !== null || resetTextureSelectors ) { materialNormalMap.setValue( material.normalMap ); } } if ( material.displacementMap !== undefined ) { materialDisplacementMapEnabled.setValue( material.displacementMap !== null ); if ( material.displacementMap !== null || resetTextureSelectors ) { materialDisplacementMap.setValue( material.displacementMap ); } materialDisplacementScale.setValue( material.displacementScale ); } if ( material.specularMap !== undefined ) { materialSpecularMapEnabled.setValue( material.specularMap !== null ); if ( material.specularMap !== null || resetTextureSelectors ) { materialSpecularMap.setValue( material.specularMap ); } } if ( material.envMap !== undefined ) { materialEnvMapEnabled.setValue( material.envMap !== null ); if ( material.envMap !== null || resetTextureSelectors ) { materialEnvMap.setValue( material.envMap ); } materialReflectivity.setValue( material.reflectivity ); } if ( material.lightMap !== undefined ) { materialLightMapEnabled.setValue( material.lightMap !== null ); if ( material.lightMap !== null || resetTextureSelectors ) { materialLightMap.setValue( material.lightMap ); } } if ( material.aoMap !== undefined ) { materialAOMapEnabled.setValue( material.aoMap !== null ); if ( material.aoMap !== null || resetTextureSelectors ) { materialAOMap.setValue( material.aoMap ); } materialAOScale.setValue( material.aoMapIntensity ); } if ( material.side !== undefined ) { materialSide.setValue( material.side ); } if ( material.shading !== undefined ) { materialShading.setValue( material.shading ); } if ( material.blending !== undefined ) { materialBlending.setValue( material.blending ); } if ( material.opacity !== undefined ) { materialOpacity.setValue( material.opacity ); } if ( material.transparent !== undefined ) { materialTransparent.setValue( material.transparent ); } if ( material.alphaTest !== undefined ) { materialAlphaTest.setValue( material.alphaTest ); } if ( material.wireframe !== undefined ) { materialWireframe.setValue( material.wireframe ); } if ( material.wireframeLinewidth !== undefined ) { materialWireframeLinewidth.setValue( material.wireframeLinewidth ); } setRowVisibility(); } // events signals.objectSelected.add( function ( object ) { if ( object && object.material ) { var objectChanged = object !== currentObject; currentObject = object; refreshUi(objectChanged); container.setDisplay( '' ); } else { currentObject = null; container.setDisplay( 'none' ); } } ); return container; } three.js-r73/editor/js/Editor.js0000644000175500017550000002057212610076566016450 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Editor = function () { var SIGNALS = signals; this.signals = { // script editScript: new SIGNALS.Signal(), // player startPlayer: new SIGNALS.Signal(), stopPlayer: new SIGNALS.Signal(), // actions showModal: new SIGNALS.Signal(), // notifications editorCleared: new SIGNALS.Signal(), savingStarted: new SIGNALS.Signal(), savingFinished: new SIGNALS.Signal(), themeChanged: new SIGNALS.Signal(), transformModeChanged: new SIGNALS.Signal(), snapChanged: new SIGNALS.Signal(), spaceChanged: new SIGNALS.Signal(), rendererChanged: new SIGNALS.Signal(), sceneGraphChanged: new SIGNALS.Signal(), cameraChanged: new SIGNALS.Signal(), geometryChanged: new SIGNALS.Signal(), objectSelected: new SIGNALS.Signal(), objectFocused: new SIGNALS.Signal(), objectAdded: new SIGNALS.Signal(), objectChanged: new SIGNALS.Signal(), objectRemoved: new SIGNALS.Signal(), helperAdded: new SIGNALS.Signal(), helperRemoved: new SIGNALS.Signal(), materialChanged: new SIGNALS.Signal(), scriptAdded: new SIGNALS.Signal(), scriptChanged: new SIGNALS.Signal(), scriptRemoved: new SIGNALS.Signal(), fogTypeChanged: new SIGNALS.Signal(), fogColorChanged: new SIGNALS.Signal(), fogParametersChanged: new SIGNALS.Signal(), windowResize: new SIGNALS.Signal(), showGridChanged: new SIGNALS.Signal() }; this.config = new Config(); this.history = new History( this ); this.storage = new Storage(); this.loader = new Loader( this ); this.camera = new THREE.PerspectiveCamera( 50, 1, 1, 100000 ); this.camera.position.set( 500, 250, 500 ); this.camera.lookAt( new THREE.Vector3() ); this.camera.name = 'Camera'; this.scene = new THREE.Scene(); this.scene.name = 'Scene'; this.sceneHelpers = new THREE.Scene(); this.object = {}; this.geometries = {}; this.materials = {}; this.textures = {}; this.scripts = {}; this.selected = null; this.helpers = {}; }; Editor.prototype = { setTheme: function ( value ) { document.getElementById( 'theme' ).href = value; this.signals.themeChanged.dispatch( value ); }, // setScene: function ( scene ) { this.scene.uuid = scene.uuid; this.scene.name = scene.name; this.scene.userData = JSON.parse( JSON.stringify( scene.userData ) ); // avoid render per object this.signals.sceneGraphChanged.active = false; while ( scene.children.length > 0 ) { this.addObject( scene.children[ 0 ] ); } this.signals.sceneGraphChanged.active = true; this.signals.sceneGraphChanged.dispatch(); }, // addObject: function ( object ) { var scope = this; object.traverse( function ( child ) { if ( child.geometry !== undefined ) scope.addGeometry( child.geometry ); if ( child.material !== undefined ) scope.addMaterial( child.material ); scope.addHelper( child ); } ); this.scene.add( object ); this.signals.objectAdded.dispatch( object ); this.signals.sceneGraphChanged.dispatch(); }, moveObject: function ( object, parent, before ) { if ( parent === undefined ) { parent = this.scene; } parent.add( object ); // sort children array if ( before !== undefined ) { var index = parent.children.indexOf( before ); parent.children.splice( index, 0, object ); parent.children.pop(); } this.signals.sceneGraphChanged.dispatch(); }, nameObject: function ( object, name ) { object.name = name; this.signals.sceneGraphChanged.dispatch(); }, removeObject: function ( object ) { if ( object.parent === null ) return; // avoid deleting the camera or scene var scope = this; object.traverse( function ( child ) { scope.removeHelper( child ); } ); object.parent.remove( object ); this.signals.objectRemoved.dispatch( object ); this.signals.sceneGraphChanged.dispatch(); }, addGeometry: function ( geometry ) { this.geometries[ geometry.uuid ] = geometry; }, setGeometryName: function ( geometry, name ) { geometry.name = name; this.signals.sceneGraphChanged.dispatch(); }, addMaterial: function ( material ) { this.materials[ material.uuid ] = material; }, setMaterialName: function ( material, name ) { material.name = name; this.signals.sceneGraphChanged.dispatch(); }, addTexture: function ( texture ) { this.textures[ texture.uuid ] = texture; }, // addHelper: function () { var geometry = new THREE.SphereBufferGeometry( 20, 4, 2 ); var material = new THREE.MeshBasicMaterial( { color: 0xff0000, visible: false } ); return function ( object ) { var helper; if ( object instanceof THREE.Camera ) { helper = new THREE.CameraHelper( object, 10 ); } else if ( object instanceof THREE.PointLight ) { helper = new THREE.PointLightHelper( object, 10 ); } else if ( object instanceof THREE.DirectionalLight ) { helper = new THREE.DirectionalLightHelper( object, 20 ); } else if ( object instanceof THREE.SpotLight ) { helper = new THREE.SpotLightHelper( object, 10 ); } else if ( object instanceof THREE.HemisphereLight ) { helper = new THREE.HemisphereLightHelper( object, 10 ); } else if ( object instanceof THREE.SkinnedMesh ) { helper = new THREE.SkeletonHelper( object ); } else { // no helper for this object type return; } var picker = new THREE.Mesh( geometry, material ); picker.name = 'picker'; picker.userData.object = object; helper.add( picker ); this.sceneHelpers.add( helper ); this.helpers[ object.id ] = helper; this.signals.helperAdded.dispatch( helper ); }; }(), removeHelper: function ( object ) { if ( this.helpers[ object.id ] !== undefined ) { var helper = this.helpers[ object.id ]; helper.parent.remove( helper ); delete this.helpers[ object.id ]; this.signals.helperRemoved.dispatch( helper ); } }, // addScript: function ( object, script ) { if ( this.scripts[ object.uuid ] === undefined ) { this.scripts[ object.uuid ] = []; } this.scripts[ object.uuid ].push( script ); this.signals.scriptAdded.dispatch( script ); }, removeScript: function ( object, script ) { if ( this.scripts[ object.uuid ] === undefined ) return; var index = this.scripts[ object.uuid ].indexOf( script ); if ( index !== - 1 ) { this.scripts[ object.uuid ].splice( index, 1 ); } this.signals.scriptRemoved.dispatch( script ); }, // select: function ( object ) { if ( this.selected === object ) return; var uuid = null; if ( object !== null ) { uuid = object.uuid; } this.selected = object; this.config.setKey( 'selected', uuid ); this.signals.objectSelected.dispatch( object ); }, selectById: function ( id ) { if ( id === this.camera.id ) { this.select( this.camera ); return; } this.select( this.scene.getObjectById( id, true ) ); }, selectByUuid: function ( uuid ) { var scope = this; this.scene.traverse( function ( child ) { if ( child.uuid === uuid ) { scope.select( child ); } } ); }, deselect: function () { this.select( null ); }, focus: function ( object ) { this.signals.objectFocused.dispatch( object ); }, focusById: function ( id ) { this.focus( this.scene.getObjectById( id, true ) ); }, clear: function () { this.history.clear(); this.storage.clear(); this.camera.position.set( 500, 250, 500 ); this.camera.lookAt( new THREE.Vector3() ); var objects = this.scene.children; while ( objects.length > 0 ) { this.removeObject( objects[ 0 ] ); } this.geometries = {}; this.materials = {}; this.textures = {}; this.scripts = {}; this.deselect(); this.signals.editorCleared.dispatch(); }, // fromJSON: function ( json ) { var loader = new THREE.ObjectLoader(); // backwards if ( json.scene === undefined ) { this.setScene( loader.parse( json ) ); return; } // TODO: Clean this up somehow var camera = loader.parse( json.camera ); this.camera.position.copy( camera.position ); this.camera.rotation.copy( camera.rotation ); this.camera.aspect = camera.aspect; this.camera.near = camera.near; this.camera.far = camera.far; this.setScene( loader.parse( json.scene ) ); this.scripts = json.scripts; }, toJSON: function () { return { project: { shadows: this.config.getKey( 'project/renderer/shadows' ), vr: this.config.getKey( 'project/vr' ) }, camera: this.camera.toJSON(), scene: this.scene.toJSON(), scripts: this.scripts }; } } three.js-r73/editor/js/Sidebar.Geometry.Modifiers.js0000644000175500017550000000115712610076566022303 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.Modifiers = function ( signals, object ) { var container = new UI.Panel().setPaddingLeft( '90px' ); var geometry = object.geometry; // Compute Vertex Normals var button = new UI.Button( 'Compute Vertex Normals' ); button.onClick( function () { geometry.computeVertexNormals(); if ( geometry instanceof THREE.BufferGeometry ) { geometry.attributes.normal.needsUpdate = true; } else { geometry.normalsNeedUpdate = true; } signals.geometryChanged.dispatch( object ); } ); container.add( button ); // return container; } three.js-r73/editor/js/Sidebar.Geometry.BoxGeometry.js0000644000175500017550000000426512610076566022631 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.BoxGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // width var widthRow = new UI.Panel(); var width = new UI.Number( parameters.width ).onChange( update ); widthRow.add( new UI.Text( 'Width' ).setWidth( '90px' ) ); widthRow.add( width ); container.add( widthRow ); // height var heightRow = new UI.Panel(); var height = new UI.Number( parameters.height ).onChange( update ); heightRow.add( new UI.Text( 'Height' ).setWidth( '90px' ) ); heightRow.add( height ); container.add( heightRow ); // depth var depthRow = new UI.Panel(); var depth = new UI.Number( parameters.depth ).onChange( update ); depthRow.add( new UI.Text( 'Depth' ).setWidth( '90px' ) ); depthRow.add( depth ); container.add( depthRow ); // widthSegments var widthSegmentsRow = new UI.Panel(); var widthSegments = new UI.Integer( parameters.widthSegments ).setRange( 1, Infinity ).onChange( update ); widthSegmentsRow.add( new UI.Text( 'Width segments' ).setWidth( '90px' ) ); widthSegmentsRow.add( widthSegments ); container.add( widthSegmentsRow ); // heightSegments var heightSegmentsRow = new UI.Panel(); var heightSegments = new UI.Integer( parameters.heightSegments ).setRange( 1, Infinity ).onChange( update ); heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ) ); heightSegmentsRow.add( heightSegments ); container.add( heightSegmentsRow ); // depthSegments var depthSegmentsRow = new UI.Panel(); var depthSegments = new UI.Integer( parameters.depthSegments ).setRange( 1, Infinity ).onChange( update ); depthSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ) ); depthSegmentsRow.add( depthSegments ); container.add( depthSegmentsRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.BoxGeometry( width.getValue(), height.getValue(), depth.getValue(), widthSegments.getValue(), heightSegments.getValue(), depthSegments.getValue() ); object.geometry.computeBoundingSphere(); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Storage.js0000644000175500017550000000401412610076566016617 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Storage = function () { var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; if ( indexedDB === undefined ) { console.warn( 'Storage: IndexedDB not available.' ); return { init: function () {}, get: function () {}, set: function () {}, clear: function () {} }; } var name = 'threejs-editor'; var version = 1; var database; return { init: function ( callback ) { var request = indexedDB.open( name, version ); request.onupgradeneeded = function ( event ) { var db = event.target.result; if ( db.objectStoreNames.contains( 'states' ) === false ) { db.createObjectStore( 'states' ); } }; request.onsuccess = function ( event ) { database = event.target.result; callback(); }; request.onerror = function ( event ) { console.error( 'IndexedDB', event ); }; }, get: function ( callback ) { var transaction = database.transaction( [ 'states' ], 'readwrite' ); var objectStore = transaction.objectStore( 'states' ); var request = objectStore.get( 0 ); request.onsuccess = function ( event ) { callback( event.target.result ); }; }, set: function ( data, callback ) { var start = performance.now(); var transaction = database.transaction( [ 'states' ], 'readwrite' ); var objectStore = transaction.objectStore( 'states' ); var request = objectStore.put( data, 0 ); request.onsuccess = function ( event ) { console.log( '[' + /\d\d\:\d\d\:\d\d/.exec( new Date() )[ 0 ] + ']', 'Saved state to IndexedDB. ' + ( performance.now() - start ).toFixed( 2 ) + 'ms' ); }; }, clear: function () { var transaction = database.transaction( [ 'states' ], 'readwrite' ); var objectStore = transaction.objectStore( 'states' ); var request = objectStore.clear(); request.onsuccess = function ( event ) { console.log( '[' + /\d\d\:\d\d\:\d\d/.exec( new Date() )[ 0 ] + ']', 'Cleared IndexedDB.' ); }; } } }; three.js-r73/editor/js/Script.js0000644000175500017550000001726212610076566016470 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Script = function ( editor ) { var signals = editor.signals; var container = new UI.Panel(); container.setId( 'script' ); container.setPosition( 'absolute' ); container.setBackgroundColor( '#272822' ); container.setDisplay( 'none' ); var header = new UI.Panel(); header.setPadding( '10px' ); container.add( header ); var title = new UI.Text().setColor( '#fff' ); header.add( title ); var buttonSVG = ( function () { var svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' ); svg.setAttribute( 'width', 32 ); svg.setAttribute( 'height', 32 ); var path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' ); path.setAttribute( 'd', 'M 12,12 L 22,22 M 22,12 12,22' ); path.setAttribute( 'stroke', '#fff' ); svg.appendChild( path ); return svg; } )(); var close = new UI.Element( buttonSVG ); close.setPosition( 'absolute' ); close.setTop( '3px' ); close.setRight( '1px' ); close.setCursor( 'pointer' ); close.onClick( function () { container.setDisplay( 'none' ); } ); header.add( close ); var renderer; signals.rendererChanged.add( function ( newRenderer ) { renderer = newRenderer; } ); var delay; var currentMode; var currentScript; var currentObject; var codemirror = CodeMirror( container.dom, { value: '', lineNumbers: true, matchBrackets: true, indentWithTabs: true, tabSize: 4, indentUnit: 4, hintOptions: { completeSingle: false } } ); codemirror.setOption( 'theme', 'monokai' ); codemirror.on( 'change', function () { clearTimeout( delay ); delay = setTimeout( function () { var value = codemirror.getValue(); if ( ! validate( value ) ) return; if ( typeof( currentScript ) === 'object' ) { currentScript.source = value; signals.scriptChanged.dispatch( currentScript ); return; } if ( currentScript !== 'programInfo' ) return; var json = JSON.parse( value ); currentObject.defines = json.defines; currentObject.uniforms = json.uniforms; currentObject.attributes = json.attributes; currentObject.needsUpdate = true; signals.materialChanged.dispatch( currentObject ); }, 300 ); }); // prevent backspace from deleting objects var wrapper = codemirror.getWrapperElement(); wrapper.addEventListener( 'keydown', function ( event ) { event.stopPropagation(); } ); // validate var errorLines = []; var widgets = []; var validate = function ( string ) { var valid; var errors = []; return codemirror.operation( function () { while ( errorLines.length > 0 ) { codemirror.removeLineClass( errorLines.shift(), 'background', 'errorLine' ); } while ( widgets.length > 0 ) { codemirror.removeLineWidget( widgets.shift() ); } // switch ( currentMode ) { case 'javascript': try { var syntax = esprima.parse( string, { tolerant: true } ); errors = syntax.errors; } catch ( error ) { errors.push( { lineNumber: error.lineNumber - 1, message: error.message } ); } for ( var i = 0; i < errors.length; i ++ ) { var error = errors[ i ]; error.message = error.message.replace(/Line [0-9]+: /, ''); } break; case 'json': errors = []; jsonlint.parseError = function ( message, info ) { message = message.split('\n')[3]; errors.push( { lineNumber: info.loc.first_line - 1, message: message } ); }; try { jsonlint.parse( string ); } catch ( error ) { // ignore failed error recovery } break; case 'glsl': try { var shaderType = currentScript === 'vertexShader' ? glslprep.Shader.VERTEX : glslprep.Shader.FRAGMENT; glslprep.parseGlsl( string, shaderType ); } catch( error ) { if ( error instanceof glslprep.SyntaxError ) { errors.push( { lineNumber: error.line, message: "Syntax Error: " + error.message } ); } else { console.error( error.stack || error ); } } if ( errors.length !== 0 ) break; if ( renderer instanceof THREE.WebGLRenderer === false ) break; currentObject[ currentScript ] = string; currentObject.needsUpdate = true; signals.materialChanged.dispatch( currentObject ); var programs = renderer.info.programs; valid = true; var parseMessage = /^(?:ERROR|WARNING): \d+:(\d+): (.*)/g; for ( var i = 0, n = programs.length; i !== n; ++ i ) { var diagnostics = programs[i].diagnostics; if ( diagnostics === undefined || diagnostics.material !== currentObject ) continue; if ( ! diagnostics.runnable ) valid = false; var shaderInfo = diagnostics[ currentScript ]; var lineOffset = shaderInfo.prefix.split(/\r\n|\r|\n/).length; while ( true ) { var parseResult = parseMessage.exec( shaderInfo.log ); if ( parseResult === null ) break; errors.push( { lineNumber: parseResult[ 1 ] - lineOffset, message: parseResult[ 2 ] } ); } // messages break; } // programs } // mode switch for ( var i = 0; i < errors.length; i ++ ) { var error = errors[ i ]; var message = document.createElement( 'div' ); message.className = 'esprima-error'; message.textContent = error.message; var lineNumber = Math.max( error.lineNumber, 0 ); errorLines.push( lineNumber ); codemirror.addLineClass( lineNumber, 'background', 'errorLine' ); var widget = codemirror.addLineWidget( lineNumber, message ); widgets.push( widget ); } return valid !== undefined ? valid : errors.length === 0; }); }; // tern js autocomplete var server = new CodeMirror.TernServer( { caseInsensitive: true, plugins: { threejs: null } } ); codemirror.setOption( 'extraKeys', { 'Ctrl-Space': function(cm) { server.complete(cm); }, 'Ctrl-I': function(cm) { server.showType(cm); }, 'Ctrl-O': function(cm) { server.showDocs(cm); }, 'Alt-.': function(cm) { server.jumpToDef(cm); }, 'Alt-,': function(cm) { server.jumpBack(cm); }, 'Ctrl-Q': function(cm) { server.rename(cm); }, 'Ctrl-.': function(cm) { server.selectName(cm); } } ); codemirror.on( 'cursorActivity', function( cm ) { if ( currentMode !== 'javascript' ) return; server.updateArgHints( cm ); } ); codemirror.on( 'keypress', function( cm, kb ) { if ( currentMode !== 'javascript' ) return; var typed = String.fromCharCode( kb.which || kb.keyCode ); if ( /[\w\.]/.exec( typed ) ) { server.complete( cm ); } } ); // signals.editorCleared.add( function () { container.setDisplay( 'none' ); } ); signals.editScript.add( function ( object, script ) { var mode, name, source; if ( typeof( script ) === 'object' ) { mode = 'javascript'; name = script.name; source = script.source; } else { switch ( script ) { case 'vertexShader': mode = 'glsl'; name = 'Vertex Shader'; source = object.vertexShader || ""; break; case 'fragmentShader': mode = 'glsl'; name = 'Fragment Shader'; source = object.fragmentShader || ""; break; case 'programInfo': mode = 'json'; name = 'Program Properties'; var json = { defines: object.defines, uniforms: object.uniforms, attributes: object.attributes }; source = JSON.stringify( json, null, '\t' ); } } currentMode = mode; currentScript = script; currentObject = object; title.setValue( object.name + ' / ' + name ); container.setDisplay( '' ); codemirror.setValue( source ); if (mode === 'json' ) mode = { name: 'javascript', json: true }; codemirror.setOption( 'mode', mode ); } ); return container; }; three.js-r73/editor/js/Sidebar.Animation.js0000644000175500017550000000442412610076566020507 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Animation = function ( editor ) { var signals = editor.signals; var options = {}; var possibleAnimations = {}; var container = new UI.CollapsiblePanel(); container.setCollapsed( editor.config.getKey( 'ui/sidebar/animation/collapsed' ) ); container.onCollapsedChange( function ( boolean ) { editor.config.setKey( 'ui/sidebar/animation/collapsed', boolean ); } ); container.setDisplay( 'none' ); container.addStatic( new UI.Text( 'Animation' ).setTextTransform( 'uppercase' ) ); container.add( new UI.Break() ); var animationsRow = new UI.Panel(); container.add( animationsRow ); /* var animations = {}; signals.objectAdded.add( function ( object ) { object.traverse( function ( child ) { if ( child instanceof THREE.SkinnedMesh ) { var material = child.material; if ( material instanceof THREE.MeshFaceMaterial ) { for ( var i = 0; i < material.materials.length; i ++ ) { material.materials[ i ].skinning = true; } } else { child.material.skinning = true; } animations[ child.id ] = new THREE.Animation( child, child.geometry.animation ); } else if ( child instanceof THREE.MorphAnimMesh ) { var animation = new THREE.MorphAnimation( child ); animation.duration = 30; // temporal hack for THREE.AnimationHandler animation._play = animation.play; animation.play = function () { this._play(); THREE.AnimationHandler.play( this ); }; animation.resetBlendWeights = function () {}; animation.stop = function () { this.pause(); THREE.AnimationHandler.stop( this ); }; animations[ child.id ] = animation; } } ); } ); signals.objectSelected.add( function ( object ) { container.setDisplay( 'none' ); if ( object instanceof THREE.SkinnedMesh || object instanceof THREE.MorphAnimMesh ) { animationsRow.clear(); var animation = animations[ object.id ]; var playButton = new UI.Button( 'Play' ).onClick( function () { animation.play(); } ); animationsRow.add( playButton ); var pauseButton = new UI.Button( 'Stop' ).onClick( function () { animation.stop(); } ); animationsRow.add( pauseButton ); container.setDisplay( 'block' ); } } ); */ return container; } three.js-r73/editor/js/Sidebar.Geometry.TorusKnotGeometry.js0000644000175500017550000000446012610076566024046 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.TorusKnotGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // radius var radiusRow = new UI.Panel(); var radius = new UI.Number( parameters.radius ).onChange( update ); radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ) ); radiusRow.add( radius ); container.add( radiusRow ); // tube var tubeRow = new UI.Panel(); var tube = new UI.Number( parameters.tube ).onChange( update ); tubeRow.add( new UI.Text( 'Tube' ).setWidth( '90px' ) ); tubeRow.add( tube ); container.add( tubeRow ); // radialSegments var radialSegmentsRow = new UI.Panel(); var radialSegments = new UI.Integer( parameters.radialSegments ).setRange( 1, Infinity ).onChange( update ); radialSegmentsRow.add( new UI.Text( 'Radial segments' ).setWidth( '90px' ) ); radialSegmentsRow.add( radialSegments ); container.add( radialSegmentsRow ); // tubularSegments var tubularSegmentsRow = new UI.Panel(); var tubularSegments = new UI.Integer( parameters.tubularSegments ).setRange( 1, Infinity ).onChange( update ); tubularSegmentsRow.add( new UI.Text( 'Tubular segments' ).setWidth( '90px' ) ); tubularSegmentsRow.add( tubularSegments ); container.add( tubularSegmentsRow ); // p var pRow = new UI.Panel(); var p = new UI.Number( parameters.p ).onChange( update ); pRow.add( new UI.Text( 'P' ).setWidth( '90px' ) ); pRow.add( p ); container.add( pRow ); // q var qRow = new UI.Panel(); var q = new UI.Number( parameters.q ).onChange( update ); pRow.add( new UI.Text( 'Q' ).setWidth( '90px' ) ); pRow.add( q ); container.add( qRow ); // heightScale var heightScaleRow = new UI.Panel(); var heightScale = new UI.Number( parameters.heightScale ).onChange( update ); pRow.add( new UI.Text( 'Height scale' ).setWidth( '90px' ) ); pRow.add( heightScale ); container.add( heightScaleRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.TorusKnotGeometry( radius.getValue(), tube.getValue(), radialSegments.getValue(), tubularSegments.getValue(), p.getValue(), q.getValue(), heightScale.getValue() ); object.geometry.computeBoundingSphere(); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Config.js0000644000175500017550000000250712610076566016425 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Config = function () { var name = 'threejs-editor'; var storage = { 'autosave': true, 'theme': 'css/light.css', 'project/renderer': 'WebGLRenderer', 'project/renderer/antialias': true, 'project/renderer/shadows': true, 'project/vr': false, 'ui/sidebar/animation/collapsed': true, 'ui/sidebar/geometry/collapsed': true, 'ui/sidebar/material/collapsed': true, 'ui/sidebar/object3d/collapsed': false, 'ui/sidebar/project/collapsed': true, 'ui/sidebar/scene/collapsed': false, 'ui/sidebar/script/collapsed': true }; if ( window.localStorage[ name ] === undefined ) { window.localStorage[ name ] = JSON.stringify( storage ); } else { var data = JSON.parse( window.localStorage[ name ] ); for ( var key in data ) { storage[ key ] = data[ key ]; } } return { getKey: function ( key ) { return storage[ key ]; }, setKey: function () { // key, value, key, value ... for ( var i = 0, l = arguments.length; i < l; i += 2 ) { storage[ arguments[ i ] ] = arguments[ i + 1 ]; } window.localStorage[ name ] = JSON.stringify( storage ); console.log( '[' + /\d\d\:\d\d\:\d\d/.exec( new Date() )[ 0 ] + ']', 'Saved config to LocalStorage.' ); }, clear: function () { delete window.localStorage[ name ]; } } }; three.js-r73/editor/js/Sidebar.Geometry.BufferGeometry.js0000644000175500017550000000206212610076566023303 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.BufferGeometry = function ( signals ) { var container = new UI.Panel(); function update( object ) { if ( object === null ) return; var geometry = object.geometry; if ( geometry instanceof THREE.BufferGeometry ) { container.clear(); container.setDisplay( 'block' ); var index = geometry.index; if ( index !== null ) { var panel = new UI.Panel(); panel.add( new UI.Text( 'index' ).setWidth( '90px' ) ); panel.add( new UI.Text( ( index.count ).format() ).setFontSize( '12px' ) ); container.add( panel ); } var attributes = geometry.attributes; for ( var name in attributes ) { var panel = new UI.Panel(); panel.add( new UI.Text( name ).setWidth( '90px' ) ); panel.add( new UI.Text( ( attributes[ name ].count ).format() ).setFontSize( '12px' ) ); container.add( panel ); } } else { container.setDisplay( 'none' ); } }; signals.objectSelected.add( update ); signals.geometryChanged.add( update ); return container; } three.js-r73/editor/js/Sidebar.Scene.js0000644000175500017550000001173412610076566017627 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Scene = function ( editor ) { var signals = editor.signals; var container = new UI.CollapsiblePanel(); container.setCollapsed( editor.config.getKey( 'ui/sidebar/scene/collapsed' ) ); container.onCollapsedChange( function ( boolean ) { editor.config.setKey( 'ui/sidebar/scene/collapsed', boolean ); } ); container.addStatic( new UI.Text( 'SCENE' ) ); container.add( new UI.Break() ); var ignoreObjectSelectedSignal = false; var outliner = new UI.Outliner( editor ); outliner.onChange( function () { ignoreObjectSelectedSignal = true; editor.selectById( parseInt( outliner.getValue() ) ); ignoreObjectSelectedSignal = false; } ); outliner.onDblClick( function () { editor.focusById( parseInt( outliner.getValue() ) ); } ); container.add( outliner ); container.add( new UI.Break() ); // fog var updateFogParameters = function () { var near = fogNear.getValue(); var far = fogFar.getValue(); var density = fogDensity.getValue(); signals.fogParametersChanged.dispatch( near, far, density ); }; var fogTypeRow = new UI.Panel(); var fogType = new UI.Select().setOptions( { 'None': 'None', 'Fog': 'Linear', 'FogExp2': 'Exponential' } ).setWidth( '150px' ); fogType.onChange( function () { var type = fogType.getValue(); signals.fogTypeChanged.dispatch( type ); refreshFogUI(); } ); fogTypeRow.add( new UI.Text( 'Fog' ).setWidth( '90px' ) ); fogTypeRow.add( fogType ); container.add( fogTypeRow ); // fog color var fogColorRow = new UI.Panel(); fogColorRow.setDisplay( 'none' ); var fogColor = new UI.Color().setValue( '#aaaaaa' ) fogColor.onChange( function () { signals.fogColorChanged.dispatch( fogColor.getHexValue() ); } ); fogColorRow.add( new UI.Text( 'Fog color' ).setWidth( '90px' ) ); fogColorRow.add( fogColor ); container.add( fogColorRow ); // fog near var fogNearRow = new UI.Panel(); fogNearRow.setDisplay( 'none' ); var fogNear = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, Infinity ).onChange( updateFogParameters ); fogNearRow.add( new UI.Text( 'Fog near' ).setWidth( '90px' ) ); fogNearRow.add( fogNear ); container.add( fogNearRow ); var fogFarRow = new UI.Panel(); fogFarRow.setDisplay( 'none' ); // fog far var fogFar = new UI.Number( 5000 ).setWidth( '60px' ).setRange( 0, Infinity ).onChange( updateFogParameters ); fogFarRow.add( new UI.Text( 'Fog far' ).setWidth( '90px' ) ); fogFarRow.add( fogFar ); container.add( fogFarRow ); // fog density var fogDensityRow = new UI.Panel(); fogDensityRow.setDisplay( 'none' ); var fogDensity = new UI.Number( 0.00025 ).setWidth( '60px' ).setRange( 0, 0.1 ).setPrecision( 5 ).onChange( updateFogParameters ); fogDensityRow.add( new UI.Text( 'Fog density' ).setWidth( '90px' ) ); fogDensityRow.add( fogDensity ); container.add( fogDensityRow ); // var refreshUI = function () { var camera = editor.camera; var scene = editor.scene; var options = []; // options.push( { value: camera.id, html: ' ' + camera.name } ); options.push( { static: true, value: scene.id, html: ' ' + scene.name } ); ( function addObjects( objects, pad ) { for ( var i = 0, l = objects.length; i < l; i ++ ) { var object = objects[ i ]; var html = pad + ' ' + object.name; if ( object instanceof THREE.Mesh ) { var geometry = object.geometry; var material = object.material; html += ' ' + geometry.name; html += ' ' + material.name; } options.push( { value: object.id, html: html } ); addObjects( object.children, pad + '   ' ); } } )( scene.children, '   ' ); outliner.setOptions( options ); if ( editor.selected !== null ) { outliner.setValue( editor.selected.id ); } if ( scene.fog ) { fogColor.setHexValue( scene.fog.color.getHex() ); if ( scene.fog instanceof THREE.Fog ) { fogType.setValue( "Fog" ); fogNear.setValue( scene.fog.near ); fogFar.setValue( scene.fog.far ); } else if ( scene.fog instanceof THREE.FogExp2 ) { fogType.setValue( "FogExp2" ); fogDensity.setValue( scene.fog.density ); } } else { fogType.setValue( "None" ); } refreshFogUI(); }; var refreshFogUI = function () { var type = fogType.getValue(); fogColorRow.setDisplay( type === 'None' ? 'none' : '' ); fogNearRow.setDisplay( type === 'Fog' ? '' : 'none' ); fogFarRow.setDisplay( type === 'Fog' ? '' : 'none' ); fogDensityRow.setDisplay( type === 'FogExp2' ? '' : 'none' ); }; refreshUI(); // events signals.sceneGraphChanged.add( refreshUI ); signals.objectSelected.add( function ( object ) { if ( ignoreObjectSelectedSignal === true ) return; outliner.setValue( object !== null ? object.id : null ); } ); return container; } three.js-r73/editor/js/Menubar.Edit.js0000644000175500017550000000547212610076566017501 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.Edit = function ( editor ) { var container = new UI.Panel(); container.setClass( 'menu' ); var title = new UI.Panel(); title.setClass( 'title' ); title.setTextContent( 'Edit' ); container.add( title ); var options = new UI.Panel(); options.setClass( 'options' ); container.add( options ); // Undo var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Undo' ); option.onClick( function () { editor.history.undo(); } ); options.add( option ); // Redo var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Redo' ); option.onClick( function () { editor.history.redo(); } ); options.add( option ); // --- options.add( new UI.HorizontalRule() ); // Clone var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Clone' ); option.onClick( function () { var object = editor.selected; if ( object.parent === null ) return; // avoid cloning the camera or scene object = object.clone(); editor.addObject( object ); editor.select( object ); } ); options.add( option ); // Delete var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Delete' ); option.onClick( function () { var object = editor.selected; if ( confirm( 'Delete ' + object.name + '?' ) === false ) return; var parent = object.parent; editor.removeObject( object ); editor.select( parent ); } ); options.add( option ); // Minify shaders var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Minify Shaders' ); option.onClick( function() { var root = editor.selected || editor.scene; var errors = []; var nMaterialsChanged = 0; var path = []; function getPath ( object ) { path.length = 0; var parent = object.parent; if ( parent !== undefined ) getPath( parent ); path.push( object.name || object.uuid ); return path; } root.traverse( function ( object ) { var material = object.material; if ( material instanceof THREE.ShaderMaterial ) { try { var shader = glslprep.minifyGlsl( [ material.vertexShader, material.fragmentShader ] ); material.vertexShader = shader[ 0 ]; material.fragmentShader = shader[ 1 ]; ++nMaterialsChanged; } catch ( e ) { var path = getPath( object ).join( "/" ); if ( e instanceof glslprep.SyntaxError ) errors.push( path + ":" + e.line + ":" + e.column + ": " + e.message ); else { errors.push( path + ": Unexpected error (see console for details)." ); console.error( e.stack || e ); } } } } ); window.alert( nMaterialsChanged + " material(s) were changed.\n" + errors.join( "\n" ) ); } ); options.add( option ); return container; }; three.js-r73/editor/js/Sidebar.Object3D.js0000644000175500017550000003634112610076566020170 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Object3D = function ( editor ) { var signals = editor.signals; var container = new UI.CollapsiblePanel(); container.setCollapsed( editor.config.getKey( 'ui/sidebar/object3d/collapsed' ) ); container.onCollapsedChange( function ( boolean ) { editor.config.setKey( 'ui/sidebar/object3d/collapsed', boolean ); } ); container.setDisplay( 'none' ); var objectType = new UI.Text().setTextTransform( 'uppercase' ); container.addStatic( objectType ); // Actions var objectActions = new UI.Select().setPosition('absolute').setRight( '8px' ).setFontSize( '11px' ); objectActions.setOptions( { 'Actions': 'Actions', 'Reset Position': 'Reset Position', 'Reset Rotation': 'Reset Rotation', 'Reset Scale': 'Reset Scale' } ); objectActions.onClick( function ( event ) { event.stopPropagation(); // Avoid panel collapsing } ); objectActions.onChange( function ( event ) { var object = editor.selected; switch ( this.getValue() ) { case 'Reset Position': object.position.set( 0, 0, 0 ); break; case 'Reset Rotation': object.rotation.set( 0, 0, 0 ); break; case 'Reset Scale': object.scale.set( 1, 1, 1 ); break; } this.setValue( 'Actions' ); signals.objectChanged.dispatch( object ); } ); container.addStatic( objectActions ); container.add( new UI.Break() ); // uuid var objectUUIDRow = new UI.Panel(); var objectUUID = new UI.Input().setWidth( '115px' ).setFontSize( '12px' ).setDisabled( true ); var objectUUIDRenew = new UI.Button( '⟳' ).setMarginLeft( '7px' ).onClick( function () { objectUUID.setValue( THREE.Math.generateUUID() ); editor.selected.uuid = objectUUID.getValue(); } ); objectUUIDRow.add( new UI.Text( 'UUID' ).setWidth( '90px' ) ); objectUUIDRow.add( objectUUID ); objectUUIDRow.add( objectUUIDRenew ); container.add( objectUUIDRow ); // name var objectNameRow = new UI.Panel(); var objectName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () { editor.nameObject( editor.selected, objectName.getValue() ); } ); objectNameRow.add( new UI.Text( 'Name' ).setWidth( '90px' ) ); objectNameRow.add( objectName ); container.add( objectNameRow ); /* // parent var objectParentRow = new UI.Panel(); var objectParent = new UI.Select().setWidth( '150px' ).setFontSize( '12px' ).onChange( update ); objectParentRow.add( new UI.Text( 'Parent' ).setWidth( '90px' ) ); objectParentRow.add( objectParent ); container.add( objectParentRow ); */ // position var objectPositionRow = new UI.Panel(); var objectPositionX = new UI.Number().setWidth( '50px' ).onChange( update ); var objectPositionY = new UI.Number().setWidth( '50px' ).onChange( update ); var objectPositionZ = new UI.Number().setWidth( '50px' ).onChange( update ); objectPositionRow.add( new UI.Text( 'Position' ).setWidth( '90px' ) ); objectPositionRow.add( objectPositionX, objectPositionY, objectPositionZ ); container.add( objectPositionRow ); // rotation var objectRotationRow = new UI.Panel(); var objectRotationX = new UI.Number().setWidth( '50px' ).onChange( update ); var objectRotationY = new UI.Number().setWidth( '50px' ).onChange( update ); var objectRotationZ = new UI.Number().setWidth( '50px' ).onChange( update ); objectRotationRow.add( new UI.Text( 'Rotation' ).setWidth( '90px' ) ); objectRotationRow.add( objectRotationX, objectRotationY, objectRotationZ ); container.add( objectRotationRow ); // scale var objectScaleRow = new UI.Panel(); var objectScaleLock = new UI.Checkbox( true ).setPosition( 'absolute' ).setLeft( '75px' ); var objectScaleX = new UI.Number( 1 ).setRange( 0.01, Infinity ).setWidth( '50px' ).onChange( updateScaleX ); var objectScaleY = new UI.Number( 1 ).setRange( 0.01, Infinity ).setWidth( '50px' ).onChange( updateScaleY ); var objectScaleZ = new UI.Number( 1 ).setRange( 0.01, Infinity ).setWidth( '50px' ).onChange( updateScaleZ ); objectScaleRow.add( new UI.Text( 'Scale' ).setWidth( '90px' ) ); objectScaleRow.add( objectScaleLock ); objectScaleRow.add( objectScaleX, objectScaleY, objectScaleZ ); container.add( objectScaleRow ); // fov var objectFovRow = new UI.Panel(); var objectFov = new UI.Number().onChange( update ); objectFovRow.add( new UI.Text( 'Fov' ).setWidth( '90px' ) ); objectFovRow.add( objectFov ); container.add( objectFovRow ); // near var objectNearRow = new UI.Panel(); var objectNear = new UI.Number().onChange( update ); objectNearRow.add( new UI.Text( 'Near' ).setWidth( '90px' ) ); objectNearRow.add( objectNear ); container.add( objectNearRow ); // far var objectFarRow = new UI.Panel(); var objectFar = new UI.Number().onChange( update ); objectFarRow.add( new UI.Text( 'Far' ).setWidth( '90px' ) ); objectFarRow.add( objectFar ); container.add( objectFarRow ); // intensity var objectIntensityRow = new UI.Panel(); var objectIntensity = new UI.Number().setRange( 0, Infinity ).onChange( update ); objectIntensityRow.add( new UI.Text( 'Intensity' ).setWidth( '90px' ) ); objectIntensityRow.add( objectIntensity ); container.add( objectIntensityRow ); // color var objectColorRow = new UI.Panel(); var objectColor = new UI.Color().onChange( update ); objectColorRow.add( new UI.Text( 'Color' ).setWidth( '90px' ) ); objectColorRow.add( objectColor ); container.add( objectColorRow ); // ground color var objectGroundColorRow = new UI.Panel(); var objectGroundColor = new UI.Color().onChange( update ); objectGroundColorRow.add( new UI.Text( 'Ground color' ).setWidth( '90px' ) ); objectGroundColorRow.add( objectGroundColor ); container.add( objectGroundColorRow ); // distance var objectDistanceRow = new UI.Panel(); var objectDistance = new UI.Number().setRange( 0, Infinity ).onChange( update ); objectDistanceRow.add( new UI.Text( 'Distance' ).setWidth( '90px' ) ); objectDistanceRow.add( objectDistance ); container.add( objectDistanceRow ); // angle var objectAngleRow = new UI.Panel(); var objectAngle = new UI.Number().setPrecision( 3 ).setRange( 0, Math.PI / 2 ).onChange( update ); objectAngleRow.add( new UI.Text( 'Angle' ).setWidth( '90px' ) ); objectAngleRow.add( objectAngle ); container.add( objectAngleRow ); // exponent var objectExponentRow = new UI.Panel(); var objectExponent = new UI.Number().setRange( 0, Infinity ).onChange( update ); objectExponentRow.add( new UI.Text( 'Exponent' ).setWidth( '90px' ) ); objectExponentRow.add( objectExponent ); container.add( objectExponentRow ); // decay var objectDecayRow = new UI.Panel(); var objectDecay = new UI.Number().setRange( 0, Infinity ).onChange( update ); objectDecayRow.add( new UI.Text( 'Decay' ).setWidth( '90px' ) ); objectDecayRow.add( objectDecay ); container.add( objectDecayRow ); // shadow var objectShadowRow = new UI.Panel(); objectShadowRow.add( new UI.Text( 'Shadow' ).setWidth( '90px' ) ); var objectCastShadowSpan = new UI.Span().setMarginRight( '10px' ); var objectCastShadow = new UI.Checkbox().onChange( update ); objectCastShadowSpan.add( objectCastShadow ); objectCastShadowSpan.add( new UI.Text( 'cast' ).setMarginLeft( '3px' ) ); objectShadowRow.add( objectCastShadowSpan ); var objectReceiveShadowSpan = new UI.Span(); var objectReceiveShadow = new UI.Checkbox().onChange( update ); objectReceiveShadowSpan.add( objectReceiveShadow ); objectReceiveShadowSpan.add( new UI.Text( 'receive' ).setMarginLeft( '3px' ) ); objectShadowRow.add( objectReceiveShadowSpan ); container.add( objectShadowRow ); // visible var objectVisibleRow = new UI.Panel(); var objectVisible = new UI.Checkbox().onChange( update ); objectVisibleRow.add( new UI.Text( 'Visible' ).setWidth( '90px' ) ); objectVisibleRow.add( objectVisible ); container.add( objectVisibleRow ); // user data var timeout; var objectUserDataRow = new UI.Panel(); var objectUserData = new UI.TextArea().setWidth( '150px' ).setHeight( '40px' ).setFontSize( '12px' ).onChange( update ); objectUserData.onKeyUp( function () { try { JSON.parse( objectUserData.getValue() ); objectUserData.dom.classList.add( 'success' ); objectUserData.dom.classList.remove( 'fail' ); } catch ( error ) { objectUserData.dom.classList.remove( 'success' ); objectUserData.dom.classList.add( 'fail' ); } } ); objectUserDataRow.add( new UI.Text( 'User data' ).setWidth( '90px' ) ); objectUserDataRow.add( objectUserData ); container.add( objectUserDataRow ); // function updateScaleX() { var object = editor.selected; if ( objectScaleLock.getValue() === true ) { var scale = objectScaleX.getValue() / object.scale.x; objectScaleY.setValue( objectScaleY.getValue() * scale ); objectScaleZ.setValue( objectScaleZ.getValue() * scale ); } update(); } function updateScaleY() { var object = editor.selected; if ( objectScaleLock.getValue() === true ) { var scale = objectScaleY.getValue() / object.scale.y; objectScaleX.setValue( objectScaleX.getValue() * scale ); objectScaleZ.setValue( objectScaleZ.getValue() * scale ); } update(); } function updateScaleZ() { var object = editor.selected; if ( objectScaleLock.getValue() === true ) { var scale = objectScaleZ.getValue() / object.scale.z; objectScaleX.setValue( objectScaleX.getValue() * scale ); objectScaleY.setValue( objectScaleY.getValue() * scale ); } update(); } function update() { var object = editor.selected; if ( object !== null ) { /* if ( object.parent !== null ) { var newParentId = parseInt( objectParent.getValue() ); if ( object.parent.id !== newParentId && object.id !== newParentId ) { editor.moveObject( object, editor.scene.getObjectById( newParentId ) ); } } */ object.position.x = objectPositionX.getValue(); object.position.y = objectPositionY.getValue(); object.position.z = objectPositionZ.getValue(); object.rotation.x = objectRotationX.getValue(); object.rotation.y = objectRotationY.getValue(); object.rotation.z = objectRotationZ.getValue(); object.scale.x = objectScaleX.getValue(); object.scale.y = objectScaleY.getValue(); object.scale.z = objectScaleZ.getValue(); if ( object.fov !== undefined ) { object.fov = objectFov.getValue(); object.updateProjectionMatrix(); } if ( object.near !== undefined ) { object.near = objectNear.getValue(); } if ( object.far !== undefined ) { object.far = objectFar.getValue(); } if ( object.intensity !== undefined ) { object.intensity = objectIntensity.getValue(); } if ( object.color !== undefined ) { object.color.setHex( objectColor.getHexValue() ); } if ( object.groundColor !== undefined ) { object.groundColor.setHex( objectGroundColor.getHexValue() ); } if ( object.distance !== undefined ) { object.distance = objectDistance.getValue(); } if ( object.angle !== undefined ) { object.angle = objectAngle.getValue(); } if ( object.exponent !== undefined ) { object.exponent = objectExponent.getValue(); } if ( object.decay !== undefined ) { object.decay = objectDecay.getValue(); } if ( object.castShadow !== undefined ) { object.castShadow = objectCastShadow.getValue(); } if ( object.receiveShadow !== undefined ) { var value = objectReceiveShadow.getValue(); if ( value !== object.receiveShadow ) { object.receiveShadow = value; object.material.needsUpdate = true; } } object.visible = objectVisible.getValue(); try { object.userData = JSON.parse( objectUserData.getValue() ); } catch ( exception ) { console.warn( exception ); } signals.objectChanged.dispatch( object ); } } function updateRows( object ) { var properties = { // 'parent': objectParentRow, 'fov': objectFovRow, 'near': objectNearRow, 'far': objectFarRow, 'intensity': objectIntensityRow, 'color': objectColorRow, 'groundColor': objectGroundColorRow, 'distance' : objectDistanceRow, 'angle' : objectAngleRow, 'exponent' : objectExponentRow, 'decay' : objectDecayRow, 'castShadow' : objectShadowRow, 'receiveShadow' : objectReceiveShadowSpan }; for ( var property in properties ) { properties[ property ].setDisplay( object[ property ] !== undefined ? '' : 'none' ); } } function updateTransformRows( object ) { if ( object instanceof THREE.Light || ( object instanceof THREE.Object3D && object.userData.targetInverse ) ) { objectRotationRow.setDisplay( 'none' ); objectScaleRow.setDisplay( 'none' ); } else { objectRotationRow.setDisplay( '' ); objectScaleRow.setDisplay( '' ); } } // events signals.objectSelected.add( function ( object ) { if ( object !== null ) { container.setDisplay( 'block' ); updateRows( object ); updateUI( object ); } else { container.setDisplay( 'none' ); } } ); /* signals.sceneGraphChanged.add( function () { var scene = editor.scene; var options = {}; scene.traverse( function ( object ) { options[ object.id ] = object.name; } ); objectParent.setOptions( options ); } ); */ signals.objectChanged.add( function ( object ) { if ( object !== editor.selected ) return; updateUI( object ); } ); function updateUI( object ) { objectType.setValue( object.type ); objectUUID.setValue( object.uuid ); objectName.setValue( object.name ); /* if ( object.parent !== null ) { objectParent.setValue( object.parent.id ); } */ objectPositionX.setValue( object.position.x ); objectPositionY.setValue( object.position.y ); objectPositionZ.setValue( object.position.z ); objectRotationX.setValue( object.rotation.x ); objectRotationY.setValue( object.rotation.y ); objectRotationZ.setValue( object.rotation.z ); objectScaleX.setValue( object.scale.x ); objectScaleY.setValue( object.scale.y ); objectScaleZ.setValue( object.scale.z ); if ( object.fov !== undefined ) { objectFov.setValue( object.fov ); } if ( object.near !== undefined ) { objectNear.setValue( object.near ); } if ( object.far !== undefined ) { objectFar.setValue( object.far ); } if ( object.intensity !== undefined ) { objectIntensity.setValue( object.intensity ); } if ( object.color !== undefined ) { objectColor.setHexValue( object.color.getHexString() ); } if ( object.groundColor !== undefined ) { objectGroundColor.setHexValue( object.groundColor.getHexString() ); } if ( object.distance !== undefined ) { objectDistance.setValue( object.distance ); } if ( object.angle !== undefined ) { objectAngle.setValue( object.angle ); } if ( object.exponent !== undefined ) { objectExponent.setValue( object.exponent ); } if ( object.decay !== undefined ) { objectDecay.setValue( object.decay ); } if ( object.castShadow !== undefined ) { objectCastShadow.setValue( object.castShadow ); } if ( object.receiveShadow !== undefined ) { objectReceiveShadow.setValue( object.receiveShadow ); } objectVisible.setValue( object.visible ); try { objectUserData.setValue( JSON.stringify( object.userData, null, ' ' ) ); } catch ( error ) { console.log( error ); } objectUserData.setBorderColor( 'transparent' ); objectUserData.setBackgroundColor( '' ); updateTransformRows( object ); } return container; } three.js-r73/editor/js/Sidebar.js0000644000175500017550000000100712610076566016563 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Sidebar = function ( editor ) { var container = new UI.Panel(); container.setId( 'sidebar' ); container.add( new Sidebar.Project( editor ) ); container.add( new Sidebar.Scene( editor ) ); container.add( new Sidebar.Object3D( editor ) ); container.add( new Sidebar.Geometry( editor ) ); container.add( new Sidebar.Material( editor ) ); container.add( new Sidebar.Animation( editor ) ); container.add( new Sidebar.Script( editor ) ); return container; }; three.js-r73/editor/js/Sidebar.Script.js0000644000175500017550000000451312610076566020033 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Script = function ( editor ) { var signals = editor.signals; var container = new UI.CollapsiblePanel(); container.setCollapsed( editor.config.getKey( 'ui/sidebar/script/collapsed' ) ); container.onCollapsedChange( function ( boolean ) { editor.config.setKey( 'ui/sidebar/script/collapsed', boolean ); } ); container.setDisplay( 'none' ); container.addStatic( new UI.Text( 'Script' ).setTextTransform( 'uppercase' ) ); container.add( new UI.Break() ); // var scriptsContainer = new UI.Panel(); container.add( scriptsContainer ); var newScript = new UI.Button( 'New' ); newScript.onClick( function () { var script = { name: '', source: 'function update( event ) {}' }; editor.addScript( editor.selected, script ); } ); container.add( newScript ); /* var loadScript = new UI.Button( 'Load' ); loadScript.setMarginLeft( '4px' ); container.add( loadScript ); */ // function update() { scriptsContainer.clear(); var object = editor.selected; if ( object === null ) { return; } var scripts = editor.scripts[ object.uuid ]; if ( scripts !== undefined ) { for ( var i = 0; i < scripts.length; i ++ ) { ( function ( object, script ) { var name = new UI.Input( script.name ).setWidth( '130px' ).setFontSize( '12px' ); name.onChange( function () { script.name = this.getValue(); signals.scriptChanged.dispatch(); } ); scriptsContainer.add( name ); var edit = new UI.Button( 'Edit' ); edit.setMarginLeft( '4px' ); edit.onClick( function () { signals.editScript.dispatch( object, script ); } ); scriptsContainer.add( edit ); var remove = new UI.Button( 'Remove' ); remove.setMarginLeft( '4px' ); remove.onClick( function () { if ( confirm( 'Are you sure?' ) ) { editor.removeScript( editor.selected, script ); } } ); scriptsContainer.add( remove ); scriptsContainer.add( new UI.Break() ); } )( object, scripts[ i ] ) } } } // signals signals.objectSelected.add( function ( object ) { if ( object !== null ) { container.setDisplay( 'block' ); update(); } else { container.setDisplay( 'none' ); } } ); signals.scriptAdded.add( update ); signals.scriptRemoved.add( update ); return container; }; three.js-r73/editor/js/Sidebar.Geometry.SphereGeometry.js0000644000175500017550000000477712610076566023337 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.SphereGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // radius var radiusRow = new UI.Panel(); var radius = new UI.Number( parameters.radius ).onChange( update ); radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ) ); radiusRow.add( radius ); container.add( radiusRow ); // widthSegments var widthSegmentsRow = new UI.Panel(); var widthSegments = new UI.Integer( parameters.widthSegments ).setRange( 1, Infinity ).onChange( update ); widthSegmentsRow.add( new UI.Text( 'Width segments' ).setWidth( '90px' ) ); widthSegmentsRow.add( widthSegments ); container.add( widthSegmentsRow ); // heightSegments var heightSegmentsRow = new UI.Panel(); var heightSegments = new UI.Integer( parameters.heightSegments ).setRange( 1, Infinity ).onChange( update ); heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ) ); heightSegmentsRow.add( heightSegments ); container.add( heightSegmentsRow ); // phiStart var phiStartRow = new UI.Panel(); var phiStart = new UI.Number( parameters.phiStart ).onChange( update ); phiStartRow.add( new UI.Text( 'Phi start' ).setWidth( '90px' ) ); phiStartRow.add( phiStart ); container.add( phiStartRow ); // phiLength var phiLengthRow = new UI.Panel(); var phiLength = new UI.Number( parameters.phiLength ).onChange( update ); phiLengthRow.add( new UI.Text( 'Phi length' ).setWidth( '90px' ) ); phiLengthRow.add( phiLength ); container.add( phiLengthRow ); // thetaStart var thetaStartRow = new UI.Panel(); var thetaStart = new UI.Number( parameters.thetaStart ).onChange( update ); thetaStartRow.add( new UI.Text( 'Theta start' ).setWidth( '90px' ) ); thetaStartRow.add( thetaStart ); container.add( thetaStartRow ); // thetaLength var thetaLengthRow = new UI.Panel(); var thetaLength = new UI.Number( parameters.thetaLength ).onChange( update ); thetaLengthRow.add( new UI.Text( 'Theta length' ).setWidth( '90px' ) ); thetaLengthRow.add( thetaLength ); container.add( thetaLengthRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.SphereGeometry( radius.getValue(), widthSegments.getValue(), heightSegments.getValue(), phiStart.getValue(), phiLength.getValue(), thetaStart.getValue(), thetaLength.getValue() ); object.geometry.computeBoundingSphere(); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Menubar.Examples.js0000644000175500017550000000221412610076566020361 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.Examples = function ( editor ) { var container = new UI.Panel(); container.setClass( 'menu' ); var title = new UI.Panel(); title.setClass( 'title' ); title.setTextContent( 'Examples' ); container.add( title ); var options = new UI.Panel(); options.setClass( 'options' ); container.add( options ); // Examples var items = [ { title: 'Arkanoid', file: 'arkanoid.app.json' }, { title: 'Camera', file: 'camera.app.json' }, { title: 'Particles', file: 'particles.app.json' }, { title: 'Pong', file: 'pong.app.json' } ]; var loader = new THREE.XHRLoader(); for ( var i = 0; i < items.length; i ++ ) { ( function ( i ) { var item = items[ i ]; var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( item.title ); option.onClick( function () { if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) { loader.load( 'examples/' + item.file, function ( text ) { editor.clear(); editor.fromJSON( JSON.parse( text ) ); } ); } } ); options.add( option ); } )( i ) } return container; }; three.js-r73/editor/js/History.js0000644000175500017550000000215612610076566016661 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var History = function ( editor ) { this.array = []; this.arrayLength = -1; this.current = -1; this.isRecording = true; // var scope = this; var signals = editor.signals; signals.objectAdded.add( function ( object ) { if ( scope.isRecording === false ) return; scope.add( function () { editor.removeObject( object ); editor.select( null ); }, function () { editor.addObject( object ); editor.select( object ); } ); } ); }; History.prototype = { add: function ( undo, redo ) { this.current ++; this.array[ this.current ] = { undo: undo, redo: redo }; this.arrayLength = this.current; }, undo: function () { if ( this.current < 0 ) return; this.isRecording = false; this.array[ this.current -- ].undo(); this.isRecording = true; }, redo: function () { if ( this.current === this.arrayLength ) return; this.isRecording = false; this.array[ ++ this.current ].redo(); this.isRecording = true; }, clear: function () { this.array = []; this.arrayLength = -1; this.current = -1; } }; three.js-r73/editor/js/Menubar.Help.js0000644000175500017550000000154112610076566017475 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.Help = function ( editor ) { var container = new UI.Panel(); container.setClass( 'menu' ); var title = new UI.Panel(); title.setClass( 'title' ); title.setTextContent( 'Help' ); container.add( title ); var options = new UI.Panel(); options.setClass( 'options' ); container.add( options ); // Source code var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Source code' ); option.onClick( function () { window.open( 'https://github.com/mrdoob/three.js/tree/master/editor', '_blank' ) } ); options.add( option ); // About var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'About' ); option.onClick( function () { window.open( 'http://threejs.org', '_blank' ); } ); options.add( option ); return container; }; three.js-r73/editor/js/Sidebar.Project.js0000644000175500017550000000712612610076566020200 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Project = function ( editor ) { var config = editor.config; var signals = editor.signals; var rendererTypes = { 'WebGLRenderer': THREE.WebGLRenderer, 'CanvasRenderer': THREE.CanvasRenderer, 'SVGRenderer': THREE.SVGRenderer, 'SoftwareRenderer': THREE.SoftwareRenderer, 'RaytracingRenderer': THREE.RaytracingRenderer }; var container = new UI.CollapsiblePanel(); container.setCollapsed( config.getKey( 'ui/sidebar/project/collapsed' ) ); container.onCollapsedChange( function ( boolean ) { config.setKey( 'ui/sidebar/project/collapsed', boolean ); } ); container.addStatic( new UI.Text( 'PROJECT' ) ); container.add( new UI.Break() ); // class var options = {}; for ( var key in rendererTypes ) { if ( key.indexOf( 'WebGL' ) >= 0 && System.support.webgl === false ) continue; options[ key ] = key; } var rendererTypeRow = new UI.Panel(); var rendererType = new UI.Select().setOptions( options ).setWidth( '150px' ).onChange( function () { var value = this.getValue(); if ( value === 'WebGLRenderer' ) { rendererPropertiesRow.setDisplay( '' ); } else { rendererPropertiesRow.setDisplay( 'none' ); } config.setKey( 'project/renderer', value ); updateRenderer(); } ); rendererTypeRow.add( new UI.Text( 'Renderer' ).setWidth( '90px' ) ); rendererTypeRow.add( rendererType ); container.add( rendererTypeRow ); if ( config.getKey( 'project/renderer' ) !== undefined ) { rendererType.setValue( config.getKey( 'project/renderer' ) ); } // antialiasing var rendererPropertiesRow = new UI.Panel(); rendererPropertiesRow.add( new UI.Text( '' ).setWidth( '90px' ) ); var rendererAntialiasSpan = new UI.Span().setMarginRight( '10px' ); var rendererAntialias = new UI.Checkbox( config.getKey( 'project/renderer/antialias' ) ).setLeft( '100px' ).onChange( function () { config.setKey( 'project/renderer/antialias', this.getValue() ); updateRenderer(); } ); rendererAntialiasSpan.add( rendererAntialias ); rendererAntialiasSpan.add( new UI.Text( 'antialias' ).setMarginLeft( '3px' ) ); rendererPropertiesRow.add( rendererAntialiasSpan ); // shadow var rendererShadowsSpan = new UI.Span(); var rendererShadows = new UI.Checkbox( config.getKey( 'project/renderer/shadows' ) ).setLeft( '100px' ).onChange( function () { config.setKey( 'project/renderer/shadows', this.getValue() ); updateRenderer(); } ); rendererShadowsSpan.add( rendererShadows ); rendererShadowsSpan.add( new UI.Text( 'shadows' ).setMarginLeft( '3px' ) ); rendererPropertiesRow.add( rendererShadowsSpan ); container.add( rendererPropertiesRow ); // VR var vrRow = new UI.Panel(); var vr = new UI.Checkbox( config.getKey( 'project/vr' ) ).setLeft( '100px' ).onChange( function () { config.setKey( 'project/vr', this.getValue() ); // updateRenderer(); } ); vrRow.add( new UI.Text( 'VR' ).setWidth( '90px' ) ); vrRow.add( vr ); container.add( vrRow ); // function updateRenderer() { createRenderer( rendererType.getValue(), rendererAntialias.getValue(), rendererShadows.getValue() ); } function createRenderer( type, antialias, shadows ) { if ( type === 'WebGLRenderer' && System.support.webgl === false ) { type = 'CanvasRenderer'; } var renderer = new rendererTypes[ type ]( { antialias: antialias } ); if ( shadows && renderer.shadowMap ) renderer.shadowMap.enabled = true; signals.rendererChanged.dispatch( renderer ); } createRenderer( config.getKey( 'project/renderer' ), config.getKey( 'project/renderer/antialias' ), config.getKey( 'project/renderer/shadows' ) ); return container; } three.js-r73/editor/js/Sidebar.Geometry.CircleGeometry.js0000644000175500017550000000300112610076566023265 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.CircleGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // radius var radiusRow = new UI.Panel(); var radius = new UI.Number( parameters.radius ).onChange( update ); radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ) ); radiusRow.add( radius ); container.add( radiusRow ); // segments var segmentsRow = new UI.Panel(); var segments = new UI.Integer( parameters.segments ).setRange( 3, Infinity ).onChange( update ); segmentsRow.add( new UI.Text( 'Segments' ).setWidth( '90px' ) ); segmentsRow.add( segments ); container.add( segmentsRow ); // thetaStart var thetaStartRow = new UI.Panel(); var thetaStart = new UI.Number( parameters.thetaStart ).onChange( update ); thetaStartRow.add( new UI.Text( 'Theta start' ).setWidth( '90px' ) ); thetaStartRow.add( thetaStart ); container.add( thetaStartRow ); // thetaLength var thetaLengthRow = new UI.Panel(); var thetaLength = new UI.Number( parameters.thetaLength ).onChange( update ); thetaLengthRow.add( new UI.Text( 'Theta length' ).setWidth( '90px' ) ); thetaLengthRow.add( thetaLength ); container.add( thetaLengthRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.CircleGeometry( radius.getValue(), segments.getValue(), thetaStart.getValue(), thetaLength.getValue() ); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Sidebar.Geometry.TorusGeometry.js0000644000175500017550000000351712610076566023214 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.TorusGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // radius var radiusRow = new UI.Panel(); var radius = new UI.Number( parameters.radius ).onChange( update ); radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ) ); radiusRow.add( radius ); container.add( radiusRow ); // tube var tubeRow = new UI.Panel(); var tube = new UI.Number( parameters.tube ).onChange( update ); tubeRow.add( new UI.Text( 'Tube' ).setWidth( '90px' ) ); tubeRow.add( tube ); container.add( tubeRow ); // radialSegments var radialSegmentsRow = new UI.Panel(); var radialSegments = new UI.Integer( parameters.radialSegments ).setRange( 1, Infinity ).onChange( update ); radialSegmentsRow.add( new UI.Text( 'Radial segments' ).setWidth( '90px' ) ); radialSegmentsRow.add( radialSegments ); container.add( radialSegmentsRow ); // tubularSegments var tubularSegmentsRow = new UI.Panel(); var tubularSegments = new UI.Integer( parameters.tubularSegments ).setRange( 1, Infinity ).onChange( update ); tubularSegmentsRow.add( new UI.Text( 'Tubular segments' ).setWidth( '90px' ) ); tubularSegmentsRow.add( tubularSegments ); container.add( tubularSegmentsRow ); // arc var arcRow = new UI.Panel(); var arc = new UI.Number( parameters.arc ).onChange( update ); arcRow.add( new UI.Text( 'Arc' ).setWidth( '90px' ) ); arcRow.add( arc ); container.add( arcRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.TorusGeometry( radius.getValue(), tube.getValue(), radialSegments.getValue(), tubularSegments.getValue(), arc.getValue() ); object.geometry.computeBoundingSphere(); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Sidebar.Geometry.IcosahedronGeometry.js0000644000175500017550000000170612610076566024334 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.IcosahedronGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // radius var radiusRow = new UI.Panel(); var radius = new UI.Number( parameters.radius ).onChange( update ); radiusRow.add( new UI.Text( 'Radius' ).setWidth( '90px' ) ); radiusRow.add( radius ); container.add( radiusRow ); // detail var detailRow = new UI.Panel(); var detail = new UI.Integer( parameters.detail ).setRange( 0, Infinity ).onChange( update ); detailRow.add( new UI.Text( 'Detail' ).setWidth( '90px' ) ); detailRow.add( detail ); container.add( detailRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.IcosahedronGeometry( radius.getValue(), detail.getValue() ); object.geometry.computeBoundingSphere(); signals.objectChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Sidebar.Geometry.TeapotBufferGeometry.js0000644000175500017550000000422112610076566024457 0ustar debacledebacle/** * @author tschw */ Sidebar.Geometry.TeapotBufferGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // size var sizeRow = new UI.Panel(); var size = new UI.Number( parameters.size ).onChange( update ); sizeRow.add( new UI.Text( 'Size' ).setWidth( '90px' ) ); sizeRow.add( size ); container.add( sizeRow ); // segments var segmentsRow = new UI.Panel(); var segments = new UI.Integer( parameters.segments ).setRange( 1, Infinity ).onChange( update ); segmentsRow.add( new UI.Text( 'Segments' ).setWidth( '90px' ) ); segmentsRow.add( segments ); container.add( segmentsRow ); // bottom var bottomRow = new UI.Panel(); var bottom = new UI.Checkbox( parameters.bottom ).onChange( update ); bottomRow.add( new UI.Text( 'Bottom' ).setWidth( '90px' ) ); bottomRow.add( bottom ); container.add( bottomRow ); // lid var lidRow = new UI.Panel(); var lid = new UI.Checkbox( parameters.lid ).onChange( update ); lidRow.add( new UI.Text( 'Lid' ).setWidth( '90px' ) ); lidRow.add( lid ); container.add( lidRow ); // body var bodyRow = new UI.Panel(); var body = new UI.Checkbox( parameters.body ).onChange( update ); bodyRow.add( new UI.Text( 'Body' ).setWidth( '90px' ) ); bodyRow.add( body ); container.add( bodyRow ); // fitted lid var fitLidRow = new UI.Panel(); var fitLid = new UI.Checkbox( parameters.fitLid ).onChange( update ); fitLidRow.add( new UI.Text( 'Fitted Lid' ).setWidth( '90px' ) ); fitLidRow.add( fitLid ); container.add( fitLidRow ); // blinn-sized var blinnRow = new UI.Panel(); var blinn = new UI.Checkbox( parameters.blinn ).onChange( update ); blinnRow.add( new UI.Text( 'Blinn-scaled' ).setWidth( '90px' ) ); blinnRow.add( blinn ); container.add( blinnRow ); function update() { object.geometry.dispose(); object.geometry = new THREE.TeapotBufferGeometry( size.getValue(), segments.getValue(), bottom.getValue(), lid.getValue(), body.getValue(), fitLid.getValue(), blinn.getValue() ); object.geometry.computeBoundingSphere(); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Sidebar.Geometry.js0000644000175500017550000000757612610076566020376 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry = function ( editor ) { var signals = editor.signals; var container = new UI.CollapsiblePanel(); container.setCollapsed( editor.config.getKey( 'ui/sidebar/geometry/collapsed' ) ); container.onCollapsedChange( function ( boolean ) { editor.config.setKey( 'ui/sidebar/geometry/collapsed', boolean ); } ); container.setDisplay( 'none' ); var geometryType = new UI.Text().setTextTransform( 'uppercase' ); container.addStatic( geometryType ); // Actions var objectActions = new UI.Select().setPosition('absolute').setRight( '8px' ).setFontSize( '11px' ); objectActions.setOptions( { 'Actions': 'Actions', 'Center': 'Center', 'Convert': 'Convert', 'Flatten': 'Flatten' } ); objectActions.onClick( function ( event ) { event.stopPropagation(); // Avoid panel collapsing } ); objectActions.onChange( function ( event ) { var action = this.getValue(); var object = editor.selected; var geometry = object.geometry; if ( confirm( action + ' ' + object.name + '?' ) === false ) return; switch ( action ) { case 'Center': var offset = geometry.center(); object.position.sub( offset ); editor.signals.geometryChanged.dispatch( geometry ); editor.signals.objectChanged.dispatch( object ); break; case 'Convert': if ( geometry instanceof THREE.Geometry ) { object.geometry = new THREE.BufferGeometry().fromGeometry( geometry ); signals.geometryChanged.dispatch( object ); } break; case 'Flatten': geometry.applyMatrix( object.matrix ); object.position.set( 0, 0, 0 ); object.rotation.set( 0, 0, 0 ); object.scale.set( 1, 1, 1 ); editor.signals.geometryChanged.dispatch( geometry ); editor.signals.objectChanged.dispatch( object ); break; } this.setValue( 'Actions' ); signals.objectChanged.dispatch( object ); } ); container.addStatic( objectActions ); container.add( new UI.Break() ); // uuid var geometryUUIDRow = new UI.Panel(); var geometryUUID = new UI.Input().setWidth( '115px' ).setFontSize( '12px' ).setDisabled( true ); var geometryUUIDRenew = new UI.Button( '⟳' ).setMarginLeft( '7px' ).onClick( function () { geometryUUID.setValue( THREE.Math.generateUUID() ); editor.selected.geometry.uuid = geometryUUID.getValue(); } ); geometryUUIDRow.add( new UI.Text( 'UUID' ).setWidth( '90px' ) ); geometryUUIDRow.add( geometryUUID ); geometryUUIDRow.add( geometryUUIDRenew ); container.add( geometryUUIDRow ); // name var geometryNameRow = new UI.Panel(); var geometryName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () { editor.setGeometryName( editor.selected.geometry, geometryName.getValue() ); } ); geometryNameRow.add( new UI.Text( 'Name' ).setWidth( '90px' ) ); geometryNameRow.add( geometryName ); container.add( geometryNameRow ); // geometry container.add( new Sidebar.Geometry.Geometry( signals ) ); // buffergeometry container.add( new Sidebar.Geometry.BufferGeometry( signals ) ); // parameters var parameters = new UI.Panel(); container.add( parameters ); // function build() { var object = editor.selected; if ( object && object.geometry ) { var geometry = object.geometry; container.setDisplay( 'block' ); geometryType.setValue( geometry.type ); geometryUUID.setValue( geometry.uuid ); geometryName.setValue( geometry.name ); // parameters.clear(); if ( geometry.type === 'BufferGeometry' || geometry.type === 'Geometry' ) { parameters.add( new Sidebar.Geometry.Modifiers( signals, object ) ); } else if ( Sidebar.Geometry[ geometry.type ] !== undefined ) { parameters.add( new Sidebar.Geometry[ geometry.type ]( signals, object ) ); } } else { container.setDisplay( 'none' ); } } signals.objectSelected.add( build ); signals.geometryChanged.add( build ); return container; } three.js-r73/editor/js/Sidebar.Geometry.PlaneGeometry.js0000644000175500017550000000314512610076566023134 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.PlaneGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // width var widthRow = new UI.Panel(); var width = new UI.Number( parameters.width ).onChange( update ); widthRow.add( new UI.Text( 'Width' ).setWidth( '90px' ) ); widthRow.add( width ); container.add( widthRow ); // height var heightRow = new UI.Panel(); var height = new UI.Number( parameters.height ).onChange( update ); heightRow.add( new UI.Text( 'Height' ).setWidth( '90px' ) ); heightRow.add( height ); container.add( heightRow ); // widthSegments var widthSegmentsRow = new UI.Panel(); var widthSegments = new UI.Integer( parameters.widthSegments ).setRange( 1, Infinity ).onChange( update ); widthSegmentsRow.add( new UI.Text( 'Width segments' ).setWidth( '90px' ) ); widthSegmentsRow.add( widthSegments ); container.add( widthSegmentsRow ); // heightSegments var heightSegmentsRow = new UI.Panel(); var heightSegments = new UI.Integer( parameters.heightSegments ).setRange( 1, Infinity ).onChange( update ); heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ) ); heightSegmentsRow.add( heightSegments ); container.add( heightSegmentsRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.PlaneGeometry( width.getValue(), height.getValue(), widthSegments.getValue(), heightSegments.getValue() ); object.geometry.computeBoundingSphere(); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Player.js0000644000175500017550000000156312610076566016455 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Player = function ( editor ) { var signals = editor.signals; var container = new UI.Panel(); container.setId( 'player' ); container.setPosition( 'absolute' ); container.setDisplay( 'none' ); // var player = new APP.Player(); window.addEventListener( 'resize', function () { if ( player.dom === undefined ) return; player.setSize( container.dom.clientWidth, container.dom.clientHeight ); } ); signals.startPlayer.add( function () { container.setDisplay( '' ); player.load( editor.toJSON() ); player.setSize( container.dom.clientWidth, container.dom.clientHeight ); player.play(); container.dom.appendChild( player.dom ); } ); signals.stopPlayer.add( function () { container.setDisplay( 'none' ); player.stop(); container.dom.removeChild( player.dom ); } ); return container; }; three.js-r73/editor/js/Sidebar.Geometry.Geometry.js0000644000175500017550000000203312610076566022147 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.Geometry = function ( signals ) { var container = new UI.Panel(); // vertices var verticesRow = new UI.Panel(); var vertices = new UI.Text().setFontSize( '12px' ); verticesRow.add( new UI.Text( 'Vertices' ).setWidth( '90px' ) ); verticesRow.add( vertices ); container.add( verticesRow ); // faces var facesRow = new UI.Panel(); var faces = new UI.Text().setFontSize( '12px' ); facesRow.add( new UI.Text( 'Faces' ).setWidth( '90px' ) ); facesRow.add( faces ); container.add( facesRow ); // var update = function ( object ) { if ( object === null ) return; var geometry = object.geometry; if ( geometry instanceof THREE.Geometry ) { container.setDisplay( 'block' ); vertices.setValue( ( geometry.vertices.length ).format() ); faces.setValue( ( geometry.faces.length ).format() ); } else { container.setDisplay( 'none' ); } }; signals.objectSelected.add( update ); signals.geometryChanged.add( update ); return container; } three.js-r73/editor/js/Menubar.Status.js0000644000175500017550000000161112610076566020066 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.Status = function ( editor ) { var container = new UI.Panel(); container.setClass( 'menu right' ); var checkbox = new UI.Checkbox( editor.config.getKey( 'autosave' ) ); checkbox.onChange( function () { var value = this.getValue(); editor.config.setKey( 'autosave', value ); if ( value === true ) { editor.signals.sceneGraphChanged.dispatch(); } } ); container.add( checkbox ); var text = new UI.Text( 'autosave' ); text.setClass( 'title' ); container.add( text ); editor.signals.savingStarted.add( function () { text.setTextDecoration( 'underline' ); } ); editor.signals.savingFinished.add( function () { text.setTextDecoration( 'none' ); } ); var version = new UI.Text( 'r' + THREE.REVISION ); version.setClass( 'title' ); version.setOpacity( 0.5 ); container.add( version ); return container; }; three.js-r73/editor/js/Viewport.Info.js0000644000175500017550000000354612610076566017735 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Viewport.Info = function ( editor ) { var signals = editor.signals; var container = new UI.Panel(); container.setId( 'info' ); container.setPosition( 'absolute' ); container.setLeft( '10px' ); container.setBottom( '10px' ); container.setFontSize( '12px' ); container.setColor( '#fff' ); var objectsText = new UI.Text( '0' ).setMarginLeft( '6px' ); var verticesText = new UI.Text( '0' ).setMarginLeft( '6px' ); var trianglesText = new UI.Text( '0' ).setMarginLeft( '6px' ); container.add( new UI.Text( 'objects' ), objectsText, new UI.Break() ); container.add( new UI.Text( 'vertices' ), verticesText, new UI.Break() ); container.add( new UI.Text( 'triangles' ), trianglesText, new UI.Break() ); signals.objectAdded.add( update ); signals.objectRemoved.add( update ); signals.geometryChanged.add( update ); // function update() { var scene = editor.scene; var objects = 0, vertices = 0, triangles = 0; for ( var i = 0, l = scene.children.length; i < l; i ++ ) { var object = scene.children[ i ]; object.traverseVisible( function ( object ) { objects ++; if ( object instanceof THREE.Mesh ) { var geometry = object.geometry; if ( geometry instanceof THREE.Geometry ) { vertices += geometry.vertices.length; triangles += geometry.faces.length; } else if ( geometry instanceof THREE.BufferGeometry ) { if ( geometry.index !== null ) { vertices += geometry.index.count * 3; triangles += geometry.index.count; } else { vertices += geometry.attributes.position.count; triangles += geometry.attributes.position.count / 3; } } } } ); } objectsText.setValue( objects.format() ); verticesText.setValue( vertices.format() ); trianglesText.setValue( triangles.format() ); } return container; } three.js-r73/editor/js/Sidebar.Geometry.CylinderGeometry.js0000644000175500017550000000437112610076566023650 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Sidebar.Geometry.CylinderGeometry = function ( signals, object ) { var container = new UI.Panel(); var parameters = object.geometry.parameters; // radiusTop var radiusTopRow = new UI.Panel(); var radiusTop = new UI.Number( parameters.radiusTop ).onChange( update ); radiusTopRow.add( new UI.Text( 'Radius top' ).setWidth( '90px' ) ); radiusTopRow.add( radiusTop ); container.add( radiusTopRow ); // radiusBottom var radiusBottomRow = new UI.Panel(); var radiusBottom = new UI.Number( parameters.radiusBottom ).onChange( update ); radiusBottomRow.add( new UI.Text( 'Radius bottom' ).setWidth( '90px' ) ); radiusBottomRow.add( radiusBottom ); container.add( radiusBottomRow ); // height var heightRow = new UI.Panel(); var height = new UI.Number( parameters.height ).onChange( update ); heightRow.add( new UI.Text( 'Height' ).setWidth( '90px' ) ); heightRow.add( height ); container.add( heightRow ); // radialSegments var radialSegmentsRow = new UI.Panel(); var radialSegments = new UI.Integer( parameters.radialSegments ).setRange( 1, Infinity ).onChange( update ); radialSegmentsRow.add( new UI.Text( 'Radial segments' ).setWidth( '90px' ) ); radialSegmentsRow.add( radialSegments ); container.add( radialSegmentsRow ); // heightSegments var heightSegmentsRow = new UI.Panel(); var heightSegments = new UI.Integer( parameters.heightSegments ).setRange( 1, Infinity ).onChange( update ); heightSegmentsRow.add( new UI.Text( 'Height segments' ).setWidth( '90px' ) ); heightSegmentsRow.add( heightSegments ); container.add( heightSegmentsRow ); // openEnded var openEndedRow = new UI.Panel(); var openEnded = new UI.Checkbox( parameters.openEnded ).onChange( update ); openEndedRow.add( new UI.Text( 'Open ended' ).setWidth( '90px' ) ); openEndedRow.add( openEnded ); container.add( openEndedRow ); // function update() { object.geometry.dispose(); object.geometry = new THREE.CylinderGeometry( radiusTop.getValue(), radiusBottom.getValue(), height.getValue(), radialSegments.getValue(), heightSegments.getValue(), openEnded.getValue() ); object.geometry.computeBoundingSphere(); signals.geometryChanged.dispatch( object ); } return container; } three.js-r73/editor/js/Viewport.js0000644000175500017550000002515212610076566017040 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Viewport = function ( editor ) { var signals = editor.signals; var container = new UI.Panel(); container.setId( 'viewport' ); container.setPosition( 'absolute' ); container.add( new Viewport.Info( editor ) ); var scene = editor.scene; var sceneHelpers = editor.sceneHelpers; var objects = []; // helpers var grid = new THREE.GridHelper( 500, 25 ); sceneHelpers.add( grid ); // var camera = editor.camera; // var selectionBox = new THREE.BoxHelper(); selectionBox.material.depthTest = false; selectionBox.material.transparent = true; selectionBox.visible = false; sceneHelpers.add( selectionBox ); var matrix = new THREE.Matrix4(); var transformControls = new THREE.TransformControls( camera, container.dom ); transformControls.addEventListener( 'change', function () { var object = transformControls.object; if ( object !== undefined ) { selectionBox.update( object ); if ( editor.helpers[ object.id ] !== undefined ) { editor.helpers[ object.id ].update(); } } render(); } ); transformControls.addEventListener( 'mouseDown', function () { var object = transformControls.object; matrix.copy( object.matrix ); controls.enabled = false; } ); transformControls.addEventListener( 'mouseUp', function () { var object = transformControls.object; if ( matrix.equals( object.matrix ) === false ) { ( function ( matrix1, matrix2 ) { editor.history.add( function () { matrix1.decompose( object.position, object.quaternion, object.scale ); signals.objectChanged.dispatch( object ); }, function () { matrix2.decompose( object.position, object.quaternion, object.scale ); signals.objectChanged.dispatch( object ); } ); } )( matrix.clone(), object.matrix.clone() ); } signals.objectChanged.dispatch( object ); controls.enabled = true; } ); sceneHelpers.add( transformControls ); // fog var oldFogType = "None"; var oldFogColor = 0xaaaaaa; var oldFogNear = 1; var oldFogFar = 5000; var oldFogDensity = 0.00025; // object picking var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); // events function getIntersects( point, objects ) { mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 ); raycaster.setFromCamera( mouse, camera ); return raycaster.intersectObjects( objects ); }; var onDownPosition = new THREE.Vector2(); var onUpPosition = new THREE.Vector2(); var onDoubleClickPosition = new THREE.Vector2(); function getMousePosition( dom, x, y ) { var rect = dom.getBoundingClientRect(); return [ ( x - rect.left ) / rect.width, ( y - rect.top ) / rect.height ]; }; function handleClick() { if ( onDownPosition.distanceTo( onUpPosition ) == 0 ) { var intersects = getIntersects( onUpPosition, objects ); if ( intersects.length > 0 ) { var object = intersects[ 0 ].object; if ( object.userData.object !== undefined ) { // helper editor.select( object.userData.object ); } else { editor.select( object ); } } else { editor.select( null ); } render(); } }; function onMouseDown( event ) { event.preventDefault(); var array = getMousePosition( container.dom, event.clientX, event.clientY ); onDownPosition.fromArray( array ); document.addEventListener( 'mouseup', onMouseUp, false ); }; function onMouseUp( event ) { var array = getMousePosition( container.dom, event.clientX, event.clientY ); onUpPosition.fromArray( array ); handleClick(); document.removeEventListener( 'mouseup', onMouseUp, false ); }; function onTouchStart( event ) { var touch = event.changedTouches[ 0 ]; var array = getMousePosition( container.dom, touch.clientX, touch.clientY ); onDownPosition.fromArray( array ); document.addEventListener( 'touchend', onTouchEnd, false ); }; function onTouchEnd( event ) { var touch = event.changedTouches[ 0 ]; var array = getMousePosition( container.dom, touch.clientX, touch.clientY ); onUpPosition.fromArray( array ); handleClick(); document.removeEventListener( 'touchend', onTouchEnd, false ); }; function onDoubleClick( event ) { var array = getMousePosition( container.dom, event.clientX, event.clientY ); onDoubleClickPosition.fromArray( array ); var intersects = getIntersects( onDoubleClickPosition, objects ); if ( intersects.length > 0 ) { var intersect = intersects[ 0 ]; signals.objectFocused.dispatch( intersect.object ); } }; container.dom.addEventListener( 'mousedown', onMouseDown, false ); container.dom.addEventListener( 'touchstart', onTouchStart, false ); container.dom.addEventListener( 'dblclick', onDoubleClick, false ); // controls need to be added *after* main logic, // otherwise controls.enabled doesn't work. var controls = new THREE.EditorControls( camera, container.dom ); controls.addEventListener( 'change', function () { transformControls.update(); signals.cameraChanged.dispatch( camera ); } ); // signals signals.editorCleared.add( function () { controls.center.set( 0, 0, 0 ); render(); } ); var clearColor; signals.themeChanged.add( function ( value ) { switch ( value ) { case 'css/light.css': grid.setColors( 0x444444, 0x888888 ); clearColor = 0xaaaaaa; break; case 'css/dark.css': grid.setColors( 0xbbbbbb, 0x888888 ); clearColor = 0x333333; break; } renderer.setClearColor( clearColor ); render(); } ); signals.transformModeChanged.add( function ( mode ) { transformControls.setMode( mode ); } ); signals.snapChanged.add( function ( dist ) { transformControls.setTranslationSnap( dist ); } ); signals.spaceChanged.add( function ( space ) { transformControls.setSpace( space ); } ); signals.rendererChanged.add( function ( newRenderer ) { if ( renderer !== null ) { container.dom.removeChild( renderer.domElement ); } renderer = newRenderer; renderer.autoClear = false; renderer.autoUpdateScene = false; renderer.setClearColor( clearColor ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight ); container.dom.appendChild( renderer.domElement ); render(); } ); signals.sceneGraphChanged.add( function () { render(); } ); var saveTimeout; signals.cameraChanged.add( function () { render(); } ); signals.objectSelected.add( function ( object ) { selectionBox.visible = false; transformControls.detach(); if ( object !== null ) { if ( object.geometry !== undefined && object instanceof THREE.Sprite === false ) { selectionBox.update( object ); selectionBox.visible = true; } transformControls.attach( object ); } render(); } ); signals.objectFocused.add( function ( object ) { controls.focus( object ); } ); signals.geometryChanged.add( function ( geometry ) { selectionBox.update( editor.selected ); render(); } ); signals.objectAdded.add( function ( object ) { var materialsNeedUpdate = false; object.traverse( function ( child ) { if ( child instanceof THREE.Light ) materialsNeedUpdate = true; objects.push( child ); } ); if ( materialsNeedUpdate === true ) updateMaterials(); } ); signals.objectChanged.add( function ( object ) { selectionBox.update( object ); transformControls.update(); if ( object instanceof THREE.PerspectiveCamera ) { object.updateProjectionMatrix(); } if ( editor.helpers[ object.id ] !== undefined ) { editor.helpers[ object.id ].update(); } render(); } ); signals.objectRemoved.add( function ( object ) { var materialsNeedUpdate = false; object.traverse( function ( child ) { if ( child instanceof THREE.Light ) materialsNeedUpdate = true; objects.splice( objects.indexOf( child ), 1 ); } ); if ( materialsNeedUpdate === true ) updateMaterials(); } ); signals.helperAdded.add( function ( object ) { objects.push( object.getObjectByName( 'picker' ) ); } ); signals.helperRemoved.add( function ( object ) { objects.splice( objects.indexOf( object.getObjectByName( 'picker' ) ), 1 ); } ); signals.materialChanged.add( function ( material ) { render(); } ); signals.fogTypeChanged.add( function ( fogType ) { if ( fogType !== oldFogType ) { if ( fogType === "None" ) { scene.fog = null; } else if ( fogType === "Fog" ) { scene.fog = new THREE.Fog( oldFogColor, oldFogNear, oldFogFar ); } else if ( fogType === "FogExp2" ) { scene.fog = new THREE.FogExp2( oldFogColor, oldFogDensity ); } updateMaterials(); oldFogType = fogType; } render(); } ); signals.fogColorChanged.add( function ( fogColor ) { oldFogColor = fogColor; updateFog( scene ); render(); } ); signals.fogParametersChanged.add( function ( near, far, density ) { oldFogNear = near; oldFogFar = far; oldFogDensity = density; updateFog( scene ); render(); } ); signals.windowResize.add( function () { camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight; camera.updateProjectionMatrix(); renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight ); render(); } ); signals.showGridChanged.add( function ( showGrid ) { grid.visible = showGrid; render(); } ); // var renderer = null; animate(); // function updateMaterials() { editor.scene.traverse( function ( node ) { if ( node.material ) { node.material.needsUpdate = true; if ( node.material instanceof THREE.MeshFaceMaterial ) { for ( var i = 0; i < node.material.materials.length; i ++ ) { node.material.materials[ i ].needsUpdate = true; } } } } ); } function updateFog( root ) { if ( root.fog ) { root.fog.color.setHex( oldFogColor ); if ( root.fog.near !== undefined ) root.fog.near = oldFogNear; if ( root.fog.far !== undefined ) root.fog.far = oldFogFar; if ( root.fog.density !== undefined ) root.fog.density = oldFogDensity; } } function animate() { requestAnimationFrame( animate ); /* // animations if ( THREE.AnimationHandler.animations.length > 0 ) { THREE.AnimationHandler.update( 0.016 ); for ( var i = 0, l = sceneHelpers.children.length; i < l; i ++ ) { var helper = sceneHelpers.children[ i ]; if ( helper instanceof THREE.SkeletonHelper ) { helper.update(); } } render(); } */ } function render() { sceneHelpers.updateMatrixWorld(); scene.updateMatrixWorld(); renderer.clear(); renderer.render( scene, camera ); if ( renderer instanceof THREE.RaytracingRenderer === false ) { renderer.render( sceneHelpers, camera ); } } return container; } three.js-r73/editor/js/Toolbar.js0000644000175500017550000000320312610076566016614 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Toolbar = function ( editor ) { var signals = editor.signals; var container = new UI.Panel(); container.setId( 'toolbar' ); var buttons = new UI.Panel(); container.add( buttons ); // translate / rotate / scale var translate = new UI.Button( 'translate' ).onClick( function () { signals.transformModeChanged.dispatch( 'translate' ); } ); buttons.add( translate ); var rotate = new UI.Button( 'rotate' ).onClick( function () { signals.transformModeChanged.dispatch( 'rotate' ); } ); buttons.add( rotate ); var scale = new UI.Button( 'scale' ).onClick( function () { signals.transformModeChanged.dispatch( 'scale' ); } ); buttons.add( scale ); // grid var grid = new UI.Number( 25 ).setWidth( '40px' ).onChange( update ); buttons.add( new UI.Text( 'Grid: ' ) ); buttons.add( grid ); var snap = new UI.Checkbox( false ).onChange( update ).setMarginLeft( '10px' ); buttons.add( snap ); buttons.add( new UI.Text( 'snap' ).setMarginLeft( '3px' ) ); var local = new UI.Checkbox( false ).onChange( update ).setMarginLeft( '10px' ); buttons.add( local ); buttons.add( new UI.Text( 'local' ).setMarginLeft( '3px' ) ); var showGrid = new UI.Checkbox().onChange( update ).setValue( true ).setMarginLeft( '10px' ); buttons.add( showGrid ); buttons.add( new UI.Text( 'show' ).setMarginLeft( '3px' ) ); function update() { signals.snapChanged.dispatch( snap.getValue() === true ? grid.getValue() : null ); signals.spaceChanged.dispatch( local.getValue() === true ? "local" : "world" ); signals.showGridChanged.dispatch( showGrid.getValue() ); } return container; } three.js-r73/editor/js/Menubar.Add.js0000644000175500017550000002206212610076566017276 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.Add = function ( editor ) { var container = new UI.Panel(); container.setClass( 'menu' ); var title = new UI.Panel(); title.setClass( 'title' ); title.setTextContent( 'Add' ); container.add( title ); var options = new UI.Panel(); options.setClass( 'options' ); container.add( options ); // var meshCount = 0; var lightCount = 0; var cameraCount = 0; editor.signals.editorCleared.add( function () { meshCount = 0; lightCount = 0; cameraCount = 0; } ); // Group var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Group' ); option.onClick( function () { var mesh = new THREE.Group(); mesh.name = 'Group ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // options.add( new UI.HorizontalRule() ); // Plane var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Plane' ); option.onClick( function () { var width = 200; var height = 200; var widthSegments = 1; var heightSegments = 1; var geometry = new THREE.PlaneGeometry( width, height, widthSegments, heightSegments ); var material = new THREE.MeshPhongMaterial(); var mesh = new THREE.Mesh( geometry, material ); mesh.name = 'Plane ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // Box var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Box' ); option.onClick( function () { var width = 100; var height = 100; var depth = 100; var widthSegments = 1; var heightSegments = 1; var depthSegments = 1; var geometry = new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() ); mesh.name = 'Box ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // Circle var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Circle' ); option.onClick( function () { var radius = 20; var segments = 32; var geometry = new THREE.CircleGeometry( radius, segments ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() ); mesh.name = 'Circle ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // Cylinder var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Cylinder' ); option.onClick( function () { var radiusTop = 20; var radiusBottom = 20; var height = 100; var radiusSegments = 32; var heightSegments = 1; var openEnded = false; var geometry = new THREE.CylinderGeometry( radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() ); mesh.name = 'Cylinder ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // Sphere var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Sphere' ); option.onClick( function () { var radius = 75; var widthSegments = 32; var heightSegments = 16; var phiStart = 0; var phiLength = Math.PI * 2; var thetaStart = 0; var thetaLength = Math.PI; var geometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() ); mesh.name = 'Sphere ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // Icosahedron var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Icosahedron' ); option.onClick( function () { var radius = 75; var detail = 2; var geometry = new THREE.IcosahedronGeometry( radius, detail ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() ); mesh.name = 'Icosahedron ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // Torus var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Torus' ); option.onClick( function () { var radius = 100; var tube = 40; var radialSegments = 8; var tubularSegments = 6; var arc = Math.PI * 2; var geometry = new THREE.TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() ); mesh.name = 'Torus ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); // TorusKnot var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'TorusKnot' ); option.onClick( function () { var radius = 100; var tube = 40; var radialSegments = 64; var tubularSegments = 8; var p = 2; var q = 3; var heightScale = 1; var geometry = new THREE.TorusKnotGeometry( radius, tube, radialSegments, tubularSegments, p, q, heightScale ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() ); mesh.name = 'TorusKnot ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); /* // Teapot var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Teapot' ); option.onClick( function () { var size = 50; var segments = 10; var bottom = true; var lid = true; var body = true; var fitLid = false; var blinnScale = true; var material = new THREE.MeshPhongMaterial(); material.side = 2; var geometry = new THREE.TeapotBufferGeometry( size, segments, bottom, lid, body, fitLid, blinnScale ); var mesh = new THREE.Mesh( geometry, material ); mesh.name = 'Teapot ' + ( ++ meshCount ); editor.addObject( mesh ); editor.select( mesh ); } ); options.add( option ); */ // Sprite var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Sprite' ); option.onClick( function () { var sprite = new THREE.Sprite( new THREE.SpriteMaterial() ); sprite.name = 'Sprite ' + ( ++ meshCount ); editor.addObject( sprite ); editor.select( sprite ); } ); options.add( option ); // options.add( new UI.HorizontalRule() ); // PointLight var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'PointLight' ); option.onClick( function () { var color = 0xffffff; var intensity = 1; var distance = 0; var light = new THREE.PointLight( color, intensity, distance ); light.name = 'PointLight ' + ( ++ lightCount ); editor.addObject( light ); editor.select( light ); } ); options.add( option ); // SpotLight var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'SpotLight' ); option.onClick( function () { var color = 0xffffff; var intensity = 1; var distance = 0; var angle = Math.PI * 0.1; var exponent = 10; var light = new THREE.SpotLight( color, intensity, distance, angle, exponent ); light.name = 'SpotLight ' + ( ++ lightCount ); light.target.name = 'SpotLight ' + ( lightCount ) + ' Target'; light.position.set( 0.5, 1, 0.75 ).multiplyScalar( 200 ); editor.addObject( light ); editor.select( light ); } ); options.add( option ); // DirectionalLight var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'DirectionalLight' ); option.onClick( function () { var color = 0xffffff; var intensity = 1; var light = new THREE.DirectionalLight( color, intensity ); light.name = 'DirectionalLight ' + ( ++ lightCount ); light.target.name = 'DirectionalLight ' + ( lightCount ) + ' Target'; light.position.set( 0.5, 1, 0.75 ).multiplyScalar( 200 ); editor.addObject( light ); editor.select( light ); } ); options.add( option ); // HemisphereLight var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'HemisphereLight' ); option.onClick( function () { var skyColor = 0x00aaff; var groundColor = 0xffaa00; var intensity = 1; var light = new THREE.HemisphereLight( skyColor, groundColor, intensity ); light.name = 'HemisphereLight ' + ( ++ lightCount ); light.position.set( 0.5, 1, 0.75 ).multiplyScalar( 200 ); editor.addObject( light ); editor.select( light ); } ); options.add( option ); // AmbientLight var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'AmbientLight' ); option.onClick( function() { var color = 0x222222; var light = new THREE.AmbientLight( color ); light.name = 'AmbientLight ' + ( ++ lightCount ); editor.addObject( light ); editor.select( light ); } ); options.add( option ); // options.add( new UI.HorizontalRule() ); // PerspectiveCamera var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'PerspectiveCamera' ); option.onClick( function() { var camera = new THREE.PerspectiveCamera( 50, 1, 1, 10000 ); camera.name = 'PerspectiveCamera ' + ( ++ cameraCount ); editor.addObject( camera ); editor.select( camera ); } ); options.add( option ); return container; } three.js-r73/editor/js/Menubar.File.js0000644000175500017550000001374312610076566017473 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.File = function ( editor ) { var container = new UI.Panel(); container.setClass( 'menu' ); var title = new UI.Panel(); title.setClass( 'title' ); title.setTextContent( 'File' ); container.add( title ); var options = new UI.Panel(); options.setClass( 'options' ); container.add( options ); // New var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'New' ); option.onClick( function () { if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) { editor.clear(); } } ); options.add( option ); // options.add( new UI.HorizontalRule() ); // Import var fileInput = document.createElement( 'input' ); fileInput.type = 'file'; fileInput.addEventListener( 'change', function ( event ) { editor.loader.loadFile( fileInput.files[ 0 ] ); } ); var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Import' ); option.onClick( function () { fileInput.click(); } ); options.add( option ); // options.add( new UI.HorizontalRule() ); // Export Geometry var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Export Geometry' ); option.onClick( function () { var object = editor.selected; if ( object === null ) { alert( 'No object selected.' ); return; } var geometry = object.geometry; if ( geometry === undefined ) { alert( 'The selected object doesn\'t have geometry.' ); return; } var output = geometry.toJSON(); try { output = JSON.stringify( output, null, '\t' ); output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' ); } catch ( e ) { output = JSON.stringify( output ); } exportString( output, 'geometry.json' ); } ); options.add( option ); // Export Object var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Export Object' ); option.onClick( function () { var object = editor.selected; if ( object === null ) { alert( 'No object selected' ); return; } var output = object.toJSON(); try { output = JSON.stringify( output, null, '\t' ); output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' ); } catch ( e ) { output = JSON.stringify( output ); } exportString( output, 'model.json' ); } ); options.add( option ); // Export Scene var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Export Scene' ); option.onClick( function () { var output = editor.scene.toJSON(); try { output = JSON.stringify( output, null, '\t' ); output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' ); } catch ( e ) { output = JSON.stringify( output ); } exportString( output, 'scene.json' ); } ); options.add( option ); // Export OBJ var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Export OBJ' ); option.onClick( function () { var object = editor.selected; if ( object === null ) { alert( 'No object selected.' ); return; } var exporter = new THREE.OBJExporter(); exportString( exporter.parse( object ), 'model.obj' ); } ); options.add( option ); // Export STL var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Export STL' ); option.onClick( function () { var exporter = new THREE.STLExporter(); exportString( exporter.parse( editor.scene ), 'model.stl' ); } ); options.add( option ); // options.add( new UI.HorizontalRule() ); // Publish var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Publish' ); option.onClick( function () { var camera = editor.camera; var zip = new JSZip(); zip.file( 'index.html', [ '', '', ' ', ' three.js', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '' ].join( '\n' ) ); // var output = editor.toJSON(); output = JSON.stringify( output, null, '\t' ); output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' ); zip.file( 'app.json', output ); // var manager = new THREE.LoadingManager( function () { location.href = 'data:application/zip;base64,' + zip.generate(); } ); var loader = new THREE.XHRLoader( manager ); loader.load( 'js/libs/app.js', function ( content ) { zip.file( 'js/app.js', content ); } ); loader.load( '../build/three.min.js', function ( content ) { zip.file( 'js/three.min.js', content ); } ); } ); options.add( option ); // var link = document.createElement( 'a' ); link.style.display = 'none'; document.body.appendChild( link ); // Firefox workaround, see #6594 var exportString = function ( output, filename ) { var blob = new Blob( [ output ], { type: 'text/plain' } ); var objectURL = URL.createObjectURL( blob ); link.href = objectURL; link.download = filename || 'data.json'; link.target = '_blank'; var event = document.createEvent("MouseEvents"); event.initMouseEvent( "click", true, false, window, 0, 0, 0, 0, 0 , false, false, false, false, 0, null ); link.dispatchEvent(event); }; return container; }; three.js-r73/editor/js/Loader.js0000644000175500017550000002337012610076566016427 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Loader = function ( editor ) { var scope = this; var signals = editor.signals; this.texturePath = ''; this.loadFile = function ( file ) { var filename = file.name; var extension = filename.split( '.' ).pop().toLowerCase(); switch ( extension ) { case 'amf': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var loader = new THREE.AMFLoader(); var amfobject = loader.parse( event.target.result ); editor.addObject( amfobject ); editor.select( amfobject ); }, false ); reader.readAsArrayBuffer( file ); break; case 'awd': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var loader = new THREE.AWDLoader(); var scene = loader.parse( event.target.result ); editor.setScene( scene ); }, false ); reader.readAsArrayBuffer( file ); break; case 'babylon': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var json = JSON.parse( contents ); var loader = new THREE.BabylonLoader(); var scene = loader.parse( json ); editor.setScene( scene ); }, false ); reader.readAsText( file ); break; case 'babylonmeshdata': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var json = JSON.parse( contents ); var loader = new THREE.BabylonLoader(); var geometry = loader.parseGeometry( json ); var material = new THREE.MeshPhongMaterial(); var mesh = new THREE.Mesh( geometry, material ); mesh.name = filename; editor.addObject( mesh ); editor.select( mesh ); }, false ); reader.readAsText( file ); break; case 'ctm': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var data = new Uint8Array( event.target.result ); var stream = new CTM.Stream( data ); stream.offset = 0; var loader = new THREE.CTMLoader(); loader.createModel( new CTM.File( stream ), function( geometry ) { geometry.sourceType = "ctm"; geometry.sourceFile = file.name; var material = new THREE.MeshPhongMaterial(); var mesh = new THREE.Mesh( geometry, material ); mesh.name = filename; editor.addObject( mesh ); editor.select( mesh ); } ); }, false ); reader.readAsArrayBuffer( file ); break; case 'dae': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var loader = new THREE.ColladaLoader(); var collada = loader.parse( contents ); collada.scene.name = filename; editor.addObject( collada.scene ); editor.select( collada.scene ); }, false ); reader.readAsText( file ); break; case 'js': case 'json': case '3geo': case '3mat': case '3obj': case '3scn': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; // 2.0 if ( contents.indexOf( 'postMessage' ) !== -1 ) { var blob = new Blob( [ contents ], { type: 'text/javascript' } ); var url = URL.createObjectURL( blob ); var worker = new Worker( url ); worker.onmessage = function ( event ) { event.data.metadata = { version: 2 }; handleJSON( event.data, file, filename ); }; worker.postMessage( Date.now() ); return; } // >= 3.0 var data; try { data = JSON.parse( contents ); } catch ( error ) { alert( error ); return; } handleJSON( data, file, filename ); }, false ); reader.readAsText( file ); break; case 'kmz': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var loader = new THREE.KMZLoader(); var collada = loader.parse( event.target.result ); collada.scene.name = filename; editor.addObject( collada.scene ); editor.select( collada.scene ); }, false ); reader.readAsArrayBuffer( file ); break; case 'md2': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var geometry = new THREE.MD2Loader().parse( contents ); var material = new THREE.MeshPhongMaterial( { morphTargets: true, morphNormals: true } ); var mesh = new THREE.Mesh( geometry, material ); mesh.mixer = new THREE.AnimationMixer( mesh ) mesh.name = filename; editor.addObject( mesh ); editor.select( mesh ); }, false ); reader.readAsArrayBuffer( file ); break; case 'obj': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var object = new THREE.OBJLoader().parse( contents ); object.name = filename; editor.addObject( object ); editor.select( object ); }, false ); reader.readAsText( file ); break; case 'ply': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var geometry = new THREE.PLYLoader().parse( contents ); geometry.sourceType = "ply"; geometry.sourceFile = file.name; var material = new THREE.MeshPhongMaterial(); var mesh = new THREE.Mesh( geometry, material ); mesh.name = filename; editor.addObject( mesh ); editor.select( mesh ); }, false ); reader.readAsText( file ); break; case 'stl': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var geometry = new THREE.STLLoader().parse( contents ); geometry.sourceType = "stl"; geometry.sourceFile = file.name; var material = new THREE.MeshPhongMaterial(); var mesh = new THREE.Mesh( geometry, material ); mesh.name = filename; editor.addObject( mesh ); editor.select( mesh ); }, false ); if ( reader.readAsBinaryString !== undefined ) { reader.readAsBinaryString( file ); } else { reader.readAsArrayBuffer( file ); } break; /* case 'utf8': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var geometry = new THREE.UTF8Loader().parse( contents ); var material = new THREE.MeshLambertMaterial(); var mesh = new THREE.Mesh( geometry, material ); editor.addObject( mesh ); editor.select( mesh ); }, false ); reader.readAsBinaryString( file ); break; */ case 'vtk': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var geometry = new THREE.VTKLoader().parse( contents ); geometry.sourceType = "vtk"; geometry.sourceFile = file.name; var material = new THREE.MeshPhongMaterial(); var mesh = new THREE.Mesh( geometry, material ); mesh.name = filename; editor.addObject( mesh ); editor.select( mesh ); }, false ); reader.readAsText( file ); break; case 'wrl': var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var contents = event.target.result; var result = new THREE.VRMLLoader().parse( contents ); editor.setScene( result ); }, false ); reader.readAsText( file ); break; default: alert( 'Unsupported file format (' + extension + ').' ); break; } } var handleJSON = function ( data, file, filename ) { if ( data.metadata === undefined ) { // 2.0 data.metadata = { type: 'Geometry' }; } if ( data.metadata.type === undefined ) { // 3.0 data.metadata.type = 'Geometry'; } if ( data.metadata.version === undefined ) { data.metadata.version = data.metadata.formatVersion; } if ( data.metadata.type === 'BufferGeometry' ) { var loader = new THREE.BufferGeometryLoader(); var result = loader.parse( data ); var mesh = new THREE.Mesh( result ); editor.addObject( mesh ); editor.select( mesh ); } else if ( data.metadata.type.toLowerCase() === 'geometry' ) { var loader = new THREE.JSONLoader(); loader.setTexturePath( scope.texturePath ); var result = loader.parse( data ); var geometry = result.geometry; var material; if ( result.materials !== undefined ) { if ( result.materials.length > 1 ) { material = new THREE.MeshFaceMaterial( result.materials ); } else { material = result.materials[ 0 ]; } } else { material = new THREE.MeshPhongMaterial(); } geometry.sourceType = "ascii"; geometry.sourceFile = file.name; var mesh; if ( geometry.animation && geometry.animation.hierarchy ) { mesh = new THREE.SkinnedMesh( geometry, material ); } else { mesh = new THREE.Mesh( geometry, material ); } mesh.name = filename; editor.addObject( mesh ); editor.select( mesh ); } else if ( data.metadata.type.toLowerCase() === 'object' ) { var loader = new THREE.ObjectLoader(); loader.setTexturePath( scope.texturePath ); var result = loader.parse( data ); if ( result instanceof THREE.Scene ) { editor.setScene( result ); } else { editor.addObject( result ); editor.select( result ); } } else if ( data.metadata.type.toLowerCase() === 'scene' ) { // DEPRECATED var loader = new THREE.SceneLoader(); loader.parse( data, function ( result ) { editor.setScene( result.scene ); }, '' ); } }; } three.js-r73/editor/js/libs/0000755000175500017550000000000012640552026015600 5ustar debacledebaclethree.js-r73/editor/js/libs/ternjs/0000755000175500017550000000000012640551241017103 5ustar debacledebaclethree.js-r73/editor/js/libs/ternjs/def.js0000644000175500017550000005016212610076566020214 0ustar debacledebacle// Type description parser // // Type description JSON files (such as ecma5.json and browser.json) // are used to // // A) describe types that come from native code // // B) to cheaply load the types for big libraries, or libraries that // can't be inferred well (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return exports.init = mod; if (typeof define == "function" && define.amd) // AMD return define({init: mod}); tern.def = {init: mod}; })(function(exports, infer) { "use strict"; function hop(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } var TypeParser = exports.TypeParser = function(spec, start, base, forceNew) { this.pos = start || 0; this.spec = spec; this.base = base; this.forceNew = forceNew; }; function unwrapType(type, self, args) { return type.call ? type(self, args) : type; } function extractProp(type, prop) { if (prop == "!ret") { if (type.retval) return type.retval; var rv = new infer.AVal; type.propagate(new infer.IsCallee(infer.ANull, [], null, rv)); return rv; } else { return type.getProp(prop); } } function computedFunc(args, retType) { return function(self, cArgs) { var realArgs = []; for (var i = 0; i < args.length; i++) realArgs.push(unwrapType(args[i], self, cArgs)); return new infer.Fn(name, infer.ANull, realArgs, unwrapType(retType, self, cArgs)); }; } function computedUnion(types) { return function(self, args) { var union = new infer.AVal; for (var i = 0; i < types.length; i++) unwrapType(types[i], self, args).propagate(union); return union; }; } function computedArray(inner) { return function(self, args) { return new infer.Arr(inner(self, args)); }; } TypeParser.prototype = { eat: function(str) { if (str.length == 1 ? this.spec.charAt(this.pos) == str : this.spec.indexOf(str, this.pos) == this.pos) { this.pos += str.length; return true; } }, word: function(re) { var word = "", ch, re = re || /[\w$]/; while ((ch = this.spec.charAt(this.pos)) && re.test(ch)) { word += ch; ++this.pos; } return word; }, error: function() { throw new Error("Unrecognized type spec: " + this.spec + " (at " + this.pos + ")"); }, parseFnType: function(comp, name, top) { var args = [], names = [], computed = false; if (!this.eat(")")) for (var i = 0; ; ++i) { var colon = this.spec.indexOf(": ", this.pos), argname; if (colon != -1) { argname = this.spec.slice(this.pos, colon); if (/^[$\w?]+$/.test(argname)) this.pos = colon + 2; else argname = null; } names.push(argname); var argType = this.parseType(comp); if (argType.call) computed = true; args.push(argType); if (!this.eat(", ")) { this.eat(")") || this.error(); break; } } var retType, computeRet, computeRetStart, fn; if (this.eat(" -> ")) { var retStart = this.pos; retType = this.parseType(true); if (retType.call) { if (top) { computeRet = retType; retType = infer.ANull; computeRetStart = retStart; } else { computed = true; } } } else { retType = infer.ANull; } if (computed) return computedFunc(args, retType); if (top && (fn = this.base)) infer.Fn.call(this.base, name, infer.ANull, args, names, retType); else fn = new infer.Fn(name, infer.ANull, args, names, retType); if (computeRet) fn.computeRet = computeRet; if (computeRetStart != null) fn.computeRetSource = this.spec.slice(computeRetStart, this.pos); return fn; }, parseType: function(comp, name, top) { var main = this.parseTypeMaybeProp(comp, name, top); if (!this.eat("|")) return main; var types = [main], computed = main.call; for (;;) { var next = this.parseTypeMaybeProp(comp, name, top); types.push(next); if (next.call) computed = true; if (!this.eat("|")) break; } if (computed) return computedUnion(types); var union = new infer.AVal; for (var i = 0; i < types.length; i++) types[i].propagate(union); return union; }, parseTypeMaybeProp: function(comp, name, top) { var result = this.parseTypeInner(comp, name, top); while (comp && this.eat(".")) result = this.extendWithProp(result); return result; }, extendWithProp: function(base) { var propName = this.word(/[\w<>$!]/) || this.error(); if (base.apply) return function(self, args) { return extractProp(base(self, args), propName); }; return extractProp(base, propName); }, parseTypeInner: function(comp, name, top) { if (this.eat("fn(")) { return this.parseFnType(comp, name, top); } else if (this.eat("[")) { var inner = this.parseType(comp); this.eat("]") || this.error(); if (inner.call) return computedArray(inner); if (top && this.base) { infer.Arr.call(this.base, inner); return this.base; } return new infer.Arr(inner); } else if (this.eat("+")) { var path = this.word(/[\w$<>\.!]/); var base = parsePath(path + ".prototype"); var type; if (!(base instanceof infer.Obj)) base = parsePath(path); if (!(base instanceof infer.Obj)) return base; if (comp && this.eat("[")) return this.parsePoly(base); if (top && this.forceNew) return new infer.Obj(base); return infer.getInstance(base); } else if (comp && this.eat("!")) { var arg = this.word(/\d/); if (arg) { arg = Number(arg); return function(_self, args) {return args[arg] || infer.ANull;}; } else if (this.eat("this")) { return function(self) {return self;}; } else if (this.eat("custom:")) { var fname = this.word(/[\w$]/); return customFunctions[fname] || function() { return infer.ANull; }; } else { return this.fromWord("!" + this.word(/[\w$<>\.!]/)); } } else if (this.eat("?")) { return infer.ANull; } else { return this.fromWord(this.word(/[\w$<>\.!`]/)); } }, fromWord: function(spec) { var cx = infer.cx(); switch (spec) { case "number": return cx.num; case "string": return cx.str; case "bool": return cx.bool; case "": return cx.topScope; } if (cx.localDefs && spec in cx.localDefs) return cx.localDefs[spec]; return parsePath(spec); }, parsePoly: function(base) { var propName = "", match; if (match = this.spec.slice(this.pos).match(/^\s*(\w+)\s*=\s*/)) { propName = match[1]; this.pos += match[0].length; } var value = this.parseType(true); if (!this.eat("]")) this.error(); if (value.call) return function(self, args) { var instance = infer.getInstance(base); value(self, args).propagate(instance.defProp(propName)); return instance; }; var instance = infer.getInstance(base); value.propagate(instance.defProp(propName)); return instance; } }; function parseType(spec, name, base, forceNew) { var type = new TypeParser(spec, null, base, forceNew).parseType(false, name, true); if (/^fn\(/.test(spec)) for (var i = 0; i < type.args.length; ++i) (function(i) { var arg = type.args[i]; if (arg instanceof infer.Fn && arg.args && arg.args.length) addEffect(type, function(_self, fArgs) { var fArg = fArgs[i]; if (fArg) fArg.propagate(new infer.IsCallee(infer.cx().topScope, arg.args, null, infer.ANull)); }); })(i); return type; } function addEffect(fn, handler, replaceRet) { var oldCmp = fn.computeRet, rv = fn.retval; fn.computeRet = function(self, args, argNodes) { var handled = handler(self, args, argNodes); var old = oldCmp ? oldCmp(self, args, argNodes) : rv; return replaceRet ? handled : old; }; } var parseEffect = exports.parseEffect = function(effect, fn) { var m; if (effect.indexOf("propagate ") == 0) { var p = new TypeParser(effect, 10); var origin = p.parseType(true); if (!p.eat(" ")) p.error(); var target = p.parseType(true); addEffect(fn, function(self, args) { unwrapType(origin, self, args).propagate(unwrapType(target, self, args)); }); } else if (effect.indexOf("call ") == 0) { var andRet = effect.indexOf("and return ", 5) == 5; var p = new TypeParser(effect, andRet ? 16 : 5); var getCallee = p.parseType(true), getSelf = null, getArgs = []; if (p.eat(" this=")) getSelf = p.parseType(true); while (p.eat(" ")) getArgs.push(p.parseType(true)); addEffect(fn, function(self, args) { var callee = unwrapType(getCallee, self, args); var slf = getSelf ? unwrapType(getSelf, self, args) : infer.ANull, as = []; for (var i = 0; i < getArgs.length; ++i) as.push(unwrapType(getArgs[i], self, args)); var result = andRet ? new infer.AVal : infer.ANull; callee.propagate(new infer.IsCallee(slf, as, null, result)); return result; }, andRet); } else if (m = effect.match(/^custom (\S+)\s*(.*)/)) { var customFunc = customFunctions[m[1]]; if (customFunc) addEffect(fn, m[2] ? customFunc(m[2]) : customFunc); } else if (effect.indexOf("copy ") == 0) { var p = new TypeParser(effect, 5); var getFrom = p.parseType(true); p.eat(" "); var getTo = p.parseType(true); addEffect(fn, function(self, args) { var from = unwrapType(getFrom, self, args), to = unwrapType(getTo, self, args); from.forAllProps(function(prop, val, local) { if (local && prop != "") to.propagate(new infer.PropHasSubset(prop, val)); }); }); } else { throw new Error("Unknown effect type: " + effect); } }; var currentTopScope; var parsePath = exports.parsePath = function(path, scope) { var cx = infer.cx(), cached = cx.paths[path], origPath = path; if (cached != null) return cached; cx.paths[path] = infer.ANull; var base = scope || currentTopScope || cx.topScope; if (cx.localDefs) for (var name in cx.localDefs) { if (path.indexOf(name) == 0) { if (path == name) return cx.paths[path] = cx.localDefs[path]; if (path.charAt(name.length) == ".") { base = cx.localDefs[name]; path = path.slice(name.length + 1); break; } } } var parts = path.split("."); for (var i = 0; i < parts.length && base != infer.ANull; ++i) { var prop = parts[i]; if (prop.charAt(0) == "!") { if (prop == "!proto") { base = (base instanceof infer.Obj && base.proto) || infer.ANull; } else { var fn = base.getFunctionType(); if (!fn) { base = infer.ANull; } else if (prop == "!ret") { base = fn.retval && fn.retval.getType(false) || infer.ANull; } else { var arg = fn.args && fn.args[Number(prop.slice(1))]; base = (arg && arg.getType(false)) || infer.ANull; } } } else if (base instanceof infer.Obj) { var propVal = (prop == "prototype" && base instanceof infer.Fn) ? base.getProp(prop) : base.props[prop]; if (!propVal || propVal.isEmpty()) base = infer.ANull; else base = propVal.types[0]; } } // Uncomment this to get feedback on your poorly written .json files // if (base == infer.ANull) console.error("bad path: " + origPath + " (" + cx.curOrigin + ")"); cx.paths[origPath] = base == infer.ANull ? null : base; return base; }; function emptyObj(ctor) { var empty = Object.create(ctor.prototype); empty.props = Object.create(null); empty.isShell = true; return empty; } function isSimpleAnnotation(spec) { if (!spec["!type"] || /^(fn\(|\[)/.test(spec["!type"])) return false; for (var prop in spec) if (prop != "!type" && prop != "!doc" && prop != "!url" && prop != "!span" && prop != "!data") return false; return true; } function passOne(base, spec, path) { if (!base) { var tp = spec["!type"]; if (tp) { if (/^fn\(/.test(tp)) base = emptyObj(infer.Fn); else if (tp.charAt(0) == "[") base = emptyObj(infer.Arr); else throw new Error("Invalid !type spec: " + tp); } else if (spec["!stdProto"]) { base = infer.cx().protos[spec["!stdProto"]]; } else { base = emptyObj(infer.Obj); } base.name = path; } for (var name in spec) if (hop(spec, name) && name.charCodeAt(0) != 33) { var inner = spec[name]; if (typeof inner == "string" || isSimpleAnnotation(inner)) continue; var prop = base.defProp(name); passOne(prop.getObjType(), inner, path ? path + "." + name : name).propagate(prop); } return base; } function passTwo(base, spec, path) { if (base.isShell) { delete base.isShell; var tp = spec["!type"]; if (tp) { parseType(tp, path, base); } else { var proto = spec["!proto"] && parseType(spec["!proto"]); infer.Obj.call(base, proto instanceof infer.Obj ? proto : true, path); } } var effects = spec["!effects"]; if (effects && base instanceof infer.Fn) for (var i = 0; i < effects.length; ++i) parseEffect(effects[i], base); copyInfo(spec, base); for (var name in spec) if (hop(spec, name) && name.charCodeAt(0) != 33) { var inner = spec[name], known = base.defProp(name), innerPath = path ? path + "." + name : name; if (typeof inner == "string") { if (known.isEmpty()) parseType(inner, innerPath).propagate(known); } else { if (!isSimpleAnnotation(inner)) passTwo(known.getObjType(), inner, innerPath); else if (known.isEmpty()) parseType(inner["!type"], innerPath, null, true).propagate(known); else continue; if (inner["!doc"]) known.doc = inner["!doc"]; if (inner["!url"]) known.url = inner["!url"]; if (inner["!span"]) known.span = inner["!span"]; } } return base; } function copyInfo(spec, type) { if (spec["!doc"]) type.doc = spec["!doc"]; if (spec["!url"]) type.url = spec["!url"]; if (spec["!span"]) type.span = spec["!span"]; if (spec["!data"]) type.metaData = spec["!data"]; } function runPasses(type, arg) { var parent = infer.cx().parent, pass = parent && parent.passes && parent.passes[type]; if (pass) for (var i = 0; i < pass.length; i++) pass[i](arg); } function doLoadEnvironment(data, scope) { var cx = infer.cx(); infer.addOrigin(cx.curOrigin = data["!name"] || "env#" + cx.origins.length); cx.localDefs = cx.definitions[cx.curOrigin] = Object.create(null); runPasses("preLoadDef", data); passOne(scope, data); var def = data["!define"]; if (def) { for (var name in def) { var spec = def[name]; cx.localDefs[name] = typeof spec == "string" ? parsePath(spec) : passOne(null, spec, name); } for (var name in def) { var spec = def[name]; if (typeof spec != "string") passTwo(cx.localDefs[name], def[name], name); } } passTwo(scope, data); runPasses("postLoadDef", data); cx.curOrigin = cx.localDefs = null; } exports.load = function(data, scope) { if (!scope) scope = infer.cx().topScope; var oldScope = currentTopScope; currentTopScope = scope; try { doLoadEnvironment(data, scope); } finally { currentTopScope = oldScope; } }; exports.parse = function(data, origin, path) { var cx = infer.cx(); if (origin) { cx.origin = origin; cx.localDefs = cx.definitions[origin]; } try { if (typeof data == "string") return parseType(data, path); else return passTwo(passOne(null, data, path), data, path); } finally { if (origin) cx.origin = cx.localDefs = null; } }; // Used to register custom logic for more involved effect or type // computation. var customFunctions = Object.create(null); infer.registerFunction = function(name, f) { customFunctions[name] = f; }; var IsCreated = infer.constraint("created, target, spec", { addType: function(tp) { if (tp instanceof infer.Obj && this.created++ < 5) { var derived = new infer.Obj(tp), spec = this.spec; if (spec instanceof infer.AVal) spec = spec.getObjType(false); if (spec instanceof infer.Obj) for (var prop in spec.props) { var cur = spec.props[prop].types[0]; var p = derived.defProp(prop); if (cur && cur instanceof infer.Obj && cur.props.value) { var vtp = cur.props.value.getType(false); if (vtp) p.addType(vtp); } } this.target.addType(derived); } } }); infer.registerFunction("Object_create", function(_self, args, argNodes) { if (argNodes && argNodes.length && argNodes[0].type == "Literal" && argNodes[0].value == null) return new infer.Obj(); var result = new infer.AVal; if (args[0]) args[0].propagate(new IsCreated(0, result, args[1])); return result; }); var PropSpec = infer.constraint("target", { addType: function(tp) { if (!(tp instanceof infer.Obj)) return; if (tp.hasProp("value")) tp.getProp("value").propagate(this.target); else if (tp.hasProp("get")) tp.getProp("get").propagate(new infer.IsCallee(infer.ANull, [], null, this.target)); } }); infer.registerFunction("Object_defineProperty", function(_self, args, argNodes) { if (argNodes && argNodes.length >= 3 && argNodes[1].type == "Literal" && typeof argNodes[1].value == "string") { var obj = args[0], connect = new infer.AVal; obj.propagate(new infer.PropHasSubset(argNodes[1].value, connect, argNodes[1])); args[2].propagate(new PropSpec(connect)); } return infer.ANull; }); infer.registerFunction("Object_defineProperties", function(_self, args, argNodes) { if (args.length >= 2) { var obj = args[0]; args[1].forAllProps(function(prop, val, local) { if (!local) return; var connect = new infer.AVal; obj.propagate(new infer.PropHasSubset(prop, connect, argNodes && argNodes[1])); val.propagate(new PropSpec(connect)); }); } return infer.ANull; }); var IsBound = infer.constraint("self, args, target", { addType: function(tp) { if (!(tp instanceof infer.Fn)) return; this.target.addType(new infer.Fn(tp.name, infer.ANull, tp.args.slice(this.args.length), tp.argNames.slice(this.args.length), tp.retval)); this.self.propagate(tp.self); for (var i = 0; i < Math.min(tp.args.length, this.args.length); ++i) this.args[i].propagate(tp.args[i]); } }); infer.registerFunction("Function_bind", function(self, args) { if (!args.length) return infer.ANull; var result = new infer.AVal; self.propagate(new IsBound(args[0], args.slice(1), result)); return result; }); infer.registerFunction("Array_ctor", function(_self, args) { var arr = new infer.Arr; if (args.length != 1 || !args[0].hasType(infer.cx().num)) { var content = arr.getProp(""); for (var i = 0; i < args.length; ++i) args[i].propagate(content); } return arr; }); infer.registerFunction("Promise_ctor", function(_self, args, argNodes) { if (args.length < 1) return infer.ANull; var self = new infer.Obj(infer.cx().definitions.ecma6["Promise.prototype"]); var valProp = self.defProp("value", argNodes && argNodes[0]); var valArg = new infer.AVal; valArg.propagate(valProp); var exec = new infer.Fn("execute", infer.ANull, [valArg], ["value"], infer.ANull); var reject = infer.cx().definitions.ecma6.promiseReject; args[0].propagate(new infer.IsCallee(infer.ANull, [exec, reject], null, infer.ANull)); return self; }); return exports; }); three.js-r73/editor/js/libs/ternjs/doc_comment.js0000644000175500017550000003400512610076566021743 0ustar debacledebacle// Parses comments above variable declarations, function declarations, // and object properties as docstrings and JSDoc-style type // annotations. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(require("../lib/infer"), require("../lib/tern"), require("../lib/comment"), require("acorn"), require("acorn/dist/walk")); if (typeof define == "function" && define.amd) // AMD return define(["../lib/infer", "../lib/tern", "../lib/comment", "acorn/dist/acorn", "acorn/dist/walk"], mod); mod(tern, tern, tern.comment, acorn, acorn.walk); })(function(infer, tern, comment, acorn, walk) { "use strict"; var WG_MADEUP = 1, WG_STRONG = 101; tern.registerPlugin("doc_comment", function(server, options) { server.jsdocTypedefs = Object.create(null); server.on("reset", function() { server.jsdocTypedefs = Object.create(null); }); server._docComment = { weight: options && options.strong ? WG_STRONG : undefined, fullDocs: options && options.fullDocs }; return { passes: { postParse: postParse, postInfer: postInfer, postLoadDef: postLoadDef } }; }); function postParse(ast, text) { function attachComments(node) { comment.ensureCommentsBefore(text, node); } walk.simple(ast, { VariableDeclaration: attachComments, FunctionDeclaration: attachComments, AssignmentExpression: function(node) { if (node.operator == "=") attachComments(node); }, ObjectExpression: function(node) { for (var i = 0; i < node.properties.length; ++i) attachComments(node.properties[i]); }, CallExpression: function(node) { if (isDefinePropertyCall(node)) attachComments(node); } }); } function isDefinePropertyCall(node) { return node.callee.type == "MemberExpression" && node.callee.object.name == "Object" && node.callee.property.name == "defineProperty" && node.arguments.length >= 3 && typeof node.arguments[1].value == "string"; } function postInfer(ast, scope) { jsdocParseTypedefs(ast.sourceFile.text, scope); walk.simple(ast, { VariableDeclaration: function(node, scope) { if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, scope.getProp(node.declarations[0].id.name)); }, FunctionDeclaration: function(node, scope) { if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, scope.getProp(node.id.name), node.body.scope.fnType); }, AssignmentExpression: function(node, scope) { if (node.commentsBefore) interpretComments(node, node.commentsBefore, scope, infer.expressionType({node: node.left, state: scope})); }, ObjectExpression: function(node, scope) { for (var i = 0; i < node.properties.length; ++i) { var prop = node.properties[i]; if (prop.commentsBefore) interpretComments(prop, prop.commentsBefore, scope, node.objType.getProp(prop.key.name)); } }, CallExpression: function(node, scope) { if (node.commentsBefore && isDefinePropertyCall(node)) { var type = infer.expressionType({node: node.arguments[0], state: scope}).getObjType(); if (type && type instanceof infer.Obj) { var prop = type.props[node.arguments[1].value]; if (prop) interpretComments(node, node.commentsBefore, scope, prop); } } } }, infer.searchVisitor, scope); } function postLoadDef(data) { var defs = data["!typedef"]; var cx = infer.cx(), orig = data["!name"]; if (defs) for (var name in defs) cx.parent.jsdocTypedefs[name] = maybeInstance(infer.def.parse(defs[name], orig, name), name); } // COMMENT INTERPRETATION function interpretComments(node, comments, scope, aval, type) { jsdocInterpretComments(node, scope, aval, comments); var cx = infer.cx(); if (!type && aval instanceof infer.AVal && aval.types.length) { type = aval.types[aval.types.length - 1]; if (!(type instanceof infer.Obj) || type.origin != cx.curOrigin || type.doc) type = null; } var result = comments[comments.length - 1]; if (cx.parent._docComment.fullDocs) { result = result.trim().replace(/\n[ \t]*\* ?/g, "\n"); } else { var dot = result.search(/\.\s/); if (dot > 5) result = result.slice(0, dot + 1); result = result.trim().replace(/\s*\n\s*\*\s*|\s{1,}/g, " "); } result = result.replace(/^\s*\*+\s*/, ""); if (aval instanceof infer.AVal) aval.doc = result; if (type) type.doc = result; } // Parses a subset of JSDoc-style comments in order to include the // explicitly defined types in the analysis. function skipSpace(str, pos) { while (/\s/.test(str.charAt(pos))) ++pos; return pos; } function isIdentifier(string) { if (!acorn.isIdentifierStart(string.charCodeAt(0))) return false; for (var i = 1; i < string.length; i++) if (!acorn.isIdentifierChar(string.charCodeAt(i))) return false; return true; } function parseLabelList(scope, str, pos, close) { var labels = [], types = [], madeUp = false; for (var first = true; ; first = false) { pos = skipSpace(str, pos); if (first && str.charAt(pos) == close) break; var colon = str.indexOf(":", pos); if (colon < 0) return null; var label = str.slice(pos, colon); if (!isIdentifier(label)) return null; labels.push(label); pos = colon + 1; var type = parseType(scope, str, pos); if (!type) return null; pos = type.end; madeUp = madeUp || type.madeUp; types.push(type.type); pos = skipSpace(str, pos); var next = str.charAt(pos); ++pos; if (next == close) break; if (next != ",") return null; } return {labels: labels, types: types, end: pos, madeUp: madeUp}; } function parseType(scope, str, pos) { var type, union = false, madeUp = false; for (;;) { var inner = parseTypeInner(scope, str, pos); if (!inner) return null; madeUp = madeUp || inner.madeUp; if (union) inner.type.propagate(union); else type = inner.type; pos = skipSpace(str, inner.end); if (str.charAt(pos) != "|") break; pos++; if (!union) { union = new infer.AVal; type.propagate(union); type = union; } } var isOptional = false; if (str.charAt(pos) == "=") { ++pos; isOptional = true; } return {type: type, end: pos, isOptional: isOptional, madeUp: madeUp}; } function parseTypeInner(scope, str, pos) { pos = skipSpace(str, pos); var type, madeUp = false; if (str.indexOf("function(", pos) == pos) { var args = parseLabelList(scope, str, pos + 9, ")"), ret = infer.ANull; if (!args) return null; pos = skipSpace(str, args.end); if (str.charAt(pos) == ":") { ++pos; var retType = parseType(scope, str, pos + 1); if (!retType) return null; pos = retType.end; ret = retType.type; madeUp = retType.madeUp; } type = new infer.Fn(null, infer.ANull, args.types, args.labels, ret); } else if (str.charAt(pos) == "[") { var inner = parseType(scope, str, pos + 1); if (!inner) return null; pos = skipSpace(str, inner.end); madeUp = inner.madeUp; if (str.charAt(pos) != "]") return null; ++pos; type = new infer.Arr(inner.type); } else if (str.charAt(pos) == "{") { var fields = parseLabelList(scope, str, pos + 1, "}"); if (!fields) return null; type = new infer.Obj(true); for (var i = 0; i < fields.types.length; ++i) { var field = type.defProp(fields.labels[i]); field.initializer = true; fields.types[i].propagate(field); } pos = fields.end; madeUp = fields.madeUp; } else if (str.charAt(pos) == "(") { var inner = parseType(scope, str, pos + 1); if (!inner) return null; pos = skipSpace(str, inner.end); if (str.charAt(pos) != ")") return null; ++pos; type = inner.type; } else { var start = pos; if (!acorn.isIdentifierStart(str.charCodeAt(pos))) return null; while (acorn.isIdentifierChar(str.charCodeAt(pos))) ++pos; if (start == pos) return null; var word = str.slice(start, pos); if (/^(number|integer)$/i.test(word)) type = infer.cx().num; else if (/^bool(ean)?$/i.test(word)) type = infer.cx().bool; else if (/^string$/i.test(word)) type = infer.cx().str; else if (/^(null|undefined)$/i.test(word)) type = infer.ANull; else if (/^array$/i.test(word)) { var inner = null; if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") { var inAngles = parseType(scope, str, pos + 2); if (!inAngles) return null; pos = skipSpace(str, inAngles.end); madeUp = inAngles.madeUp; if (str.charAt(pos++) != ">") return null; inner = inAngles.type; } type = new infer.Arr(inner); } else if (/^object$/i.test(word)) { type = new infer.Obj(true); if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") { var key = parseType(scope, str, pos + 2); if (!key) return null; pos = skipSpace(str, key.end); madeUp = madeUp || key.madeUp; if (str.charAt(pos++) != ",") return null; var val = parseType(scope, str, pos); if (!val) return null; pos = skipSpace(str, val.end); madeUp = key.madeUp || val.madeUp; if (str.charAt(pos++) != ">") return null; val.type.propagate(type.defProp("")); } } else { while (str.charCodeAt(pos) == 46 || acorn.isIdentifierChar(str.charCodeAt(pos))) ++pos; var path = str.slice(start, pos); var cx = infer.cx(), defs = cx.parent && cx.parent.jsdocTypedefs, found; if (defs && (path in defs)) { type = defs[path]; } else if (found = infer.def.parsePath(path, scope).getObjType()) { type = maybeInstance(found, path); } else { if (!cx.jsdocPlaceholders) cx.jsdocPlaceholders = Object.create(null); if (!(path in cx.jsdocPlaceholders)) type = cx.jsdocPlaceholders[path] = new infer.Obj(null, path); else type = cx.jsdocPlaceholders[path]; madeUp = true; } } } return {type: type, end: pos, madeUp: madeUp}; } function maybeInstance(type, path) { if (type instanceof infer.Fn && /^[A-Z]/.test(path)) { var proto = type.getProp("prototype").getObjType(); if (proto instanceof infer.Obj) return infer.getInstance(proto); } return type; } function parseTypeOuter(scope, str, pos) { pos = skipSpace(str, pos || 0); if (str.charAt(pos) != "{") return null; var result = parseType(scope, str, pos + 1); if (!result) return null; var end = skipSpace(str, result.end); if (str.charAt(end) != "}") return null; result.end = end + 1; return result; } function jsdocInterpretComments(node, scope, aval, comments) { var type, args, ret, foundOne, self, parsed; for (var i = 0; i < comments.length; ++i) { var comment = comments[i]; var decl = /(?:\n|$|\*)\s*@(type|param|arg(?:ument)?|returns?|this)\s+(.*)/g, m; while (m = decl.exec(comment)) { if (m[1] == "this" && (parsed = parseType(scope, m[2], 0))) { self = parsed; foundOne = true; continue; } if (!(parsed = parseTypeOuter(scope, m[2]))) continue; foundOne = true; switch(m[1]) { case "returns": case "return": ret = parsed; break; case "type": type = parsed; break; case "param": case "arg": case "argument": var name = m[2].slice(parsed.end).match(/^\s*(\[?)\s*([^\]\s=]+)\s*(?:=[^\]]+\s*)?(\]?).*/); if (!name) continue; var argname = name[2] + (parsed.isOptional || (name[1] === '[' && name[3] === ']') ? "?" : ""); (args || (args = Object.create(null)))[argname] = parsed; break; } } } if (foundOne) applyType(type, self, args, ret, node, aval); }; function jsdocParseTypedefs(text, scope) { var cx = infer.cx(); var re = /\s@typedef\s+(.*)/g, m; while (m = re.exec(text)) { var parsed = parseTypeOuter(scope, m[1]); var name = parsed && m[1].slice(parsed.end).match(/^\s*(\S+)/); if (name) cx.parent.jsdocTypedefs[name[1]] = parsed.type; } } function propagateWithWeight(type, target) { var weight = infer.cx().parent._docComment.weight; type.type.propagate(target, weight || (type.madeUp ? WG_MADEUP : undefined)); } function applyType(type, self, args, ret, node, aval) { var fn; if (node.type == "VariableDeclaration") { var decl = node.declarations[0]; if (decl.init && decl.init.type == "FunctionExpression") fn = decl.init.body.scope.fnType; } else if (node.type == "FunctionDeclaration") { fn = node.body.scope.fnType; } else if (node.type == "AssignmentExpression") { if (node.right.type == "FunctionExpression") fn = node.right.body.scope.fnType; } else if (node.type == "CallExpression") { } else { // An object property if (node.value.type == "FunctionExpression") fn = node.value.body.scope.fnType; } if (fn && (args || ret || self)) { if (args) for (var i = 0; i < fn.argNames.length; ++i) { var name = fn.argNames[i], known = args[name]; if (!known && (known = args[name + "?"])) fn.argNames[i] += "?"; if (known) propagateWithWeight(known, fn.args[i]); } if (ret) propagateWithWeight(ret, fn.retval); if (self) propagateWithWeight(self, fn.self); } else if (type) { propagateWithWeight(type, aval); } }; }); three.js-r73/editor/js/libs/ternjs/tern.js0000644000175500017550000010420712610076566020426 0ustar debacledebacle// The Tern server object // A server is a stateful object that manages the analysis for a // project, and defines an interface for querying the code in the // project. (function(root, mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(exports, require("./infer"), require("./signal"), require("acorn"), require("acorn/dist/walk")); if (typeof define == "function" && define.amd) // AMD return define(["exports", "./infer", "./signal", "acorn/dist/acorn", "acorn/dist/walk"], mod); mod(root.tern || (root.tern = {}), tern, tern.signal, acorn, acorn.walk); // Plain browser env })(this, function(exports, infer, signal, acorn, walk) { "use strict"; var plugins = Object.create(null); exports.registerPlugin = function(name, init) { plugins[name] = init; }; var defaultOptions = exports.defaultOptions = { debug: false, async: false, getFile: function(_f, c) { if (this.async) c(null, null); }, defs: [], plugins: {}, fetchTimeout: 1000, dependencyBudget: 20000, reuseInstances: true, stripCRs: false }; var queryTypes = { completions: { takesFile: true, run: findCompletions }, properties: { run: findProperties }, type: { takesFile: true, run: findTypeAt }, documentation: { takesFile: true, run: findDocs }, definition: { takesFile: true, run: findDef }, refs: { takesFile: true, fullFile: true, run: findRefs }, rename: { takesFile: true, fullFile: true, run: buildRename }, files: { run: listFiles } }; exports.defineQueryType = function(name, desc) { queryTypes[name] = desc; }; function File(name, parent) { this.name = name; this.parent = parent; this.scope = this.text = this.ast = this.lineOffsets = null; } File.prototype.asLineChar = function(pos) { return asLineChar(this, pos); }; function updateText(file, text, srv) { file.text = srv.options.stripCRs ? text.replace(/\r\n/g, "\n") : text; infer.withContext(srv.cx, function() { file.ast = infer.parse(file.text, srv.passes, {directSourceFile: file, allowReturnOutsideFunction: true}); }); file.lineOffsets = null; } var Server = exports.Server = function(options) { this.cx = null; this.options = options || {}; for (var o in defaultOptions) if (!options.hasOwnProperty(o)) options[o] = defaultOptions[o]; this.handlers = Object.create(null); this.files = []; this.fileMap = Object.create(null); this.needsPurge = []; this.budgets = Object.create(null); this.uses = 0; this.pending = 0; this.asyncError = null; this.passes = Object.create(null); this.defs = options.defs.slice(0); for (var plugin in options.plugins) if (options.plugins.hasOwnProperty(plugin) && plugin in plugins) { var init = plugins[plugin](this, options.plugins[plugin]); if (init && init.defs) { if (init.loadFirst) this.defs.unshift(init.defs); else this.defs.push(init.defs); } if (init && init.passes) for (var type in init.passes) if (init.passes.hasOwnProperty(type)) (this.passes[type] || (this.passes[type] = [])).push(init.passes[type]); } this.reset(); }; Server.prototype = signal.mixin({ addFile: function(name, /*optional*/ text, parent) { // Don't crash when sloppy plugins pass non-existent parent ids if (parent && !(parent in this.fileMap)) parent = null; ensureFile(this, name, parent, text); }, delFile: function(name) { var file = this.findFile(name); if (file) { this.needsPurge.push(file.name); this.files.splice(this.files.indexOf(file), 1); delete this.fileMap[name]; } }, reset: function() { this.signal("reset"); this.cx = new infer.Context(this.defs, this); this.uses = 0; this.budgets = Object.create(null); for (var i = 0; i < this.files.length; ++i) { var file = this.files[i]; file.scope = null; } }, request: function(doc, c) { var inv = invalidDoc(doc); if (inv) return c(inv); var self = this; doRequest(this, doc, function(err, data) { c(err, data); if (self.uses > 40) { self.reset(); analyzeAll(self, null, function(){}); } }); }, findFile: function(name) { return this.fileMap[name]; }, flush: function(c) { var cx = this.cx; analyzeAll(this, null, function(err) { if (err) return c(err); infer.withContext(cx, c); }); }, startAsyncAction: function() { ++this.pending; }, finishAsyncAction: function(err) { if (err) this.asyncError = err; if (--this.pending === 0) this.signal("everythingFetched"); } }); function doRequest(srv, doc, c) { if (doc.query && !queryTypes.hasOwnProperty(doc.query.type)) return c("No query type '" + doc.query.type + "' defined"); var query = doc.query; // Respond as soon as possible when this just uploads files if (!query) c(null, {}); var files = doc.files || []; if (files.length) ++srv.uses; for (var i = 0; i < files.length; ++i) { var file = files[i]; if (file.type == "delete") srv.delFile(file.name); else ensureFile(srv, file.name, null, file.type == "full" ? file.text : null); } var timeBudget = typeof doc.timeout == "number" ? [doc.timeout] : null; if (!query) { analyzeAll(srv, timeBudget, function(){}); return; } var queryType = queryTypes[query.type]; if (queryType.takesFile) { if (typeof query.file != "string") return c(".query.file must be a string"); if (!/^#/.test(query.file)) ensureFile(srv, query.file, null); } analyzeAll(srv, timeBudget, function(err) { if (err) return c(err); var file = queryType.takesFile && resolveFile(srv, files, query.file); if (queryType.fullFile && file.type == "part") return c("Can't run a " + query.type + " query on a file fragment"); function run() { var result; try { result = queryType.run(srv, query, file); } catch (e) { if (srv.options.debug && e.name != "TernError") console.error(e.stack); return c(e); } c(null, result); } infer.withContext(srv.cx, timeBudget ? function() { infer.withTimeout(timeBudget[0], run); } : run); }); } function analyzeFile(srv, file) { infer.withContext(srv.cx, function() { file.scope = srv.cx.topScope; srv.signal("beforeLoad", file); infer.analyze(file.ast, file.name, file.scope, srv.passes); srv.signal("afterLoad", file); }); return file; } function ensureFile(srv, name, parent, text) { var known = srv.findFile(name); if (known) { if (text != null) { if (known.scope) { srv.needsPurge.push(name); known.scope = null; } updateText(known, text, srv); } if (parentDepth(srv, known.parent) > parentDepth(srv, parent)) { known.parent = parent; if (known.excluded) known.excluded = null; } return; } var file = new File(name, parent); srv.files.push(file); srv.fileMap[name] = file; if (text != null) { updateText(file, text, srv); } else if (srv.options.async) { srv.startAsyncAction(); srv.options.getFile(name, function(err, text) { updateText(file, text || "", srv); srv.finishAsyncAction(err); }); } else { updateText(file, srv.options.getFile(name) || "", srv); } } function fetchAll(srv, c) { var done = true, returned = false; srv.files.forEach(function(file) { if (file.text != null) return; if (srv.options.async) { done = false; srv.options.getFile(file.name, function(err, text) { if (err && !returned) { returned = true; return c(err); } updateText(file, text || "", srv); fetchAll(srv, c); }); } else { try { updateText(file, srv.options.getFile(file.name) || "", srv); } catch (e) { return c(e); } } }); if (done) c(); } function waitOnFetch(srv, timeBudget, c) { var done = function() { srv.off("everythingFetched", done); clearTimeout(timeout); analyzeAll(srv, timeBudget, c); }; srv.on("everythingFetched", done); var timeout = setTimeout(done, srv.options.fetchTimeout); } function analyzeAll(srv, timeBudget, c) { if (srv.pending) return waitOnFetch(srv, timeBudget, c); var e = srv.fetchError; if (e) { srv.fetchError = null; return c(e); } if (srv.needsPurge.length > 0) infer.withContext(srv.cx, function() { infer.purge(srv.needsPurge); srv.needsPurge.length = 0; }); var done = true; // The second inner loop might add new files. The outer loop keeps // repeating both inner loops until all files have been looked at. for (var i = 0; i < srv.files.length;) { var toAnalyze = []; for (; i < srv.files.length; ++i) { var file = srv.files[i]; if (file.text == null) done = false; else if (file.scope == null && !file.excluded) toAnalyze.push(file); } toAnalyze.sort(function(a, b) { return parentDepth(srv, a.parent) - parentDepth(srv, b.parent); }); for (var j = 0; j < toAnalyze.length; j++) { var file = toAnalyze[j]; if (file.parent && !chargeOnBudget(srv, file)) { file.excluded = true; } else if (timeBudget) { var startTime = +new Date; infer.withTimeout(timeBudget[0], function() { analyzeFile(srv, file); }); timeBudget[0] -= +new Date - startTime; } else { analyzeFile(srv, file); } } } if (done) c(); else waitOnFetch(srv, timeBudget, c); } function firstLine(str) { var end = str.indexOf("\n"); if (end < 0) return str; return str.slice(0, end); } function findMatchingPosition(line, file, near) { var pos = Math.max(0, near - 500), closest = null; if (!/^\s*$/.test(line)) for (;;) { var found = file.indexOf(line, pos); if (found < 0 || found > near + 500) break; if (closest == null || Math.abs(closest - near) > Math.abs(found - near)) closest = found; pos = found + line.length; } return closest; } function scopeDepth(s) { for (var i = 0; s; ++i, s = s.prev) {} return i; } function ternError(msg) { var err = new Error(msg); err.name = "TernError"; return err; } function resolveFile(srv, localFiles, name) { var isRef = name.match(/^#(\d+)$/); if (!isRef) return srv.findFile(name); var file = localFiles[isRef[1]]; if (!file || file.type == "delete") throw ternError("Reference to unknown file " + name); if (file.type == "full") return srv.findFile(file.name); // This is a partial file var realFile = file.backing = srv.findFile(file.name); var offset = file.offset; if (file.offsetLines) offset = {line: file.offsetLines, ch: 0}; file.offset = offset = resolvePos(realFile, file.offsetLines == null ? file.offset : {line: file.offsetLines, ch: 0}, true); var line = firstLine(file.text); var foundPos = findMatchingPosition(line, realFile.text, offset); var pos = foundPos == null ? Math.max(0, realFile.text.lastIndexOf("\n", offset)) : foundPos; var inObject, atFunction; infer.withContext(srv.cx, function() { infer.purge(file.name, pos, pos + file.text.length); var text = file.text, m; if (m = text.match(/(?:"([^"]*)"|([\w$]+))\s*:\s*function\b/)) { var objNode = walk.findNodeAround(file.backing.ast, pos, "ObjectExpression"); if (objNode && objNode.node.objType) inObject = {type: objNode.node.objType, prop: m[2] || m[1]}; } if (foundPos && (m = line.match(/^(.*?)\bfunction\b/))) { var cut = m[1].length, white = ""; for (var i = 0; i < cut; ++i) white += " "; text = white + text.slice(cut); atFunction = true; } var scopeStart = infer.scopeAt(realFile.ast, pos, realFile.scope); var scopeEnd = infer.scopeAt(realFile.ast, pos + text.length, realFile.scope); var scope = file.scope = scopeDepth(scopeStart) < scopeDepth(scopeEnd) ? scopeEnd : scopeStart; file.ast = infer.parse(text, srv.passes, {directSourceFile: file, allowReturnOutsideFunction: true}); infer.analyze(file.ast, file.name, scope, srv.passes); // This is a kludge to tie together the function types (if any) // outside and inside of the fragment, so that arguments and // return values have some information known about them. tieTogether: if (inObject || atFunction) { var newInner = infer.scopeAt(file.ast, line.length, scopeStart); if (!newInner.fnType) break tieTogether; if (inObject) { var prop = inObject.type.getProp(inObject.prop); prop.addType(newInner.fnType); } else if (atFunction) { var inner = infer.scopeAt(realFile.ast, pos + line.length, realFile.scope); if (inner == scopeStart || !inner.fnType) break tieTogether; var fOld = inner.fnType, fNew = newInner.fnType; if (!fNew || (fNew.name != fOld.name && fOld.name)) break tieTogether; for (var i = 0, e = Math.min(fOld.args.length, fNew.args.length); i < e; ++i) fOld.args[i].propagate(fNew.args[i]); fOld.self.propagate(fNew.self); fNew.retval.propagate(fOld.retval); } } }); return file; } // Budget management function astSize(node) { var size = 0; walk.simple(node, {Expression: function() { ++size; }}); return size; } function parentDepth(srv, parent) { var depth = 0; while (parent) { parent = srv.findFile(parent).parent; ++depth; } return depth; } function budgetName(srv, file) { for (;;) { var parent = srv.findFile(file.parent); if (!parent.parent) break; file = parent; } return file.name; } function chargeOnBudget(srv, file) { var bName = budgetName(srv, file); var size = astSize(file.ast); var known = srv.budgets[bName]; if (known == null) known = srv.budgets[bName] = srv.options.dependencyBudget; if (known < size) return false; srv.budgets[bName] = known - size; return true; } // Query helpers function isPosition(val) { return typeof val == "number" || typeof val == "object" && typeof val.line == "number" && typeof val.ch == "number"; } // Baseline query document validation function invalidDoc(doc) { if (doc.query) { if (typeof doc.query.type != "string") return ".query.type must be a string"; if (doc.query.start && !isPosition(doc.query.start)) return ".query.start must be a position"; if (doc.query.end && !isPosition(doc.query.end)) return ".query.end must be a position"; } if (doc.files) { if (!Array.isArray(doc.files)) return "Files property must be an array"; for (var i = 0; i < doc.files.length; ++i) { var file = doc.files[i]; if (typeof file != "object") return ".files[n] must be objects"; else if (typeof file.name != "string") return ".files[n].name must be a string"; else if (file.type == "delete") continue; else if (typeof file.text != "string") return ".files[n].text must be a string"; else if (file.type == "part") { if (!isPosition(file.offset) && typeof file.offsetLines != "number") return ".files[n].offset must be a position"; } else if (file.type != "full") return ".files[n].type must be \"full\" or \"part\""; } } } var offsetSkipLines = 25; function findLineStart(file, line) { var text = file.text, offsets = file.lineOffsets || (file.lineOffsets = [0]); var pos = 0, curLine = 0; var storePos = Math.min(Math.floor(line / offsetSkipLines), offsets.length - 1); var pos = offsets[storePos], curLine = storePos * offsetSkipLines; while (curLine < line) { ++curLine; pos = text.indexOf("\n", pos) + 1; if (pos === 0) return null; if (curLine % offsetSkipLines === 0) offsets.push(pos); } return pos; } var resolvePos = exports.resolvePos = function(file, pos, tolerant) { if (typeof pos != "number") { var lineStart = findLineStart(file, pos.line); if (lineStart == null) { if (tolerant) pos = file.text.length; else throw ternError("File doesn't contain a line " + pos.line); } else { pos = lineStart + pos.ch; } } if (pos > file.text.length) { if (tolerant) pos = file.text.length; else throw ternError("Position " + pos + " is outside of file."); } return pos; }; function asLineChar(file, pos) { if (!file) return {line: 0, ch: 0}; var offsets = file.lineOffsets || (file.lineOffsets = [0]); var text = file.text, line, lineStart; for (var i = offsets.length - 1; i >= 0; --i) if (offsets[i] <= pos) { line = i * offsetSkipLines; lineStart = offsets[i]; } for (;;) { var eol = text.indexOf("\n", lineStart); if (eol >= pos || eol < 0) break; lineStart = eol + 1; ++line; } return {line: line, ch: pos - lineStart}; } var outputPos = exports.outputPos = function(query, file, pos) { if (query.lineCharPositions) { var out = asLineChar(file, pos); if (file.type == "part") out.line += file.offsetLines != null ? file.offsetLines : asLineChar(file.backing, file.offset).line; return out; } else { return pos + (file.type == "part" ? file.offset : 0); } }; // Delete empty fields from result objects function clean(obj) { for (var prop in obj) if (obj[prop] == null) delete obj[prop]; return obj; } function maybeSet(obj, prop, val) { if (val != null) obj[prop] = val; } // Built-in query types function compareCompletions(a, b) { if (typeof a != "string") { a = a.name; b = b.name; } var aUp = /^[A-Z]/.test(a), bUp = /^[A-Z]/.test(b); if (aUp == bUp) return a < b ? -1 : a == b ? 0 : 1; else return aUp ? 1 : -1; } function isStringAround(node, start, end) { return node.type == "Literal" && typeof node.value == "string" && node.start == start - 1 && node.end <= end + 1; } function pointInProp(objNode, point) { for (var i = 0; i < objNode.properties.length; i++) { var curProp = objNode.properties[i]; if (curProp.key.start <= point && curProp.key.end >= point) return curProp; } } var jsKeywords = ("break do instanceof typeof case else new var " + "catch finally return void continue for switch while debugger " + "function this with default if throw delete in try").split(" "); function findCompletions(srv, query, file) { if (query.end == null) throw ternError("missing .query.end field"); if (srv.passes.completion) for (var i = 0; i < srv.passes.completion.length; i++) { var result = srv.passes.completion[i](file, query); if (result) return result; } var wordStart = resolvePos(file, query.end), wordEnd = wordStart, text = file.text; while (wordStart && acorn.isIdentifierChar(text.charCodeAt(wordStart - 1))) --wordStart; if (query.expandWordForward !== false) while (wordEnd < text.length && acorn.isIdentifierChar(text.charCodeAt(wordEnd))) ++wordEnd; var word = text.slice(wordStart, wordEnd), completions = [], ignoreObj; if (query.caseInsensitive) word = word.toLowerCase(); var wrapAsObjs = query.types || query.depths || query.docs || query.urls || query.origins; function gather(prop, obj, depth, addInfo) { // 'hasOwnProperty' and such are usually just noise, leave them // out when no prefix is provided. if ((objLit || query.omitObjectPrototype !== false) && obj == srv.cx.protos.Object && !word) return; if (query.filter !== false && word && (query.caseInsensitive ? prop.toLowerCase() : prop).indexOf(word) !== 0) return; if (ignoreObj && ignoreObj.props[prop]) return; for (var i = 0; i < completions.length; ++i) { var c = completions[i]; if ((wrapAsObjs ? c.name : c) == prop) return; } var rec = wrapAsObjs ? {name: prop} : prop; completions.push(rec); if (obj && (query.types || query.docs || query.urls || query.origins)) { var val = obj.props[prop]; infer.resetGuessing(); var type = val.getType(); rec.guess = infer.didGuess(); if (query.types) rec.type = infer.toString(val); if (query.docs) maybeSet(rec, "doc", val.doc || type && type.doc); if (query.urls) maybeSet(rec, "url", val.url || type && type.url); if (query.origins) maybeSet(rec, "origin", val.origin || type && type.origin); } if (query.depths) rec.depth = depth; if (wrapAsObjs && addInfo) addInfo(rec); } var hookname, prop, objType, isKey; var exprAt = infer.findExpressionAround(file.ast, null, wordStart, file.scope); var memberExpr, objLit; // Decide whether this is an object property, either in a member // expression or an object literal. if (exprAt) { if (exprAt.node.type == "MemberExpression" && exprAt.node.object.end < wordStart) { memberExpr = exprAt; } else if (isStringAround(exprAt.node, wordStart, wordEnd)) { var parent = infer.parentNode(exprAt.node, file.ast); if (parent.type == "MemberExpression" && parent.property == exprAt.node) memberExpr = {node: parent, state: exprAt.state}; } else if (exprAt.node.type == "ObjectExpression") { var objProp = pointInProp(exprAt.node, wordEnd); if (objProp) { objLit = exprAt; prop = isKey = objProp.key.name; } else if (!word && !/:\s*$/.test(file.text.slice(0, wordStart))) { objLit = exprAt; prop = isKey = true; } } } if (objLit) { // Since we can't use the type of the literal itself to complete // its properties (it doesn't contain the information we need), // we have to try asking the surrounding expression for type info. objType = infer.typeFromContext(file.ast, objLit); ignoreObj = objLit.node.objType; } else if (memberExpr) { prop = memberExpr.node.property; prop = prop.type == "Literal" ? prop.value.slice(1) : prop.name; memberExpr.node = memberExpr.node.object; objType = infer.expressionType(memberExpr); } else if (text.charAt(wordStart - 1) == ".") { var pathStart = wordStart - 1; while (pathStart && (text.charAt(pathStart - 1) == "." || acorn.isIdentifierChar(text.charCodeAt(pathStart - 1)))) pathStart--; var path = text.slice(pathStart, wordStart - 1); if (path) { objType = infer.def.parsePath(path, file.scope).getObjType(); prop = word; } } if (prop != null) { srv.cx.completingProperty = prop; if (objType) infer.forAllPropertiesOf(objType, gather); if (!completions.length && query.guess !== false && objType && objType.guessProperties) objType.guessProperties(function(p, o, d) {if (p != prop && p != "✖") gather(p, o, d);}); if (!completions.length && word.length >= 2 && query.guess !== false) for (var prop in srv.cx.props) gather(prop, srv.cx.props[prop][0], 0); hookname = "memberCompletion"; } else { infer.forAllLocalsAt(file.ast, wordStart, file.scope, gather); if (query.includeKeywords) jsKeywords.forEach(function(kw) { gather(kw, null, 0, function(rec) { rec.isKeyword = true; }); }); hookname = "variableCompletion"; } if (srv.passes[hookname]) srv.passes[hookname].forEach(function(hook) {hook(file, wordStart, wordEnd, gather);}); if (query.sort !== false) completions.sort(compareCompletions); srv.cx.completingProperty = null; return {start: outputPos(query, file, wordStart), end: outputPos(query, file, wordEnd), isProperty: !!prop, isObjectKey: !!isKey, completions: completions}; } function findProperties(srv, query) { var prefix = query.prefix, found = []; for (var prop in srv.cx.props) if (prop != "" && (!prefix || prop.indexOf(prefix) === 0)) found.push(prop); if (query.sort !== false) found.sort(compareCompletions); return {completions: found}; } var findExpr = exports.findQueryExpr = function(file, query, wide) { if (query.end == null) throw ternError("missing .query.end field"); if (query.variable) { var scope = infer.scopeAt(file.ast, resolvePos(file, query.end), file.scope); return {node: {type: "Identifier", name: query.variable, start: query.end, end: query.end + 1}, state: scope}; } else { var start = query.start && resolvePos(file, query.start), end = resolvePos(file, query.end); var expr = infer.findExpressionAt(file.ast, start, end, file.scope); if (expr) return expr; expr = infer.findExpressionAround(file.ast, start, end, file.scope); if (expr && (expr.node.type == "ObjectExpression" || wide || (start == null ? end : start) - expr.node.start < 20 || expr.node.end - end < 20)) return expr; return null; } }; function findExprOrThrow(file, query, wide) { var expr = findExpr(file, query, wide); if (expr) return expr; throw ternError("No expression at the given position."); } function ensureObj(tp) { if (!tp || !(tp = tp.getType()) || !(tp instanceof infer.Obj)) return null; return tp; } function findExprType(srv, query, file, expr) { var type; if (expr) { infer.resetGuessing(); type = infer.expressionType(expr); } if (srv.passes["typeAt"]) { var pos = resolvePos(file, query.end); srv.passes["typeAt"].forEach(function(hook) { type = hook(file, pos, expr, type); }); } if (!type) throw ternError("No type found at the given position."); var objProp; if (expr.node.type == "ObjectExpression" && query.end != null && (objProp = pointInProp(expr.node, resolvePos(file, query.end)))) { var name = objProp.key.name; var fromCx = ensureObj(infer.typeFromContext(file.ast, expr)); if (fromCx && fromCx.hasProp(name)) { type = fromCx.hasProp(name); } else { var fromLocal = ensureObj(type); if (fromLocal && fromLocal.hasProp(name)) type = fromLocal.hasProp(name); } } return type; }; function findTypeAt(srv, query, file) { var expr = findExpr(file, query), exprName; var type = findExprType(srv, query, file, expr), exprType = type; if (query.preferFunction) type = type.getFunctionType() || type.getType(); else type = type.getType(); if (expr) { if (expr.node.type == "Identifier") exprName = expr.node.name; else if (expr.node.type == "MemberExpression" && !expr.node.computed) exprName = expr.node.property.name; } if (query.depth != null && typeof query.depth != "number") throw ternError(".query.depth must be a number"); var result = {guess: infer.didGuess(), type: infer.toString(exprType, query.depth), name: type && type.name, exprName: exprName}; if (type) storeTypeDocs(type, result); if (!result.doc && exprType.doc) result.doc = exprType.doc; return clean(result); } function findDocs(srv, query, file) { var expr = findExpr(file, query); var type = findExprType(srv, query, file, expr); var result = {url: type.url, doc: type.doc, type: infer.toString(type)}; var inner = type.getType(); if (inner) storeTypeDocs(inner, result); return clean(result); } function storeTypeDocs(type, out) { if (!out.url) out.url = type.url; if (!out.doc) out.doc = type.doc; if (!out.origin) out.origin = type.origin; var ctor, boring = infer.cx().protos; if (!out.url && !out.doc && type.proto && (ctor = type.proto.hasCtor) && type.proto != boring.Object && type.proto != boring.Function && type.proto != boring.Array) { out.url = ctor.url; out.doc = ctor.doc; } } var getSpan = exports.getSpan = function(obj) { if (!obj.origin) return; if (obj.originNode) { var node = obj.originNode; if (/^Function/.test(node.type) && node.id) node = node.id; return {origin: obj.origin, node: node}; } if (obj.span) return {origin: obj.origin, span: obj.span}; }; var storeSpan = exports.storeSpan = function(srv, query, span, target) { target.origin = span.origin; if (span.span) { var m = /^(\d+)\[(\d+):(\d+)\]-(\d+)\[(\d+):(\d+)\]$/.exec(span.span); target.start = query.lineCharPositions ? {line: Number(m[2]), ch: Number(m[3])} : Number(m[1]); target.end = query.lineCharPositions ? {line: Number(m[5]), ch: Number(m[6])} : Number(m[4]); } else { var file = srv.findFile(span.origin); target.start = outputPos(query, file, span.node.start); target.end = outputPos(query, file, span.node.end); } }; function findDef(srv, query, file) { var expr = findExpr(file, query); var type = findExprType(srv, query, file, expr); if (infer.didGuess()) return {}; var span = getSpan(type); var result = {url: type.url, doc: type.doc, origin: type.origin}; if (type.types) for (var i = type.types.length - 1; i >= 0; --i) { var tp = type.types[i]; storeTypeDocs(tp, result); if (!span) span = getSpan(tp); } if (span && span.node) { // refers to a loaded file var spanFile = span.node.sourceFile || srv.findFile(span.origin); var start = outputPos(query, spanFile, span.node.start), end = outputPos(query, spanFile, span.node.end); result.start = start; result.end = end; result.file = span.origin; var cxStart = Math.max(0, span.node.start - 50); result.contextOffset = span.node.start - cxStart; result.context = spanFile.text.slice(cxStart, cxStart + 50); } else if (span) { // external result.file = span.origin; storeSpan(srv, query, span, result); } return clean(result); } function findRefsToVariable(srv, query, file, expr, checkShadowing) { var name = expr.node.name; for (var scope = expr.state; scope && !(name in scope.props); scope = scope.prev) {} if (!scope) throw ternError("Could not find a definition for " + name + " " + !!srv.cx.topScope.props.x); var type, refs = []; function storeRef(file) { return function(node, scopeHere) { if (checkShadowing) for (var s = scopeHere; s != scope; s = s.prev) { var exists = s.hasProp(checkShadowing); if (exists) throw ternError("Renaming `" + name + "` to `" + checkShadowing + "` would make a variable at line " + (asLineChar(file, node.start).line + 1) + " point to the definition at line " + (asLineChar(file, exists.name.start).line + 1)); } refs.push({file: file.name, start: outputPos(query, file, node.start), end: outputPos(query, file, node.end)}); }; } if (scope.originNode) { type = "local"; if (checkShadowing) { for (var prev = scope.prev; prev; prev = prev.prev) if (checkShadowing in prev.props) break; if (prev) infer.findRefs(scope.originNode, scope, checkShadowing, prev, function(node) { throw ternError("Renaming `" + name + "` to `" + checkShadowing + "` would shadow the definition used at line " + (asLineChar(file, node.start).line + 1)); }); } infer.findRefs(scope.originNode, scope, name, scope, storeRef(file)); } else { type = "global"; for (var i = 0; i < srv.files.length; ++i) { var cur = srv.files[i]; infer.findRefs(cur.ast, cur.scope, name, scope, storeRef(cur)); } } return {refs: refs, type: type, name: name}; } function findRefsToProperty(srv, query, expr, prop) { var objType = infer.expressionType(expr).getObjType(); if (!objType) throw ternError("Couldn't determine type of base object."); var refs = []; function storeRef(file) { return function(node) { refs.push({file: file.name, start: outputPos(query, file, node.start), end: outputPos(query, file, node.end)}); }; } for (var i = 0; i < srv.files.length; ++i) { var cur = srv.files[i]; infer.findPropRefs(cur.ast, cur.scope, objType, prop.name, storeRef(cur)); } return {refs: refs, name: prop.name}; } function findRefs(srv, query, file) { var expr = findExprOrThrow(file, query, true); if (expr && expr.node.type == "Identifier") { return findRefsToVariable(srv, query, file, expr); } else if (expr && expr.node.type == "MemberExpression" && !expr.node.computed) { var p = expr.node.property; expr.node = expr.node.object; return findRefsToProperty(srv, query, expr, p); } else if (expr && expr.node.type == "ObjectExpression") { var pos = resolvePos(file, query.end); for (var i = 0; i < expr.node.properties.length; ++i) { var k = expr.node.properties[i].key; if (k.start <= pos && k.end >= pos) return findRefsToProperty(srv, query, expr, k); } } throw ternError("Not at a variable or property name."); } function buildRename(srv, query, file) { if (typeof query.newName != "string") throw ternError(".query.newName should be a string"); var expr = findExprOrThrow(file, query); if (!expr || expr.node.type != "Identifier") throw ternError("Not at a variable."); var data = findRefsToVariable(srv, query, file, expr, query.newName), refs = data.refs; delete data.refs; data.files = srv.files.map(function(f){return f.name;}); var changes = data.changes = []; for (var i = 0; i < refs.length; ++i) { var use = refs[i]; use.text = query.newName; changes.push(use); } return data; } function listFiles(srv) { return {files: srv.files.map(function(f){return f.name;})}; } exports.version = "0.11.1"; }); three.js-r73/editor/js/libs/ternjs/comment.js0000644000175500017550000000551312610076566021120 0ustar debacledebacle(function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(exports); if (typeof define == "function" && define.amd) // AMD return define(["exports"], mod); mod(tern.comment || (tern.comment = {})); })(function(exports) { function isSpace(ch) { return (ch < 14 && ch > 8) || ch === 32 || ch === 160; } function onOwnLine(text, pos) { for (; pos > 0; --pos) { var ch = text.charCodeAt(pos - 1); if (ch == 10) break; if (!isSpace(ch)) return false; } return true; } // Gather comments directly before a function exports.commentsBefore = function(text, pos) { var found = null, emptyLines = 0, topIsLineComment; out: while (pos > 0) { var prev = text.charCodeAt(pos - 1); if (prev == 10) { for (var scan = --pos, sawNonWS = false; scan > 0; --scan) { prev = text.charCodeAt(scan - 1); if (prev == 47 && text.charCodeAt(scan - 2) == 47) { if (!onOwnLine(text, scan - 2)) break out; var content = text.slice(scan, pos); if (!emptyLines && topIsLineComment) found[0] = content + "\n" + found[0]; else (found || (found = [])).unshift(content); topIsLineComment = true; emptyLines = 0; pos = scan - 2; break; } else if (prev == 10) { if (!sawNonWS && ++emptyLines > 1) break out; break; } else if (!sawNonWS && !isSpace(prev)) { sawNonWS = true; } } } else if (prev == 47 && text.charCodeAt(pos - 2) == 42) { for (var scan = pos - 2; scan > 1; --scan) { if (text.charCodeAt(scan - 1) == 42 && text.charCodeAt(scan - 2) == 47) { if (!onOwnLine(text, scan - 2)) break out; (found || (found = [])).unshift(text.slice(scan, pos - 2)); topIsLineComment = false; emptyLines = 0; break; } } pos = scan - 2; } else if (isSpace(prev)) { --pos; } else { break; } } return found; }; exports.commentAfter = function(text, pos) { while (pos < text.length) { var next = text.charCodeAt(pos); if (next == 47) { var after = text.charCodeAt(pos + 1), end; if (after == 47) // line comment end = text.indexOf("\n", pos + 2); else if (after == 42) // block comment end = text.indexOf("*/", pos + 2); else return; return text.slice(pos + 2, end < 0 ? text.length : end); } else if (isSpace(next)) { ++pos; } } }; exports.ensureCommentsBefore = function(text, node) { if (node.hasOwnProperty("commentsBefore")) return node.commentsBefore; return node.commentsBefore = exports.commentsBefore(text, node.start); }; }); three.js-r73/editor/js/libs/ternjs/signal.js0000644000175500017550000000170312610076566020730 0ustar debacledebacle(function(root, mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(exports); if (typeof define == "function" && define.amd) // AMD return define(["exports"], mod); mod((root.tern || (root.tern = {})).signal = {}); // Plain browser env })(this, function(exports) { function on(type, f) { var handlers = this._handlers || (this._handlers = Object.create(null)); (handlers[type] || (handlers[type] = [])).push(f); } function off(type, f) { var arr = this._handlers && this._handlers[type]; if (arr) for (var i = 0; i < arr.length; ++i) if (arr[i] == f) { arr.splice(i, 1); break; } } function signal(type, a1, a2, a3, a4) { var arr = this._handlers && this._handlers[type]; if (arr) for (var i = 0; i < arr.length; ++i) arr[i].call(this, a1, a2, a3, a4); } exports.mixin = function(obj) { obj.on = on; obj.off = off; obj.signal = signal; return obj; }; }); three.js-r73/editor/js/libs/ternjs/infer.js0000644000175500017550000015651212610076566020567 0ustar debacledebacle// Main type inference engine // Walks an AST, building up a graph of abstract values and constraints // that cause types to flow from one node to another. Also defines a // number of utilities for accessing ASTs and scopes. // Analysis is done in a context, which is tracked by the dynamically // bound cx variable. Use withContext to set the current context. // For memory-saving reasons, individual types export an interface // similar to abstract values (which can hold multiple types), and can // thus be used in place abstract values that only ever contain a // single type. (function(root, mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(exports, require("acorn"), require("acorn/dist/acorn_loose"), require("acorn/dist/walk"), require("./def"), require("./signal")); if (typeof define == "function" && define.amd) // AMD return define(["exports", "acorn/dist/acorn", "acorn/dist/acorn_loose", "acorn/dist/walk", "./def", "./signal"], mod); mod(root.tern || (root.tern = {}), acorn, acorn, acorn.walk, tern.def, tern.signal); // Plain browser env })(this, function(exports, acorn, acorn_loose, walk, def, signal) { "use strict"; var toString = exports.toString = function(type, maxDepth, parent) { if (!type || type == parent || maxDepth && maxDepth < -3) return "?"; return type.toString(maxDepth, parent); }; // A variant of AVal used for unknown, dead-end values. Also serves // as prototype for AVals, Types, and Constraints because it // implements 'empty' versions of all the methods that the code // expects. var ANull = exports.ANull = signal.mixin({ addType: function() {}, propagate: function() {}, getProp: function() { return ANull; }, forAllProps: function() {}, hasType: function() { return false; }, isEmpty: function() { return true; }, getFunctionType: function() {}, getObjType: function() {}, getType: function() {}, gatherProperties: function() {}, propagatesTo: function() {}, typeHint: function() {}, propHint: function() {}, toString: function() { return "?"; } }); function extend(proto, props) { var obj = Object.create(proto); if (props) for (var prop in props) obj[prop] = props[prop]; return obj; } // ABSTRACT VALUES var WG_DEFAULT = 100, WG_NEW_INSTANCE = 90, WG_MADEUP_PROTO = 10, WG_MULTI_MEMBER = 5, WG_CATCH_ERROR = 5, WG_GLOBAL_THIS = 90, WG_SPECULATIVE_THIS = 2; var AVal = exports.AVal = function() { this.types = []; this.forward = null; this.maxWeight = 0; }; AVal.prototype = extend(ANull, { addType: function(type, weight) { weight = weight || WG_DEFAULT; if (this.maxWeight < weight) { this.maxWeight = weight; if (this.types.length == 1 && this.types[0] == type) return; this.types.length = 0; } else if (this.maxWeight > weight || this.types.indexOf(type) > -1) { return; } this.signal("addType", type); this.types.push(type); var forward = this.forward; if (forward) withWorklist(function(add) { for (var i = 0; i < forward.length; ++i) add(type, forward[i], weight); }); }, propagate: function(target, weight) { if (target == ANull || (target instanceof Type && this.forward && this.forward.length > 2)) return; if (weight && weight != WG_DEFAULT) target = new Muffle(target, weight); (this.forward || (this.forward = [])).push(target); var types = this.types; if (types.length) withWorklist(function(add) { for (var i = 0; i < types.length; ++i) add(types[i], target, weight); }); }, getProp: function(prop) { if (prop == "__proto__" || prop == "✖") return ANull; var found = (this.props || (this.props = Object.create(null)))[prop]; if (!found) { found = this.props[prop] = new AVal; this.propagate(new PropIsSubset(prop, found)); } return found; }, forAllProps: function(c) { this.propagate(new ForAllProps(c)); }, hasType: function(type) { return this.types.indexOf(type) > -1; }, isEmpty: function() { return this.types.length === 0; }, getFunctionType: function() { for (var i = this.types.length - 1; i >= 0; --i) if (this.types[i] instanceof Fn) return this.types[i]; }, getObjType: function() { var seen = null; for (var i = this.types.length - 1; i >= 0; --i) { var type = this.types[i]; if (!(type instanceof Obj)) continue; if (type.name) return type; if (!seen) seen = type; } return seen; }, getType: function(guess) { if (this.types.length === 0 && guess !== false) return this.makeupType(); if (this.types.length === 1) return this.types[0]; return canonicalType(this.types); }, toString: function(maxDepth, parent) { if (this.types.length == 0) return toString(this.makeupType(), maxDepth, parent); if (this.types.length == 1) return toString(this.types[0], maxDepth, parent); var simplified = simplifyTypes(this.types); if (simplified.length > 2) return "?"; return simplified.map(function(tp) { return toString(tp, maxDepth, parent); }).join("|"); }, computedPropType: function() { if (!this.propertyOf) return null; if (this.propertyOf.hasProp("")) { var computedProp = this.propertyOf.getProp(""); if (computedProp == this) return null; return computedProp.getType(); } else if (this.propertyOf.maybeProps && this.propertyOf.maybeProps[""] == this) { for (var prop in this.propertyOf.props) { var val = this.propertyOf.props[prop]; if (!val.isEmpty()) return val; } return null; } }, makeupType: function() { var computed = this.computedPropType(); if (computed) return computed; if (!this.forward) return null; for (var i = this.forward.length - 1; i >= 0; --i) { var hint = this.forward[i].typeHint(); if (hint && !hint.isEmpty()) {guessing = true; return hint;} } var props = Object.create(null), foundProp = null; for (var i = 0; i < this.forward.length; ++i) { var prop = this.forward[i].propHint(); if (prop && prop != "length" && prop != "" && prop != "✖" && prop != cx.completingProperty) { props[prop] = true; foundProp = prop; } } if (!foundProp) return null; var objs = objsWithProp(foundProp); if (objs) { var matches = []; search: for (var i = 0; i < objs.length; ++i) { var obj = objs[i]; for (var prop in props) if (!obj.hasProp(prop)) continue search; if (obj.hasCtor) obj = getInstance(obj); matches.push(obj); } var canon = canonicalType(matches); if (canon) {guessing = true; return canon;} } }, typeHint: function() { return this.types.length ? this.getType() : null; }, propagatesTo: function() { return this; }, gatherProperties: function(f, depth) { for (var i = 0; i < this.types.length; ++i) this.types[i].gatherProperties(f, depth); }, guessProperties: function(f) { if (this.forward) for (var i = 0; i < this.forward.length; ++i) { var prop = this.forward[i].propHint(); if (prop) f(prop, null, 0); } var guessed = this.makeupType(); if (guessed) guessed.gatherProperties(f); } }); function similarAVal(a, b, depth) { var typeA = a.getType(false), typeB = b.getType(false); if (!typeA || !typeB) return true; return similarType(typeA, typeB, depth); } function similarType(a, b, depth) { if (!a || depth >= 5) return b; if (!a || a == b) return a; if (!b) return a; if (a.constructor != b.constructor) return false; if (a.constructor == Arr) { var innerA = a.getProp("").getType(false); if (!innerA) return b; var innerB = b.getProp("").getType(false); if (!innerB || similarType(innerA, innerB, depth + 1)) return b; } else if (a.constructor == Obj) { var propsA = 0, propsB = 0, same = 0; for (var prop in a.props) { propsA++; if (prop in b.props && similarAVal(a.props[prop], b.props[prop], depth + 1)) same++; } for (var prop in b.props) propsB++; if (propsA && propsB && same < Math.max(propsA, propsB) / 2) return false; return propsA > propsB ? a : b; } else if (a.constructor == Fn) { if (a.args.length != b.args.length || !a.args.every(function(tp, i) { return similarAVal(tp, b.args[i], depth + 1); }) || !similarAVal(a.retval, b.retval, depth + 1) || !similarAVal(a.self, b.self, depth + 1)) return false; return a; } else { return false; } } var simplifyTypes = exports.simplifyTypes = function(types) { var found = []; outer: for (var i = 0; i < types.length; ++i) { var tp = types[i]; for (var j = 0; j < found.length; j++) { var similar = similarType(tp, found[j], 0); if (similar) { found[j] = similar; continue outer; } } found.push(tp); } return found; }; function canonicalType(types) { var arrays = 0, fns = 0, objs = 0, prim = null; for (var i = 0; i < types.length; ++i) { var tp = types[i]; if (tp instanceof Arr) ++arrays; else if (tp instanceof Fn) ++fns; else if (tp instanceof Obj) ++objs; else if (tp instanceof Prim) { if (prim && tp.name != prim.name) return null; prim = tp; } } var kinds = (arrays && 1) + (fns && 1) + (objs && 1) + (prim && 1); if (kinds > 1) return null; if (prim) return prim; var maxScore = 0, maxTp = null; for (var i = 0; i < types.length; ++i) { var tp = types[i], score = 0; if (arrays) { score = tp.getProp("").isEmpty() ? 1 : 2; } else if (fns) { score = 1; for (var j = 0; j < tp.args.length; ++j) if (!tp.args[j].isEmpty()) ++score; if (!tp.retval.isEmpty()) ++score; } else if (objs) { score = tp.name ? 100 : 2; } if (score >= maxScore) { maxScore = score; maxTp = tp; } } return maxTp; } // PROPAGATION STRATEGIES function Constraint() {} Constraint.prototype = extend(ANull, { init: function() { this.origin = cx.curOrigin; } }); var constraint = exports.constraint = function(props, methods) { var body = "this.init();"; props = props ? props.split(", ") : []; for (var i = 0; i < props.length; ++i) body += "this." + props[i] + " = " + props[i] + ";"; var ctor = Function.apply(null, props.concat([body])); ctor.prototype = Object.create(Constraint.prototype); for (var m in methods) if (methods.hasOwnProperty(m)) ctor.prototype[m] = methods[m]; return ctor; }; var PropIsSubset = constraint("prop, target", { addType: function(type, weight) { if (type.getProp) type.getProp(this.prop).propagate(this.target, weight); }, propHint: function() { return this.prop; }, propagatesTo: function() { if (this.prop == "" || !/[^\w_]/.test(this.prop)) return {target: this.target, pathExt: "." + this.prop}; } }); var PropHasSubset = exports.PropHasSubset = constraint("prop, type, originNode", { addType: function(type, weight) { if (!(type instanceof Obj)) return; var prop = type.defProp(this.prop, this.originNode); if (!prop.origin) prop.origin = this.origin; this.type.propagate(prop, weight); }, propHint: function() { return this.prop; } }); var ForAllProps = constraint("c", { addType: function(type) { if (!(type instanceof Obj)) return; type.forAllProps(this.c); } }); function withDisabledComputing(fn, body) { cx.disabledComputing = {fn: fn, prev: cx.disabledComputing}; try { return body(); } finally { cx.disabledComputing = cx.disabledComputing.prev; } } var IsCallee = exports.IsCallee = constraint("self, args, argNodes, retval", { init: function() { Constraint.prototype.init.call(this); this.disabled = cx.disabledComputing; }, addType: function(fn, weight) { if (!(fn instanceof Fn)) return; for (var i = 0; i < this.args.length; ++i) { if (i < fn.args.length) this.args[i].propagate(fn.args[i], weight); if (fn.arguments) this.args[i].propagate(fn.arguments, weight); } this.self.propagate(fn.self, this.self == cx.topScope ? WG_GLOBAL_THIS : weight); var compute = fn.computeRet; if (compute) for (var d = this.disabled; d; d = d.prev) if (d.fn == fn || fn.originNode && d.fn.originNode == fn.originNode) compute = null; if (compute) compute(this.self, this.args, this.argNodes).propagate(this.retval, weight); else fn.retval.propagate(this.retval, weight); }, typeHint: function() { var names = []; for (var i = 0; i < this.args.length; ++i) names.push("?"); return new Fn(null, this.self, this.args, names, ANull); }, propagatesTo: function() { return {target: this.retval, pathExt: ".!ret"}; } }); var HasMethodCall = constraint("propName, args, argNodes, retval", { init: function() { Constraint.prototype.init.call(this); this.disabled = cx.disabledComputing; }, addType: function(obj, weight) { var callee = new IsCallee(obj, this.args, this.argNodes, this.retval); callee.disabled = this.disabled; obj.getProp(this.propName).propagate(callee, weight); }, propHint: function() { return this.propName; } }); var IsCtor = exports.IsCtor = constraint("target, noReuse", { addType: function(f, weight) { if (!(f instanceof Fn)) return; if (cx.parent && !cx.parent.options.reuseInstances) this.noReuse = true; f.getProp("prototype").propagate(new IsProto(this.noReuse ? false : f, this.target), weight); } }); var getInstance = exports.getInstance = function(obj, ctor) { if (ctor === false) return new Obj(obj); if (!ctor) ctor = obj.hasCtor; if (!obj.instances) obj.instances = []; for (var i = 0; i < obj.instances.length; ++i) { var cur = obj.instances[i]; if (cur.ctor == ctor) return cur.instance; } var instance = new Obj(obj, ctor && ctor.name); instance.origin = obj.origin; obj.instances.push({ctor: ctor, instance: instance}); return instance; }; var IsProto = exports.IsProto = constraint("ctor, target", { addType: function(o, _weight) { if (!(o instanceof Obj)) return; if ((this.count = (this.count || 0) + 1) > 8) return; if (o == cx.protos.Array) this.target.addType(new Arr); else this.target.addType(getInstance(o, this.ctor)); } }); var FnPrototype = constraint("fn", { addType: function(o, _weight) { if (o instanceof Obj && !o.hasCtor) { o.hasCtor = this.fn; var adder = new SpeculativeThis(o, this.fn); adder.addType(this.fn); o.forAllProps(function(_prop, val, local) { if (local) val.propagate(adder); }); } } }); var IsAdded = constraint("other, target", { addType: function(type, weight) { if (type == cx.str) this.target.addType(cx.str, weight); else if (type == cx.num && this.other.hasType(cx.num)) this.target.addType(cx.num, weight); }, typeHint: function() { return this.other; } }); var IfObj = exports.IfObj = constraint("target", { addType: function(t, weight) { if (t instanceof Obj) this.target.addType(t, weight); }, propagatesTo: function() { return this.target; } }); var SpeculativeThis = constraint("obj, ctor", { addType: function(tp) { if (tp instanceof Fn && tp.self && tp.self.isEmpty()) tp.self.addType(getInstance(this.obj, this.ctor), WG_SPECULATIVE_THIS); } }); var Muffle = constraint("inner, weight", { addType: function(tp, weight) { this.inner.addType(tp, Math.min(weight, this.weight)); }, propagatesTo: function() { return this.inner.propagatesTo(); }, typeHint: function() { return this.inner.typeHint(); }, propHint: function() { return this.inner.propHint(); } }); // TYPE OBJECTS var Type = exports.Type = function() {}; Type.prototype = extend(ANull, { constructor: Type, propagate: function(c, w) { c.addType(this, w); }, hasType: function(other) { return other == this; }, isEmpty: function() { return false; }, typeHint: function() { return this; }, getType: function() { return this; } }); var Prim = exports.Prim = function(proto, name) { this.name = name; this.proto = proto; }; Prim.prototype = extend(Type.prototype, { constructor: Prim, toString: function() { return this.name; }, getProp: function(prop) {return this.proto.hasProp(prop) || ANull;}, gatherProperties: function(f, depth) { if (this.proto) this.proto.gatherProperties(f, depth); } }); var Obj = exports.Obj = function(proto, name) { if (!this.props) this.props = Object.create(null); this.proto = proto === true ? cx.protos.Object : proto; if (proto && !name && proto.name && !(this instanceof Fn)) { var match = /^(.*)\.prototype$/.exec(this.proto.name); if (match) name = match[1]; } this.name = name; this.maybeProps = null; this.origin = cx.curOrigin; }; Obj.prototype = extend(Type.prototype, { constructor: Obj, toString: function(maxDepth) { if (maxDepth == null) maxDepth = 0; if (maxDepth <= 0 && this.name) return this.name; var props = [], etc = false; for (var prop in this.props) if (prop != "") { if (props.length > 5) { etc = true; break; } if (maxDepth) props.push(prop + ": " + toString(this.props[prop], maxDepth - 1, this)); else props.push(prop); } props.sort(); if (etc) props.push("..."); return "{" + props.join(", ") + "}"; }, hasProp: function(prop, searchProto) { var found = this.props[prop]; if (searchProto !== false) for (var p = this.proto; p && !found; p = p.proto) found = p.props[prop]; return found; }, defProp: function(prop, originNode) { var found = this.hasProp(prop, false); if (found) { if (originNode && !found.originNode) found.originNode = originNode; return found; } if (prop == "__proto__" || prop == "✖") return ANull; var av = this.maybeProps && this.maybeProps[prop]; if (av) { delete this.maybeProps[prop]; this.maybeUnregProtoPropHandler(); } else { av = new AVal; av.propertyOf = this; } this.props[prop] = av; av.originNode = originNode; av.origin = cx.curOrigin; this.broadcastProp(prop, av, true); return av; }, getProp: function(prop) { var found = this.hasProp(prop, true) || (this.maybeProps && this.maybeProps[prop]); if (found) return found; if (prop == "__proto__" || prop == "✖") return ANull; var av = this.ensureMaybeProps()[prop] = new AVal; av.propertyOf = this; return av; }, broadcastProp: function(prop, val, local) { if (local) { this.signal("addProp", prop, val); // If this is a scope, it shouldn't be registered if (!(this instanceof Scope)) registerProp(prop, this); } if (this.onNewProp) for (var i = 0; i < this.onNewProp.length; ++i) { var h = this.onNewProp[i]; h.onProtoProp ? h.onProtoProp(prop, val, local) : h(prop, val, local); } }, onProtoProp: function(prop, val, _local) { var maybe = this.maybeProps && this.maybeProps[prop]; if (maybe) { delete this.maybeProps[prop]; this.maybeUnregProtoPropHandler(); this.proto.getProp(prop).propagate(maybe); } this.broadcastProp(prop, val, false); }, ensureMaybeProps: function() { if (!this.maybeProps) { if (this.proto) this.proto.forAllProps(this); this.maybeProps = Object.create(null); } return this.maybeProps; }, removeProp: function(prop) { var av = this.props[prop]; delete this.props[prop]; this.ensureMaybeProps()[prop] = av; av.types.length = 0; }, forAllProps: function(c) { if (!this.onNewProp) { this.onNewProp = []; if (this.proto) this.proto.forAllProps(this); } this.onNewProp.push(c); for (var o = this; o; o = o.proto) for (var prop in o.props) { if (c.onProtoProp) c.onProtoProp(prop, o.props[prop], o == this); else c(prop, o.props[prop], o == this); } }, maybeUnregProtoPropHandler: function() { if (this.maybeProps) { for (var _n in this.maybeProps) return; this.maybeProps = null; } if (!this.proto || this.onNewProp && this.onNewProp.length) return; this.proto.unregPropHandler(this); }, unregPropHandler: function(handler) { for (var i = 0; i < this.onNewProp.length; ++i) if (this.onNewProp[i] == handler) { this.onNewProp.splice(i, 1); break; } this.maybeUnregProtoPropHandler(); }, gatherProperties: function(f, depth) { for (var prop in this.props) if (prop != "") f(prop, this, depth); if (this.proto) this.proto.gatherProperties(f, depth + 1); }, getObjType: function() { return this; } }); var Fn = exports.Fn = function(name, self, args, argNames, retval) { Obj.call(this, cx.protos.Function, name); this.self = self; this.args = args; this.argNames = argNames; this.retval = retval; }; Fn.prototype = extend(Obj.prototype, { constructor: Fn, toString: function(maxDepth) { if (maxDepth == null) maxDepth = 0; var str = "fn("; for (var i = 0; i < this.args.length; ++i) { if (i) str += ", "; var name = this.argNames[i]; if (name && name != "?") str += name + ": "; str += maxDepth > -3 ? toString(this.args[i], maxDepth - 1, this) : "?"; } str += ")"; if (!this.retval.isEmpty()) str += " -> " + (maxDepth > -3 ? toString(this.retval, maxDepth - 1, this) : "?"); return str; }, getProp: function(prop) { if (prop == "prototype") { var known = this.hasProp(prop, false); if (!known) { known = this.defProp(prop); var proto = new Obj(true, this.name && this.name + ".prototype"); proto.origin = this.origin; known.addType(proto, WG_MADEUP_PROTO); } return known; } return Obj.prototype.getProp.call(this, prop); }, defProp: function(prop, originNode) { if (prop == "prototype") { var found = this.hasProp(prop, false); if (found) return found; found = Obj.prototype.defProp.call(this, prop, originNode); found.origin = this.origin; found.propagate(new FnPrototype(this)); return found; } return Obj.prototype.defProp.call(this, prop, originNode); }, getFunctionType: function() { return this; } }); var Arr = exports.Arr = function(contentType) { Obj.call(this, cx.protos.Array); var content = this.defProp(""); if (contentType) contentType.propagate(content); }; Arr.prototype = extend(Obj.prototype, { constructor: Arr, toString: function(maxDepth) { if (maxDepth == null) maxDepth = 0; return "[" + (maxDepth > -3 ? toString(this.getProp(""), maxDepth - 1, this) : "?") + "]"; } }); // THE PROPERTY REGISTRY function registerProp(prop, obj) { var data = cx.props[prop] || (cx.props[prop] = []); data.push(obj); } function objsWithProp(prop) { return cx.props[prop]; } // INFERENCE CONTEXT exports.Context = function(defs, parent) { this.parent = parent; this.props = Object.create(null); this.protos = Object.create(null); this.origins = []; this.curOrigin = "ecma5"; this.paths = Object.create(null); this.definitions = Object.create(null); this.purgeGen = 0; this.workList = null; this.disabledComputing = null; exports.withContext(this, function() { cx.protos.Object = new Obj(null, "Object.prototype"); cx.topScope = new Scope(); cx.topScope.name = ""; cx.protos.Array = new Obj(true, "Array.prototype"); cx.protos.Function = new Obj(true, "Function.prototype"); cx.protos.RegExp = new Obj(true, "RegExp.prototype"); cx.protos.String = new Obj(true, "String.prototype"); cx.protos.Number = new Obj(true, "Number.prototype"); cx.protos.Boolean = new Obj(true, "Boolean.prototype"); cx.str = new Prim(cx.protos.String, "string"); cx.bool = new Prim(cx.protos.Boolean, "bool"); cx.num = new Prim(cx.protos.Number, "number"); cx.curOrigin = null; if (defs) for (var i = 0; i < defs.length; ++i) def.load(defs[i]); }); }; var cx = null; exports.cx = function() { return cx; }; exports.withContext = function(context, f) { var old = cx; cx = context; try { return f(); } finally { cx = old; } }; exports.TimedOut = function() { this.message = "Timed out"; this.stack = (new Error()).stack; }; exports.TimedOut.prototype = Object.create(Error.prototype); exports.TimedOut.prototype.name = "infer.TimedOut"; var timeout; exports.withTimeout = function(ms, f) { var end = +new Date + ms; var oldEnd = timeout; if (oldEnd && oldEnd < end) return f(); timeout = end; try { return f(); } finally { timeout = oldEnd; } }; exports.addOrigin = function(origin) { if (cx.origins.indexOf(origin) < 0) cx.origins.push(origin); }; var baseMaxWorkDepth = 20, reduceMaxWorkDepth = 0.0001; function withWorklist(f) { if (cx.workList) return f(cx.workList); var list = [], depth = 0; var add = cx.workList = function(type, target, weight) { if (depth < baseMaxWorkDepth - reduceMaxWorkDepth * list.length) list.push(type, target, weight, depth); }; try { var ret = f(add); for (var i = 0; i < list.length; i += 4) { if (timeout && +new Date >= timeout) throw new exports.TimedOut(); depth = list[i + 3] + 1; list[i + 1].addType(list[i], list[i + 2]); } return ret; } finally { cx.workList = null; } } // SCOPES var Scope = exports.Scope = function(prev) { Obj.call(this, prev || true); this.prev = prev; }; Scope.prototype = extend(Obj.prototype, { constructor: Scope, defVar: function(name, originNode) { for (var s = this; ; s = s.proto) { var found = s.props[name]; if (found) return found; if (!s.prev) return s.defProp(name, originNode); } } }); // RETVAL COMPUTATION HEURISTICS function maybeInstantiate(scope, score) { if (scope.fnType) scope.fnType.instantiateScore = (scope.fnType.instantiateScore || 0) + score; } var NotSmaller = {}; function nodeSmallerThan(node, n) { try { walk.simple(node, {Expression: function() { if (--n <= 0) throw NotSmaller; }}); return true; } catch(e) { if (e == NotSmaller) return false; throw e; } } function maybeTagAsInstantiated(node, scope) { var score = scope.fnType.instantiateScore; if (!cx.disabledComputing && score && scope.fnType.args.length && nodeSmallerThan(node, score * 5)) { maybeInstantiate(scope.prev, score / 2); setFunctionInstantiated(node, scope); return true; } else { scope.fnType.instantiateScore = null; } } function setFunctionInstantiated(node, scope) { var fn = scope.fnType; // Disconnect the arg avals, so that we can add info to them without side effects for (var i = 0; i < fn.args.length; ++i) fn.args[i] = new AVal; fn.self = new AVal; fn.computeRet = function(self, args) { // Prevent recursion return withDisabledComputing(fn, function() { var oldOrigin = cx.curOrigin; cx.curOrigin = fn.origin; var scopeCopy = new Scope(scope.prev); scopeCopy.originNode = scope.originNode; for (var v in scope.props) { var local = scopeCopy.defProp(v, scope.props[v].originNode); for (var i = 0; i < args.length; ++i) if (fn.argNames[i] == v && i < args.length) args[i].propagate(local); } var argNames = fn.argNames.length != args.length ? fn.argNames.slice(0, args.length) : fn.argNames; while (argNames.length < args.length) argNames.push("?"); scopeCopy.fnType = new Fn(fn.name, self, args, argNames, ANull); scopeCopy.fnType.originNode = fn.originNode; if (fn.arguments) { var argset = scopeCopy.fnType.arguments = new AVal; scopeCopy.defProp("arguments").addType(new Arr(argset)); for (var i = 0; i < args.length; ++i) args[i].propagate(argset); } node.body.scope = scopeCopy; walk.recursive(node.body, scopeCopy, null, scopeGatherer); walk.recursive(node.body, scopeCopy, null, inferWrapper); cx.curOrigin = oldOrigin; return scopeCopy.fnType.retval; }); }; } function maybeTagAsGeneric(scope) { var fn = scope.fnType, target = fn.retval; if (target == ANull) return; var targetInner, asArray; if (!target.isEmpty() && (targetInner = target.getType()) instanceof Arr) target = asArray = targetInner.getProp(""); function explore(aval, path, depth) { if (depth > 3 || !aval.forward) return; for (var i = 0; i < aval.forward.length; ++i) { var prop = aval.forward[i].propagatesTo(); if (!prop) continue; var newPath = path, dest; if (prop instanceof AVal) { dest = prop; } else if (prop.target instanceof AVal) { newPath += prop.pathExt; dest = prop.target; } else continue; if (dest == target) return newPath; var found = explore(dest, newPath, depth + 1); if (found) return found; } } var foundPath = explore(fn.self, "!this", 0); for (var i = 0; !foundPath && i < fn.args.length; ++i) foundPath = explore(fn.args[i], "!" + i, 0); if (foundPath) { if (asArray) foundPath = "[" + foundPath + "]"; var p = new def.TypeParser(foundPath); var parsed = p.parseType(true); fn.computeRet = parsed.apply ? parsed : function() { return parsed; }; fn.computeRetSource = foundPath; return true; } } // SCOPE GATHERING PASS function addVar(scope, nameNode) { return scope.defProp(nameNode.name, nameNode); } var scopeGatherer = walk.make({ Function: function(node, scope, c) { var inner = node.body.scope = new Scope(scope); inner.originNode = node; var argVals = [], argNames = []; for (var i = 0; i < node.params.length; ++i) { var param = node.params[i]; argNames.push(param.name); argVals.push(addVar(inner, param)); } inner.fnType = new Fn(node.id && node.id.name, new AVal, argVals, argNames, ANull); inner.fnType.originNode = node; if (node.id) { var decl = node.type == "FunctionDeclaration"; addVar(decl ? scope : inner, node.id); } c(node.body, inner, "ScopeBody"); }, TryStatement: function(node, scope, c) { c(node.block, scope, "Statement"); if (node.handler) { var v = addVar(scope, node.handler.param); c(node.handler.body, scope, "ScopeBody"); var e5 = cx.definitions.ecma5; if (e5 && v.isEmpty()) getInstance(e5["Error.prototype"]).propagate(v, WG_CATCH_ERROR); } if (node.finalizer) c(node.finalizer, scope, "Statement"); }, VariableDeclaration: function(node, scope, c) { for (var i = 0; i < node.declarations.length; ++i) { var decl = node.declarations[i]; addVar(scope, decl.id); if (decl.init) c(decl.init, scope, "Expression"); } } }); // CONSTRAINT GATHERING PASS function propName(node, scope, c) { var prop = node.property; if (!node.computed) return prop.name; if (prop.type == "Literal" && typeof prop.value == "string") return prop.value; if (c) infer(prop, scope, c, ANull); return ""; } function unopResultType(op) { switch (op) { case "+": case "-": case "~": return cx.num; case "!": return cx.bool; case "typeof": return cx.str; case "void": case "delete": return ANull; } } function binopIsBoolean(op) { switch (op) { case "==": case "!=": case "===": case "!==": case "<": case ">": case ">=": case "<=": case "in": case "instanceof": return true; } } function literalType(node) { if (node.regex) return getInstance(cx.protos.RegExp); switch (typeof node.value) { case "boolean": return cx.bool; case "number": return cx.num; case "string": return cx.str; case "object": case "function": if (!node.value) return ANull; return getInstance(cx.protos.RegExp); } } function ret(f) { return function(node, scope, c, out, name) { var r = f(node, scope, c, name); if (out) r.propagate(out); return r; }; } function fill(f) { return function(node, scope, c, out, name) { if (!out) out = new AVal; f(node, scope, c, out, name); return out; }; } var inferExprVisitor = { ArrayExpression: ret(function(node, scope, c) { var eltval = new AVal; for (var i = 0; i < node.elements.length; ++i) { var elt = node.elements[i]; if (elt) infer(elt, scope, c, eltval); } return new Arr(eltval); }), ObjectExpression: ret(function(node, scope, c, name) { var obj = node.objType = new Obj(true, name); obj.originNode = node; for (var i = 0; i < node.properties.length; ++i) { var prop = node.properties[i], key = prop.key, name; if (prop.value.name == "✖") continue; if (key.type == "Identifier") { name = key.name; } else if (typeof key.value == "string") { name = key.value; } if (!name || prop.kind == "set") { infer(prop.value, scope, c, ANull); continue; } var val = obj.defProp(name, key), out = val; val.initializer = true; if (prop.kind == "get") out = new IsCallee(obj, [], null, val); infer(prop.value, scope, c, out, name); } return obj; }), FunctionExpression: ret(function(node, scope, c, name) { var inner = node.body.scope, fn = inner.fnType; if (name && !fn.name) fn.name = name; c(node.body, scope, "ScopeBody"); maybeTagAsInstantiated(node, inner) || maybeTagAsGeneric(inner); if (node.id) inner.getProp(node.id.name).addType(fn); return fn; }), SequenceExpression: ret(function(node, scope, c) { for (var i = 0, l = node.expressions.length - 1; i < l; ++i) infer(node.expressions[i], scope, c, ANull); return infer(node.expressions[l], scope, c); }), UnaryExpression: ret(function(node, scope, c) { infer(node.argument, scope, c, ANull); return unopResultType(node.operator); }), UpdateExpression: ret(function(node, scope, c) { infer(node.argument, scope, c, ANull); return cx.num; }), BinaryExpression: ret(function(node, scope, c) { if (node.operator == "+") { var lhs = infer(node.left, scope, c); var rhs = infer(node.right, scope, c); if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str; if (lhs.hasType(cx.num) && rhs.hasType(cx.num)) return cx.num; var result = new AVal; lhs.propagate(new IsAdded(rhs, result)); rhs.propagate(new IsAdded(lhs, result)); return result; } else { infer(node.left, scope, c, ANull); infer(node.right, scope, c, ANull); return binopIsBoolean(node.operator) ? cx.bool : cx.num; } }), AssignmentExpression: ret(function(node, scope, c) { var rhs, name, pName; if (node.left.type == "MemberExpression") { pName = propName(node.left, scope, c); if (node.left.object.type == "Identifier") name = node.left.object.name + "." + pName; } else { name = node.left.name; } if (node.operator != "=" && node.operator != "+=") { infer(node.right, scope, c, ANull); rhs = cx.num; } else { rhs = infer(node.right, scope, c, null, name); } if (node.left.type == "MemberExpression") { var obj = infer(node.left.object, scope, c); if (pName == "prototype") maybeInstantiate(scope, 20); if (pName == "") { // This is a hack to recognize for/in loops that copy // properties, and do the copying ourselves, insofar as we // manage, because such loops tend to be relevant for type // information. var v = node.left.property.name, local = scope.props[v], over = local && local.iteratesOver; if (over) { maybeInstantiate(scope, 20); var fromRight = node.right.type == "MemberExpression" && node.right.computed && node.right.property.name == v; over.forAllProps(function(prop, val, local) { if (local && prop != "prototype" && prop != "") obj.propagate(new PropHasSubset(prop, fromRight ? val : ANull)); }); return rhs; } } obj.propagate(new PropHasSubset(pName, rhs, node.left.property)); } else { // Identifier rhs.propagate(scope.defVar(node.left.name, node.left)); } return rhs; }), LogicalExpression: fill(function(node, scope, c, out) { infer(node.left, scope, c, out); infer(node.right, scope, c, out); }), ConditionalExpression: fill(function(node, scope, c, out) { infer(node.test, scope, c, ANull); infer(node.consequent, scope, c, out); infer(node.alternate, scope, c, out); }), NewExpression: fill(function(node, scope, c, out, name) { if (node.callee.type == "Identifier" && node.callee.name in scope.props) maybeInstantiate(scope, 20); for (var i = 0, args = []; i < node.arguments.length; ++i) args.push(infer(node.arguments[i], scope, c)); var callee = infer(node.callee, scope, c); var self = new AVal; callee.propagate(new IsCtor(self, name && /\.prototype$/.test(name))); self.propagate(out, WG_NEW_INSTANCE); callee.propagate(new IsCallee(self, args, node.arguments, new IfObj(out))); }), CallExpression: fill(function(node, scope, c, out) { for (var i = 0, args = []; i < node.arguments.length; ++i) args.push(infer(node.arguments[i], scope, c)); if (node.callee.type == "MemberExpression") { var self = infer(node.callee.object, scope, c); var pName = propName(node.callee, scope, c); if ((pName == "call" || pName == "apply") && scope.fnType && scope.fnType.args.indexOf(self) > -1) maybeInstantiate(scope, 30); self.propagate(new HasMethodCall(pName, args, node.arguments, out)); } else { var callee = infer(node.callee, scope, c); if (scope.fnType && scope.fnType.args.indexOf(callee) > -1) maybeInstantiate(scope, 30); var knownFn = callee.getFunctionType(); if (knownFn && knownFn.instantiateScore && scope.fnType) maybeInstantiate(scope, knownFn.instantiateScore / 5); callee.propagate(new IsCallee(cx.topScope, args, node.arguments, out)); } }), MemberExpression: fill(function(node, scope, c, out) { var name = propName(node, scope); var obj = infer(node.object, scope, c); var prop = obj.getProp(name); if (name == "") { var propType = infer(node.property, scope, c); if (!propType.hasType(cx.num)) return prop.propagate(out, WG_MULTI_MEMBER); } prop.propagate(out); }), Identifier: ret(function(node, scope) { if (node.name == "arguments" && scope.fnType && !(node.name in scope.props)) scope.defProp(node.name, scope.fnType.originNode) .addType(new Arr(scope.fnType.arguments = new AVal)); return scope.getProp(node.name); }), ThisExpression: ret(function(_node, scope) { return scope.fnType ? scope.fnType.self : cx.topScope; }), Literal: ret(function(node) { return literalType(node); }) }; function infer(node, scope, c, out, name) { return inferExprVisitor[node.type](node, scope, c, out, name); } var inferWrapper = walk.make({ Expression: function(node, scope, c) { infer(node, scope, c, ANull); }, FunctionDeclaration: function(node, scope, c) { var inner = node.body.scope, fn = inner.fnType; c(node.body, scope, "ScopeBody"); maybeTagAsInstantiated(node, inner) || maybeTagAsGeneric(inner); var prop = scope.getProp(node.id.name); prop.addType(fn); }, VariableDeclaration: function(node, scope, c) { for (var i = 0; i < node.declarations.length; ++i) { var decl = node.declarations[i], prop = scope.getProp(decl.id.name); if (decl.init) infer(decl.init, scope, c, prop, decl.id.name); } }, ReturnStatement: function(node, scope, c) { if (!node.argument) return; var output = ANull; if (scope.fnType) { if (scope.fnType.retval == ANull) scope.fnType.retval = new AVal; output = scope.fnType.retval; } infer(node.argument, scope, c, output); }, ForInStatement: function(node, scope, c) { var source = infer(node.right, scope, c); if ((node.right.type == "Identifier" && node.right.name in scope.props) || (node.right.type == "MemberExpression" && node.right.property.name == "prototype")) { maybeInstantiate(scope, 5); var varName; if (node.left.type == "Identifier") { varName = node.left.name; } else if (node.left.type == "VariableDeclaration") { varName = node.left.declarations[0].id.name; } if (varName && varName in scope.props) scope.getProp(varName).iteratesOver = source; } c(node.body, scope, "Statement"); }, ScopeBody: function(node, scope, c) { c(node, node.scope || scope); } }); // PARSING function runPasses(passes, pass) { var arr = passes && passes[pass]; var args = Array.prototype.slice.call(arguments, 2); if (arr) for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); } var parse = exports.parse = function(text, passes, options) { var ast; try { ast = acorn.parse(text, options); } catch(e) { ast = acorn_loose.parse_dammit(text, options); } runPasses(passes, "postParse", ast, text); return ast; }; // ANALYSIS INTERFACE exports.analyze = function(ast, name, scope, passes) { if (typeof ast == "string") ast = parse(ast); if (!name) name = "file#" + cx.origins.length; exports.addOrigin(cx.curOrigin = name); if (!scope) scope = cx.topScope; walk.recursive(ast, scope, null, scopeGatherer); runPasses(passes, "preInfer", ast, scope); walk.recursive(ast, scope, null, inferWrapper); runPasses(passes, "postInfer", ast, scope); cx.curOrigin = null; }; // PURGING exports.purge = function(origins, start, end) { var test = makePredicate(origins, start, end); ++cx.purgeGen; cx.topScope.purge(test); for (var prop in cx.props) { var list = cx.props[prop]; for (var i = 0; i < list.length; ++i) { var obj = list[i], av = obj.props[prop]; if (!av || test(av, av.originNode)) list.splice(i--, 1); } if (!list.length) delete cx.props[prop]; } }; function makePredicate(origins, start, end) { var arr = Array.isArray(origins); if (arr && origins.length == 1) { origins = origins[0]; arr = false; } if (arr) { if (end == null) return function(n) { return origins.indexOf(n.origin) > -1; }; return function(n, pos) { return pos && pos.start >= start && pos.end <= end && origins.indexOf(n.origin) > -1; }; } else { if (end == null) return function(n) { return n.origin == origins; }; return function(n, pos) { return pos && pos.start >= start && pos.end <= end && n.origin == origins; }; } } AVal.prototype.purge = function(test) { if (this.purgeGen == cx.purgeGen) return; this.purgeGen = cx.purgeGen; for (var i = 0; i < this.types.length; ++i) { var type = this.types[i]; if (test(type, type.originNode)) this.types.splice(i--, 1); else type.purge(test); } if (this.forward) for (var i = 0; i < this.forward.length; ++i) { var f = this.forward[i]; if (test(f)) { this.forward.splice(i--, 1); if (this.props) this.props = null; } else if (f.purge) { f.purge(test); } } }; ANull.purge = function() {}; Obj.prototype.purge = function(test) { if (this.purgeGen == cx.purgeGen) return true; this.purgeGen = cx.purgeGen; for (var p in this.props) { var av = this.props[p]; if (test(av, av.originNode)) this.removeProp(p); av.purge(test); } }; Fn.prototype.purge = function(test) { if (Obj.prototype.purge.call(this, test)) return; this.self.purge(test); this.retval.purge(test); for (var i = 0; i < this.args.length; ++i) this.args[i].purge(test); }; // EXPRESSION TYPE DETERMINATION function findByPropertyName(name) { guessing = true; var found = objsWithProp(name); if (found) for (var i = 0; i < found.length; ++i) { var val = found[i].getProp(name); if (!val.isEmpty()) return val; } return ANull; } var typeFinder = { ArrayExpression: function(node, scope) { var eltval = new AVal; for (var i = 0; i < node.elements.length; ++i) { var elt = node.elements[i]; if (elt) findType(elt, scope).propagate(eltval); } return new Arr(eltval); }, ObjectExpression: function(node) { return node.objType; }, FunctionExpression: function(node) { return node.body.scope.fnType; }, SequenceExpression: function(node, scope) { return findType(node.expressions[node.expressions.length-1], scope); }, UnaryExpression: function(node) { return unopResultType(node.operator); }, UpdateExpression: function() { return cx.num; }, BinaryExpression: function(node, scope) { if (binopIsBoolean(node.operator)) return cx.bool; if (node.operator == "+") { var lhs = findType(node.left, scope); var rhs = findType(node.right, scope); if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str; } return cx.num; }, AssignmentExpression: function(node, scope) { return findType(node.right, scope); }, LogicalExpression: function(node, scope) { var lhs = findType(node.left, scope); return lhs.isEmpty() ? findType(node.right, scope) : lhs; }, ConditionalExpression: function(node, scope) { var lhs = findType(node.consequent, scope); return lhs.isEmpty() ? findType(node.alternate, scope) : lhs; }, NewExpression: function(node, scope) { var f = findType(node.callee, scope).getFunctionType(); var proto = f && f.getProp("prototype").getObjType(); if (!proto) return ANull; return getInstance(proto, f); }, CallExpression: function(node, scope) { var f = findType(node.callee, scope).getFunctionType(); if (!f) return ANull; if (f.computeRet) { for (var i = 0, args = []; i < node.arguments.length; ++i) args.push(findType(node.arguments[i], scope)); var self = ANull; if (node.callee.type == "MemberExpression") self = findType(node.callee.object, scope); return f.computeRet(self, args, node.arguments); } else { return f.retval; } }, MemberExpression: function(node, scope) { var propN = propName(node, scope), obj = findType(node.object, scope).getType(); if (obj) return obj.getProp(propN); if (propN == "") return ANull; return findByPropertyName(propN); }, Identifier: function(node, scope) { return scope.hasProp(node.name) || ANull; }, ThisExpression: function(_node, scope) { return scope.fnType ? scope.fnType.self : cx.topScope; }, Literal: function(node) { return literalType(node); } }; function findType(node, scope) { return typeFinder[node.type](node, scope); } var searchVisitor = exports.searchVisitor = walk.make({ Function: function(node, _st, c) { var scope = node.body.scope; if (node.id) c(node.id, scope); for (var i = 0; i < node.params.length; ++i) c(node.params[i], scope); c(node.body, scope, "ScopeBody"); }, TryStatement: function(node, st, c) { if (node.handler) c(node.handler.param, st); walk.base.TryStatement(node, st, c); }, VariableDeclaration: function(node, st, c) { for (var i = 0; i < node.declarations.length; ++i) { var decl = node.declarations[i]; c(decl.id, st); if (decl.init) c(decl.init, st, "Expression"); } } }); exports.fullVisitor = walk.make({ MemberExpression: function(node, st, c) { c(node.object, st, "Expression"); c(node.property, st, node.computed ? "Expression" : null); }, ObjectExpression: function(node, st, c) { for (var i = 0; i < node.properties.length; ++i) { c(node.properties[i].value, st, "Expression"); c(node.properties[i].key, st); } } }, searchVisitor); exports.findExpressionAt = function(ast, start, end, defaultScope, filter) { var test = filter || function(_t, node) { if (node.type == "Identifier" && node.name == "✖") return false; return typeFinder.hasOwnProperty(node.type); }; return walk.findNodeAt(ast, start, end, test, searchVisitor, defaultScope || cx.topScope); }; exports.findExpressionAround = function(ast, start, end, defaultScope, filter) { var test = filter || function(_t, node) { if (start != null && node.start > start) return false; if (node.type == "Identifier" && node.name == "✖") return false; return typeFinder.hasOwnProperty(node.type); }; return walk.findNodeAround(ast, end, test, searchVisitor, defaultScope || cx.topScope); }; exports.expressionType = function(found) { return findType(found.node, found.state); }; // Finding the expected type of something, from context exports.parentNode = function(child, ast) { var stack = []; function c(node, st, override) { if (node.start <= child.start && node.end >= child.end) { var top = stack[stack.length - 1]; if (node == child) throw {found: top}; if (top != node) stack.push(node); walk.base[override || node.type](node, st, c); if (top != node) stack.pop(); } } try { c(ast, null); } catch (e) { if (e.found) return e.found; throw e; } }; var findTypeFromContext = { ArrayExpression: function(parent, _, get) { return get(parent, true).getProp(""); }, ObjectExpression: function(parent, node, get) { for (var i = 0; i < parent.properties.length; ++i) { var prop = node.properties[i]; if (prop.value == node) return get(parent, true).getProp(prop.key.name); } }, UnaryExpression: function(parent) { return unopResultType(parent.operator); }, UpdateExpression: function() { return cx.num; }, BinaryExpression: function(parent) { return binopIsBoolean(parent.operator) ? cx.bool : cx.num; }, AssignmentExpression: function(parent, _, get) { return get(parent.left); }, LogicalExpression: function(parent, _, get) { return get(parent, true); }, ConditionalExpression: function(parent, node, get) { if (parent.consequent == node || parent.alternate == node) return get(parent, true); }, NewExpression: function(parent, node, get) { return this.CallExpression(parent, node, get); }, CallExpression: function(parent, node, get) { for (var i = 0; i < parent.arguments.length; i++) { var arg = parent.arguments[i]; if (arg == node) { var calleeType = get(parent.callee).getFunctionType(); if (calleeType instanceof Fn) return calleeType.args[i]; break; } } }, ReturnStatement: function(_parent, node, get) { var fnNode = walk.findNodeAround(node.sourceFile.ast, node.start, "Function"); if (fnNode) { var fnType = fnNode.node.type == "FunctionExpression" ? get(fnNode.node, true).getFunctionType() : fnNode.node.body.scope.fnType; if (fnType) return fnType.retval.getType(); } }, VariableDeclaration: function(parent, node, get) { for (var i = 0; i < parent.declarations.length; i++) { var decl = parent.declarations[i]; if (decl.init == node) return get(decl.id); } } }; exports.typeFromContext = function(ast, found) { var parent = exports.parentNode(found.node, ast); var type = null; if (findTypeFromContext.hasOwnProperty(parent.type)) { type = findTypeFromContext[parent.type](parent, found.node, function(node, fromContext) { var obj = {node: node, state: found.state}; var tp = fromContext ? exports.typeFromContext(ast, obj) : exports.expressionType(obj); return tp || ANull; }); } return type || exports.expressionType(found); }; // Flag used to indicate that some wild guessing was used to produce // a type or set of completions. var guessing = false; exports.resetGuessing = function(val) { guessing = val; }; exports.didGuess = function() { return guessing; }; exports.forAllPropertiesOf = function(type, f) { type.gatherProperties(f, 0); }; var refFindWalker = walk.make({}, searchVisitor); exports.findRefs = function(ast, baseScope, name, refScope, f) { refFindWalker.Identifier = function(node, scope) { if (node.name != name) return; for (var s = scope; s; s = s.prev) { if (s == refScope) f(node, scope); if (name in s.props) return; } }; walk.recursive(ast, baseScope, null, refFindWalker); }; var simpleWalker = walk.make({ Function: function(node, _st, c) { c(node.body, node.body.scope, "ScopeBody"); } }); exports.findPropRefs = function(ast, scope, objType, propName, f) { walk.simple(ast, { MemberExpression: function(node, scope) { if (node.computed || node.property.name != propName) return; if (findType(node.object, scope).getType() == objType) f(node.property); }, ObjectExpression: function(node, scope) { if (findType(node, scope).getType() != objType) return; for (var i = 0; i < node.properties.length; ++i) if (node.properties[i].key.name == propName) f(node.properties[i].key); } }, simpleWalker, scope); }; // LOCAL-VARIABLE QUERIES var scopeAt = exports.scopeAt = function(ast, pos, defaultScope) { var found = walk.findNodeAround(ast, pos, function(tp, node) { return tp == "ScopeBody" && node.scope; }); if (found) return found.node.scope; else return defaultScope || cx.topScope; }; exports.forAllLocalsAt = function(ast, pos, defaultScope, f) { var scope = scopeAt(ast, pos, defaultScope); scope.gatherProperties(f, 0); }; // INIT DEF MODULE // Delayed initialization because of cyclic dependencies. def = exports.def = def.init({}, exports); }); three.js-r73/editor/js/libs/codemirror/0000755000175500017550000000000012610076566017754 5ustar debacledebaclethree.js-r73/editor/js/libs/codemirror/codemirror.css0000644000175500017550000001704612610076566022643 0ustar debacledebacle/* BASICS */ .CodeMirror { /* Set height, width, borders, and global font properties here */ font-family: monospace; height: 300px; color: black; } /* PADDING */ .CodeMirror-lines { padding: 4px 0; /* Vertical padding around content */ } .CodeMirror pre { padding: 0 4px; /* Horizontal padding of content */ } .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { background-color: white; /* The little square between H and V scrollbars */ } /* GUTTER */ .CodeMirror-gutters { border-right: 1px solid #ddd; background-color: #f7f7f7; white-space: nowrap; } .CodeMirror-linenumbers {} .CodeMirror-linenumber { padding: 0 3px 0 5px; min-width: 20px; text-align: right; color: #999; white-space: nowrap; } .CodeMirror-guttermarker { color: black; } .CodeMirror-guttermarker-subtle { color: #999; } /* CURSOR */ .CodeMirror div.CodeMirror-cursor { border-left: 1px solid black; } /* Shown when moving in bi-directional text */ .CodeMirror div.CodeMirror-secondarycursor { border-left: 1px solid silver; } .CodeMirror.cm-fat-cursor div.CodeMirror-cursor { width: auto; border: 0; background: #7e7; } .CodeMirror.cm-fat-cursor div.CodeMirror-cursors { z-index: 1; } .cm-animate-fat-cursor { width: auto; border: 0; -webkit-animation: blink 1.06s steps(1) infinite; -moz-animation: blink 1.06s steps(1) infinite; animation: blink 1.06s steps(1) infinite; } @-moz-keyframes blink { 0% { background: #7e7; } 50% { background: none; } 100% { background: #7e7; } } @-webkit-keyframes blink { 0% { background: #7e7; } 50% { background: none; } 100% { background: #7e7; } } @keyframes blink { 0% { background: #7e7; } 50% { background: none; } 100% { background: #7e7; } } /* Can style cursor different in overwrite (non-insert) mode */ div.CodeMirror-overwrite div.CodeMirror-cursor {} .cm-tab { display: inline-block; text-decoration: inherit; } .CodeMirror-ruler { border-left: 1px solid #ccc; position: absolute; } /* DEFAULT THEME */ .cm-s-default .cm-keyword {color: #708;} .cm-s-default .cm-atom {color: #219;} .cm-s-default .cm-number {color: #164;} .cm-s-default .cm-def {color: #00f;} .cm-s-default .cm-variable, .cm-s-default .cm-punctuation, .cm-s-default .cm-property, .cm-s-default .cm-operator {} .cm-s-default .cm-variable-2 {color: #05a;} .cm-s-default .cm-variable-3 {color: #085;} .cm-s-default .cm-comment {color: #a50;} .cm-s-default .cm-string {color: #a11;} .cm-s-default .cm-string-2 {color: #f50;} .cm-s-default .cm-meta {color: #555;} .cm-s-default .cm-qualifier {color: #555;} .cm-s-default .cm-builtin {color: #30a;} .cm-s-default .cm-bracket {color: #997;} .cm-s-default .cm-tag {color: #170;} .cm-s-default .cm-attribute {color: #00c;} .cm-s-default .cm-header {color: blue;} .cm-s-default .cm-quote {color: #090;} .cm-s-default .cm-hr {color: #999;} .cm-s-default .cm-link {color: #00c;} .cm-negative {color: #d44;} .cm-positive {color: #292;} .cm-header, .cm-strong {font-weight: bold;} .cm-em {font-style: italic;} .cm-link {text-decoration: underline;} .cm-strikethrough {text-decoration: line-through;} .cm-s-default .cm-error {color: #f00;} .cm-invalidchar {color: #f00;} /* Default styles for common addons */ div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } .CodeMirror-activeline-background {background: #e8f2ff;} /* STOP */ /* The rest of this file contains styles related to the mechanics of the editor. You probably shouldn't touch them. */ .CodeMirror { position: relative; overflow: hidden; background: white; } .CodeMirror-scroll { overflow: scroll !important; /* Things will break if this is overridden */ /* 30px is the magic margin used to hide the element's real scrollbars */ /* See overflow: hidden in .CodeMirror */ margin-bottom: -30px; margin-right: -30px; padding-bottom: 30px; height: 100%; outline: none; /* Prevent dragging from highlighting the element */ position: relative; } .CodeMirror-sizer { position: relative; border-right: 30px solid transparent; } /* The fake, visible scrollbars. Used to force redraw during scrolling before actuall scrolling happens, thus preventing shaking and flickering artifacts. */ .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none; } .CodeMirror-vscrollbar { right: 0; top: 0; overflow-x: hidden; overflow-y: scroll; } .CodeMirror-hscrollbar { bottom: 0; left: 0; overflow-y: hidden; overflow-x: scroll; } .CodeMirror-scrollbar-filler { right: 0; bottom: 0; } .CodeMirror-gutter-filler { left: 0; bottom: 0; } .CodeMirror-gutters { position: absolute; left: 0; top: 0; z-index: 3; } .CodeMirror-gutter { white-space: normal; height: 100%; display: inline-block; margin-bottom: -30px; /* Hack to make IE7 behave */ *zoom:1; *display:inline; } .CodeMirror-gutter-wrapper { position: absolute; z-index: 4; height: 100%; } .CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; } .CodeMirror-gutter-wrapper { -webkit-user-select: none; -moz-user-select: none; user-select: none; } .CodeMirror-lines { cursor: text; min-height: 1px; /* prevents collapsing before first draw */ } .CodeMirror pre { /* Reset some styles that the rest of the page might have set */ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; border-width: 0; background: transparent; font-family: inherit; font-size: inherit; margin: 0; white-space: pre; word-wrap: normal; line-height: inherit; color: inherit; z-index: 2; position: relative; overflow: visible; -webkit-tap-highlight-color: transparent; } .CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; } .CodeMirror-linebackground { position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: 0; } .CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; } .CodeMirror-widget {} .CodeMirror-code { outline: none; } /* Force content-box sizing for the elements where we expect it */ .CodeMirror-scroll, .CodeMirror-sizer, .CodeMirror-gutter, .CodeMirror-gutters, .CodeMirror-linenumber { -moz-box-sizing: content-box; box-sizing: content-box; } .CodeMirror-measure { position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden; } .CodeMirror-measure pre { position: static; } .CodeMirror div.CodeMirror-cursor { position: absolute; border-right: none; width: 0; } div.CodeMirror-cursors { visibility: hidden; position: relative; z-index: 3; } .CodeMirror-focused div.CodeMirror-cursors { visibility: visible; } .CodeMirror-selected { background: #d9d9d9; } .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } .CodeMirror-crosshair { cursor: crosshair; } .CodeMirror ::selection { background: #d7d4f0; } .CodeMirror ::-moz-selection { background: #d7d4f0; } .cm-searching { background: #ffa; background: rgba(255, 255, 0, .4); } /* IE7 hack to prevent it from returning funny offsetTops on the spans */ .CodeMirror span { *vertical-align: text-bottom; } /* Used to force a border model for a node */ .cm-force-border { padding-right: .1px; } @media print { /* Hide the cursor when printing */ .CodeMirror div.CodeMirror-cursors { visibility: hidden; } } /* See issue #2901 */ .cm-tab-wrap-hack:after { content: ''; } /* Help users use markselection to safely style text background */ span.CodeMirror-selectedtext { background: none; } three.js-r73/editor/js/libs/codemirror/mode/0000755000175500017550000000000012610076566020700 5ustar debacledebaclethree.js-r73/editor/js/libs/codemirror/mode/javascript.js0000644000175500017550000006354612610076566023422 0ustar debacledebacle// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE // TODO actually recognize syntax of TypeScript constructs (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { "use strict"; CodeMirror.defineMode("javascript", function(config, parserConfig) { var indentUnit = config.indentUnit; var statementIndent = parserConfig.statementIndent; var jsonldMode = parserConfig.jsonld; var jsonMode = parserConfig.json || jsonldMode; var isTS = parserConfig.typescript; var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; // Tokenizer var keywords = function(){ function kw(type) {return {type: type, style: "keyword"};} var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); var operator = kw("operator"), atom = {type: "atom", style: "atom"}; var jsKeywords = { "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C, "var": kw("var"), "const": kw("var"), "let": kw("var"), "function": kw("function"), "catch": kw("catch"), "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), "in": operator, "typeof": operator, "instanceof": operator, "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"), "yield": C, "export": kw("export"), "import": kw("import"), "extends": C }; // Extend the 'normal' keywords with the TypeScript language extensions if (isTS) { var type = {type: "variable", style: "variable-3"}; var tsKeywords = { // object-like things "interface": kw("interface"), "extends": kw("extends"), "constructor": kw("constructor"), // scope modifiers "public": kw("public"), "private": kw("private"), "protected": kw("protected"), "static": kw("static"), // types "string": type, "number": type, "bool": type, "any": type }; for (var attr in tsKeywords) { jsKeywords[attr] = tsKeywords[attr]; } } return jsKeywords; }(); var isOperatorChar = /[+\-*&%=<>!?|~^]/; var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; function readRegexp(stream) { var escaped = false, next, inSet = false; while ((next = stream.next()) != null) { if (!escaped) { if (next == "/" && !inSet) return; if (next == "[") inSet = true; else if (inSet && next == "]") inSet = false; } escaped = !escaped && next == "\\"; } } // Used as scratch variables to communicate multiple values without // consing up tons of objects. var type, content; function ret(tp, style, cont) { type = tp; content = cont; return style; } function tokenBase(stream, state) { var ch = stream.next(); if (ch == '"' || ch == "'") { state.tokenize = tokenString(ch); return state.tokenize(stream, state); } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { return ret("number", "number"); } else if (ch == "." && stream.match("..")) { return ret("spread", "meta"); } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { return ret(ch); } else if (ch == "=" && stream.eat(">")) { return ret("=>", "operator"); } else if (ch == "0" && stream.eat(/x/i)) { stream.eatWhile(/[\da-f]/i); return ret("number", "number"); } else if (/\d/.test(ch)) { stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); return ret("number", "number"); } else if (ch == "/") { if (stream.eat("*")) { state.tokenize = tokenComment; return tokenComment(stream, state); } else if (stream.eat("/")) { stream.skipToEnd(); return ret("comment", "comment"); } else if (state.lastType == "operator" || state.lastType == "keyword c" || state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { readRegexp(stream); stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); return ret("regexp", "string-2"); } else { stream.eatWhile(isOperatorChar); return ret("operator", "operator", stream.current()); } } else if (ch == "`") { state.tokenize = tokenQuasi; return tokenQuasi(stream, state); } else if (ch == "#") { stream.skipToEnd(); return ret("error", "error"); } else if (isOperatorChar.test(ch)) { stream.eatWhile(isOperatorChar); return ret("operator", "operator", stream.current()); } else if (wordRE.test(ch)) { stream.eatWhile(wordRE); var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; return (known && state.lastType != ".") ? ret(known.type, known.style, word) : ret("variable", "variable", word); } } function tokenString(quote) { return function(stream, state) { var escaped = false, next; if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ state.tokenize = tokenBase; return ret("jsonld-keyword", "meta"); } while ((next = stream.next()) != null) { if (next == quote && !escaped) break; escaped = !escaped && next == "\\"; } if (!escaped) state.tokenize = tokenBase; return ret("string", "string"); }; } function tokenComment(stream, state) { var maybeEnd = false, ch; while (ch = stream.next()) { if (ch == "/" && maybeEnd) { state.tokenize = tokenBase; break; } maybeEnd = (ch == "*"); } return ret("comment", "comment"); } function tokenQuasi(stream, state) { var escaped = false, next; while ((next = stream.next()) != null) { if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { state.tokenize = tokenBase; break; } escaped = !escaped && next == "\\"; } return ret("quasi", "string-2", stream.current()); } var brackets = "([{}])"; // This is a crude lookahead trick to try and notice that we're // parsing the argument patterns for a fat-arrow function before we // actually hit the arrow token. It only works if the arrow is on // the same line as the arguments and there's no strange noise // (comments) in between. Fallback is to only notice when we hit the // arrow, and not declare the arguments as locals for the arrow // body. function findFatArrow(stream, state) { if (state.fatArrowAt) state.fatArrowAt = null; var arrow = stream.string.indexOf("=>", stream.start); if (arrow < 0) return; var depth = 0, sawSomething = false; for (var pos = arrow - 1; pos >= 0; --pos) { var ch = stream.string.charAt(pos); var bracket = brackets.indexOf(ch); if (bracket >= 0 && bracket < 3) { if (!depth) { ++pos; break; } if (--depth == 0) break; } else if (bracket >= 3 && bracket < 6) { ++depth; } else if (wordRE.test(ch)) { sawSomething = true; } else if (/["'\/]/.test(ch)) { return; } else if (sawSomething && !depth) { ++pos; break; } } if (sawSomething && !depth) state.fatArrowAt = pos; } // Parser var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; function JSLexical(indented, column, type, align, prev, info) { this.indented = indented; this.column = column; this.type = type; this.prev = prev; this.info = info; if (align != null) this.align = align; } function inScope(state, varname) { for (var v = state.localVars; v; v = v.next) if (v.name == varname) return true; for (var cx = state.context; cx; cx = cx.prev) { for (var v = cx.vars; v; v = v.next) if (v.name == varname) return true; } } function parseJS(state, style, type, content, stream) { var cc = state.cc; // Communicate our context to the combinators. // (Less wasteful than consing up a hundred closures on every call.) cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; if (!state.lexical.hasOwnProperty("align")) state.lexical.align = true; while(true) { var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; if (combinator(type, content)) { while(cc.length && cc[cc.length - 1].lex) cc.pop()(); if (cx.marked) return cx.marked; if (type == "variable" && inScope(state, content)) return "variable-2"; return style; } } } // Combinator utils var cx = {state: null, column: null, marked: null, cc: null}; function pass() { for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); } function cont() { pass.apply(null, arguments); return true; } function register(varname) { function inList(list) { for (var v = list; v; v = v.next) if (v.name == varname) return true; return false; } var state = cx.state; if (state.context) { cx.marked = "def"; if (inList(state.localVars)) return; state.localVars = {name: varname, next: state.localVars}; } else { if (inList(state.globalVars)) return; if (parserConfig.globalVars) state.globalVars = {name: varname, next: state.globalVars}; } } // Combinators var defaultVars = {name: "this", next: {name: "arguments"}}; function pushcontext() { cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; cx.state.localVars = defaultVars; } function popcontext() { cx.state.localVars = cx.state.context.vars; cx.state.context = cx.state.context.prev; } function pushlex(type, info) { var result = function() { var state = cx.state, indent = state.indented; if (state.lexical.type == "stat") indent = state.lexical.indented; else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) indent = outer.indented; state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); }; result.lex = true; return result; } function poplex() { var state = cx.state; if (state.lexical.prev) { if (state.lexical.type == ")") state.indented = state.lexical.indented; state.lexical = state.lexical.prev; } } poplex.lex = true; function expect(wanted) { function exp(type) { if (type == wanted) return cont(); else if (wanted == ";") return pass(); else return cont(exp); }; return exp; } function statement(type, value) { if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); if (type == "keyword b") return cont(pushlex("form"), statement, poplex); if (type == "{") return cont(pushlex("}"), block, poplex); if (type == ";") return cont(); if (type == "if") { if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) cx.state.cc.pop()(); return cont(pushlex("form"), expression, statement, poplex, maybeelse); } if (type == "function") return cont(functiondef); if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); if (type == "variable") return cont(pushlex("stat"), maybelabel); if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), block, poplex, poplex); if (type == "case") return cont(expression, expect(":")); if (type == "default") return cont(expect(":")); if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), statement, poplex, popcontext); if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex); if (type == "class") return cont(pushlex("form"), className, poplex); if (type == "export") return cont(pushlex("form"), afterExport, poplex); if (type == "import") return cont(pushlex("form"), afterImport, poplex); return pass(pushlex("stat"), expression, expect(";"), poplex); } function expression(type) { return expressionInner(type, false); } function expressionNoComma(type) { return expressionInner(type, true); } function expressionInner(type, noComma) { if (cx.state.fatArrowAt == cx.stream.start) { var body = noComma ? arrowBodyNoComma : arrowBody; if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); } var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); if (type == "function") return cont(functiondef, maybeop); if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop); if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); if (type == "{") return contCommasep(objprop, "}", null, maybeop); if (type == "quasi") { return pass(quasi, maybeop); } return cont(); } function maybeexpression(type) { if (type.match(/[;\}\)\],]/)) return pass(); return pass(expression); } function maybeexpressionNoComma(type) { if (type.match(/[;\}\)\],]/)) return pass(); return pass(expressionNoComma); } function maybeoperatorComma(type, value) { if (type == ",") return cont(expression); return maybeoperatorNoComma(type, value, false); } function maybeoperatorNoComma(type, value, noComma) { var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; var expr = noComma == false ? expression : expressionNoComma; if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); if (type == "operator") { if (/\+\+|--/.test(value)) return cont(me); if (value == "?") return cont(expression, expect(":"), expr); return cont(expr); } if (type == "quasi") { return pass(quasi, me); } if (type == ";") return; if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); if (type == ".") return cont(property, me); if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); } function quasi(type, value) { if (type != "quasi") return pass(); if (value.slice(value.length - 2) != "${") return cont(quasi); return cont(expression, continueQuasi); } function continueQuasi(type) { if (type == "}") { cx.marked = "string-2"; cx.state.tokenize = tokenQuasi; return cont(quasi); } } function arrowBody(type) { findFatArrow(cx.stream, cx.state); return pass(type == "{" ? statement : expression); } function arrowBodyNoComma(type) { findFatArrow(cx.stream, cx.state); return pass(type == "{" ? statement : expressionNoComma); } function maybelabel(type) { if (type == ":") return cont(poplex, statement); return pass(maybeoperatorComma, expect(";"), poplex); } function property(type) { if (type == "variable") {cx.marked = "property"; return cont();} } function objprop(type, value) { if (type == "variable" || cx.style == "keyword") { cx.marked = "property"; if (value == "get" || value == "set") return cont(getterSetter); return cont(afterprop); } else if (type == "number" || type == "string") { cx.marked = jsonldMode ? "property" : (cx.style + " property"); return cont(afterprop); } else if (type == "jsonld-keyword") { return cont(afterprop); } else if (type == "[") { return cont(expression, expect("]"), afterprop); } } function getterSetter(type) { if (type != "variable") return pass(afterprop); cx.marked = "property"; return cont(functiondef); } function afterprop(type) { if (type == ":") return cont(expressionNoComma); if (type == "(") return pass(functiondef); } function commasep(what, end) { function proceed(type) { if (type == ",") { var lex = cx.state.lexical; if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; return cont(what, proceed); } if (type == end) return cont(); return cont(expect(end)); } return function(type) { if (type == end) return cont(); return pass(what, proceed); }; } function contCommasep(what, end, info) { for (var i = 3; i < arguments.length; i++) cx.cc.push(arguments[i]); return cont(pushlex(end, info), commasep(what, end), poplex); } function block(type) { if (type == "}") return cont(); return pass(statement, block); } function maybetype(type) { if (isTS && type == ":") return cont(typedef); } function typedef(type) { if (type == "variable"){cx.marked = "variable-3"; return cont();} } function vardef() { return pass(pattern, maybetype, maybeAssign, vardefCont); } function pattern(type, value) { if (type == "variable") { register(value); return cont(); } if (type == "[") return contCommasep(pattern, "]"); if (type == "{") return contCommasep(proppattern, "}"); } function proppattern(type, value) { if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { register(value); return cont(maybeAssign); } if (type == "variable") cx.marked = "property"; return cont(expect(":"), pattern, maybeAssign); } function maybeAssign(_type, value) { if (value == "=") return cont(expressionNoComma); } function vardefCont(type) { if (type == ",") return cont(vardef); } function maybeelse(type, value) { if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); } function forspec(type) { if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); } function forspec1(type) { if (type == "var") return cont(vardef, expect(";"), forspec2); if (type == ";") return cont(forspec2); if (type == "variable") return cont(formaybeinof); return pass(expression, expect(";"), forspec2); } function formaybeinof(_type, value) { if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } return cont(maybeoperatorComma, forspec2); } function forspec2(type, value) { if (type == ";") return cont(forspec3); if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } return pass(expression, expect(";"), forspec3); } function forspec3(type) { if (type != ")") cont(expression); } function functiondef(type, value) { if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} if (type == "variable") {register(value); return cont(functiondef);} if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext); } function funarg(type) { if (type == "spread") return cont(funarg); return pass(pattern, maybetype); } function className(type, value) { if (type == "variable") {register(value); return cont(classNameAfter);} } function classNameAfter(type, value) { if (value == "extends") return cont(expression, classNameAfter); if (type == "{") return cont(pushlex("}"), classBody, poplex); } function classBody(type, value) { if (type == "variable" || cx.style == "keyword") { if (value == "static") { cx.marked = "keyword"; return cont(classBody); } cx.marked = "property"; if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); return cont(functiondef, classBody); } if (value == "*") { cx.marked = "keyword"; return cont(classBody); } if (type == ";") return cont(classBody); if (type == "}") return cont(); } function classGetterSetter(type) { if (type != "variable") return pass(); cx.marked = "property"; return cont(); } function afterModule(type, value) { if (type == "string") return cont(statement); if (type == "variable") { register(value); return cont(maybeFrom); } } function afterExport(_type, value) { if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } return pass(statement); } function afterImport(type) { if (type == "string") return cont(); return pass(importSpec, maybeFrom); } function importSpec(type, value) { if (type == "{") return contCommasep(importSpec, "}"); if (type == "variable") register(value); return cont(); } function maybeFrom(_type, value) { if (value == "from") { cx.marked = "keyword"; return cont(expression); } } function arrayLiteral(type) { if (type == "]") return cont(); return pass(expressionNoComma, maybeArrayComprehension); } function maybeArrayComprehension(type) { if (type == "for") return pass(comprehension, expect("]")); if (type == ",") return cont(commasep(maybeexpressionNoComma, "]")); return pass(commasep(expressionNoComma, "]")); } function comprehension(type) { if (type == "for") return cont(forspec, comprehension); if (type == "if") return cont(expression, comprehension); } function isContinuedStatement(state, textAfter) { return state.lastType == "operator" || state.lastType == "," || isOperatorChar.test(textAfter.charAt(0)) || /[,.]/.test(textAfter.charAt(0)); } // Interface return { startState: function(basecolumn) { var state = { tokenize: tokenBase, lastType: "sof", cc: [], lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), localVars: parserConfig.localVars, context: parserConfig.localVars && {vars: parserConfig.localVars}, indented: 0 }; if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") state.globalVars = parserConfig.globalVars; return state; }, token: function(stream, state) { if (stream.sol()) { if (!state.lexical.hasOwnProperty("align")) state.lexical.align = false; state.indented = stream.indentation(); findFatArrow(stream, state); } if (state.tokenize != tokenComment && stream.eatSpace()) return null; var style = state.tokenize(stream, state); if (type == "comment") return style; state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; return parseJS(state, style, type, content, stream); }, indent: function(state, textAfter) { if (state.tokenize == tokenComment) return CodeMirror.Pass; if (state.tokenize != tokenBase) return 0; var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; // Kludge to prevent 'maybelse' from blocking lexical scope pops if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { var c = state.cc[i]; if (c == poplex) lexical = lexical.prev; else if (c != maybeelse) break; } if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") lexical = lexical.prev; var type = lexical.type, closing = firstChar == type; if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); else if (type == "form" && firstChar == "{") return lexical.indented; else if (type == "form") return lexical.indented + indentUnit; else if (type == "stat") return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); else if (lexical.align) return lexical.column + (closing ? 0 : 1); else return lexical.indented + (closing ? 0 : indentUnit); }, electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, blockCommentStart: jsonMode ? null : "/*", blockCommentEnd: jsonMode ? null : "*/", lineComment: jsonMode ? null : "//", fold: "brace", closeBrackets: "()[]{}''\"\"``", helperType: jsonMode ? "json" : "javascript", jsonldMode: jsonldMode, jsonMode: jsonMode }; }); CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); CodeMirror.defineMIME("text/javascript", "javascript"); CodeMirror.defineMIME("text/ecmascript", "javascript"); CodeMirror.defineMIME("application/javascript", "javascript"); CodeMirror.defineMIME("application/x-javascript", "javascript"); CodeMirror.defineMIME("application/ecmascript", "javascript"); CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); }); three.js-r73/editor/js/libs/codemirror/mode/glsl.js0000644000175500017550000002113612610076566022202 0ustar debacledebacle// Full source: // // https://github.com/hughsk/glsl-editor // // (C) Copyright Hugh Kennedy // // This software is released under the MIT license: // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL- // INGS IN THE SOFTWARE. // The original source code has been slightly modified for the purpose of // integration (tschw). (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { "use strict"; CodeMirror.defineMode("glsl", function(config, parserConfig) { var indentUnit = config.indentUnit, keywords = parserConfig.keywords || words(glslKeywords), builtins = parserConfig.builtins || words(glslBuiltins), blockKeywords = parserConfig.blockKeywords || words("case do else for if switch while struct"), atoms = parserConfig.atoms || words("null"), hooks = parserConfig.hooks || {}, multiLineStrings = parserConfig.multiLineStrings; var isOperatorChar = /[+\-*&%=<>!?|\/]/; var curPunc; function tokenBase(stream, state) { var ch = stream.next(); if (hooks[ch]) { var result = hooks[ch](stream, state); if (result !== false) return result; } if (ch == '"' || ch == "'") { state.tokenize = tokenString(ch); return state.tokenize(stream, state); } if (/[\[\]{}\(\),;\:\.]/.test(ch)) { curPunc = ch; return "bracket"; } if (/\d/.test(ch)) { stream.eatWhile(/[\w\.]/); return "number"; } if (ch == "/") { if (stream.eat("*")) { state.tokenize = tokenComment; return tokenComment(stream, state); } if (stream.eat("/")) { stream.skipToEnd(); return "comment"; } } if (ch == "#") { stream.eatWhile(/[\S]+/); stream.eatWhile(/[\s]+/); stream.eatWhile(/[\S]+/); stream.eatWhile(/[\s]+/); return "comment"; } if (isOperatorChar.test(ch)) { stream.eatWhile(isOperatorChar); return "operator"; } stream.eatWhile(/[\w\$_]/); var cur = stream.current(); if (keywords.propertyIsEnumerable(cur)) { if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; return "keyword"; } if (builtins.propertyIsEnumerable(cur)) { return "builtin"; } if (atoms.propertyIsEnumerable(cur)) return "atom"; return "word"; } function tokenString(quote) { return function(stream, state) { var escaped = false, next, end = false; while ((next = stream.next()) != null) { if (next == quote && !escaped) {end = true; break;} escaped = !escaped && next == "\\"; } if (end || !(escaped || multiLineStrings)) state.tokenize = tokenBase; return "string"; }; } function tokenComment(stream, state) { var maybeEnd = false, ch; while (ch = stream.next()) { if (ch == "/" && maybeEnd) { state.tokenize = tokenBase; break; } maybeEnd = (ch == "*"); } return "comment"; } function Context(indented, column, type, align, prev) { this.indented = indented; this.column = column; this.type = type; this.align = align; this.prev = prev; } function pushContext(state, col, type) { return state.context = new Context(state.indented, col, type, null, state.context); } function popContext(state) { var t = state.context.type; if (t == ")" || t == "]" || t == "}") state.indented = state.context.indented; return state.context = state.context.prev; } // Interface return { startState: function(basecolumn) { return { tokenize: null, context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), indented: 0, startOfLine: true }; }, token: function(stream, state) { var ctx = state.context; if (stream.sol()) { if (ctx.align == null) ctx.align = false; state.indented = stream.indentation(); state.startOfLine = true; } if (stream.eatSpace()) return null; curPunc = null; var style = (state.tokenize || tokenBase)(stream, state); if (style == "comment" || style == "meta") return style; if (ctx.align == null) ctx.align = true; if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state); else if (curPunc == "{") pushContext(state, stream.column(), "}"); else if (curPunc == "[") pushContext(state, stream.column(), "]"); else if (curPunc == "(") pushContext(state, stream.column(), ")"); else if (curPunc == "}") { while (ctx.type == "statement") ctx = popContext(state); if (ctx.type == "}") ctx = popContext(state); while (ctx.type == "statement") ctx = popContext(state); } else if (curPunc == ctx.type) popContext(state); else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement")) pushContext(state, stream.column(), "statement"); state.startOfLine = false; return style; }, indent: function(state, textAfter) { if (state.tokenize != tokenBase && state.tokenize != null) return 0; var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type; if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit); else if (ctx.align) return ctx.column + (closing ? 0 : 1); else return ctx.indented + (closing ? 0 : indentUnit); }, electricChars: "{}" }; }); function words(str) { var obj = {}, words = str.split(" "); for (var i = 0; i < words.length; ++i) obj[words[i]] = true; return obj; } var glslKeywords = "attribute const uniform varying break continue " + "do for while if else in out inout float int void bool true false " + "lowp mediump highp precision invariant discard return mat2 mat3 " + "mat4 vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 sampler2D " + "samplerCube struct gl_FragCoord gl_FragColor"; var glslBuiltins = "radians degrees sin cos tan asin acos atan pow " + "exp log exp2 log2 sqrt inversesqrt abs sign floor ceil fract mod " + "min max clamp mix step smoothstep length distance dot cross " + "normalize faceforward reflect refract matrixCompMult lessThan " + "lessThanEqual greaterThan greaterThanEqual equal notEqual any all " + "not dFdx dFdy fwidth texture2D texture2DProj texture2DLod " + "texture2DProjLod textureCube textureCubeLod require export"; function cppHook(stream, state) { if (!state.startOfLine) return false; stream.skipToEnd(); return "meta"; } ;(function() { // C#-style strings where "" escapes a quote. function tokenAtString(stream, state) { var next; while ((next = stream.next()) != null) { if (next == '"' && !stream.eat('"')) { state.tokenize = null; break; } } return "string"; } CodeMirror.defineMIME("text/x-glsl", { name: "glsl", keywords: words(glslKeywords), builtins: words(glslBuiltins), blockKeywords: words("case do else for if switch while struct"), atoms: words("null"), hooks: {"#": cppHook} }); }()); }); three.js-r73/editor/js/libs/codemirror/codemirror.js0000644000175500017550000124125612610076566022472 0ustar debacledebacle// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE // This is CodeMirror (http://codemirror.net), a code editor // implemented in JavaScript on top of the browser's DOM. // // You can find some technical background for some of the code below // at http://marijnhaverbeke.nl/blog/#cm-internals . (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS module.exports = mod(); else if (typeof define == "function" && define.amd) // AMD return define([], mod); else // Plain browser env this.CodeMirror = mod(); })(function() { "use strict"; // BROWSER SNIFFING // Kludges for bugs and behavior differences that can't be feature // detected are enabled based on userAgent etc sniffing. var gecko = /gecko\/\d/i.test(navigator.userAgent); var ie_upto10 = /MSIE \d/.test(navigator.userAgent); var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); var ie = ie_upto10 || ie_11up; var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); var webkit = /WebKit\//.test(navigator.userAgent); var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); var chrome = /Chrome\//.test(navigator.userAgent); var presto = /Opera\//.test(navigator.userAgent); var safari = /Apple Computer/.test(navigator.vendor); var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); var phantom = /PhantomJS/.test(navigator.userAgent); var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); // This is woefully incomplete. Suggestions for alternative methods welcome. var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); var mac = ios || /Mac/.test(navigator.platform); var windows = /win/i.test(navigator.platform); var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); if (presto_version) presto_version = Number(presto_version[1]); if (presto_version && presto_version >= 15) { presto = false; webkit = true; } // Some browsers use the wrong event properties to signal cmd/ctrl on OS X var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); var captureRightClick = gecko || (ie && ie_version >= 9); // Optimize some code when these features are not used. var sawReadOnlySpans = false, sawCollapsedSpans = false; // EDITOR CONSTRUCTOR // A CodeMirror instance represents an editor. This is the object // that user code is usually dealing with. function CodeMirror(place, options) { if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); this.options = options = options ? copyObj(options) : {}; // Determine effective options based on given values and defaults. copyObj(defaults, options, false); setGuttersForLineNumbers(options); var doc = options.value; if (typeof doc == "string") doc = new Doc(doc, options.mode); this.doc = doc; var input = new CodeMirror.inputStyles[options.inputStyle](this); var display = this.display = new Display(place, doc, input); display.wrapper.CodeMirror = this; updateGutters(this); themeChanged(this); if (options.lineWrapping) this.display.wrapper.className += " CodeMirror-wrap"; if (options.autofocus && !mobile) display.input.focus(); initScrollbars(this); this.state = { keyMaps: [], // stores maps added by addKeyMap overlays: [], // highlighting overlays, as added by addOverlay modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info overwrite: false, delayingBlurEvent: false, focused: false, suppressEdits: false, // used to disable editing during key handlers when in readOnly mode pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll draggingText: false, highlight: new Delayed(), // stores highlight worker timeout keySeq: null, // Unfinished key sequence specialChars: null }; var cm = this; // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); registerEventHandlers(this); ensureGlobalHandlers(); startOperation(this); this.curOp.forceUpdate = true; attachDoc(this, doc); if ((options.autofocus && !mobile) || cm.hasFocus()) setTimeout(bind(onFocus, this), 20); else onBlur(this); for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) optionHandlers[opt](this, options[opt], Init); maybeUpdateLineNumberWidth(this); if (options.finishInit) options.finishInit(this); for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); endOperation(this); // Suppress optimizelegibility in Webkit, since it breaks text // measuring on line wrapping boundaries. if (webkit && options.lineWrapping && getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") display.lineDiv.style.textRendering = "auto"; } // DISPLAY CONSTRUCTOR // The display handles the DOM integration, both for input reading // and content drawing. It holds references to DOM nodes and // display-related state. function Display(place, doc, input) { var d = this; this.input = input; // Covers bottom-right square when both scrollbars are present. d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); d.scrollbarFiller.setAttribute("cm-not-content", "true"); // Covers bottom of gutter when coverGutterNextToScrollbar is on // and h scrollbar is present. d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); d.gutterFiller.setAttribute("cm-not-content", "true"); // Will contain the actual code, positioned to cover the viewport. d.lineDiv = elt("div", null, "CodeMirror-code"); // Elements are added to these to represent selection and cursors. d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); d.cursorDiv = elt("div", null, "CodeMirror-cursors"); // A visibility: hidden element used to find the size of things. d.measure = elt("div", null, "CodeMirror-measure"); // When lines outside of the viewport are measured, they are drawn in this. d.lineMeasure = elt("div", null, "CodeMirror-measure"); // Wraps everything that needs to exist inside the vertically-padded coordinate system d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], null, "position: relative; outline: none"); // Moved around its parent to cover visible view. d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); // Set to the height of the document, allowing scrolling. d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); d.sizerWidth = null; // Behavior of elts with overflow: auto and padding is // inconsistent across browsers. This is used to ensure the // scrollable area is big enough. d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); // Will contain the gutters, if any. d.gutters = elt("div", null, "CodeMirror-gutters"); d.lineGutter = null; // Actual scrollable element. d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); d.scroller.setAttribute("tabIndex", "-1"); // The element in which the editor lives. d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; if (place) { if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper); } // Current rendered range (may be bigger than the view window). d.viewFrom = d.viewTo = doc.first; d.reportedViewFrom = d.reportedViewTo = doc.first; // Information about the rendered lines. d.view = []; d.renderedView = null; // Holds info about a single rendered line when it was rendered // for measurement, while not in view. d.externalMeasured = null; // Empty space (in pixels) above the view d.viewOffset = 0; d.lastWrapHeight = d.lastWrapWidth = 0; d.updateLineNumbers = null; d.nativeBarWidth = d.barHeight = d.barWidth = 0; d.scrollbarsClipped = false; // Used to only resize the line number gutter when necessary (when // the amount of lines crosses a boundary that makes its width change) d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; // Set to true when a non-horizontal-scrolling line widget is // added. As an optimization, line widget aligning is skipped when // this is false. d.alignWidgets = false; d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; // Tracks the maximum line length so that the horizontal scrollbar // can be kept static when scrolling. d.maxLine = null; d.maxLineLength = 0; d.maxLineChanged = false; // Used for measuring wheel scrolling granularity d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; // True when shift is held down. d.shift = false; // Used to track whether anything happened since the context menu // was opened. d.selForContextMenu = null; d.activeTouch = null; input.init(d); } // STATE UPDATES // Used to get the editor into a consistent state again when options change. function loadMode(cm) { cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); resetModeState(cm); } function resetModeState(cm) { cm.doc.iter(function(line) { if (line.stateAfter) line.stateAfter = null; if (line.styles) line.styles = null; }); cm.doc.frontier = cm.doc.first; startWorker(cm, 100); cm.state.modeGen++; if (cm.curOp) regChange(cm); } function wrappingChanged(cm) { if (cm.options.lineWrapping) { addClass(cm.display.wrapper, "CodeMirror-wrap"); cm.display.sizer.style.minWidth = ""; cm.display.sizerWidth = null; } else { rmClass(cm.display.wrapper, "CodeMirror-wrap"); findMaxLine(cm); } estimateLineHeights(cm); regChange(cm); clearCaches(cm); setTimeout(function(){updateScrollbars(cm);}, 100); } // Returns a function that estimates the height of a line, to use as // first approximation until the line becomes visible (and is thus // properly measurable). function estimateHeight(cm) { var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); return function(line) { if (lineIsHidden(cm.doc, line)) return 0; var widgetsHeight = 0; if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; } if (wrapping) return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; else return widgetsHeight + th; }; } function estimateLineHeights(cm) { var doc = cm.doc, est = estimateHeight(cm); doc.iter(function(line) { var estHeight = est(line); if (estHeight != line.height) updateLineHeight(line, estHeight); }); } function themeChanged(cm) { cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); clearCaches(cm); } function guttersChanged(cm) { updateGutters(cm); regChange(cm); setTimeout(function(){alignHorizontally(cm);}, 20); } // Rebuild the gutter elements, ensure the margin to the left of the // code matches their width. function updateGutters(cm) { var gutters = cm.display.gutters, specs = cm.options.gutters; removeChildren(gutters); for (var i = 0; i < specs.length; ++i) { var gutterClass = specs[i]; var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); if (gutterClass == "CodeMirror-linenumbers") { cm.display.lineGutter = gElt; gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; } } gutters.style.display = i ? "" : "none"; updateGutterSpace(cm); } function updateGutterSpace(cm) { var width = cm.display.gutters.offsetWidth; cm.display.sizer.style.marginLeft = width + "px"; } // Compute the character length of a line, taking into account // collapsed ranges (see markText) that might hide parts, and join // other lines onto it. function lineLength(line) { if (line.height == 0) return 0; var len = line.text.length, merged, cur = line; while (merged = collapsedSpanAtStart(cur)) { var found = merged.find(0, true); cur = found.from.line; len += found.from.ch - found.to.ch; } cur = line; while (merged = collapsedSpanAtEnd(cur)) { var found = merged.find(0, true); len -= cur.text.length - found.from.ch; cur = found.to.line; len += cur.text.length - found.to.ch; } return len; } // Find the longest line in the document. function findMaxLine(cm) { var d = cm.display, doc = cm.doc; d.maxLine = getLine(doc, doc.first); d.maxLineLength = lineLength(d.maxLine); d.maxLineChanged = true; doc.iter(function(line) { var len = lineLength(line); if (len > d.maxLineLength) { d.maxLineLength = len; d.maxLine = line; } }); } // Make sure the gutters options contains the element // "CodeMirror-linenumbers" when the lineNumbers option is true. function setGuttersForLineNumbers(options) { var found = indexOf(options.gutters, "CodeMirror-linenumbers"); if (found == -1 && options.lineNumbers) { options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); } else if (found > -1 && !options.lineNumbers) { options.gutters = options.gutters.slice(0); options.gutters.splice(found, 1); } } // SCROLLBARS // Prepare DOM reads needed to update the scrollbars. Done in one // shot to minimize update/measure roundtrips. function measureForScrollbars(cm) { var d = cm.display, gutterW = d.gutters.offsetWidth; var docH = Math.round(cm.doc.height + paddingVert(cm.display)); return { clientHeight: d.scroller.clientHeight, viewHeight: d.wrapper.clientHeight, scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, viewWidth: d.wrapper.clientWidth, barLeft: cm.options.fixedGutter ? gutterW : 0, docHeight: docH, scrollHeight: docH + scrollGap(cm) + d.barHeight, nativeBarWidth: d.nativeBarWidth, gutterWidth: gutterW }; } function NativeScrollbars(place, scroll, cm) { this.cm = cm; var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); place(vert); place(horiz); on(vert, "scroll", function() { if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); }); on(horiz, "scroll", function() { if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); }); this.checkedOverlay = false; // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; } NativeScrollbars.prototype = copyObj({ update: function(measure) { var needsH = measure.scrollWidth > measure.clientWidth + 1; var needsV = measure.scrollHeight > measure.clientHeight + 1; var sWidth = measure.nativeBarWidth; if (needsV) { this.vert.style.display = "block"; this.vert.style.bottom = needsH ? sWidth + "px" : "0"; var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); // A bug in IE8 can cause this value to be negative, so guard it. this.vert.firstChild.style.height = Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; } else { this.vert.style.display = ""; this.vert.firstChild.style.height = "0"; } if (needsH) { this.horiz.style.display = "block"; this.horiz.style.right = needsV ? sWidth + "px" : "0"; this.horiz.style.left = measure.barLeft + "px"; var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); this.horiz.firstChild.style.width = (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; } else { this.horiz.style.display = ""; this.horiz.firstChild.style.width = "0"; } if (!this.checkedOverlay && measure.clientHeight > 0) { if (sWidth == 0) this.overlayHack(); this.checkedOverlay = true; } return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; }, setScrollLeft: function(pos) { if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; }, setScrollTop: function(pos) { if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; }, overlayHack: function() { var w = mac && !mac_geMountainLion ? "12px" : "18px"; this.horiz.style.minHeight = this.vert.style.minWidth = w; var self = this; var barMouseDown = function(e) { if (e_target(e) != self.vert && e_target(e) != self.horiz) operation(self.cm, onMouseDown)(e); }; on(this.vert, "mousedown", barMouseDown); on(this.horiz, "mousedown", barMouseDown); }, clear: function() { var parent = this.horiz.parentNode; parent.removeChild(this.horiz); parent.removeChild(this.vert); } }, NativeScrollbars.prototype); function NullScrollbars() {} NullScrollbars.prototype = copyObj({ update: function() { return {bottom: 0, right: 0}; }, setScrollLeft: function() {}, setScrollTop: function() {}, clear: function() {} }, NullScrollbars.prototype); CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; function initScrollbars(cm) { if (cm.display.scrollbars) { cm.display.scrollbars.clear(); if (cm.display.scrollbars.addClass) rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); } cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) { cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); // Prevent clicks in the scrollbars from killing focus on(node, "mousedown", function() { if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); }); node.setAttribute("cm-not-content", "true"); }, function(pos, axis) { if (axis == "horizontal") setScrollLeft(cm, pos); else setScrollTop(cm, pos); }, cm); if (cm.display.scrollbars.addClass) addClass(cm.display.wrapper, cm.display.scrollbars.addClass); } function updateScrollbars(cm, measure) { if (!measure) measure = measureForScrollbars(cm); var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; updateScrollbarsInner(cm, measure); for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { if (startWidth != cm.display.barWidth && cm.options.lineWrapping) updateHeightsInViewport(cm); updateScrollbarsInner(cm, measureForScrollbars(cm)); startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; } } // Re-synchronize the fake scrollbars with the actual size of the // content. function updateScrollbarsInner(cm, measure) { var d = cm.display; var sizes = d.scrollbars.update(measure); d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; if (sizes.right && sizes.bottom) { d.scrollbarFiller.style.display = "block"; d.scrollbarFiller.style.height = sizes.bottom + "px"; d.scrollbarFiller.style.width = sizes.right + "px"; } else d.scrollbarFiller.style.display = ""; if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { d.gutterFiller.style.display = "block"; d.gutterFiller.style.height = sizes.bottom + "px"; d.gutterFiller.style.width = measure.gutterWidth + "px"; } else d.gutterFiller.style.display = ""; } // Compute the lines that are visible in a given viewport (defaults // the the current scroll position). viewport may contain top, // height, and ensure (see op.scrollToPos) properties. function visibleLines(display, doc, viewport) { var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; top = Math.floor(top - paddingTop(display)); var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); // Ensure is a {from: {line, ch}, to: {line, ch}} object, and // forces those lines into the viewport (if possible). if (viewport && viewport.ensure) { var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; if (ensureFrom < from) { from = ensureFrom; to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); } else if (Math.min(ensureTo, doc.lastLine()) >= to) { from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); to = ensureTo; } } return {from: from, to: Math.max(to, from + 1)}; } // LINE NUMBERS // Re-align line numbers and gutter marks to compensate for // horizontal scrolling. function alignHorizontally(cm) { var display = cm.display, view = display.view; if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; var gutterW = display.gutters.offsetWidth, left = comp + "px"; for (var i = 0; i < view.length; i++) if (!view[i].hidden) { if (cm.options.fixedGutter && view[i].gutter) view[i].gutter.style.left = left; var align = view[i].alignable; if (align) for (var j = 0; j < align.length; j++) align[j].style.left = left; } if (cm.options.fixedGutter) display.gutters.style.left = (comp + gutterW) + "px"; } // Used to ensure that the line number gutter is still the right // size for the current document size. Returns true when an update // is needed. function maybeUpdateLineNumberWidth(cm) { if (!cm.options.lineNumbers) return false; var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; if (last.length != display.lineNumChars) { var test = display.measure.appendChild(elt("div", [elt("div", last)], "CodeMirror-linenumber CodeMirror-gutter-elt")); var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; display.lineGutter.style.width = ""; display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; display.lineNumWidth = display.lineNumInnerWidth + padding; display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; display.lineGutter.style.width = display.lineNumWidth + "px"; updateGutterSpace(cm); return true; } return false; } function lineNumberFor(options, i) { return String(options.lineNumberFormatter(i + options.firstLineNumber)); } // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, // but using getBoundingClientRect to get a sub-pixel-accurate // result. function compensateForHScroll(display) { return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; } // DISPLAY DRAWING function DisplayUpdate(cm, viewport, force) { var display = cm.display; this.viewport = viewport; // Store some values that we'll need later (but don't want to force a relayout for) this.visible = visibleLines(display, cm.doc, viewport); this.editorIsHidden = !display.wrapper.offsetWidth; this.wrapperHeight = display.wrapper.clientHeight; this.wrapperWidth = display.wrapper.clientWidth; this.oldDisplayWidth = displayWidth(cm); this.force = force; this.dims = getDimensions(cm); this.events = []; } DisplayUpdate.prototype.signal = function(emitter, type) { if (hasHandler(emitter, type)) this.events.push(arguments); }; DisplayUpdate.prototype.finish = function() { for (var i = 0; i < this.events.length; i++) signal.apply(null, this.events[i]); }; function maybeClipScrollbars(cm) { var display = cm.display; if (!display.scrollbarsClipped && display.scroller.offsetWidth) { display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; display.heightForcer.style.height = scrollGap(cm) + "px"; display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; display.scrollbarsClipped = true; } } // Does the actual updating of the line display. Bails out // (returning false) when there is nothing to be done and forced is // false. function updateDisplayIfNeeded(cm, update) { var display = cm.display, doc = cm.doc; if (update.editorIsHidden) { resetView(cm); return false; } // Bail out if the visible area is already rendered and nothing changed. if (!update.force && update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && display.renderedView == display.view && countDirtyView(cm) == 0) return false; if (maybeUpdateLineNumberWidth(cm)) { resetView(cm); update.dims = getDimensions(cm); } // Compute a suitable new viewport (from & to) var end = doc.first + doc.size; var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); var to = Math.min(end, update.visible.to + cm.options.viewportMargin); if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); if (sawCollapsedSpans) { from = visualLineNo(cm.doc, from); to = visualLineEndNo(cm.doc, to); } var different = from != display.viewFrom || to != display.viewTo || display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; adjustView(cm, from, to); display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); // Position the mover div to align with the current scroll position cm.display.mover.style.top = display.viewOffset + "px"; var toUpdate = countDirtyView(cm); if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) return false; // For big changes, we hide the enclosing element during the // update, since that speeds up the operations on most browsers. var focused = activeElt(); if (toUpdate > 4) display.lineDiv.style.display = "none"; patchDisplay(cm, display.updateLineNumbers, update.dims); if (toUpdate > 4) display.lineDiv.style.display = ""; display.renderedView = display.view; // There might have been a widget with a focused element that got // hidden or updated, if so re-focus it. if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); // Prevent selection and cursors from interfering with the scroll // width and height. removeChildren(display.cursorDiv); removeChildren(display.selectionDiv); display.gutters.style.height = 0; if (different) { display.lastWrapHeight = update.wrapperHeight; display.lastWrapWidth = update.wrapperWidth; startWorker(cm, 400); } display.updateLineNumbers = null; return true; } function postUpdateDisplay(cm, update) { var force = update.force, viewport = update.viewport; for (var first = true;; first = false) { if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) { force = true; } else { force = false; // Clip forced viewport to actual scrollable area. if (viewport && viewport.top != null) viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; // Updated line heights might result in the drawn area not // actually covering the viewport. Keep looping until it does. update.visible = visibleLines(cm.display, cm.doc, viewport); if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) break; } if (!updateDisplayIfNeeded(cm, update)) break; updateHeightsInViewport(cm); var barMeasure = measureForScrollbars(cm); updateSelection(cm); setDocumentHeight(cm, barMeasure); updateScrollbars(cm, barMeasure); } update.signal(cm, "update", cm); if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; } } function updateDisplaySimple(cm, viewport) { var update = new DisplayUpdate(cm, viewport); if (updateDisplayIfNeeded(cm, update)) { updateHeightsInViewport(cm); postUpdateDisplay(cm, update); var barMeasure = measureForScrollbars(cm); updateSelection(cm); setDocumentHeight(cm, barMeasure); updateScrollbars(cm, barMeasure); update.finish(); } } function setDocumentHeight(cm, measure) { cm.display.sizer.style.minHeight = measure.docHeight + "px"; var total = measure.docHeight + cm.display.barHeight; cm.display.heightForcer.style.top = total + "px"; cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; } // Read the actual heights of the rendered lines, and update their // stored heights to match. function updateHeightsInViewport(cm) { var display = cm.display; var prevBottom = display.lineDiv.offsetTop; for (var i = 0; i < display.view.length; i++) { var cur = display.view[i], height; if (cur.hidden) continue; if (ie && ie_version < 8) { var bot = cur.node.offsetTop + cur.node.offsetHeight; height = bot - prevBottom; prevBottom = bot; } else { var box = cur.node.getBoundingClientRect(); height = box.bottom - box.top; } var diff = cur.line.height - height; if (height < 2) height = textHeight(display); if (diff > .001 || diff < -.001) { updateLineHeight(cur.line, height); updateWidgetHeight(cur.line); if (cur.rest) for (var j = 0; j < cur.rest.length; j++) updateWidgetHeight(cur.rest[j]); } } } // Read and store the height of line widgets associated with the // given line. function updateWidgetHeight(line) { if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) line.widgets[i].height = line.widgets[i].node.offsetHeight; } // Do a bulk-read of the DOM positions and sizes needed to draw the // view, so that we don't interleave reading and writing to the DOM. function getDimensions(cm) { var d = cm.display, left = {}, width = {}; var gutterLeft = d.gutters.clientLeft; for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; width[cm.options.gutters[i]] = n.clientWidth; } return {fixedPos: compensateForHScroll(d), gutterTotalWidth: d.gutters.offsetWidth, gutterLeft: left, gutterWidth: width, wrapperWidth: d.wrapper.clientWidth}; } // Sync the actual display DOM structure with display.view, removing // nodes for lines that are no longer in view, and creating the ones // that are not there yet, and updating the ones that are out of // date. function patchDisplay(cm, updateNumbersFrom, dims) { var display = cm.display, lineNumbers = cm.options.lineNumbers; var container = display.lineDiv, cur = container.firstChild; function rm(node) { var next = node.nextSibling; // Works around a throw-scroll bug in OS X Webkit if (webkit && mac && cm.display.currentWheelTarget == node) node.style.display = "none"; else node.parentNode.removeChild(node); return next; } var view = display.view, lineN = display.viewFrom; // Loop over the elements in the view, syncing cur (the DOM nodes // in display.lineDiv) with the view as we go. for (var i = 0; i < view.length; i++) { var lineView = view[i]; if (lineView.hidden) { } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet var node = buildLineElement(cm, lineView, lineN, dims); container.insertBefore(node, cur); } else { // Already drawn while (cur != lineView.node) cur = rm(cur); var updateNumber = lineNumbers && updateNumbersFrom != null && updateNumbersFrom <= lineN && lineView.lineNumber; if (lineView.changes) { if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; updateLineForChanges(cm, lineView, lineN, dims); } if (updateNumber) { removeChildren(lineView.lineNumber); lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); } cur = lineView.node.nextSibling; } lineN += lineView.size; } while (cur) cur = rm(cur); } // When an aspect of a line changes, a string is added to // lineView.changes. This updates the relevant part of the line's // DOM structure. function updateLineForChanges(cm, lineView, lineN, dims) { for (var j = 0; j < lineView.changes.length; j++) { var type = lineView.changes[j]; if (type == "text") updateLineText(cm, lineView); else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); else if (type == "class") updateLineClasses(lineView); else if (type == "widget") updateLineWidgets(cm, lineView, dims); } lineView.changes = null; } // Lines with gutter elements, widgets or a background class need to // be wrapped, and have the extra elements added to the wrapper div function ensureLineWrapped(lineView) { if (lineView.node == lineView.text) { lineView.node = elt("div", null, null, "position: relative"); if (lineView.text.parentNode) lineView.text.parentNode.replaceChild(lineView.node, lineView.text); lineView.node.appendChild(lineView.text); if (ie && ie_version < 8) lineView.node.style.zIndex = 2; } return lineView.node; } function updateLineBackground(lineView) { var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; if (cls) cls += " CodeMirror-linebackground"; if (lineView.background) { if (cls) lineView.background.className = cls; else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } } else if (cls) { var wrap = ensureLineWrapped(lineView); lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); } } // Wrapper around buildLineContent which will reuse the structure // in display.externalMeasured when possible. function getLineContent(cm, lineView) { var ext = cm.display.externalMeasured; if (ext && ext.line == lineView.line) { cm.display.externalMeasured = null; lineView.measure = ext.measure; return ext.built; } return buildLineContent(cm, lineView); } // Redraw the line's text. Interacts with the background and text // classes because the mode may output tokens that influence these // classes. function updateLineText(cm, lineView) { var cls = lineView.text.className; var built = getLineContent(cm, lineView); if (lineView.text == lineView.node) lineView.node = built.pre; lineView.text.parentNode.replaceChild(built.pre, lineView.text); lineView.text = built.pre; if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { lineView.bgClass = built.bgClass; lineView.textClass = built.textClass; updateLineClasses(lineView); } else if (cls) { lineView.text.className = cls; } } function updateLineClasses(lineView) { updateLineBackground(lineView); if (lineView.line.wrapClass) ensureLineWrapped(lineView).className = lineView.line.wrapClass; else if (lineView.node != lineView.text) lineView.node.className = ""; var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; lineView.text.className = textClass || ""; } function updateLineGutter(cm, lineView, lineN, dims) { if (lineView.gutter) { lineView.node.removeChild(lineView.gutter); lineView.gutter = null; } var markers = lineView.line.gutterMarkers; if (cm.options.lineNumbers || markers) { var wrap = ensureLineWrapped(lineView); var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + dims.gutterTotalWidth + "px"); cm.display.input.setUneditable(gutterWrap); wrap.insertBefore(gutterWrap, lineView.text); if (lineView.line.gutterClass) gutterWrap.className += " " + lineView.line.gutterClass; if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) lineView.lineNumber = gutterWrap.appendChild( elt("div", lineNumberFor(cm.options, lineN), "CodeMirror-linenumber CodeMirror-gutter-elt", "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + cm.display.lineNumInnerWidth + "px")); if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; if (found) gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); } } } function updateLineWidgets(cm, lineView, dims) { if (lineView.alignable) lineView.alignable = null; for (var node = lineView.node.firstChild, next; node; node = next) { var next = node.nextSibling; if (node.className == "CodeMirror-linewidget") lineView.node.removeChild(node); } insertLineWidgets(cm, lineView, dims); } // Build a line's DOM representation from scratch function buildLineElement(cm, lineView, lineN, dims) { var built = getLineContent(cm, lineView); lineView.text = lineView.node = built.pre; if (built.bgClass) lineView.bgClass = built.bgClass; if (built.textClass) lineView.textClass = built.textClass; updateLineClasses(lineView); updateLineGutter(cm, lineView, lineN, dims); insertLineWidgets(cm, lineView, dims); return lineView.node; } // A lineView may contain multiple logical lines (when merged by // collapsed spans). The widgets for all of them need to be drawn. function insertLineWidgets(cm, lineView, dims) { insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { if (!line.widgets) return; var wrap = ensureLineWrapped(lineView); for (var i = 0, ws = line.widgets; i < ws.length; ++i) { var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); positionLineWidget(widget, node, lineView, dims); cm.display.input.setUneditable(node); if (allowAbove && widget.above) wrap.insertBefore(node, lineView.gutter || lineView.text); else wrap.appendChild(node); signalLater(widget, "redraw"); } } function positionLineWidget(widget, node, lineView, dims) { if (widget.noHScroll) { (lineView.alignable || (lineView.alignable = [])).push(node); var width = dims.wrapperWidth; node.style.left = dims.fixedPos + "px"; if (!widget.coverGutter) { width -= dims.gutterTotalWidth; node.style.paddingLeft = dims.gutterTotalWidth + "px"; } node.style.width = width + "px"; } if (widget.coverGutter) { node.style.zIndex = 5; node.style.position = "relative"; if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; } } // POSITION OBJECT // A Pos instance represents a position within the text. var Pos = CodeMirror.Pos = function(line, ch) { if (!(this instanceof Pos)) return new Pos(line, ch); this.line = line; this.ch = ch; }; // Compare two positions, return 0 if they are the same, a negative // number when a is less, and a positive number otherwise. var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; function copyPos(x) {return Pos(x.line, x.ch);} function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } // INPUT HANDLING function ensureFocus(cm) { if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } } function isReadOnly(cm) { return cm.options.readOnly || cm.doc.cantEdit; } // This will be set to an array of strings when copying, so that, // when pasting, we know what kind of selections the copied text // was made out of. var lastCopied = null; function applyTextInput(cm, inserted, deleted, sel) { var doc = cm.doc; cm.display.shift = false; if (!sel) sel = doc.sel; var textLines = splitLines(inserted), multiPaste = null; // When pasing N lines into N selections, insert one line per selection if (cm.state.pasteIncoming && sel.ranges.length > 1) { if (lastCopied && lastCopied.join("\n") == inserted) multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); else if (textLines.length == sel.ranges.length) multiPaste = map(textLines, function(l) { return [l]; }); } // Normal behavior is to insert the new text into every selection for (var i = sel.ranges.length - 1; i >= 0; i--) { var range = sel.ranges[i]; var from = range.from(), to = range.to(); if (range.empty()) { if (deleted && deleted > 0) // Handle deletion from = Pos(from.line, from.ch - deleted); else if (cm.state.overwrite && !cm.state.pasteIncoming) // Handle overwrite to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } var updateInput = cm.curOp.updateInput; var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; makeChange(cm.doc, changeEvent); signalLater(cm, "inputRead", cm, changeEvent); // When an 'electric' character is inserted, immediately trigger a reindent if (inserted && !cm.state.pasteIncoming && cm.options.electricChars && cm.options.smartIndent && range.head.ch < 100 && (!i || sel.ranges[i - 1].head.line != range.head.line)) { var mode = cm.getModeAt(range.head); var end = changeEnd(changeEvent); if (mode.electricChars) { for (var j = 0; j < mode.electricChars.length; j++) if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { indentLine(cm, end.line, "smart"); break; } } else if (mode.electricInput) { if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch))) indentLine(cm, end.line, "smart"); } } } ensureCursorVisible(cm); cm.curOp.updateInput = updateInput; cm.curOp.typing = true; cm.state.pasteIncoming = cm.state.cutIncoming = false; } function copyableRanges(cm) { var text = [], ranges = []; for (var i = 0; i < cm.doc.sel.ranges.length; i++) { var line = cm.doc.sel.ranges[i].head.line; var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; ranges.push(lineRange); text.push(cm.getRange(lineRange.anchor, lineRange.head)); } return {text: text, ranges: ranges}; } function disableBrowserMagic(field) { field.setAttribute("autocorrect", "off"); field.setAttribute("autocapitalize", "off"); field.setAttribute("spellcheck", "false"); } // TEXTAREA INPUT STYLE function TextareaInput(cm) { this.cm = cm; // See input.poll and input.reset this.prevInput = ""; // Flag that indicates whether we expect input to appear real soon // now (after some event like 'keypress' or 'input') and are // polling intensively. this.pollingFast = false; // Self-resetting timeout for the poller this.polling = new Delayed(); // Tracks when input.reset has punted to just putting a short // string into the textarea instead of the full selection. this.inaccurateSelection = false; // Used to work around IE issue with selection being forgotten when focus moves away from textarea this.hasSelection = false; }; function hiddenTextarea() { var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); // The textarea is kept positioned near the cursor to prevent the // fact that it'll be scrolled into view on input from scrolling // our fake cursor out of view. On webkit, when wrap=off, paste is // very slow. So make the area wide instead. if (webkit) te.style.width = "1000px"; else te.setAttribute("wrap", "off"); // If border: 0; -- iOS fails to open keyboard (issue #1287) if (ios) te.style.border = "1px solid black"; disableBrowserMagic(te); return div; } TextareaInput.prototype = copyObj({ init: function(display) { var input = this, cm = this.cm; // Wraps and hides input textarea var div = this.wrapper = hiddenTextarea(); // The semihidden textarea that is focused when the editor is // focused, and receives input. var te = this.textarea = div.firstChild; display.wrapper.insertBefore(div, display.wrapper.firstChild); // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) if (ios) te.style.width = "0px"; on(te, "input", function() { if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; input.poll(); }); on(te, "paste", function() { // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 // Add a char to the end of textarea before paste occur so that // selection doesn't span to the end of textarea. if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { var start = te.selectionStart, end = te.selectionEnd; te.value += "$"; // The selection end needs to be set before the start, otherwise there // can be an intermediate non-empty selection between the two, which // can override the middle-click paste buffer on linux and cause the // wrong thing to get pasted. te.selectionEnd = end; te.selectionStart = start; cm.state.fakedLastChar = true; } cm.state.pasteIncoming = true; input.fastPoll(); }); function prepareCopyCut(e) { if (cm.somethingSelected()) { lastCopied = cm.getSelections(); if (input.inaccurateSelection) { input.prevInput = ""; input.inaccurateSelection = false; te.value = lastCopied.join("\n"); selectInput(te); } } else { var ranges = copyableRanges(cm); lastCopied = ranges.text; if (e.type == "cut") { cm.setSelections(ranges.ranges, null, sel_dontScroll); } else { input.prevInput = ""; te.value = ranges.text.join("\n"); selectInput(te); } } if (e.type == "cut") cm.state.cutIncoming = true; } on(te, "cut", prepareCopyCut); on(te, "copy", prepareCopyCut); on(display.scroller, "paste", function(e) { if (eventInWidget(display, e)) return; cm.state.pasteIncoming = true; input.focus(); }); // Prevent normal selection in the editor (we handle our own) on(display.lineSpace, "selectstart", function(e) { if (!eventInWidget(display, e)) e_preventDefault(e); }); }, prepareSelection: function() { // Redraw the selection and/or cursor var cm = this.cm, display = cm.display, doc = cm.doc; var result = prepareSelection(cm); // Move the hidden textarea near the cursor to prevent scrolling artifacts if (cm.options.moveInputWithCursor) { var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, headPos.top + lineOff.top - wrapOff.top)); result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, headPos.left + lineOff.left - wrapOff.left)); } return result; }, showSelection: function(drawn) { var cm = this.cm, display = cm.display; removeChildrenAndAdd(display.cursorDiv, drawn.cursors); removeChildrenAndAdd(display.selectionDiv, drawn.selection); if (drawn.teTop != null) { this.wrapper.style.top = drawn.teTop + "px"; this.wrapper.style.left = drawn.teLeft + "px"; } }, // Reset the input to correspond to the selection (or to be empty, // when not typing and nothing is selected) reset: function(typing) { if (this.contextMenuPending) return; var minimal, selected, cm = this.cm, doc = cm.doc; if (cm.somethingSelected()) { this.prevInput = ""; var range = doc.sel.primary(); minimal = hasCopyEvent && (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); var content = minimal ? "-" : selected || cm.getSelection(); this.textarea.value = content; if (cm.state.focused) selectInput(this.textarea); if (ie && ie_version >= 9) this.hasSelection = content; } else if (!typing) { this.prevInput = this.textarea.value = ""; if (ie && ie_version >= 9) this.hasSelection = null; } this.inaccurateSelection = minimal; }, getField: function() { return this.textarea; }, supportsTouch: function() { return false; }, focus: function() { if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { try { this.textarea.focus(); } catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM } }, blur: function() { this.textarea.blur(); }, resetPosition: function() { this.wrapper.style.top = this.wrapper.style.left = 0; }, receivedFocus: function() { this.slowPoll(); }, // Poll for input changes, using the normal rate of polling. This // runs as long as the editor is focused. slowPoll: function() { var input = this; if (input.pollingFast) return; input.polling.set(this.cm.options.pollInterval, function() { input.poll(); if (input.cm.state.focused) input.slowPoll(); }); }, // When an event has just come in that is likely to add or change // something in the input textarea, we poll faster, to ensure that // the change appears on the screen quickly. fastPoll: function() { var missed = false, input = this; input.pollingFast = true; function p() { var changed = input.poll(); if (!changed && !missed) {missed = true; input.polling.set(60, p);} else {input.pollingFast = false; input.slowPoll();} } input.polling.set(20, p); }, // Read input from the textarea, and update the document to match. // When something is selected, it is present in the textarea, and // selected (unless it is huge, in which case a placeholder is // used). When nothing is selected, the cursor sits after previously // seen text (can be empty), which is stored in prevInput (we must // not reset the textarea when typing, because that breaks IME). poll: function() { var cm = this.cm, input = this.textarea, prevInput = this.prevInput; // Since this is called a *lot*, try to bail out as cheaply as // possible when it is clear that nothing happened. hasSelection // will be the case when there is a lot of text in the textarea, // in which case reading its value would be expensive. if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq) return false; // See paste handler for more on the fakedLastChar kludge if (cm.state.pasteIncoming && cm.state.fakedLastChar) { input.value = input.value.substring(0, input.value.length - 1); cm.state.fakedLastChar = false; } var text = input.value; // If nothing changed, bail. if (text == prevInput && !cm.somethingSelected()) return false; // Work around nonsensical selection resetting in IE9/10, and // inexplicable appearance of private area unicode characters on // some key combos in Mac (#2689). if (ie && ie_version >= 9 && this.hasSelection === text || mac && /[\uf700-\uf7ff]/.test(text)) { cm.display.input.reset(); return false; } if (cm.doc.sel == cm.display.selForContextMenu) { if (text.charCodeAt(0) == 0x200b) { if (!prevInput) prevInput = "\u200b"; } else if (prevInput == "\u200b") { text = text.slice(1); prevInput = ""; } } // Find the part of the input that is actually new var same = 0, l = Math.min(prevInput.length, text.length); while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; var self = this; runInOp(cm, function() { applyTextInput(cm, text.slice(same), prevInput.length - same); // Don't leave long text in the textarea, since it makes further polling slow if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; else self.prevInput = text; }); return true; }, ensurePolled: function() { if (this.pollingFast && this.poll()) this.pollingFast = false; }, onKeyPress: function() { if (ie && ie_version >= 9) this.hasSelection = null; this.fastPoll(); }, onContextMenu: function(e) { var input = this, cm = input.cm, display = cm.display, te = input.textarea; var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; if (!pos || presto) return; // Opera is difficult. // Reset the current text selection only if the click is done outside of the selection // and 'resetSelectionOnContextMenu' option is true. var reset = cm.options.resetSelectionOnContextMenu; if (reset && cm.doc.sel.contains(pos) == -1) operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); var oldCSS = te.style.cssText; input.wrapper.style.position = "absolute"; te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) display.input.focus(); if (webkit) window.scrollTo(null, oldScrollY); display.input.reset(); // Adds "Select all" to context menu in FF if (!cm.somethingSelected()) te.value = input.prevInput = " "; input.contextMenuPending = true; display.selForContextMenu = cm.doc.sel; clearTimeout(display.detectingSelectAll); // Select-all will be greyed out if there's nothing to select, so // this adds a zero-width space so that we can later check whether // it got selected. function prepareSelectAllHack() { if (te.selectionStart != null) { var selected = cm.somethingSelected(); var extval = te.value = "\u200b" + (selected ? te.value : ""); input.prevInput = selected ? "" : "\u200b"; te.selectionStart = 1; te.selectionEnd = extval.length; // Re-set this, in case some other handler touched the // selection in the meantime. display.selForContextMenu = cm.doc.sel; } } function rehide() { input.contextMenuPending = false; input.wrapper.style.position = "relative"; te.style.cssText = oldCSS; if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); // Try to detect the user choosing select-all if (te.selectionStart != null) { if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); var i = 0, poll = function() { if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && input.prevInput == "\u200b") operation(cm, commands.selectAll)(cm); else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); else display.input.reset(); }; display.detectingSelectAll = setTimeout(poll, 200); } } if (ie && ie_version >= 9) prepareSelectAllHack(); if (captureRightClick) { e_stop(e); var mouseup = function() { off(window, "mouseup", mouseup); setTimeout(rehide, 20); }; on(window, "mouseup", mouseup); } else { setTimeout(rehide, 50); } }, setUneditable: nothing, needsContentAttribute: false }, TextareaInput.prototype); // CONTENTEDITABLE INPUT STYLE function ContentEditableInput(cm) { this.cm = cm; this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; this.polling = new Delayed(); this.gracePeriod = false; } ContentEditableInput.prototype = copyObj({ init: function(display) { var input = this, cm = input.cm; var div = input.div = display.lineDiv; div.contentEditable = "true"; disableBrowserMagic(div); on(div, "paste", function(e) { var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); if (pasted) { e.preventDefault(); cm.replaceSelection(pasted, null, "paste"); } }); on(div, "compositionstart", function(e) { var data = e.data; input.composing = {sel: cm.doc.sel, data: data, startData: data}; if (!data) return; var prim = cm.doc.sel.primary(); var line = cm.getLine(prim.head.line); var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); if (found > -1 && found <= prim.head.ch) input.composing.sel = simpleSelection(Pos(prim.head.line, found), Pos(prim.head.line, found + data.length)); }); on(div, "compositionupdate", function(e) { input.composing.data = e.data; }); on(div, "compositionend", function(e) { var ours = input.composing; if (!ours) return; if (e.data != ours.startData && !/\u200b/.test(e.data)) ours.data = e.data; // Need a small delay to prevent other code (input event, // selection polling) from doing damage when fired right after // compositionend. setTimeout(function() { if (!ours.handled) input.applyComposition(ours); if (input.composing == ours) input.composing = null; }, 50); }); on(div, "touchstart", function() { input.forceCompositionEnd(); }); on(div, "input", function() { if (input.composing) return; if (!input.pollContent()) runInOp(input.cm, function() {regChange(cm);}); }); function onCopyCut(e) { if (cm.somethingSelected()) { lastCopied = cm.getSelections(); if (e.type == "cut") cm.replaceSelection("", null, "cut"); } else { var ranges = copyableRanges(cm); lastCopied = ranges.text; if (e.type == "cut") { cm.operation(function() { cm.setSelections(ranges.ranges, 0, sel_dontScroll); cm.replaceSelection("", null, "cut"); }); } } // iOS exposes the clipboard API, but seems to discard content inserted into it if (e.clipboardData && !ios) { e.preventDefault(); e.clipboardData.clearData(); e.clipboardData.setData("text/plain", lastCopied.join("\n")); } else { // Old-fashioned briefly-focus-a-textarea hack var kludge = hiddenTextarea(), te = kludge.firstChild; cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); te.value = lastCopied.join("\n"); var hadFocus = document.activeElement; selectInput(te); setTimeout(function() { cm.display.lineSpace.removeChild(kludge); hadFocus.focus(); }, 50); } } on(div, "copy", onCopyCut); on(div, "cut", onCopyCut); }, prepareSelection: function() { var result = prepareSelection(this.cm, false); result.focus = this.cm.state.focused; return result; }, showSelection: function(info) { if (!info || !this.cm.display.view.length) return; if (info.focus) this.showPrimarySelection(); this.showMultipleSelections(info); }, showPrimarySelection: function() { var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) return; var start = posToDOM(this.cm, prim.from()); var end = posToDOM(this.cm, prim.to()); if (!start && !end) return; var view = this.cm.display.view; var old = sel.rangeCount && sel.getRangeAt(0); if (!start) { start = {node: view[0].measure.map[2], offset: 0}; } else if (!end) { // FIXME dangerously hacky var measure = view[view.length - 1].measure; var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; } try { var rng = range(start.node, start.offset, end.offset, end.node); } catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible if (rng) { sel.removeAllRanges(); sel.addRange(rng); if (old && sel.anchorNode == null) sel.addRange(old); else if (gecko) this.startGracePeriod(); } this.rememberSelection(); }, startGracePeriod: function() { var input = this; clearTimeout(this.gracePeriod); this.gracePeriod = setTimeout(function() { input.gracePeriod = false; if (input.selectionChanged()) input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); }, 20); }, showMultipleSelections: function(info) { removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); }, rememberSelection: function() { var sel = window.getSelection(); this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; }, selectionInEditor: function() { var sel = window.getSelection(); if (!sel.rangeCount) return false; var node = sel.getRangeAt(0).commonAncestorContainer; return contains(this.div, node); }, focus: function() { if (this.cm.options.readOnly != "nocursor") this.div.focus(); }, blur: function() { this.div.blur(); }, getField: function() { return this.div; }, supportsTouch: function() { return true; }, receivedFocus: function() { var input = this; if (this.selectionInEditor()) this.pollSelection(); else runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); function poll() { if (input.cm.state.focused) { input.pollSelection(); input.polling.set(input.cm.options.pollInterval, poll); } } this.polling.set(this.cm.options.pollInterval, poll); }, selectionChanged: function() { var sel = window.getSelection(); return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; }, pollSelection: function() { if (!this.composing && !this.gracePeriod && this.selectionChanged()) { var sel = window.getSelection(), cm = this.cm; this.rememberSelection(); var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); var head = domToPos(cm, sel.focusNode, sel.focusOffset); if (anchor && head) runInOp(cm, function() { setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; }); } }, pollContent: function() { var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); var from = sel.from(), to = sel.to(); if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; var fromIndex; if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { var fromLine = lineNo(display.view[0].line); var fromNode = display.view[0].node; } else { var fromLine = lineNo(display.view[fromIndex].line); var fromNode = display.view[fromIndex - 1].node.nextSibling; } var toIndex = findViewIndex(cm, to.line); if (toIndex == display.view.length - 1) { var toLine = display.viewTo - 1; var toNode = display.view[toIndex].node; } else { var toLine = lineNo(display.view[toIndex + 1].line) - 1; var toNode = display.view[toIndex + 1].node.previousSibling; } var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); while (newText.length > 1 && oldText.length > 1) { if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } else break; } var cutFront = 0, cutEnd = 0; var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) ++cutFront; var newBot = lst(newText), oldBot = lst(oldText); var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), oldBot.length - (oldText.length == 1 ? cutFront : 0)); while (cutEnd < maxCutEnd && newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) ++cutEnd; newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); newText[0] = newText[0].slice(cutFront); var chFrom = Pos(fromLine, cutFront); var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { replaceRange(cm.doc, newText, chFrom, chTo, "+input"); return true; } }, ensurePolled: function() { this.forceCompositionEnd(); }, reset: function() { this.forceCompositionEnd(); }, forceCompositionEnd: function() { if (!this.composing || this.composing.handled) return; this.applyComposition(this.composing); this.composing.handled = true; this.div.blur(); this.div.focus(); }, applyComposition: function(composing) { if (composing.data && composing.data != composing.startData) operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); }, setUneditable: function(node) { node.setAttribute("contenteditable", "false"); }, onKeyPress: function(e) { e.preventDefault(); operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }, onContextMenu: nothing, resetPosition: nothing, needsContentAttribute: true }, ContentEditableInput.prototype); function posToDOM(cm, pos) { var view = findViewForLine(cm, pos.line); if (!view || view.hidden) return null; var line = getLine(cm.doc, pos.line); var info = mapFromLineView(view, line, pos.line); var order = getOrder(line), side = "left"; if (order) { var partPos = getBidiPartAt(order, pos.ch); side = partPos % 2 ? "right" : "left"; } var result = nodeAndOffsetInLineMap(info.map, pos.ch, "left"); result.offset = result.collapse == "right" ? result.end : result.start; return result; } function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } function domToPos(cm, node, offset) { var lineNode; if (node == cm.display.lineDiv) { lineNode = cm.display.lineDiv.childNodes[offset]; if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); node = null; offset = 0; } else { for (lineNode = node;; lineNode = lineNode.parentNode) { if (!lineNode || lineNode == cm.display.lineDiv) return null; if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; } } for (var i = 0; i < cm.display.view.length; i++) { var lineView = cm.display.view[i]; if (lineView.node == lineNode) return locateNodeInLineView(lineView, node, offset); } } function locateNodeInLineView(lineView, node, offset) { var wrapper = lineView.text.firstChild, bad = false; if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); if (node == wrapper) { bad = true; node = wrapper.childNodes[offset]; offset = 0; if (!node) { var line = lineView.rest ? lst(lineView.rest) : lineView.line; return badPos(Pos(lineNo(line), line.text.length), bad); } } var textNode = node.nodeType == 3 ? node : null, topNode = node; if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { textNode = node.firstChild; if (offset) offset = textNode.nodeValue.length; } while (topNode.parentNode != wrapper) topNode = topNode.parentNode; var measure = lineView.measure, maps = measure.maps; function find(textNode, topNode, offset) { for (var i = -1; i < (maps ? maps.length : 0); i++) { var map = i < 0 ? measure.map : maps[i]; for (var j = 0; j < map.length; j += 3) { var curNode = map[j + 2]; if (curNode == textNode || curNode == topNode) { var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); var ch = map[j] + offset; if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; return Pos(line, ch); } } } } var found = find(textNode, topNode, offset); if (found) return badPos(found, bad); // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { found = find(after, after.firstChild, 0); if (found) return badPos(Pos(found.line, found.ch - dist), bad); else dist += after.textContent.length; } for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { found = find(before, before.firstChild, -1); if (found) return badPos(Pos(found.line, found.ch + dist), bad); else dist += after.textContent.length; } } function domTextBetween(cm, from, to, fromLine, toLine) { var text = "", closing = false; function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } function walk(node) { if (node.nodeType == 1) { var cmText = node.getAttribute("cm-text"); if (cmText != null) { if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); text += cmText; return; } var markerID = node.getAttribute("cm-marker"), range; if (markerID) { var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); if (found.length && (range = found[0].find())) text += getBetween(cm.doc, range.from, range.to).join("\n"); return; } if (node.getAttribute("contenteditable") == "false") return; for (var i = 0; i < node.childNodes.length; i++) walk(node.childNodes[i]); if (/^(pre|div|p)$/i.test(node.nodeName)) closing = true; } else if (node.nodeType == 3) { var val = node.nodeValue; if (!val) return; if (closing) { text += "\n"; closing = false; } text += val; } } for (;;) { walk(from); if (from == to) break; from = from.nextSibling; } return text; } CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; // SELECTION / CURSOR // Selection objects are immutable. A new one is created every time // the selection changes. A selection is one or more non-overlapping // (and non-touching) ranges, sorted, and an integer that indicates // which one is the primary selection (the one that's scrolled into // view, that getCursor returns, etc). function Selection(ranges, primIndex) { this.ranges = ranges; this.primIndex = primIndex; } Selection.prototype = { primary: function() { return this.ranges[this.primIndex]; }, equals: function(other) { if (other == this) return true; if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; for (var i = 0; i < this.ranges.length; i++) { var here = this.ranges[i], there = other.ranges[i]; if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; } return true; }, deepCopy: function() { for (var out = [], i = 0; i < this.ranges.length; i++) out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); return new Selection(out, this.primIndex); }, somethingSelected: function() { for (var i = 0; i < this.ranges.length; i++) if (!this.ranges[i].empty()) return true; return false; }, contains: function(pos, end) { if (!end) end = pos; for (var i = 0; i < this.ranges.length; i++) { var range = this.ranges[i]; if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) return i; } return -1; } }; function Range(anchor, head) { this.anchor = anchor; this.head = head; } Range.prototype = { from: function() { return minPos(this.anchor, this.head); }, to: function() { return maxPos(this.anchor, this.head); }, empty: function() { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; } }; // Take an unsorted, potentially overlapping set of ranges, and // build a selection out of it. 'Consumes' ranges array (modifying // it). function normalizeSelection(ranges, primIndex) { var prim = ranges[primIndex]; ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); primIndex = indexOf(ranges, prim); for (var i = 1; i < ranges.length; i++) { var cur = ranges[i], prev = ranges[i - 1]; if (cmp(prev.to(), cur.from()) >= 0) { var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; if (i <= primIndex) --primIndex; ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); } } return new Selection(ranges, primIndex); } function simpleSelection(anchor, head) { return new Selection([new Range(anchor, head || anchor)], 0); } // Most of the external API clips given positions to make sure they // actually exist within the document. function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} function clipPos(doc, pos) { if (pos.line < doc.first) return Pos(doc.first, 0); var last = doc.first + doc.size - 1; if (pos.line > last) return Pos(last, getLine(doc, last).text.length); return clipToLen(pos, getLine(doc, pos.line).text.length); } function clipToLen(pos, linelen) { var ch = pos.ch; if (ch == null || ch > linelen) return Pos(pos.line, linelen); else if (ch < 0) return Pos(pos.line, 0); else return pos; } function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} function clipPosArray(doc, array) { for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); return out; } // SELECTION UPDATES // The 'scroll' parameter given to many of these indicated whether // the new cursor position should be scrolled into view after // modifying the selection. // If shift is held or the extend flag is set, extends a range to // include a given position (and optionally a second position). // Otherwise, simply returns the range between the given positions. // Used for cursor motion and such. function extendRange(doc, range, head, other) { if (doc.cm && doc.cm.display.shift || doc.extend) { var anchor = range.anchor; if (other) { var posBefore = cmp(head, anchor) < 0; if (posBefore != (cmp(other, anchor) < 0)) { anchor = head; head = other; } else if (posBefore != (cmp(head, other) < 0)) { head = other; } } return new Range(anchor, head); } else { return new Range(other || head, head); } } // Extend the primary selection range, discard the rest. function extendSelection(doc, head, other, options) { setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); } // Extend all selections (pos is an array of selections with length // equal the number of selections) function extendSelections(doc, heads, options) { for (var out = [], i = 0; i < doc.sel.ranges.length; i++) out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); var newSel = normalizeSelection(out, doc.sel.primIndex); setSelection(doc, newSel, options); } // Updates a single range in the selection. function replaceOneSelection(doc, i, range, options) { var ranges = doc.sel.ranges.slice(0); ranges[i] = range; setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); } // Reset the selection to a single range. function setSimpleSelection(doc, anchor, head, options) { setSelection(doc, simpleSelection(anchor, head), options); } // Give beforeSelectionChange handlers a change to influence a // selection update. function filterSelectionChange(doc, sel) { var obj = { ranges: sel.ranges, update: function(ranges) { this.ranges = []; for (var i = 0; i < ranges.length; i++) this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), clipPos(doc, ranges[i].head)); } }; signal(doc, "beforeSelectionChange", doc, obj); if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); else return sel; } function setSelectionReplaceHistory(doc, sel, options) { var done = doc.history.done, last = lst(done); if (last && last.ranges) { done[done.length - 1] = sel; setSelectionNoUndo(doc, sel, options); } else { setSelection(doc, sel, options); } } // Set a new selection. function setSelection(doc, sel, options) { setSelectionNoUndo(doc, sel, options); addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); } function setSelectionNoUndo(doc, sel, options) { if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) sel = filterSelectionChange(doc, sel); var bias = options && options.bias || (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); if (!(options && options.scroll === false) && doc.cm) ensureCursorVisible(doc.cm); } function setSelectionInner(doc, sel) { if (sel.equals(doc.sel)) return; doc.sel = sel; if (doc.cm) { doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; signalCursorActivity(doc.cm); } signalLater(doc, "cursorActivity", doc); } // Verify that the selection does not partially select any atomic // marked ranges. function reCheckSelection(doc) { setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); } // Return a selection that does not partially select any atomic // ranges. function skipAtomicInSelection(doc, sel, bias, mayClear) { var out; for (var i = 0; i < sel.ranges.length; i++) { var range = sel.ranges[i]; var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); var newHead = skipAtomic(doc, range.head, bias, mayClear); if (out || newAnchor != range.anchor || newHead != range.head) { if (!out) out = sel.ranges.slice(0, i); out[i] = new Range(newAnchor, newHead); } } return out ? normalizeSelection(out, sel.primIndex) : sel; } // Ensure a given position is not inside an atomic range. function skipAtomic(doc, pos, bias, mayClear) { var flipped = false, curPos = pos; var dir = bias || 1; doc.cantEdit = false; search: for (;;) { var line = getLine(doc, curPos.line); if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { var sp = line.markedSpans[i], m = sp.marker; if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { if (mayClear) { signal(m, "beforeCursorEnter"); if (m.explicitlyCleared) { if (!line.markedSpans) break; else {--i; continue;} } } if (!m.atomic) continue; var newPos = m.find(dir < 0 ? -1 : 1); if (cmp(newPos, curPos) == 0) { newPos.ch += dir; if (newPos.ch < 0) { if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); else newPos = null; } else if (newPos.ch > line.text.length) { if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); else newPos = null; } if (!newPos) { if (flipped) { // Driven in a corner -- no valid cursor position found at all // -- try again *with* clearing, if we didn't already if (!mayClear) return skipAtomic(doc, pos, bias, true); // Otherwise, turn off editing until further notice, and return the start of the doc doc.cantEdit = true; return Pos(doc.first, 0); } flipped = true; newPos = pos; dir = -dir; } } curPos = newPos; continue search; } } } return curPos; } } // SELECTION DRAWING function updateSelection(cm) { cm.display.input.showSelection(cm.display.input.prepareSelection()); } function prepareSelection(cm, primary) { var doc = cm.doc, result = {}; var curFragment = result.cursors = document.createDocumentFragment(); var selFragment = result.selection = document.createDocumentFragment(); for (var i = 0; i < doc.sel.ranges.length; i++) { if (primary === false && i == doc.sel.primIndex) continue; var range = doc.sel.ranges[i]; var collapsed = range.empty(); if (collapsed || cm.options.showCursorWhenSelecting) drawSelectionCursor(cm, range, curFragment); if (!collapsed) drawSelectionRange(cm, range, selFragment); } return result; } // Draws a cursor for the given range function drawSelectionCursor(cm, range, output) { var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); cursor.style.left = pos.left + "px"; cursor.style.top = pos.top + "px"; cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; if (pos.other) { // Secondary cursor, shown when on a 'jump' in bi-directional text var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); otherCursor.style.display = ""; otherCursor.style.left = pos.other.left + "px"; otherCursor.style.top = pos.other.top + "px"; otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; } } // Draws the given range as a highlighted selection function drawSelectionRange(cm, range, output) { var display = cm.display, doc = cm.doc; var fragment = document.createDocumentFragment(); var padding = paddingH(cm.display), leftSide = padding.left; var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; function add(left, top, width, bottom) { if (top < 0) top = 0; top = Math.round(top); bottom = Math.round(bottom); fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px; height: " + (bottom - top) + "px")); } function drawForLine(line, fromArg, toArg) { var lineObj = getLine(doc, line); var lineLen = lineObj.text.length; var start, end; function coords(ch, bias) { return charCoords(cm, Pos(line, ch), "div", lineObj, bias); } iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { var leftPos = coords(from, "left"), rightPos, left, right; if (from == to) { rightPos = leftPos; left = right = leftPos.left; } else { rightPos = coords(to - 1, "right"); if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } left = leftPos.left; right = rightPos.right; } if (fromArg == null && from == 0) left = leftSide; if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part add(left, leftPos.top, null, leftPos.bottom); left = leftSide; if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); } if (toArg == null && to == lineLen) right = rightSide; if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) start = leftPos; if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) end = rightPos; if (left < leftSide + 1) left = leftSide; add(left, rightPos.top, right - left, rightPos.bottom); }); return {start: start, end: end}; } var sFrom = range.from(), sTo = range.to(); if (sFrom.line == sTo.line) { drawForLine(sFrom.line, sFrom.ch, sTo.ch); } else { var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); var singleVLine = visualLine(fromLine) == visualLine(toLine); var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; if (singleVLine) { if (leftEnd.top < rightStart.top - 2) { add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); } else { add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); } } if (leftEnd.bottom < rightStart.top) add(leftSide, leftEnd.bottom, null, rightStart.top); } output.appendChild(fragment); } // Cursor-blinking function restartBlink(cm) { if (!cm.state.focused) return; var display = cm.display; clearInterval(display.blinker); var on = true; display.cursorDiv.style.visibility = ""; if (cm.options.cursorBlinkRate > 0) display.blinker = setInterval(function() { display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, cm.options.cursorBlinkRate); else if (cm.options.cursorBlinkRate < 0) display.cursorDiv.style.visibility = "hidden"; } // HIGHLIGHT WORKER function startWorker(cm, time) { if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) cm.state.highlight.set(time, bind(highlightWorker, cm)); } function highlightWorker(cm) { var doc = cm.doc; if (doc.frontier < doc.first) doc.frontier = doc.first; if (doc.frontier >= cm.display.viewTo) return; var end = +new Date + cm.options.workTime; var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); var changedLines = []; doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { if (doc.frontier >= cm.display.viewFrom) { // Visible var oldStyles = line.styles; var highlighted = highlightLine(cm, line, state, true); line.styles = highlighted.styles; var oldCls = line.styleClasses, newCls = highlighted.classes; if (newCls) line.styleClasses = newCls; else if (oldCls) line.styleClasses = null; var ischange = !oldStyles || oldStyles.length != line.styles.length || oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; if (ischange) changedLines.push(doc.frontier); line.stateAfter = copyState(doc.mode, state); } else { processLine(cm, line.text, state); line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; } ++doc.frontier; if (+new Date > end) { startWorker(cm, cm.options.workDelay); return true; } }); if (changedLines.length) runInOp(cm, function() { for (var i = 0; i < changedLines.length; i++) regLineChange(cm, changedLines[i], "text"); }); } // Finds the line to start with when starting a parse. Tries to // find a line with a stateAfter, so that it can start with a // valid state. If that fails, it returns the line with the // smallest indentation, which tends to need the least context to // parse correctly. function findStartLine(cm, n, precise) { var minindent, minline, doc = cm.doc; var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); for (var search = n; search > lim; --search) { if (search <= doc.first) return doc.first; var line = getLine(doc, search - 1); if (line.stateAfter && (!precise || search <= doc.frontier)) return search; var indented = countColumn(line.text, null, cm.options.tabSize); if (minline == null || minindent > indented) { minline = search - 1; minindent = indented; } } return minline; } function getStateBefore(cm, n, precise) { var doc = cm.doc, display = cm.display; if (!doc.mode.startState) return true; var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; if (!state) state = startState(doc.mode); else state = copyState(doc.mode, state); doc.iter(pos, n, function(line) { processLine(cm, line.text, state); var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; line.stateAfter = save ? copyState(doc.mode, state) : null; ++pos; }); if (precise) doc.frontier = pos; return state; } // POSITION MEASUREMENT function paddingTop(display) {return display.lineSpace.offsetTop;} function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} function paddingH(display) { if (display.cachedPaddingH) return display.cachedPaddingH; var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; return data; } function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } function displayWidth(cm) { return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; } function displayHeight(cm) { return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; } // Ensure the lineView.wrapping.heights array is populated. This is // an array of bottom offsets for the lines that make up a drawn // line. When lineWrapping is on, there might be more than one // height. function ensureLineHeights(cm, lineView, rect) { var wrapping = cm.options.lineWrapping; var curWidth = wrapping && displayWidth(cm); if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { var heights = lineView.measure.heights = []; if (wrapping) { lineView.measure.width = curWidth; var rects = lineView.text.firstChild.getClientRects(); for (var i = 0; i < rects.length - 1; i++) { var cur = rects[i], next = rects[i + 1]; if (Math.abs(cur.bottom - next.bottom) > 2) heights.push((cur.bottom + next.top) / 2 - rect.top); } } heights.push(rect.bottom - rect.top); } } // Find a line map (mapping character offsets to text nodes) and a // measurement cache for the given line number. (A line view might // contain multiple lines when collapsed ranges are present.) function mapFromLineView(lineView, line, lineN) { if (lineView.line == line) return {map: lineView.measure.map, cache: lineView.measure.cache}; for (var i = 0; i < lineView.rest.length; i++) if (lineView.rest[i] == line) return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; for (var i = 0; i < lineView.rest.length; i++) if (lineNo(lineView.rest[i]) > lineN) return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; } // Render a line into the hidden node display.externalMeasured. Used // when measurement is needed for a line that's not in the viewport. function updateExternalMeasurement(cm, line) { line = visualLine(line); var lineN = lineNo(line); var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); view.lineN = lineN; var built = view.built = buildLineContent(cm, view); view.text = built.pre; removeChildrenAndAdd(cm.display.lineMeasure, built.pre); return view; } // Get a {top, bottom, left, right} box (in line-local coordinates) // for a given character. function measureChar(cm, line, ch, bias) { return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); } // Find a line view that corresponds to the given line number. function findViewForLine(cm, lineN) { if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) return cm.display.view[findViewIndex(cm, lineN)]; var ext = cm.display.externalMeasured; if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) return ext; } // Measurement can be split in two steps, the set-up work that // applies to the whole line, and the measurement of the actual // character. Functions like coordsChar, that need to do a lot of // measurements in a row, can thus ensure that the set-up work is // only done once. function prepareMeasureForLine(cm, line) { var lineN = lineNo(line); var view = findViewForLine(cm, lineN); if (view && !view.text) view = null; else if (view && view.changes) updateLineForChanges(cm, view, lineN, getDimensions(cm)); if (!view) view = updateExternalMeasurement(cm, line); var info = mapFromLineView(view, line, lineN); return { line: line, view: view, rect: null, map: info.map, cache: info.cache, before: info.before, hasHeights: false }; } // Given a prepared measurement object, measures the position of an // actual character (or fetches it from the cache). function measureCharPrepared(cm, prepared, ch, bias, varHeight) { if (prepared.before) ch = -1; var key = ch + (bias || ""), found; if (prepared.cache.hasOwnProperty(key)) { found = prepared.cache[key]; } else { if (!prepared.rect) prepared.rect = prepared.view.text.getBoundingClientRect(); if (!prepared.hasHeights) { ensureLineHeights(cm, prepared.view, prepared.rect); prepared.hasHeights = true; } found = measureCharInner(cm, prepared, ch, bias); if (!found.bogus) prepared.cache[key] = found; } return {left: found.left, right: found.right, top: varHeight ? found.rtop : found.top, bottom: varHeight ? found.rbottom : found.bottom}; } var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; function nodeAndOffsetInLineMap(map, ch, bias) { var node, start, end, collapse; // First, search the line map for the text node corresponding to, // or closest to, the target character. for (var i = 0; i < map.length; i += 3) { var mStart = map[i], mEnd = map[i + 1]; if (ch < mStart) { start = 0; end = 1; collapse = "left"; } else if (ch < mEnd) { start = ch - mStart; end = start + 1; } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { end = mEnd - mStart; start = end - 1; if (ch >= mEnd) collapse = "right"; } if (start != null) { node = map[i + 2]; if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) collapse = bias; if (bias == "left" && start == 0) while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { node = map[(i -= 3) + 2]; collapse = "left"; } if (bias == "right" && start == mEnd - mStart) while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { node = map[(i += 3) + 2]; collapse = "right"; } break; } } return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; } function measureCharInner(cm, prepared, ch, bias) { var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); var node = place.node, start = place.start, end = place.end, collapse = place.collapse; var rect; if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) { rect = node.parentNode.getBoundingClientRect(); } else if (ie && cm.options.lineWrapping) { var rects = range(node, start, end).getClientRects(); if (rects.length) rect = rects[bias == "right" ? rects.length - 1 : 0]; else rect = nullRect; } else { rect = range(node, start, end).getBoundingClientRect() || nullRect; } if (rect.left || rect.right || start == 0) break; end = start; start = start - 1; collapse = "right"; } if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); } else { // If it is a widget, simply get the box for the whole widget. if (start > 0) collapse = bias = "right"; var rects; if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) rect = rects[bias == "right" ? rects.length - 1 : 0]; else rect = node.getBoundingClientRect(); } if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { var rSpan = node.parentNode.getClientRects()[0]; if (rSpan) rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; else rect = nullRect; } var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; var mid = (rtop + rbot) / 2; var heights = prepared.view.measure.heights; for (var i = 0; i < heights.length - 1; i++) if (mid < heights[i]) break; var top = i ? heights[i - 1] : 0, bot = heights[i]; var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, top: top, bottom: bot}; if (!rect.left && !rect.right) result.bogus = true; if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } return result; } // Work around problem with bounding client rects on ranges being // returned incorrectly when zoomed on IE10 and below. function maybeUpdateRectForZooming(measure, rect) { if (!window.screen || screen.logicalXDPI == null || screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) return rect; var scaleX = screen.logicalXDPI / screen.deviceXDPI; var scaleY = screen.logicalYDPI / screen.deviceYDPI; return {left: rect.left * scaleX, right: rect.right * scaleX, top: rect.top * scaleY, bottom: rect.bottom * scaleY}; } function clearLineMeasurementCacheFor(lineView) { if (lineView.measure) { lineView.measure.cache = {}; lineView.measure.heights = null; if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) lineView.measure.caches[i] = {}; } } function clearLineMeasurementCache(cm) { cm.display.externalMeasure = null; removeChildren(cm.display.lineMeasure); for (var i = 0; i < cm.display.view.length; i++) clearLineMeasurementCacheFor(cm.display.view[i]); } function clearCaches(cm) { clearLineMeasurementCache(cm); cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; cm.display.lineNumChars = null; } function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } // Converts a {top, bottom, left, right} box from line-local // coordinates into another coordinate system. Context may be one of // "line", "div" (display.lineDiv), "local"/null (editor), "window", // or "page". function intoCoordSystem(cm, lineObj, rect, context) { if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { var size = widgetHeight(lineObj.widgets[i]); rect.top += size; rect.bottom += size; } if (context == "line") return rect; if (!context) context = "local"; var yOff = heightAtLine(lineObj); if (context == "local") yOff += paddingTop(cm.display); else yOff -= cm.display.viewOffset; if (context == "page" || context == "window") { var lOff = cm.display.lineSpace.getBoundingClientRect(); yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); rect.left += xOff; rect.right += xOff; } rect.top += yOff; rect.bottom += yOff; return rect; } // Coverts a box from "div" coords to another coordinate system. // Context may be "window", "page", "div", or "local"/null. function fromCoordSystem(cm, coords, context) { if (context == "div") return coords; var left = coords.left, top = coords.top; // First move into "page" coordinate system if (context == "page") { left -= pageScrollX(); top -= pageScrollY(); } else if (context == "local" || !context) { var localBox = cm.display.sizer.getBoundingClientRect(); left += localBox.left; top += localBox.top; } var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; } function charCoords(cm, pos, context, lineObj, bias) { if (!lineObj) lineObj = getLine(cm.doc, pos.line); return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); } // Returns a box for a given cursor position, which may have an // 'other' property containing the position of the secondary cursor // on a bidi boundary. function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { lineObj = lineObj || getLine(cm.doc, pos.line); if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); function get(ch, right) { var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); if (right) m.left = m.right; else m.right = m.left; return intoCoordSystem(cm, lineObj, m, context); } function getBidi(ch, partPos) { var part = order[partPos], right = part.level % 2; if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { part = order[--partPos]; ch = bidiRight(part) - (part.level % 2 ? 0 : 1); right = true; } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { part = order[++partPos]; ch = bidiLeft(part) - part.level % 2; right = false; } if (right && ch == part.to && ch > part.from) return get(ch - 1); return get(ch, right); } var order = getOrder(lineObj), ch = pos.ch; if (!order) return get(ch); var partPos = getBidiPartAt(order, ch); var val = getBidi(ch, partPos); if (bidiOther != null) val.other = getBidi(ch, bidiOther); return val; } // Used to cheaply estimate the coordinates for a position. Used for // intermediate scroll updates. function estimateCoords(cm, pos) { var left = 0, pos = clipPos(cm.doc, pos); if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; var lineObj = getLine(cm.doc, pos.line); var top = heightAtLine(lineObj) + paddingTop(cm.display); return {left: left, right: left, top: top, bottom: top + lineObj.height}; } // Positions returned by coordsChar contain some extra information. // xRel is the relative x position of the input coordinates compared // to the found position (so xRel > 0 means the coordinates are to // the right of the character position, for example). When outside // is true, that means the coordinates lie outside the line's // vertical range. function PosWithInfo(line, ch, outside, xRel) { var pos = Pos(line, ch); pos.xRel = xRel; if (outside) pos.outside = true; return pos; } // Compute the character position closest to the given coordinates. // Input must be lineSpace-local ("div" coordinate system). function coordsChar(cm, x, y) { var doc = cm.doc; y += cm.display.viewOffset; if (y < 0) return PosWithInfo(doc.first, 0, true, -1); var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineN > last) return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); if (x < 0) x = 0; var lineObj = getLine(doc, lineN); for (;;) { var found = coordsCharInner(cm, lineObj, lineN, x, y); var merged = collapsedSpanAtEnd(lineObj); var mergedPos = merged && merged.find(0, true); if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) lineN = lineNo(lineObj = mergedPos.to.line); else return found; } } function coordsCharInner(cm, lineObj, lineNo, x, y) { var innerOff = y - heightAtLine(lineObj); var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; var preparedMeasure = prepareMeasureForLine(cm, lineObj); function getX(ch) { var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); wrongLine = true; if (innerOff > sp.bottom) return sp.left - adjust; else if (innerOff < sp.top) return sp.left + adjust; else wrongLine = false; return sp.left; } var bidi = getOrder(lineObj), dist = lineObj.text.length; var from = lineLeft(lineObj), to = lineRight(lineObj); var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); // Do a binary search between these bounds. for (;;) { if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { var ch = x < fromX || x - fromX <= toX - x ? from : to; var xDiff = x - (ch == from ? fromX : toX); while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); return pos; } var step = Math.ceil(dist / 2), middle = from + step; if (bidi) { middle = from; for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); } var middleX = getX(middle); if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} } } var measureText; // Compute the default text height. function textHeight(display) { if (display.cachedTextHeight != null) return display.cachedTextHeight; if (measureText == null) { measureText = elt("pre"); // Measure a bunch of lines, for browsers that compute // fractional heights. for (var i = 0; i < 49; ++i) { measureText.appendChild(document.createTextNode("x")); measureText.appendChild(elt("br")); } measureText.appendChild(document.createTextNode("x")); } removeChildrenAndAdd(display.measure, measureText); var height = measureText.offsetHeight / 50; if (height > 3) display.cachedTextHeight = height; removeChildren(display.measure); return height || 1; } // Compute the default character width. function charWidth(display) { if (display.cachedCharWidth != null) return display.cachedCharWidth; var anchor = elt("span", "xxxxxxxxxx"); var pre = elt("pre", [anchor]); removeChildrenAndAdd(display.measure, pre); var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; if (width > 2) display.cachedCharWidth = width; return width || 10; } // OPERATIONS // Operations are used to wrap a series of changes to the editor // state in such a way that each change won't have to update the // cursor and display (which would be awkward, slow, and // error-prone). Instead, display updates are batched and then all // combined and executed at once. var operationGroup = null; var nextOpId = 0; // Start a new operation. function startOperation(cm) { cm.curOp = { cm: cm, viewChanged: false, // Flag that indicates that lines might need to be redrawn startHeight: cm.doc.height, // Used to detect need to update scrollbar forceUpdate: false, // Used to force a redraw updateInput: null, // Whether to reset the input textarea typing: false, // Whether this reset should be careful to leave existing text (for compositing) changeObjs: null, // Accumulated changes, for firing change events cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already selectionChanged: false, // Whether the selection needs to be redrawn updateMaxLine: false, // Set when the widest line needs to be determined anew scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet scrollToPos: null, // Used to scroll to a specific position id: ++nextOpId // Unique ID }; if (operationGroup) { operationGroup.ops.push(cm.curOp); } else { cm.curOp.ownsGroup = operationGroup = { ops: [cm.curOp], delayedCallbacks: [] }; } } function fireCallbacksForOps(group) { // Calls delayed callbacks and cursorActivity handlers until no // new ones appear var callbacks = group.delayedCallbacks, i = 0; do { for (; i < callbacks.length; i++) callbacks[i](); for (var j = 0; j < group.ops.length; j++) { var op = group.ops[j]; if (op.cursorActivityHandlers) while (op.cursorActivityCalled < op.cursorActivityHandlers.length) op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); } } while (i < callbacks.length); } // Finish an operation, updating the display and signalling delayed events function endOperation(cm) { var op = cm.curOp, group = op.ownsGroup; if (!group) return; try { fireCallbacksForOps(group); } finally { operationGroup = null; for (var i = 0; i < group.ops.length; i++) group.ops[i].cm.curOp = null; endOperations(group); } } // The DOM updates done when an operation finishes are batched so // that the minimum number of relayouts are required. function endOperations(group) { var ops = group.ops; for (var i = 0; i < ops.length; i++) // Read DOM endOperation_R1(ops[i]); for (var i = 0; i < ops.length; i++) // Write DOM (maybe) endOperation_W1(ops[i]); for (var i = 0; i < ops.length; i++) // Read DOM endOperation_R2(ops[i]); for (var i = 0; i < ops.length; i++) // Write DOM (maybe) endOperation_W2(ops[i]); for (var i = 0; i < ops.length; i++) // Read DOM endOperation_finish(ops[i]); } function endOperation_R1(op) { var cm = op.cm, display = cm.display; maybeClipScrollbars(cm); if (op.updateMaxLine) findMaxLine(cm); op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || op.scrollToPos.to.line >= display.viewTo) || display.maxLineChanged && cm.options.lineWrapping; op.update = op.mustUpdate && new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); } function endOperation_W1(op) { op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); } function endOperation_R2(op) { var cm = op.cm, display = cm.display; if (op.updatedDisplay) updateHeightsInViewport(cm); op.barMeasure = measureForScrollbars(cm); // If the max line changed since it was last measured, measure it, // and ensure the document's width matches it. // updateDisplay_W2 will use these properties to do the actual resizing if (display.maxLineChanged && !cm.options.lineWrapping) { op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; cm.display.sizerWidth = op.adjustWidthTo; op.barMeasure.scrollWidth = Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); } if (op.updatedDisplay || op.selectionChanged) op.preparedSelection = display.input.prepareSelection(); } function endOperation_W2(op) { var cm = op.cm; if (op.adjustWidthTo != null) { cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; if (op.maxScrollLeft < cm.doc.scrollLeft) setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); cm.display.maxLineChanged = false; } if (op.preparedSelection) cm.display.input.showSelection(op.preparedSelection); if (op.updatedDisplay) setDocumentHeight(cm, op.barMeasure); if (op.updatedDisplay || op.startHeight != cm.doc.height) updateScrollbars(cm, op.barMeasure); if (op.selectionChanged) restartBlink(cm); if (cm.state.focused && op.updateInput) cm.display.input.reset(op.typing); } function endOperation_finish(op) { var cm = op.cm, display = cm.display, doc = cm.doc; if (op.updatedDisplay) postUpdateDisplay(cm, op.update); // Abort mouse wheel delta measurement, when scrolling explicitly if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) display.wheelStartX = display.wheelStartY = null; // Propagate the scroll position to the actual DOM scroller if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); display.scrollbars.setScrollTop(doc.scrollTop); display.scroller.scrollTop = doc.scrollTop; } if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); display.scrollbars.setScrollLeft(doc.scrollLeft); display.scroller.scrollLeft = doc.scrollLeft; alignHorizontally(cm); } // If we need to scroll a specific position into view, do so. if (op.scrollToPos) { var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); } // Fire events for markers that are hidden/unidden by editing or // undoing var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; if (hidden) for (var i = 0; i < hidden.length; ++i) if (!hidden[i].lines.length) signal(hidden[i], "hide"); if (unhidden) for (var i = 0; i < unhidden.length; ++i) if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); if (display.wrapper.offsetHeight) doc.scrollTop = cm.display.scroller.scrollTop; // Fire change events, and delayed event handlers if (op.changeObjs) signal(cm, "changes", cm, op.changeObjs); if (op.update) op.update.finish(); } // Run the given function in an operation function runInOp(cm, f) { if (cm.curOp) return f(); startOperation(cm); try { return f(); } finally { endOperation(cm); } } // Wraps a function in an operation. Returns the wrapped function. function operation(cm, f) { return function() { if (cm.curOp) return f.apply(cm, arguments); startOperation(cm); try { return f.apply(cm, arguments); } finally { endOperation(cm); } }; } // Used to add methods to editor and doc instances, wrapping them in // operations. function methodOp(f) { return function() { if (this.curOp) return f.apply(this, arguments); startOperation(this); try { return f.apply(this, arguments); } finally { endOperation(this); } }; } function docMethodOp(f) { return function() { var cm = this.cm; if (!cm || cm.curOp) return f.apply(this, arguments); startOperation(cm); try { return f.apply(this, arguments); } finally { endOperation(cm); } }; } // VIEW TRACKING // These objects are used to represent the visible (currently drawn) // part of the document. A LineView may correspond to multiple // logical lines, if those are connected by collapsed ranges. function LineView(doc, line, lineN) { // The starting line this.line = line; // Continuing lines, if any this.rest = visualLineContinued(line); // Number of logical lines in this visual line this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; this.node = this.text = null; this.hidden = lineIsHidden(doc, line); } // Create a range of LineView objects for the given lines. function buildViewArray(cm, from, to) { var array = [], nextPos; for (var pos = from; pos < to; pos = nextPos) { var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); nextPos = pos + view.size; array.push(view); } return array; } // Updates the display.view data structure for a given change to the // document. From and to are in pre-change coordinates. Lendiff is // the amount of lines added or subtracted by the change. This is // used for changes that span multiple lines, or change the way // lines are divided into visual lines. regLineChange (below) // registers single-line changes. function regChange(cm, from, to, lendiff) { if (from == null) from = cm.doc.first; if (to == null) to = cm.doc.first + cm.doc.size; if (!lendiff) lendiff = 0; var display = cm.display; if (lendiff && to < display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers > from)) display.updateLineNumbers = from; cm.curOp.viewChanged = true; if (from >= display.viewTo) { // Change after if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) resetView(cm); } else if (to <= display.viewFrom) { // Change before if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { resetView(cm); } else { display.viewFrom += lendiff; display.viewTo += lendiff; } } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap resetView(cm); } else if (from <= display.viewFrom) { // Top overlap var cut = viewCuttingPoint(cm, to, to + lendiff, 1); if (cut) { display.view = display.view.slice(cut.index); display.viewFrom = cut.lineN; display.viewTo += lendiff; } else { resetView(cm); } } else if (to >= display.viewTo) { // Bottom overlap var cut = viewCuttingPoint(cm, from, from, -1); if (cut) { display.view = display.view.slice(0, cut.index); display.viewTo = cut.lineN; } else { resetView(cm); } } else { // Gap in the middle var cutTop = viewCuttingPoint(cm, from, from, -1); var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); if (cutTop && cutBot) { display.view = display.view.slice(0, cutTop.index) .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) .concat(display.view.slice(cutBot.index)); display.viewTo += lendiff; } else { resetView(cm); } } var ext = display.externalMeasured; if (ext) { if (to < ext.lineN) ext.lineN += lendiff; else if (from < ext.lineN + ext.size) display.externalMeasured = null; } } // Register a change to a single line. Type must be one of "text", // "gutter", "class", "widget" function regLineChange(cm, line, type) { cm.curOp.viewChanged = true; var display = cm.display, ext = cm.display.externalMeasured; if (ext && line >= ext.lineN && line < ext.lineN + ext.size) display.externalMeasured = null; if (line < display.viewFrom || line >= display.viewTo) return; var lineView = display.view[findViewIndex(cm, line)]; if (lineView.node == null) return; var arr = lineView.changes || (lineView.changes = []); if (indexOf(arr, type) == -1) arr.push(type); } // Clear the view. function resetView(cm) { cm.display.viewFrom = cm.display.viewTo = cm.doc.first; cm.display.view = []; cm.display.viewOffset = 0; } // Find the view element corresponding to a given line. Return null // when the line isn't visible. function findViewIndex(cm, n) { if (n >= cm.display.viewTo) return null; n -= cm.display.viewFrom; if (n < 0) return null; var view = cm.display.view; for (var i = 0; i < view.length; i++) { n -= view[i].size; if (n < 0) return i; } } function viewCuttingPoint(cm, oldN, newN, dir) { var index = findViewIndex(cm, oldN), diff, view = cm.display.view; if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) return {index: index, lineN: newN}; for (var i = 0, n = cm.display.viewFrom; i < index; i++) n += view[i].size; if (n != oldN) { if (dir > 0) { if (index == view.length - 1) return null; diff = (n + view[index].size) - oldN; index++; } else { diff = n - oldN; } oldN += diff; newN += diff; } while (visualLineNo(cm.doc, newN) != newN) { if (index == (dir < 0 ? 0 : view.length - 1)) return null; newN += dir * view[index - (dir < 0 ? 1 : 0)].size; index += dir; } return {index: index, lineN: newN}; } // Force the view to cover a given range, adding empty view element // or clipping off existing ones as needed. function adjustView(cm, from, to) { var display = cm.display, view = display.view; if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { display.view = buildViewArray(cm, from, to); display.viewFrom = from; } else { if (display.viewFrom > from) display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); else if (display.viewFrom < from) display.view = display.view.slice(findViewIndex(cm, from)); display.viewFrom = from; if (display.viewTo < to) display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); else if (display.viewTo > to) display.view = display.view.slice(0, findViewIndex(cm, to)); } display.viewTo = to; } // Count the number of lines in the view whose DOM representation is // out of date (or nonexistent). function countDirtyView(cm) { var view = cm.display.view, dirty = 0; for (var i = 0; i < view.length; i++) { var lineView = view[i]; if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; } return dirty; } // EVENT HANDLERS // Attach the necessary event handlers when initializing the editor function registerEventHandlers(cm) { var d = cm.display; on(d.scroller, "mousedown", operation(cm, onMouseDown)); // Older IE's will not fire a second mousedown for a double click if (ie && ie_version < 11) on(d.scroller, "dblclick", operation(cm, function(e) { if (signalDOMEvent(cm, e)) return; var pos = posFromMouse(cm, e); if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; e_preventDefault(e); var word = cm.findWordAt(pos); extendSelection(cm.doc, word.anchor, word.head); })); else on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); // Some browsers fire contextmenu *after* opening the menu, at // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for these browsers. if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); // Used to suppress mouse event handling when a touch happens var touchFinished, prevTouch = {end: 0}; function finishTouch() { if (d.activeTouch) { touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); prevTouch = d.activeTouch; prevTouch.end = +new Date; } }; function isMouseLikeTouchEvent(e) { if (e.touches.length != 1) return false; var touch = e.touches[0]; return touch.radiusX <= 1 && touch.radiusY <= 1; } function farAway(touch, other) { if (other.left == null) return true; var dx = other.left - touch.left, dy = other.top - touch.top; return dx * dx + dy * dy > 20 * 20; } on(d.scroller, "touchstart", function(e) { if (!isMouseLikeTouchEvent(e)) { clearTimeout(touchFinished); var now = +new Date; d.activeTouch = {start: now, moved: false, prev: now - prevTouch.end <= 300 ? prevTouch : null}; if (e.touches.length == 1) { d.activeTouch.left = e.touches[0].pageX; d.activeTouch.top = e.touches[0].pageY; } } }); on(d.scroller, "touchmove", function() { if (d.activeTouch) d.activeTouch.moved = true; }); on(d.scroller, "touchend", function(e) { var touch = d.activeTouch; if (touch && !eventInWidget(d, e) && touch.left != null && !touch.moved && new Date - touch.start < 300) { var pos = cm.coordsChar(d.activeTouch, "page"), range; if (!touch.prev || farAway(touch, touch.prev)) // Single tap range = new Range(pos, pos); else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap range = cm.findWordAt(pos); else // Triple tap range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); cm.setSelection(range.anchor, range.head); cm.focus(); e_preventDefault(e); } finishTouch(); }); on(d.scroller, "touchcancel", finishTouch); // Sync scrolling between fake scrollbars and real scrollable // area, ensure viewport is updated when scrolling. on(d.scroller, "scroll", function() { if (d.scroller.clientHeight) { setScrollTop(cm, d.scroller.scrollTop); setScrollLeft(cm, d.scroller.scrollLeft, true); signal(cm, "scroll", cm); } }); // Listen to wheel events in order to try and update the viewport on time. on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); // Prevent wrapper from ever scrolling on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); function drag_(e) { if (!signalDOMEvent(cm, e)) e_stop(e); } if (cm.options.dragDrop) { on(d.scroller, "dragstart", function(e){onDragStart(cm, e);}); on(d.scroller, "dragenter", drag_); on(d.scroller, "dragover", drag_); on(d.scroller, "drop", operation(cm, onDrop)); } var inp = d.input.getField(); on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); on(inp, "keydown", operation(cm, onKeyDown)); on(inp, "keypress", operation(cm, onKeyPress)); on(inp, "focus", bind(onFocus, cm)); on(inp, "blur", bind(onBlur, cm)); } // Called when the window resizes function onResize(cm) { var d = cm.display; if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) return; // Might be a text scaling operation, clear size caches. d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; d.scrollbarsClipped = false; cm.setSize(); } // MOUSE EVENTS // Return true when the given mouse event happened in a widget function eventInWidget(display, e) { for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || (n.parentNode == display.sizer && n != display.mover)) return true; } } // Given a mouse event, find the corresponding position. If liberal // is false, it checks whether a gutter or scrollbar was clicked, // and returns null if it was. forRect is used by rectangular // selections, and tries to estimate a character position even for // coordinates beyond the right of the text. function posFromMouse(cm, e, liberal, forRect) { var display = cm.display; if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; var x, y, space = display.lineSpace.getBoundingClientRect(); // Fails unpredictably on IE[67] when mouse is dragged around quickly. try { x = e.clientX - space.left; y = e.clientY - space.top; } catch (e) { return null; } var coords = coordsChar(cm, x, y), line; if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); } return coords; } // A mouse down can be a single click, double click, triple click, // start of selection drag, start of text drag, new cursor // (ctrl-click), rectangle drag (alt-drag), or xwin // middle-click-paste. Or it might be a click on something we should // not interfere with, such as a scrollbar or widget. function onMouseDown(e) { var cm = this, display = cm.display; if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return; display.shift = e.shiftKey; if (eventInWidget(display, e)) { if (!webkit) { // Briefly turn off draggability, to allow widgets to do // normal dragging things. display.scroller.draggable = false; setTimeout(function(){display.scroller.draggable = true;}, 100); } return; } if (clickInGutter(cm, e)) return; var start = posFromMouse(cm, e); window.focus(); switch (e_button(e)) { case 1: if (start) leftButtonDown(cm, e, start); else if (e_target(e) == display.scroller) e_preventDefault(e); break; case 2: if (webkit) cm.state.lastMiddleDown = +new Date; if (start) extendSelection(cm.doc, start); setTimeout(function() {display.input.focus();}, 20); e_preventDefault(e); break; case 3: if (captureRightClick) onContextMenu(cm, e); else delayBlurEvent(cm); break; } } var lastClick, lastDoubleClick; function leftButtonDown(cm, e, start) { if (ie) setTimeout(bind(ensureFocus, cm), 0); else ensureFocus(cm); var now = +new Date, type; if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { type = "triple"; } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { type = "double"; lastDoubleClick = {time: now, pos: start}; } else { type = "single"; lastClick = {time: now, pos: start}; } var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && type == "single" && (contained = sel.contains(start)) > -1 && !sel.ranges[contained].empty()) leftButtonStartDrag(cm, e, start, modifier); else leftButtonSelect(cm, e, start, type, modifier); } // Start a text drag. When it ends, see if any dragging actually // happen, and treat as a click if it didn't. function leftButtonStartDrag(cm, e, start, modifier) { var display = cm.display; var dragEnd = operation(cm, function(e2) { if (webkit) display.scroller.draggable = false; cm.state.draggingText = false; off(document, "mouseup", dragEnd); off(display.scroller, "drop", dragEnd); if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { e_preventDefault(e2); if (!modifier) extendSelection(cm.doc, start); // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) if (webkit || ie && ie_version == 9) setTimeout(function() {document.body.focus(); display.input.focus();}, 20); else display.input.focus(); } }); // Let the drag handler handle this. if (webkit) display.scroller.draggable = true; cm.state.draggingText = dragEnd; // IE's approach to draggable if (display.scroller.dragDrop) display.scroller.dragDrop(); on(document, "mouseup", dragEnd); on(display.scroller, "drop", dragEnd); } // Normal selection, as opposed to text dragging. function leftButtonSelect(cm, e, start, type, addNew) { var display = cm.display, doc = cm.doc; e_preventDefault(e); var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; if (addNew && !e.shiftKey) { ourIndex = doc.sel.contains(start); if (ourIndex > -1) ourRange = ranges[ourIndex]; else ourRange = new Range(start, start); } else { ourRange = doc.sel.primary(); ourIndex = doc.sel.primIndex; } if (e.altKey) { type = "rect"; if (!addNew) ourRange = new Range(start, start); start = posFromMouse(cm, e, true, true); ourIndex = -1; } else if (type == "double") { var word = cm.findWordAt(start); if (cm.display.shift || doc.extend) ourRange = extendRange(doc, ourRange, word.anchor, word.head); else ourRange = word; } else if (type == "triple") { var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); if (cm.display.shift || doc.extend) ourRange = extendRange(doc, ourRange, line.anchor, line.head); else ourRange = line; } else { ourRange = extendRange(doc, ourRange, start); } if (!addNew) { ourIndex = 0; setSelection(doc, new Selection([ourRange], 0), sel_mouse); startSel = doc.sel; } else if (ourIndex == -1) { ourIndex = ranges.length; setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), {scroll: false, origin: "*mouse"}); } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0)); startSel = doc.sel; } else { replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); } var lastPos = start; function extendTo(pos) { if (cmp(lastPos, pos) == 0) return; lastPos = pos; if (type == "rect") { var ranges = [], tabSize = cm.options.tabSize; var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); line <= end; line++) { var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); if (left == right) ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); else if (text.length > leftPos) ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); } if (!ranges.length) ranges.push(new Range(start, start)); setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), {origin: "*mouse", scroll: false}); cm.scrollIntoView(pos); } else { var oldRange = ourRange; var anchor = oldRange.anchor, head = pos; if (type != "single") { if (type == "double") var range = cm.findWordAt(pos); else var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); if (cmp(range.anchor, anchor) > 0) { head = range.head; anchor = minPos(oldRange.from(), range.anchor); } else { head = range.anchor; anchor = maxPos(oldRange.to(), range.head); } } var ranges = startSel.ranges.slice(0); ranges[ourIndex] = new Range(clipPos(doc, anchor), head); setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); } } var editorSize = display.wrapper.getBoundingClientRect(); // Used to ensure timeout re-tries don't fire when another extend // happened in the meantime (clearTimeout isn't reliable -- at // least on Chrome, the timeouts still happen even when cleared, // if the clear happens after their scheduled firing time). var counter = 0; function extend(e) { var curCount = ++counter; var cur = posFromMouse(cm, e, true, type == "rect"); if (!cur) return; if (cmp(cur, lastPos) != 0) { ensureFocus(cm); extendTo(cur); var visible = visibleLines(display, doc); if (cur.line >= visible.to || cur.line < visible.from) setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); } else { var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; if (outside) setTimeout(operation(cm, function() { if (counter != curCount) return; display.scroller.scrollTop += outside; extend(e); }), 50); } } function done(e) { counter = Infinity; e_preventDefault(e); display.input.focus(); off(document, "mousemove", move); off(document, "mouseup", up); doc.history.lastSelOrigin = null; } var move = operation(cm, function(e) { if (!e_button(e)) done(e); else extend(e); }); var up = operation(cm, done); on(document, "mousemove", move); on(document, "mouseup", up); } // Determines whether an event happened in the gutter, and fires the // handlers for the corresponding event. function gutterEvent(cm, e, type, prevent, signalfn) { try { var mX = e.clientX, mY = e.clientY; } catch(e) { return false; } if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; if (prevent) e_preventDefault(e); var display = cm.display; var lineBox = display.lineDiv.getBoundingClientRect(); if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); mY -= lineBox.top - display.viewOffset; for (var i = 0; i < cm.options.gutters.length; ++i) { var g = display.gutters.childNodes[i]; if (g && g.getBoundingClientRect().right >= mX) { var line = lineAtHeight(cm.doc, mY); var gutter = cm.options.gutters[i]; signalfn(cm, type, cm, line, gutter, e); return e_defaultPrevented(e); } } } function clickInGutter(cm, e) { return gutterEvent(cm, e, "gutterClick", true, signalLater); } // Kludge to work around strange IE behavior where it'll sometimes // re-fire a series of drag-related events right after the drop (#1551) var lastDrop = 0; function onDrop(e) { var cm = this; if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; e_preventDefault(e); if (ie) lastDrop = +new Date; var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; if (!pos || isReadOnly(cm)) return; // Might be a file drop, in which case we simply extract the text // and insert it. if (files && files.length && window.FileReader && window.File) { var n = files.length, text = Array(n), read = 0; var loadFile = function(file, i) { var reader = new FileReader; reader.onload = operation(cm, function() { text[i] = reader.result; if (++read == n) { pos = clipPos(cm.doc, pos); var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; makeChange(cm.doc, change); setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); } }); reader.readAsText(file); }; for (var i = 0; i < n; ++i) loadFile(files[i], i); } else { // Normal drop // Don't do a replace if the drop happened inside of the selected text. if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { cm.state.draggingText(e); // Ensure the editor is re-focused setTimeout(function() {cm.display.input.focus();}, 20); return; } try { var text = e.dataTransfer.getData("Text"); if (text) { if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey)) var selected = cm.listSelections(); setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); if (selected) for (var i = 0; i < selected.length; ++i) replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); cm.replaceSelection(text, "around", "paste"); cm.display.input.focus(); } } catch(e){} } } function onDragStart(cm, e) { if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; e.dataTransfer.setData("Text", cm.getSelection()); // Use dummy image instead of default browsers image. // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. if (e.dataTransfer.setDragImage && !safari) { var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; if (presto) { img.width = img.height = 1; cm.display.wrapper.appendChild(img); // Force a relayout, or Opera won't use our image for some obscure reason img._top = img.offsetTop; } e.dataTransfer.setDragImage(img, 0, 0); if (presto) img.parentNode.removeChild(img); } } // SCROLL EVENTS // Sync the scrollable area and scrollbars, ensure the viewport // covers the visible area. function setScrollTop(cm, val) { if (Math.abs(cm.doc.scrollTop - val) < 2) return; cm.doc.scrollTop = val; if (!gecko) updateDisplaySimple(cm, {top: val}); if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; cm.display.scrollbars.setScrollTop(val); if (gecko) updateDisplaySimple(cm); startWorker(cm, 100); } // Sync scroller and scrollbar, ensure the gutter elements are // aligned. function setScrollLeft(cm, val, isScroller) { if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); cm.doc.scrollLeft = val; alignHorizontally(cm); if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; cm.display.scrollbars.setScrollLeft(val); } // Since the delta values reported on mouse wheel events are // unstandardized between browsers and even browser versions, and // generally horribly unpredictable, this code starts by measuring // the scroll effect that the first few mouse wheel events have, // and, from that, detects the way it can convert deltas to pixel // offsets afterwards. // // The reason we want to know the amount a wheel event will scroll // is that it gives us a chance to update the display before the // actual scrolling happens, reducing flickering. var wheelSamples = 0, wheelPixelsPerUnit = null; // Fill in a browser-detected starting value on browsers where we // know one. These don't have to be accurate -- the result of them // being wrong would just be a slight flicker on the first wheel // scroll (if it is large enough). if (ie) wheelPixelsPerUnit = -.53; else if (gecko) wheelPixelsPerUnit = 15; else if (chrome) wheelPixelsPerUnit = -.7; else if (safari) wheelPixelsPerUnit = -1/3; var wheelEventDelta = function(e) { var dx = e.wheelDeltaX, dy = e.wheelDeltaY; if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; else if (dy == null) dy = e.wheelDelta; return {x: dx, y: dy}; }; CodeMirror.wheelEventPixels = function(e) { var delta = wheelEventDelta(e); delta.x *= wheelPixelsPerUnit; delta.y *= wheelPixelsPerUnit; return delta; }; function onScrollWheel(cm, e) { var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; var display = cm.display, scroll = display.scroller; // Quit if there's nothing to scroll here if (!(dx && scroll.scrollWidth > scroll.clientWidth || dy && scroll.scrollHeight > scroll.clientHeight)) return; // Webkit browsers on OS X abort momentum scrolls when the target // of the scroll event is removed from the scrollable element. // This hack (see related code in patchDisplay) makes sure the // element is kept around. if (dy && mac && webkit) { outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { for (var i = 0; i < view.length; i++) { if (view[i].node == cur) { cm.display.currentWheelTarget = cur; break outer; } } } } // On some browsers, horizontal scrolling will cause redraws to // happen before the gutter has been realigned, causing it to // wriggle around in a most unseemly way. When we have an // estimated pixels/delta value, we just handle horizontal // scrolling entirely here. It'll be slightly off from native, but // better than glitching out. if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { if (dy) setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); e_preventDefault(e); display.wheelStartX = null; // Abort measurement, if in progress return; } // 'Project' the visible viewport to cover the area that is being // scrolled into view (if we know enough to estimate it). if (dy && wheelPixelsPerUnit != null) { var pixels = dy * wheelPixelsPerUnit; var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; if (pixels < 0) top = Math.max(0, top + pixels - 50); else bot = Math.min(cm.doc.height, bot + pixels + 50); updateDisplaySimple(cm, {top: top, bottom: bot}); } if (wheelSamples < 20) { if (display.wheelStartX == null) { display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; display.wheelDX = dx; display.wheelDY = dy; setTimeout(function() { if (display.wheelStartX == null) return; var movedX = scroll.scrollLeft - display.wheelStartX; var movedY = scroll.scrollTop - display.wheelStartY; var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || (movedX && display.wheelDX && movedX / display.wheelDX); display.wheelStartX = display.wheelStartY = null; if (!sample) return; wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); ++wheelSamples; }, 200); } else { display.wheelDX += dx; display.wheelDY += dy; } } } // KEY EVENTS // Run a handler that was bound to a key. function doHandleBinding(cm, bound, dropShift) { if (typeof bound == "string") { bound = commands[bound]; if (!bound) return false; } // Ensure previous input has been read, so that the handler sees a // consistent view of the document cm.display.input.ensurePolled(); var prevShift = cm.display.shift, done = false; try { if (isReadOnly(cm)) cm.state.suppressEdits = true; if (dropShift) cm.display.shift = false; done = bound(cm) != Pass; } finally { cm.display.shift = prevShift; cm.state.suppressEdits = false; } return done; } function lookupKeyForEditor(cm, name, handle) { for (var i = 0; i < cm.state.keyMaps.length; i++) { var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); if (result) return result; } return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) || lookupKey(name, cm.options.keyMap, handle, cm); } var stopSeq = new Delayed; function dispatchKey(cm, name, e, handle) { var seq = cm.state.keySeq; if (seq) { if (isModifierKey(name)) return "handled"; stopSeq.set(50, function() { if (cm.state.keySeq == seq) { cm.state.keySeq = null; cm.display.input.reset(); } }); name = seq + " " + name; } var result = lookupKeyForEditor(cm, name, handle); if (result == "multi") cm.state.keySeq = name; if (result == "handled") signalLater(cm, "keyHandled", cm, name, e); if (result == "handled" || result == "multi") { e_preventDefault(e); restartBlink(cm); } if (seq && !result && /\'$/.test(name)) { e_preventDefault(e); return true; } return !!result; } // Handle a key from the keydown event. function handleKeyBinding(cm, e) { var name = keyName(e, true); if (!name) return false; if (e.shiftKey && !cm.state.keySeq) { // First try to resolve full name (including 'Shift-'). Failing // that, see if there is a cursor-motion command (starting with // 'go') bound to the keyname without 'Shift-'. return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) || dispatchKey(cm, name, e, function(b) { if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) return doHandleBinding(cm, b); }); } else { return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); } } // Handle a key from the keypress event function handleCharBinding(cm, e, ch) { return dispatchKey(cm, "'" + ch + "'", e, function(b) { return doHandleBinding(cm, b, true); }); } var lastStoppedKey = null; function onKeyDown(e) { var cm = this; ensureFocus(cm); if (signalDOMEvent(cm, e)) return; // IE does strange things with escape. if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; var code = e.keyCode; cm.display.shift = code == 16 || e.shiftKey; var handled = handleKeyBinding(cm, e); if (presto) { lastStoppedKey = handled ? code : null; // Opera has no cut event... we try to at least catch the key combo if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) cm.replaceSelection("", null, "cut"); } // Turn mouse into crosshair when Alt is held on Mac. if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) showCrossHair(cm); } function showCrossHair(cm) { var lineDiv = cm.display.lineDiv; addClass(lineDiv, "CodeMirror-crosshair"); function up(e) { if (e.keyCode == 18 || !e.altKey) { rmClass(lineDiv, "CodeMirror-crosshair"); off(document, "keyup", up); off(document, "mouseover", up); } } on(document, "keyup", up); on(document, "mouseover", up); } function onKeyUp(e) { if (e.keyCode == 16) this.doc.sel.shift = false; signalDOMEvent(this, e); } function onKeyPress(e) { var cm = this; if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; var keyCode = e.keyCode, charCode = e.charCode; if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; var ch = String.fromCharCode(charCode == null ? keyCode : charCode); if (handleCharBinding(cm, e, ch)) return; cm.display.input.onKeyPress(e); } // FOCUS/BLUR EVENTS function delayBlurEvent(cm) { cm.state.delayingBlurEvent = true; setTimeout(function() { if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; onBlur(cm); } }, 100); } function onFocus(cm) { if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; if (cm.options.readOnly == "nocursor") return; if (!cm.state.focused) { signal(cm, "focus", cm); cm.state.focused = true; addClass(cm.display.wrapper, "CodeMirror-focused"); // This test prevents this from firing when a context // menu is closed (since the input reset would kill the // select-all detection hack) if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { cm.display.input.reset(); if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 } cm.display.input.receivedFocus(); } restartBlink(cm); } function onBlur(cm) { if (cm.state.delayingBlurEvent) return; if (cm.state.focused) { signal(cm, "blur", cm); cm.state.focused = false; rmClass(cm.display.wrapper, "CodeMirror-focused"); } clearInterval(cm.display.blinker); setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); } // CONTEXT MENU HANDLING // To make the context menu work, we need to briefly unhide the // textarea (making it as unobtrusive as possible) to let the // right-click take effect on it. function onContextMenu(cm, e) { if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; cm.display.input.onContextMenu(e); } function contextMenuInGutter(cm, e) { if (!hasHandler(cm, "gutterContextMenu")) return false; return gutterEvent(cm, e, "gutterContextMenu", false, signal); } // UPDATING // Compute the position of the end of a change (its 'to' property // refers to the pre-change end). var changeEnd = CodeMirror.changeEnd = function(change) { if (!change.text) return change.to; return Pos(change.from.line + change.text.length - 1, lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); }; // Adjust a position to refer to the post-change position of the // same text, or the end of the change if the change covers it. function adjustForChange(pos, change) { if (cmp(pos, change.from) < 0) return pos; if (cmp(pos, change.to) <= 0) return changeEnd(change); var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; return Pos(line, ch); } function computeSelAfterChange(doc, change) { var out = []; for (var i = 0; i < doc.sel.ranges.length; i++) { var range = doc.sel.ranges[i]; out.push(new Range(adjustForChange(range.anchor, change), adjustForChange(range.head, change))); } return normalizeSelection(out, doc.sel.primIndex); } function offsetPos(pos, old, nw) { if (pos.line == old.line) return Pos(nw.line, pos.ch - old.ch + nw.ch); else return Pos(nw.line + (pos.line - old.line), pos.ch); } // Used by replaceSelections to allow moving the selection to the // start or around the replaced test. Hint may be "start" or "around". function computeReplacedSel(doc, changes, hint) { var out = []; var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; for (var i = 0; i < changes.length; i++) { var change = changes[i]; var from = offsetPos(change.from, oldPrev, newPrev); var to = offsetPos(changeEnd(change), oldPrev, newPrev); oldPrev = change.to; newPrev = to; if (hint == "around") { var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; out[i] = new Range(inv ? to : from, inv ? from : to); } else { out[i] = new Range(from, from); } } return new Selection(out, doc.sel.primIndex); } // Allow "beforeChange" event handlers to influence a change function filterChange(doc, change, update) { var obj = { canceled: false, from: change.from, to: change.to, text: change.text, origin: change.origin, cancel: function() { this.canceled = true; } }; if (update) obj.update = function(from, to, text, origin) { if (from) this.from = clipPos(doc, from); if (to) this.to = clipPos(doc, to); if (text) this.text = text; if (origin !== undefined) this.origin = origin; }; signal(doc, "beforeChange", doc, obj); if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); if (obj.canceled) return null; return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; } // Apply a change to a document, and add it to the document's // history, and propagating it to all linked documents. function makeChange(doc, change, ignoreReadOnly) { if (doc.cm) { if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); if (doc.cm.state.suppressEdits) return; } if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { change = filterChange(doc, change, true); if (!change) return; } // Possibly split or suppress the update based on the presence // of read-only spans in its range. var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); if (split) { for (var i = split.length - 1; i >= 0; --i) makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); } else { makeChangeInner(doc, change); } } function makeChangeInner(doc, change) { if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; var selAfter = computeSelAfterChange(doc, change); addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); var rebased = []; linkedDocs(doc, function(doc, sharedHist) { if (!sharedHist && indexOf(rebased, doc.history) == -1) { rebaseHist(doc.history, change); rebased.push(doc.history); } makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); }); } // Revert a change stored in a document's history. function makeChangeFromHistory(doc, type, allowSelectionOnly) { if (doc.cm && doc.cm.state.suppressEdits) return; var hist = doc.history, event, selAfter = doc.sel; var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; // Verify that there is a useable event (so that ctrl-z won't // needlessly clear selection events) for (var i = 0; i < source.length; i++) { event = source[i]; if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) break; } if (i == source.length) return; hist.lastOrigin = hist.lastSelOrigin = null; for (;;) { event = source.pop(); if (event.ranges) { pushSelectionToHistory(event, dest); if (allowSelectionOnly && !event.equals(doc.sel)) { setSelection(doc, event, {clearRedo: false}); return; } selAfter = event; } else break; } // Build up a reverse change object to add to the opposite history // stack (redo when undoing, and vice versa). var antiChanges = []; pushSelectionToHistory(selAfter, dest); dest.push({changes: antiChanges, generation: hist.generation}); hist.generation = event.generation || ++hist.maxGeneration; var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); for (var i = event.changes.length - 1; i >= 0; --i) { var change = event.changes[i]; change.origin = type; if (filter && !filterChange(doc, change, false)) { source.length = 0; return; } antiChanges.push(historyChangeFromChange(doc, change)); var after = i ? computeSelAfterChange(doc, change) : lst(source); makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); var rebased = []; // Propagate to the linked documents linkedDocs(doc, function(doc, sharedHist) { if (!sharedHist && indexOf(rebased, doc.history) == -1) { rebaseHist(doc.history, change); rebased.push(doc.history); } makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); }); } } // Sub-views need their line numbers shifted when text is added // above or below them in the parent document. function shiftDoc(doc, distance) { if (distance == 0) return; doc.first += distance; doc.sel = new Selection(map(doc.sel.ranges, function(range) { return new Range(Pos(range.anchor.line + distance, range.anchor.ch), Pos(range.head.line + distance, range.head.ch)); }), doc.sel.primIndex); if (doc.cm) { regChange(doc.cm, doc.first, doc.first - distance, distance); for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) regLineChange(doc.cm, l, "gutter"); } } // More lower-level change function, handling only a single document // (not linked ones). function makeChangeSingleDoc(doc, change, selAfter, spans) { if (doc.cm && !doc.cm.curOp) return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); if (change.to.line < doc.first) { shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); return; } if (change.from.line > doc.lastLine()) return; // Clip the change to the size of this doc if (change.from.line < doc.first) { var shift = change.text.length - 1 - (doc.first - change.from.line); shiftDoc(doc, shift); change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), text: [lst(change.text)], origin: change.origin}; } var last = doc.lastLine(); if (change.to.line > last) { change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), text: [change.text[0]], origin: change.origin}; } change.removed = getBetween(doc, change.from, change.to); if (!selAfter) selAfter = computeSelAfterChange(doc, change); if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); else updateDoc(doc, change, spans); setSelectionNoUndo(doc, selAfter, sel_dontScroll); } // Handle the interaction of a change to a document with the editor // that this document is part of. function makeChangeSingleDocInEditor(cm, change, spans) { var doc = cm.doc, display = cm.display, from = change.from, to = change.to; var recomputeMaxLength = false, checkWidthStart = from.line; if (!cm.options.lineWrapping) { checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); doc.iter(checkWidthStart, to.line + 1, function(line) { if (line == display.maxLine) { recomputeMaxLength = true; return true; } }); } if (doc.sel.contains(change.from, change.to) > -1) signalCursorActivity(cm); updateDoc(doc, change, spans, estimateHeight(cm)); if (!cm.options.lineWrapping) { doc.iter(checkWidthStart, from.line + change.text.length, function(line) { var len = lineLength(line); if (len > display.maxLineLength) { display.maxLine = line; display.maxLineLength = len; display.maxLineChanged = true; recomputeMaxLength = false; } }); if (recomputeMaxLength) cm.curOp.updateMaxLine = true; } // Adjust frontier, schedule worker doc.frontier = Math.min(doc.frontier, from.line); startWorker(cm, 400); var lendiff = change.text.length - (to.line - from.line) - 1; // Remember that these lines changed, for updating the display if (change.full) regChange(cm); else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) regLineChange(cm, from.line, "text"); else regChange(cm, from.line, to.line + 1, lendiff); var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); if (changeHandler || changesHandler) { var obj = { from: from, to: to, text: change.text, removed: change.removed, origin: change.origin }; if (changeHandler) signalLater(cm, "change", cm, obj); if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); } cm.display.selForContextMenu = null; } function replaceRange(doc, code, from, to, origin) { if (!to) to = from; if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } if (typeof code == "string") code = splitLines(code); makeChange(doc, {from: from, to: to, text: code, origin: origin}); } // SCROLLING THINGS INTO VIEW // If an editor sits on the top or bottom of the window, partially // scrolled out of view, this ensures that the cursor is visible. function maybeScrollWindow(cm, coords) { if (signalDOMEvent(cm, "scrollCursorIntoView")) return; var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; if (coords.top + box.top < 0) doScroll = true; else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; if (doScroll != null && !phantom) { var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + coords.left + "px; width: 2px;"); cm.display.lineSpace.appendChild(scrollNode); scrollNode.scrollIntoView(doScroll); cm.display.lineSpace.removeChild(scrollNode); } } // Scroll a given position into view (immediately), verifying that // it actually became visible (as line heights are accurately // measured, the position of something may 'drift' during drawing). function scrollPosIntoView(cm, pos, end, margin) { if (margin == null) margin = 0; for (var limit = 0; limit < 5; limit++) { var changed = false, coords = cursorCoords(cm, pos); var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), Math.min(coords.top, endCoords.top) - margin, Math.max(coords.left, endCoords.left), Math.max(coords.bottom, endCoords.bottom) + margin); var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; if (scrollPos.scrollTop != null) { setScrollTop(cm, scrollPos.scrollTop); if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; } if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; } if (!changed) break; } return coords; } // Scroll a given set of coordinates into view (immediately). function scrollIntoView(cm, x1, y1, x2, y2) { var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); } // Calculate a new scroll position needed to scroll the given // rectangle into view. Returns an object with scrollTop and // scrollLeft properties. When these are undefined, the // vertical/horizontal position does not need to be adjusted. function calculateScrollPos(cm, x1, y1, x2, y2) { var display = cm.display, snapMargin = textHeight(cm.display); if (y1 < 0) y1 = 0; var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; var screen = displayHeight(cm), result = {}; if (y2 - y1 > screen) y2 = y1 + screen; var docBottom = cm.doc.height + paddingVert(display); var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; if (y1 < screentop) { result.scrollTop = atTop ? 0 : y1; } else if (y2 > screentop + screen) { var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); if (newTop != screentop) result.scrollTop = newTop; } var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); var tooWide = x2 - x1 > screenw; if (tooWide) x2 = x1 + screenw; if (x1 < 10) result.scrollLeft = 0; else if (x1 < screenleft) result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); else if (x2 > screenw + screenleft - 3) result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; return result; } // Store a relative adjustment to the scroll position in the current // operation (to be applied when the operation finishes). function addToScrollPos(cm, left, top) { if (left != null || top != null) resolveScrollToPos(cm); if (left != null) cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; if (top != null) cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; } // Make sure that at the end of the operation the current cursor is // shown. function ensureCursorVisible(cm) { resolveScrollToPos(cm); var cur = cm.getCursor(), from = cur, to = cur; if (!cm.options.lineWrapping) { from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; to = Pos(cur.line, cur.ch + 1); } cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; } // When an operation has its scrollToPos property set, and another // scroll action is applied before the end of the operation, this // 'simulates' scrolling that position into view in a cheap way, so // that the effect of intermediate scroll commands is not ignored. function resolveScrollToPos(cm) { var range = cm.curOp.scrollToPos; if (range) { cm.curOp.scrollToPos = null; var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), Math.min(from.top, to.top) - range.margin, Math.max(from.right, to.right), Math.max(from.bottom, to.bottom) + range.margin); cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); } } // API UTILITIES // Indent the given line. The how parameter can be "smart", // "add"/null, "subtract", or "prev". When aggressive is false // (typically set to true for forced single-line indents), empty // lines are not indented, and places where the mode returns Pass // are left alone. function indentLine(cm, n, how, aggressive) { var doc = cm.doc, state; if (how == null) how = "add"; if (how == "smart") { // Fall back to "prev" when the mode doesn't have an indentation // method. if (!doc.mode.indent) how = "prev"; else state = getStateBefore(cm, n); } var tabSize = cm.options.tabSize; var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); if (line.stateAfter) line.stateAfter = null; var curSpaceString = line.text.match(/^\s*/)[0], indentation; if (!aggressive && !/\S/.test(line.text)) { indentation = 0; how = "not"; } else if (how == "smart") { indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); if (indentation == Pass || indentation > 150) { if (!aggressive) return; how = "prev"; } } if (how == "prev") { if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); else indentation = 0; } else if (how == "add") { indentation = curSpace + cm.options.indentUnit; } else if (how == "subtract") { indentation = curSpace - cm.options.indentUnit; } else if (typeof how == "number") { indentation = curSpace + how; } indentation = Math.max(0, indentation); var indentString = "", pos = 0; if (cm.options.indentWithTabs) for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} if (pos < indentation) indentString += spaceStr(indentation - pos); if (indentString != curSpaceString) { replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); } else { // Ensure that, if the cursor was in the whitespace at the start // of the line, it is moved to the end of that space. for (var i = 0; i < doc.sel.ranges.length; i++) { var range = doc.sel.ranges[i]; if (range.head.line == n && range.head.ch < curSpaceString.length) { var pos = Pos(n, curSpaceString.length); replaceOneSelection(doc, i, new Range(pos, pos)); break; } } } line.stateAfter = null; } // Utility for applying a change to a line by handle or number, // returning the number and optionally registering the line as // changed. function changeLine(doc, handle, changeType, op) { var no = handle, line = handle; if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); else no = lineNo(handle); if (no == null) return null; if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); return line; } // Helper for deleting text near the selection(s), used to implement // backspace, delete, and similar functionality. function deleteNearSelection(cm, compute) { var ranges = cm.doc.sel.ranges, kill = []; // Build up a set of ranges to kill first, merging overlapping // ranges. for (var i = 0; i < ranges.length; i++) { var toKill = compute(ranges[i]); while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { var replaced = kill.pop(); if (cmp(replaced.from, toKill.from) < 0) { toKill.from = replaced.from; break; } } kill.push(toKill); } // Next, remove those actual ranges. runInOp(cm, function() { for (var i = kill.length - 1; i >= 0; i--) replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); ensureCursorVisible(cm); }); } // Used for horizontal relative motion. Dir is -1 or 1 (left or // right), unit can be "char", "column" (like char, but doesn't // cross line boundaries), "word" (across next word), or "group" (to // the start of next group of word or non-word-non-whitespace // chars). The visually param controls whether, in right-to-left // text, direction 1 means to move towards the next index in the // string, or towards the character to the right of the current // position. The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosH(doc, pos, dir, unit, visually) { var line = pos.line, ch = pos.ch, origDir = dir; var lineObj = getLine(doc, line); var possible = true; function findNextLine() { var l = line + dir; if (l < doc.first || l >= doc.first + doc.size) return (possible = false); line = l; return lineObj = getLine(doc, l); } function moveOnce(boundToLine) { var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); if (next == null) { if (!boundToLine && findNextLine()) { if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); else ch = dir < 0 ? lineObj.text.length : 0; } else return (possible = false); } else ch = next; return true; } if (unit == "char") moveOnce(); else if (unit == "column") moveOnce(true); else if (unit == "word" || unit == "group") { var sawType = null, group = unit == "group"; var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); for (var first = true;; first = false) { if (dir < 0 && !moveOnce(!first)) break; var cur = lineObj.text.charAt(ch) || "\n"; var type = isWordChar(cur, helper) ? "w" : group && cur == "\n" ? "n" : !group || /\s/.test(cur) ? null : "p"; if (group && !first && !type) type = "s"; if (sawType && sawType != type) { if (dir < 0) {dir = 1; moveOnce();} break; } if (type) sawType = type; if (dir > 0 && !moveOnce(!first)) break; } } var result = skipAtomic(doc, Pos(line, ch), origDir, true); if (!possible) result.hitSide = true; return result; } // For relative vertical movement. Dir may be -1 or 1. Unit can be // "page" or "line". The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosV(cm, pos, dir, unit) { var doc = cm.doc, x = pos.left, y; if (unit == "page") { var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); } else if (unit == "line") { y = dir > 0 ? pos.bottom + 3 : pos.top - 3; } for (;;) { var target = coordsChar(cm, x, y); if (!target.outside) break; if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } y += dir * 5; } return target; } // EDITOR METHODS // The publicly visible API. Note that methodOp(f) means // 'wrap f in an operation, performed on its `this` parameter'. // This is not the complete set of editor methods. Most of the // methods defined on the Doc type are also injected into // CodeMirror.prototype, for backwards compatibility and // convenience. CodeMirror.prototype = { constructor: CodeMirror, focus: function(){window.focus(); this.display.input.focus();}, setOption: function(option, value) { var options = this.options, old = options[option]; if (options[option] == value && option != "mode") return; options[option] = value; if (optionHandlers.hasOwnProperty(option)) operation(this, optionHandlers[option])(this, value, old); }, getOption: function(option) {return this.options[option];}, getDoc: function() {return this.doc;}, addKeyMap: function(map, bottom) { this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); }, removeKeyMap: function(map) { var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) if (maps[i] == map || maps[i].name == map) { maps.splice(i, 1); return true; } }, addOverlay: methodOp(function(spec, options) { var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); if (mode.startState) throw new Error("Overlays may not be stateful."); this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); this.state.modeGen++; regChange(this); }), removeOverlay: methodOp(function(spec) { var overlays = this.state.overlays; for (var i = 0; i < overlays.length; ++i) { var cur = overlays[i].modeSpec; if (cur == spec || typeof spec == "string" && cur.name == spec) { overlays.splice(i, 1); this.state.modeGen++; regChange(this); return; } } }), indentLine: methodOp(function(n, dir, aggressive) { if (typeof dir != "string" && typeof dir != "number") { if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; else dir = dir ? "add" : "subtract"; } if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); }), indentSelection: methodOp(function(how) { var ranges = this.doc.sel.ranges, end = -1; for (var i = 0; i < ranges.length; i++) { var range = ranges[i]; if (!range.empty()) { var from = range.from(), to = range.to(); var start = Math.max(end, from.line); end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; for (var j = start; j < end; ++j) indentLine(this, j, how); var newRanges = this.doc.sel.ranges; if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } else if (range.head.line > end) { indentLine(this, range.head.line, how, true); end = range.head.line; if (i == this.doc.sel.primIndex) ensureCursorVisible(this); } } }), // Fetch the parser token for a given character. Useful for hacks // that want to inspect the mode state (say, for completion). getTokenAt: function(pos, precise) { return takeToken(this, pos, precise); }, getLineTokens: function(line, precise) { return takeToken(this, Pos(line), precise, true); }, getTokenTypeAt: function(pos) { pos = clipPos(this.doc, pos); var styles = getLineStyles(this, getLine(this.doc, pos.line)); var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; var type; if (ch == 0) type = styles[2]; else for (;;) { var mid = (before + after) >> 1; if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; else if (styles[mid * 2 + 1] < ch) before = mid + 1; else { type = styles[mid * 2 + 2]; break; } } var cut = type ? type.indexOf("cm-overlay ") : -1; return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); }, getModeAt: function(pos) { var mode = this.doc.mode; if (!mode.innerMode) return mode; return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; }, getHelper: function(pos, type) { return this.getHelpers(pos, type)[0]; }, getHelpers: function(pos, type) { var found = []; if (!helpers.hasOwnProperty(type)) return found; var help = helpers[type], mode = this.getModeAt(pos); if (typeof mode[type] == "string") { if (help[mode[type]]) found.push(help[mode[type]]); } else if (mode[type]) { for (var i = 0; i < mode[type].length; i++) { var val = help[mode[type][i]]; if (val) found.push(val); } } else if (mode.helperType && help[mode.helperType]) { found.push(help[mode.helperType]); } else if (help[mode.name]) { found.push(help[mode.name]); } for (var i = 0; i < help._global.length; i++) { var cur = help._global[i]; if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) found.push(cur.val); } return found; }, getStateAfter: function(line, precise) { var doc = this.doc; line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); return getStateBefore(this, line + 1, precise); }, cursorCoords: function(start, mode) { var pos, range = this.doc.sel.primary(); if (start == null) pos = range.head; else if (typeof start == "object") pos = clipPos(this.doc, start); else pos = start ? range.from() : range.to(); return cursorCoords(this, pos, mode || "page"); }, charCoords: function(pos, mode) { return charCoords(this, clipPos(this.doc, pos), mode || "page"); }, coordsChar: function(coords, mode) { coords = fromCoordSystem(this, coords, mode || "page"); return coordsChar(this, coords.left, coords.top); }, lineAtHeight: function(height, mode) { height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; return lineAtHeight(this.doc, height + this.display.viewOffset); }, heightAtLine: function(line, mode) { var end = false, last = this.doc.first + this.doc.size - 1; if (line < this.doc.first) line = this.doc.first; else if (line > last) { line = last; end = true; } var lineObj = getLine(this.doc, line); return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + (end ? this.doc.height - heightAtLine(lineObj) : 0); }, defaultTextHeight: function() { return textHeight(this.display); }, defaultCharWidth: function() { return charWidth(this.display); }, setGutterMarker: methodOp(function(line, gutterID, value) { return changeLine(this.doc, line, "gutter", function(line) { var markers = line.gutterMarkers || (line.gutterMarkers = {}); markers[gutterID] = value; if (!value && isEmpty(markers)) line.gutterMarkers = null; return true; }); }), clearGutter: methodOp(function(gutterID) { var cm = this, doc = cm.doc, i = doc.first; doc.iter(function(line) { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { line.gutterMarkers[gutterID] = null; regLineChange(cm, i, "gutter"); if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; } ++i; }); }), lineInfo: function(line) { if (typeof line == "number") { if (!isLine(this.doc, line)) return null; var n = line; line = getLine(this.doc, line); if (!line) return null; } else { var n = lineNo(line); if (n == null) return null; } return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, widgets: line.widgets}; }, getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, addWidget: function(pos, node, scroll, vert, horiz) { var display = this.display; pos = cursorCoords(this, clipPos(this.doc, pos)); var top = pos.bottom, left = pos.left; node.style.position = "absolute"; node.setAttribute("cm-ignore-events", "true"); this.display.input.setUneditable(node); display.sizer.appendChild(node); if (vert == "over") { top = pos.top; } else if (vert == "above" || vert == "near") { var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); // Default to positioning above (if specified and possible); otherwise default to positioning below if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) top = pos.top - node.offsetHeight; else if (pos.bottom + node.offsetHeight <= vspace) top = pos.bottom; if (left + node.offsetWidth > hspace) left = hspace - node.offsetWidth; } node.style.top = top + "px"; node.style.left = node.style.right = ""; if (horiz == "right") { left = display.sizer.clientWidth - node.offsetWidth; node.style.right = "0px"; } else { if (horiz == "left") left = 0; else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; node.style.left = left + "px"; } if (scroll) scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); }, triggerOnKeyDown: methodOp(onKeyDown), triggerOnKeyPress: methodOp(onKeyPress), triggerOnKeyUp: onKeyUp, execCommand: function(cmd) { if (commands.hasOwnProperty(cmd)) return commands[cmd](this); }, findPosH: function(from, amount, unit, visually) { var dir = 1; if (amount < 0) { dir = -1; amount = -amount; } for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { cur = findPosH(this.doc, cur, dir, unit, visually); if (cur.hitSide) break; } return cur; }, moveH: methodOp(function(dir, unit) { var cm = this; cm.extendSelectionsBy(function(range) { if (cm.display.shift || cm.doc.extend || range.empty()) return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); else return dir < 0 ? range.from() : range.to(); }, sel_move); }), deleteH: methodOp(function(dir, unit) { var sel = this.doc.sel, doc = this.doc; if (sel.somethingSelected()) doc.replaceSelection("", null, "+delete"); else deleteNearSelection(this, function(range) { var other = findPosH(doc, range.head, dir, unit, false); return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; }); }), findPosV: function(from, amount, unit, goalColumn) { var dir = 1, x = goalColumn; if (amount < 0) { dir = -1; amount = -amount; } for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { var coords = cursorCoords(this, cur, "div"); if (x == null) x = coords.left; else coords.left = x; cur = findPosV(this, coords, dir, unit); if (cur.hitSide) break; } return cur; }, moveV: methodOp(function(dir, unit) { var cm = this, doc = this.doc, goals = []; var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); doc.extendSelectionsBy(function(range) { if (collapse) return dir < 0 ? range.from() : range.to(); var headPos = cursorCoords(cm, range.head, "div"); if (range.goalColumn != null) headPos.left = range.goalColumn; goals.push(headPos.left); var pos = findPosV(cm, headPos, dir, unit); if (unit == "page" && range == doc.sel.primary()) addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); return pos; }, sel_move); if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) doc.sel.ranges[i].goalColumn = goals[i]; }), // Find the word at the given position (as returned by coordsChar). findWordAt: function(pos) { var doc = this.doc, line = getLine(doc, pos.line).text; var start = pos.ch, end = pos.ch; if (line) { var helper = this.getHelper(pos, "wordChars"); if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; var startChar = line.charAt(start); var check = isWordChar(startChar, helper) ? function(ch) { return isWordChar(ch, helper); } : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; while (start > 0 && check(line.charAt(start - 1))) --start; while (end < line.length && check(line.charAt(end))) ++end; } return new Range(Pos(pos.line, start), Pos(pos.line, end)); }, toggleOverwrite: function(value) { if (value != null && value == this.state.overwrite) return; if (this.state.overwrite = !this.state.overwrite) addClass(this.display.cursorDiv, "CodeMirror-overwrite"); else rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); signal(this, "overwriteToggle", this, this.state.overwrite); }, hasFocus: function() { return this.display.input.getField() == activeElt(); }, scrollTo: methodOp(function(x, y) { if (x != null || y != null) resolveScrollToPos(this); if (x != null) this.curOp.scrollLeft = x; if (y != null) this.curOp.scrollTop = y; }), getScrollInfo: function() { var scroller = this.display.scroller; return {left: scroller.scrollLeft, top: scroller.scrollTop, height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; }, scrollIntoView: methodOp(function(range, margin) { if (range == null) { range = {from: this.doc.sel.primary().head, to: null}; if (margin == null) margin = this.options.cursorScrollMargin; } else if (typeof range == "number") { range = {from: Pos(range, 0), to: null}; } else if (range.from == null) { range = {from: range, to: null}; } if (!range.to) range.to = range.from; range.margin = margin || 0; if (range.from.line != null) { resolveScrollToPos(this); this.curOp.scrollToPos = range; } else { var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), Math.min(range.from.top, range.to.top) - range.margin, Math.max(range.from.right, range.to.right), Math.max(range.from.bottom, range.to.bottom) + range.margin); this.scrollTo(sPos.scrollLeft, sPos.scrollTop); } }), setSize: methodOp(function(width, height) { var cm = this; function interpret(val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; } if (width != null) cm.display.wrapper.style.width = interpret(width); if (height != null) cm.display.wrapper.style.height = interpret(height); if (cm.options.lineWrapping) clearLineMeasurementCache(this); var lineNo = cm.display.viewFrom; cm.doc.iter(lineNo, cm.display.viewTo, function(line) { if (line.widgets) for (var i = 0; i < line.widgets.length; i++) if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } ++lineNo; }); cm.curOp.forceUpdate = true; signal(cm, "refresh", this); }), operation: function(f){return runInOp(this, f);}, refresh: methodOp(function() { var oldHeight = this.display.cachedTextHeight; regChange(this); this.curOp.forceUpdate = true; clearCaches(this); this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); updateGutterSpace(this); if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) estimateLineHeights(this); signal(this, "refresh", this); }), swapDoc: methodOp(function(doc) { var old = this.doc; old.cm = null; attachDoc(this, doc); clearCaches(this); this.display.input.reset(); this.scrollTo(doc.scrollLeft, doc.scrollTop); this.curOp.forceScroll = true; signalLater(this, "swapDoc", this, old); return old; }), getInputField: function(){return this.display.input.getField();}, getWrapperElement: function(){return this.display.wrapper;}, getScrollerElement: function(){return this.display.scroller;}, getGutterElement: function(){return this.display.gutters;} }; eventMixin(CodeMirror); // OPTION DEFAULTS // The default configuration options. var defaults = CodeMirror.defaults = {}; // Functions to run when options are changed. var optionHandlers = CodeMirror.optionHandlers = {}; function option(name, deflt, handle, notOnInit) { CodeMirror.defaults[name] = deflt; if (handle) optionHandlers[name] = notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; } // Passed to option handlers when there is no old value. var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; // These two are, on init, called from the constructor because they // have to be initialized before the editor can start at all. option("value", "", function(cm, val) { cm.setValue(val); }, true); option("mode", null, function(cm, val) { cm.doc.modeOption = val; loadMode(cm); }, true); option("indentUnit", 2, loadMode, true); option("indentWithTabs", false); option("smartIndent", true); option("tabSize", 4, function(cm) { resetModeState(cm); clearCaches(cm); regChange(cm); }, true); option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); if (old != CodeMirror.Init) cm.refresh(); }); option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); option("electricChars", true); option("inputStyle", mobile ? "contenteditable" : "textarea", function() { throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME }, true); option("rtlMoveVisually", !windows); option("wholeLineUpdateBefore", true); option("theme", "default", function(cm) { themeChanged(cm); guttersChanged(cm); }, true); option("keyMap", "default", function(cm, val, old) { var next = getKeyMap(val); var prev = old != CodeMirror.Init && getKeyMap(old); if (prev && prev.detach) prev.detach(cm, next); if (next.attach) next.attach(cm, prev || null); }); option("extraKeys", null); option("lineWrapping", false, wrappingChanged, true); option("gutters", [], function(cm) { setGuttersForLineNumbers(cm.options); guttersChanged(cm); }, true); option("fixedGutter", true, function(cm, val) { cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; cm.refresh(); }, true); option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); option("scrollbarStyle", "native", function(cm) { initScrollbars(cm); updateScrollbars(cm); cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); }, true); option("lineNumbers", false, function(cm) { setGuttersForLineNumbers(cm.options); guttersChanged(cm); }, true); option("firstLineNumber", 1, guttersChanged, true); option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); option("showCursorWhenSelecting", false, updateSelection, true); option("resetSelectionOnContextMenu", true); option("readOnly", false, function(cm, val) { if (val == "nocursor") { onBlur(cm); cm.display.input.blur(); cm.display.disabled = true; } else { cm.display.disabled = false; if (!val) cm.display.input.reset(); } }); option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); option("dragDrop", true); option("cursorBlinkRate", 530); option("cursorScrollMargin", 0); option("cursorHeight", 1, updateSelection, true); option("singleCursorHeightPerLine", true, updateSelection, true); option("workTime", 100); option("workDelay", 100); option("flattenSpans", true, resetModeState, true); option("addModeClass", false, resetModeState, true); option("pollInterval", 100); option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); option("historyEventDelay", 1250); option("viewportMargin", 10, function(cm){cm.refresh();}, true); option("maxHighlightLength", 10000, resetModeState, true); option("moveInputWithCursor", true, function(cm, val) { if (!val) cm.display.input.resetPosition(); }); option("tabindex", null, function(cm, val) { cm.display.input.getField().tabIndex = val || ""; }); option("autofocus", null); // MODE DEFINITION AND QUERYING // Known modes, by name and by MIME var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; // Extra arguments are stored as the mode's dependencies, which is // used by (legacy) mechanisms like loadmode.js to automatically // load a mode. (Preferred mechanism is the require/define calls.) CodeMirror.defineMode = function(name, mode) { if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; if (arguments.length > 2) mode.dependencies = Array.prototype.slice.call(arguments, 2); modes[name] = mode; }; CodeMirror.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; // Given a MIME type, a {name, ...options} config object, or a name // string, return a mode config object. CodeMirror.resolveMode = function(spec) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { spec = mimeModes[spec]; } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { var found = mimeModes[spec.name]; if (typeof found == "string") found = {name: found}; spec = createObj(found, spec); spec.name = found.name; } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { return CodeMirror.resolveMode("application/xml"); } if (typeof spec == "string") return {name: spec}; else return spec || {name: "null"}; }; // Given a mode spec (anything that resolveMode accepts), find and // initialize an actual mode object. CodeMirror.getMode = function(options, spec) { var spec = CodeMirror.resolveMode(spec); var mfactory = modes[spec.name]; if (!mfactory) return CodeMirror.getMode(options, "text/plain"); var modeObj = mfactory(options, spec); if (modeExtensions.hasOwnProperty(spec.name)) { var exts = modeExtensions[spec.name]; for (var prop in exts) { if (!exts.hasOwnProperty(prop)) continue; if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; modeObj[prop] = exts[prop]; } } modeObj.name = spec.name; if (spec.helperType) modeObj.helperType = spec.helperType; if (spec.modeProps) for (var prop in spec.modeProps) modeObj[prop] = spec.modeProps[prop]; return modeObj; }; // Minimal default mode. CodeMirror.defineMode("null", function() { return {token: function(stream) {stream.skipToEnd();}}; }); CodeMirror.defineMIME("text/plain", "null"); // This can be used to attach properties to mode objects from // outside the actual mode definition. var modeExtensions = CodeMirror.modeExtensions = {}; CodeMirror.extendMode = function(mode, properties) { var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); copyObj(properties, exts); }; // EXTENSIONS CodeMirror.defineExtension = function(name, func) { CodeMirror.prototype[name] = func; }; CodeMirror.defineDocExtension = function(name, func) { Doc.prototype[name] = func; }; CodeMirror.defineOption = option; var initHooks = []; CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; var helpers = CodeMirror.helpers = {}; CodeMirror.registerHelper = function(type, name, value) { if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; helpers[type][name] = value; }; CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { CodeMirror.registerHelper(type, name, value); helpers[type]._global.push({pred: predicate, val: value}); }; // MODE STATE HANDLING // Utility functions for working with state. Exported because nested // modes need to do this for their inner modes. var copyState = CodeMirror.copyState = function(mode, state) { if (state === true) return state; if (mode.copyState) return mode.copyState(state); var nstate = {}; for (var n in state) { var val = state[n]; if (val instanceof Array) val = val.concat([]); nstate[n] = val; } return nstate; }; var startState = CodeMirror.startState = function(mode, a1, a2) { return mode.startState ? mode.startState(a1, a2) : true; }; // Given a mode and a state (for that mode), find the inner mode and // state at the position that the state refers to. CodeMirror.innerMode = function(mode, state) { while (mode.innerMode) { var info = mode.innerMode(state); if (!info || info.mode == mode) break; state = info.state; mode = info.mode; } return info || {mode: mode, state: state}; }; // STANDARD COMMANDS // Commands are parameter-less actions that can be performed on an // editor, mostly used for keybindings. var commands = CodeMirror.commands = { selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, singleSelection: function(cm) { cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); }, killLine: function(cm) { deleteNearSelection(cm, function(range) { if (range.empty()) { var len = getLine(cm.doc, range.head.line).text.length; if (range.head.ch == len && range.head.line < cm.lastLine()) return {from: range.head, to: Pos(range.head.line + 1, 0)}; else return {from: range.head, to: Pos(range.head.line, len)}; } else { return {from: range.from(), to: range.to()}; } }); }, deleteLine: function(cm) { deleteNearSelection(cm, function(range) { return {from: Pos(range.from().line, 0), to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; }); }, delLineLeft: function(cm) { deleteNearSelection(cm, function(range) { return {from: Pos(range.from().line, 0), to: range.from()}; }); }, delWrappedLineLeft: function(cm) { deleteNearSelection(cm, function(range) { var top = cm.charCoords(range.head, "div").top + 5; var leftPos = cm.coordsChar({left: 0, top: top}, "div"); return {from: leftPos, to: range.from()}; }); }, delWrappedLineRight: function(cm) { deleteNearSelection(cm, function(range) { var top = cm.charCoords(range.head, "div").top + 5; var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); return {from: range.from(), to: rightPos }; }); }, undo: function(cm) {cm.undo();}, redo: function(cm) {cm.redo();}, undoSelection: function(cm) {cm.undoSelection();}, redoSelection: function(cm) {cm.redoSelection();}, goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, goLineStart: function(cm) { cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, {origin: "+move", bias: 1}); }, goLineStartSmart: function(cm) { cm.extendSelectionsBy(function(range) { return lineStartSmart(cm, range.head); }, {origin: "+move", bias: 1}); }, goLineEnd: function(cm) { cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, {origin: "+move", bias: -1}); }, goLineRight: function(cm) { cm.extendSelectionsBy(function(range) { var top = cm.charCoords(range.head, "div").top + 5; return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); }, sel_move); }, goLineLeft: function(cm) { cm.extendSelectionsBy(function(range) { var top = cm.charCoords(range.head, "div").top + 5; return cm.coordsChar({left: 0, top: top}, "div"); }, sel_move); }, goLineLeftSmart: function(cm) { cm.extendSelectionsBy(function(range) { var top = cm.charCoords(range.head, "div").top + 5; var pos = cm.coordsChar({left: 0, top: top}, "div"); if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); return pos; }, sel_move); }, goLineUp: function(cm) {cm.moveV(-1, "line");}, goLineDown: function(cm) {cm.moveV(1, "line");}, goPageUp: function(cm) {cm.moveV(-1, "page");}, goPageDown: function(cm) {cm.moveV(1, "page");}, goCharLeft: function(cm) {cm.moveH(-1, "char");}, goCharRight: function(cm) {cm.moveH(1, "char");}, goColumnLeft: function(cm) {cm.moveH(-1, "column");}, goColumnRight: function(cm) {cm.moveH(1, "column");}, goWordLeft: function(cm) {cm.moveH(-1, "word");}, goGroupRight: function(cm) {cm.moveH(1, "group");}, goGroupLeft: function(cm) {cm.moveH(-1, "group");}, goWordRight: function(cm) {cm.moveH(1, "word");}, delCharBefore: function(cm) {cm.deleteH(-1, "char");}, delCharAfter: function(cm) {cm.deleteH(1, "char");}, delWordBefore: function(cm) {cm.deleteH(-1, "word");}, delWordAfter: function(cm) {cm.deleteH(1, "word");}, delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, delGroupAfter: function(cm) {cm.deleteH(1, "group");}, indentAuto: function(cm) {cm.indentSelection("smart");}, indentMore: function(cm) {cm.indentSelection("add");}, indentLess: function(cm) {cm.indentSelection("subtract");}, insertTab: function(cm) {cm.replaceSelection("\t");}, insertSoftTab: function(cm) { var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; for (var i = 0; i < ranges.length; i++) { var pos = ranges[i].from(); var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); } cm.replaceSelections(spaces); }, defaultTab: function(cm) { if (cm.somethingSelected()) cm.indentSelection("add"); else cm.execCommand("insertTab"); }, transposeChars: function(cm) { runInOp(cm, function() { var ranges = cm.listSelections(), newSel = []; for (var i = 0; i < ranges.length; i++) { var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; if (line) { if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); if (cur.ch > 0) { cur = new Pos(cur.line, cur.ch + 1); cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), Pos(cur.line, cur.ch - 2), cur, "+transpose"); } else if (cur.line > cm.doc.first) { var prev = getLine(cm.doc, cur.line - 1).text; if (prev) cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); } } newSel.push(new Range(cur, cur)); } cm.setSelections(newSel); }); }, newlineAndIndent: function(cm) { runInOp(cm, function() { var len = cm.listSelections().length; for (var i = 0; i < len; i++) { var range = cm.listSelections()[i]; cm.replaceRange("\n", range.anchor, range.head, "+input"); cm.indentLine(range.from().line + 1, null, true); ensureCursorVisible(cm); } }); }, toggleOverwrite: function(cm) {cm.toggleOverwrite();} }; // STANDARD KEYMAPS var keyMap = CodeMirror.keyMap = {}; keyMap.basic = { "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", "Tab": "defaultTab", "Shift-Tab": "indentAuto", "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", "Esc": "singleSelection" }; // Note that the save and find-related commands aren't defined by // default. User code or addons can define them. Unknown commands // are simply ignored. keyMap.pcDefault = { "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", fallthrough: "basic" }; // Very basic readline/emacs-style bindings, which are standard on Mac. keyMap.emacsy = { "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" }; keyMap.macDefault = { "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", fallthrough: ["basic", "emacsy"] }; keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; // KEYMAP DISPATCH function normalizeKeyName(name) { var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; var alt, ctrl, shift, cmd; for (var i = 0; i < parts.length - 1; i++) { var mod = parts[i]; if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; else if (/^a(lt)?$/i.test(mod)) alt = true; else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; else if (/^s(hift)$/i.test(mod)) shift = true; else throw new Error("Unrecognized modifier name: " + mod); } if (alt) name = "Alt-" + name; if (ctrl) name = "Ctrl-" + name; if (cmd) name = "Cmd-" + name; if (shift) name = "Shift-" + name; return name; } // This is a kludge to keep keymaps mostly working as raw objects // (backwards compatibility) while at the same time support features // like normalization and multi-stroke key bindings. It compiles a // new normalized keymap, and then updates the old object to reflect // this. CodeMirror.normalizeKeyMap = function(keymap) { var copy = {}; for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { var value = keymap[keyname]; if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; if (value == "...") { delete keymap[keyname]; continue; } var keys = map(keyname.split(" "), normalizeKeyName); for (var i = 0; i < keys.length; i++) { var val, name; if (i == keys.length - 1) { name = keyname; val = value; } else { name = keys.slice(0, i + 1).join(" "); val = "..."; } var prev = copy[name]; if (!prev) copy[name] = val; else if (prev != val) throw new Error("Inconsistent bindings for " + name); } delete keymap[keyname]; } for (var prop in copy) keymap[prop] = copy[prop]; return keymap; }; var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { map = getKeyMap(map); var found = map.call ? map.call(key, context) : map[key]; if (found === false) return "nothing"; if (found === "...") return "multi"; if (found != null && handle(found)) return "handled"; if (map.fallthrough) { if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") return lookupKey(key, map.fallthrough, handle, context); for (var i = 0; i < map.fallthrough.length; i++) { var result = lookupKey(key, map.fallthrough[i], handle, context); if (result) return result; } } }; // Modifier key presses don't count as 'real' key presses for the // purpose of keymap fallthrough. var isModifierKey = CodeMirror.isModifierKey = function(value) { var name = typeof value == "string" ? value : keyNames[value.keyCode]; return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; }; // Look up the name of a key as indicated by an event object. var keyName = CodeMirror.keyName = function(event, noShift) { if (presto && event.keyCode == 34 && event["char"]) return false; var base = keyNames[event.keyCode], name = base; if (name == null || event.altGraphKey) return false; if (event.altKey && base != "Alt") name = "Alt-" + name; if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; return name; }; function getKeyMap(val) { return typeof val == "string" ? keyMap[val] : val; } // FROMTEXTAREA CodeMirror.fromTextArea = function(textarea, options) { options = options ? copyObj(options) : {}; options.value = textarea.value; if (!options.tabindex && textarea.tabIndex) options.tabindex = textarea.tabIndex; if (!options.placeholder && textarea.placeholder) options.placeholder = textarea.placeholder; // Set autofocus to true if this textarea is focused, or if it has // autofocus and no other element is focused. if (options.autofocus == null) { var hasFocus = activeElt(); options.autofocus = hasFocus == textarea || textarea.getAttribute("autofocus") != null && hasFocus == document.body; } function save() {textarea.value = cm.getValue();} if (textarea.form) { on(textarea.form, "submit", save); // Deplorable hack to make the submit method do the right thing. if (!options.leaveSubmitMethodAlone) { var form = textarea.form, realSubmit = form.submit; try { var wrappedSubmit = form.submit = function() { save(); form.submit = realSubmit; form.submit(); form.submit = wrappedSubmit; }; } catch(e) {} } } options.finishInit = function(cm) { cm.save = save; cm.getTextArea = function() { return textarea; }; cm.toTextArea = function() { cm.toTextArea = isNaN; // Prevent this from being ran twice save(); textarea.parentNode.removeChild(cm.getWrapperElement()); textarea.style.display = ""; if (textarea.form) { off(textarea.form, "submit", save); if (typeof textarea.form.submit == "function") textarea.form.submit = realSubmit; } }; }; textarea.style.display = "none"; var cm = CodeMirror(function(node) { textarea.parentNode.insertBefore(node, textarea.nextSibling); }, options); return cm; }; // STRING STREAM // Fed to the mode parsers, provides helper functions to make // parsers more succinct. var StringStream = CodeMirror.StringStream = function(string, tabSize) { this.pos = this.start = 0; this.string = string; this.tabSize = tabSize || 8; this.lastColumnPos = this.lastColumnValue = 0; this.lineStart = 0; }; StringStream.prototype = { eol: function() {return this.pos >= this.string.length;}, sol: function() {return this.pos == this.lineStart;}, peek: function() {return this.string.charAt(this.pos) || undefined;}, next: function() { if (this.pos < this.string.length) return this.string.charAt(this.pos++); }, eat: function(match) { var ch = this.string.charAt(this.pos); if (typeof match == "string") var ok = ch == match; else var ok = ch && (match.test ? match.test(ch) : match(ch)); if (ok) {++this.pos; return ch;} }, eatWhile: function(match) { var start = this.pos; while (this.eat(match)){} return this.pos > start; }, eatSpace: function() { var start = this.pos; while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; return this.pos > start; }, skipToEnd: function() {this.pos = this.string.length;}, skipTo: function(ch) { var found = this.string.indexOf(ch, this.pos); if (found > -1) {this.pos = found; return true;} }, backUp: function(n) {this.pos -= n;}, column: function() { if (this.lastColumnPos < this.start) { this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); this.lastColumnPos = this.start; } return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); }, indentation: function() { return countColumn(this.string, null, this.tabSize) - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); }, match: function(pattern, consume, caseInsensitive) { if (typeof pattern == "string") { var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; var substr = this.string.substr(this.pos, pattern.length); if (cased(substr) == cased(pattern)) { if (consume !== false) this.pos += pattern.length; return true; } } else { var match = this.string.slice(this.pos).match(pattern); if (match && match.index > 0) return null; if (match && consume !== false) this.pos += match[0].length; return match; } }, current: function(){return this.string.slice(this.start, this.pos);}, hideFirstChars: function(n, inner) { this.lineStart += n; try { return inner(); } finally { this.lineStart -= n; } } }; // TEXTMARKERS // Created with markText and setBookmark methods. A TextMarker is a // handle that can be used to clear or find a marked position in the // document. Line objects hold arrays (markedSpans) containing // {from, to, marker} object pointing to such marker objects, and // indicating that such a marker is present on that line. Multiple // lines may point to the same marker when it spans across lines. // The spans will have null for their from/to properties when the // marker continues beyond the start/end of the line. Markers have // links back to the lines they currently touch. var nextMarkerId = 0; var TextMarker = CodeMirror.TextMarker = function(doc, type) { this.lines = []; this.type = type; this.doc = doc; this.id = ++nextMarkerId; }; eventMixin(TextMarker); // Clear the marker. TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; var cm = this.doc.cm, withOp = cm && !cm.curOp; if (withOp) startOperation(cm); if (hasHandler(this, "clear")) { var found = this.find(); if (found) signalLater(this, "clear", found.from, found.to); } var min = null, max = null; for (var i = 0; i < this.lines.length; ++i) { var line = this.lines[i]; var span = getMarkedSpanFor(line.markedSpans, this); if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); else if (cm) { if (span.to != null) max = lineNo(line); if (span.from != null) min = lineNo(line); } line.markedSpans = removeMarkedSpan(line.markedSpans, span); if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) updateLineHeight(line, textHeight(cm.display)); } if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { var visual = visualLine(this.lines[i]), len = lineLength(visual); if (len > cm.display.maxLineLength) { cm.display.maxLine = visual; cm.display.maxLineLength = len; cm.display.maxLineChanged = true; } } if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); this.lines.length = 0; this.explicitlyCleared = true; if (this.atomic && this.doc.cantEdit) { this.doc.cantEdit = false; if (cm) reCheckSelection(cm.doc); } if (cm) signalLater(cm, "markerCleared", cm, this); if (withOp) endOperation(cm); if (this.parent) this.parent.clear(); }; // Find the position of the marker in the document. Returns a {from, // to} object by default. Side can be passed to get a specific side // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the // Pos objects returned contain a line object, rather than a line // number (used to prevent looking up the same line twice). TextMarker.prototype.find = function(side, lineObj) { if (side == null && this.type == "bookmark") side = 1; var from, to; for (var i = 0; i < this.lines.length; ++i) { var line = this.lines[i]; var span = getMarkedSpanFor(line.markedSpans, this); if (span.from != null) { from = Pos(lineObj ? line : lineNo(line), span.from); if (side == -1) return from; } if (span.to != null) { to = Pos(lineObj ? line : lineNo(line), span.to); if (side == 1) return to; } } return from && {from: from, to: to}; }; // Signals that the marker's widget changed, and surrounding layout // should be recomputed. TextMarker.prototype.changed = function() { var pos = this.find(-1, true), widget = this, cm = this.doc.cm; if (!pos || !cm) return; runInOp(cm, function() { var line = pos.line, lineN = lineNo(pos.line); var view = findViewForLine(cm, lineN); if (view) { clearLineMeasurementCacheFor(view); cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; } cm.curOp.updateMaxLine = true; if (!lineIsHidden(widget.doc, line) && widget.height != null) { var oldHeight = widget.height; widget.height = null; var dHeight = widgetHeight(widget) - oldHeight; if (dHeight) updateLineHeight(line, line.height + dHeight); } }); }; TextMarker.prototype.attachLine = function(line) { if (!this.lines.length && this.doc.cm) { var op = this.doc.cm.curOp; if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); } this.lines.push(line); }; TextMarker.prototype.detachLine = function(line) { this.lines.splice(indexOf(this.lines, line), 1); if (!this.lines.length && this.doc.cm) { var op = this.doc.cm.curOp; (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); } }; // Collapsed markers have unique ids, in order to be able to order // them, which is needed for uniquely determining an outer marker // when they overlap (they may nest, but not partially overlap). var nextMarkerId = 0; // Create a marker, wire it up to the right lines, and function markText(doc, from, to, options, type) { // Shared markers (across linked documents) are handled separately // (markTextShared will call out to this again, once per // document). if (options && options.shared) return markTextShared(doc, from, to, options, type); // Ensure we are in an operation. if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); var marker = new TextMarker(doc, type), diff = cmp(from, to); if (options) copyObj(options, marker, false); // Don't connect empty markers unless clearWhenEmpty is false if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) return marker; if (marker.replacedWith) { // Showing up as a widget implies collapsed (widget replaces text) marker.collapsed = true; marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); if (options.insertLeft) marker.widgetNode.insertLeft = true; } if (marker.collapsed) { if (conflictingCollapsedRange(doc, from.line, from, to, marker) || from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) throw new Error("Inserting collapsed marker partially overlapping an existing one"); sawCollapsedSpans = true; } if (marker.addToHistory) addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); var curLine = from.line, cm = doc.cm, updateMaxLine; doc.iter(curLine, to.line + 1, function(line) { if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) updateMaxLine = true; if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); addMarkedSpan(line, new MarkedSpan(marker, curLine == from.line ? from.ch : null, curLine == to.line ? to.ch : null)); ++curLine; }); // lineIsHidden depends on the presence of the spans, so needs a second pass if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { if (lineIsHidden(doc, line)) updateLineHeight(line, 0); }); if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); if (marker.readOnly) { sawReadOnlySpans = true; if (doc.history.done.length || doc.history.undone.length) doc.clearHistory(); } if (marker.collapsed) { marker.id = ++nextMarkerId; marker.atomic = true; } if (cm) { // Sync editor state if (updateMaxLine) cm.curOp.updateMaxLine = true; if (marker.collapsed) regChange(cm, from.line, to.line + 1); else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); if (marker.atomic) reCheckSelection(cm.doc); signalLater(cm, "markerAdded", cm, marker); } return marker; } // SHARED TEXTMARKERS // A shared marker spans multiple linked documents. It is // implemented as a meta-marker-object controlling multiple normal // markers. var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { this.markers = markers; this.primary = primary; for (var i = 0; i < markers.length; ++i) markers[i].parent = this; }; eventMixin(SharedTextMarker); SharedTextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; this.explicitlyCleared = true; for (var i = 0; i < this.markers.length; ++i) this.markers[i].clear(); signalLater(this, "clear"); }; SharedTextMarker.prototype.find = function(side, lineObj) { return this.primary.find(side, lineObj); }; function markTextShared(doc, from, to, options, type) { options = copyObj(options); options.shared = false; var markers = [markText(doc, from, to, options, type)], primary = markers[0]; var widget = options.widgetNode; linkedDocs(doc, function(doc) { if (widget) options.widgetNode = widget.cloneNode(true); markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); for (var i = 0; i < doc.linked.length; ++i) if (doc.linked[i].isParent) return; primary = lst(markers); }); return new SharedTextMarker(markers, primary); } function findSharedMarkers(doc) { return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function(m) { return m.parent; }); } function copySharedMarkers(doc, markers) { for (var i = 0; i < markers.length; i++) { var marker = markers[i], pos = marker.find(); var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); if (cmp(mFrom, mTo)) { var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); marker.markers.push(subMark); subMark.parent = marker; } } } function detachSharedMarkers(markers) { for (var i = 0; i < markers.length; i++) { var marker = markers[i], linked = [marker.primary.doc];; linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); for (var j = 0; j < marker.markers.length; j++) { var subMarker = marker.markers[j]; if (indexOf(linked, subMarker.doc) == -1) { subMarker.parent = null; marker.markers.splice(j--, 1); } } } } // TEXTMARKER SPANS function MarkedSpan(marker, from, to) { this.marker = marker; this.from = from; this.to = to; } // Search an array of spans for a span matching the given marker. function getMarkedSpanFor(spans, marker) { if (spans) for (var i = 0; i < spans.length; ++i) { var span = spans[i]; if (span.marker == marker) return span; } } // Remove a span from an array, returning undefined if no spans are // left (we don't store arrays for lines without spans). function removeMarkedSpan(spans, span) { for (var r, i = 0; i < spans.length; ++i) if (spans[i] != span) (r || (r = [])).push(spans[i]); return r; } // Add a span to a line. function addMarkedSpan(line, span) { line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; span.marker.attachLine(line); } // Used for the algorithm that adjusts markers for a change in the // document. These functions cut an array of spans at a given // character position, returning an array of remaining chunks (or // undefined if nothing remains). function markedSpansBefore(old, startCh, isInsert) { if (old) for (var i = 0, nw; i < old.length; ++i) { var span = old[i], marker = span.marker; var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); } } return nw; } function markedSpansAfter(old, endCh, isInsert) { if (old) for (var i = 0, nw; i < old.length; ++i) { var span = old[i], marker = span.marker; var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, span.to == null ? null : span.to - endCh)); } } return nw; } // Given a change object, compute the new set of marker spans that // cover the line in which the change took place. Removes spans // entirely within the change, reconnects spans belonging to the // same marker that appear on both sides of the change, and cuts off // spans partially within the change. Returns an array of span // arrays with one element for each line in (after) the change. function stretchSpansOverChange(doc, change) { if (change.full) return null; var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; if (!oldFirst && !oldLast) return null; var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; // Get the spans that 'stick out' on both sides var first = markedSpansBefore(oldFirst, startCh, isInsert); var last = markedSpansAfter(oldLast, endCh, isInsert); // Next, merge those two ends var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); if (first) { // Fix up .to properties of first for (var i = 0; i < first.length; ++i) { var span = first[i]; if (span.to == null) { var found = getMarkedSpanFor(last, span.marker); if (!found) span.to = startCh; else if (sameLine) span.to = found.to == null ? null : found.to + offset; } } } if (last) { // Fix up .from in last (or move them into first in case of sameLine) for (var i = 0; i < last.length; ++i) { var span = last[i]; if (span.to != null) span.to += offset; if (span.from == null) { var found = getMarkedSpanFor(first, span.marker); if (!found) { span.from = offset; if (sameLine) (first || (first = [])).push(span); } } else { span.from += offset; if (sameLine) (first || (first = [])).push(span); } } } // Make sure we didn't create any zero-length spans if (first) first = clearEmptySpans(first); if (last && last != first) last = clearEmptySpans(last); var newMarkers = [first]; if (!sameLine) { // Fill gap with whole-line-spans var gap = change.text.length - 2, gapMarkers; if (gap > 0 && first) for (var i = 0; i < first.length; ++i) if (first[i].to == null) (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); for (var i = 0; i < gap; ++i) newMarkers.push(gapMarkers); newMarkers.push(last); } return newMarkers; } // Remove spans that are empty and don't have a clearWhenEmpty // option of false. function clearEmptySpans(spans) { for (var i = 0; i < spans.length; ++i) { var span = spans[i]; if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) spans.splice(i--, 1); } if (!spans.length) return null; return spans; } // Used for un/re-doing changes from the history. Combines the // result of computing the existing spans with the set of spans that // existed in the history (so that deleting around a span and then // undoing brings back the span). function mergeOldSpans(doc, change) { var old = getOldSpans(doc, change); var stretched = stretchSpansOverChange(doc, change); if (!old) return stretched; if (!stretched) return old; for (var i = 0; i < old.length; ++i) { var oldCur = old[i], stretchCur = stretched[i]; if (oldCur && stretchCur) { spans: for (var j = 0; j < stretchCur.length; ++j) { var span = stretchCur[j]; for (var k = 0; k < oldCur.length; ++k) if (oldCur[k].marker == span.marker) continue spans; oldCur.push(span); } } else if (stretchCur) { old[i] = stretchCur; } } return old; } // Used to 'clip' out readOnly ranges when making a change. function removeReadOnlyRanges(doc, from, to) { var markers = null; doc.iter(from.line, to.line + 1, function(line) { if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { var mark = line.markedSpans[i].marker; if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) (markers || (markers = [])).push(mark); } }); if (!markers) return null; var parts = [{from: from, to: to}]; for (var i = 0; i < markers.length; ++i) { var mk = markers[i], m = mk.find(0); for (var j = 0; j < parts.length; ++j) { var p = parts[j]; if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) newParts.push({from: p.from, to: m.from}); if (dto > 0 || !mk.inclusiveRight && !dto) newParts.push({from: m.to, to: p.to}); parts.splice.apply(parts, newParts); j += newParts.length - 1; } } return parts; } // Connect or disconnect spans from a line. function detachMarkedSpans(line) { var spans = line.markedSpans; if (!spans) return; for (var i = 0; i < spans.length; ++i) spans[i].marker.detachLine(line); line.markedSpans = null; } function attachMarkedSpans(line, spans) { if (!spans) return; for (var i = 0; i < spans.length; ++i) spans[i].marker.attachLine(line); line.markedSpans = spans; } // Helpers used when computing which overlapping collapsed span // counts as the larger one. function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } // Returns a number indicating which of two overlapping collapsed // spans is larger (and thus includes the other). Falls back to // comparing ids when the spans cover exactly the same range. function compareCollapsedMarkers(a, b) { var lenDiff = a.lines.length - b.lines.length; if (lenDiff != 0) return lenDiff; var aPos = a.find(), bPos = b.find(); var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); if (fromCmp) return -fromCmp; var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); if (toCmp) return toCmp; return b.id - a.id; } // Find out whether a line ends or starts in a collapsed span. If // so, return the marker for that span. function collapsedSpanAtSide(line, start) { var sps = sawCollapsedSpans && line.markedSpans, found; if (sps) for (var sp, i = 0; i < sps.length; ++i) { sp = sps[i]; if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && (!found || compareCollapsedMarkers(found, sp.marker) < 0)) found = sp.marker; } return found; } function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } // Test whether there exists a collapsed span that partially // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. function conflictingCollapsedRange(doc, lineNo, from, to, marker) { var line = getLine(doc, lineNo); var sps = sawCollapsedSpans && line.markedSpans; if (sps) for (var i = 0; i < sps.length; ++i) { var sp = sps[i]; if (!sp.marker.collapsed) continue; var found = sp.marker.find(0); var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) return true; } } // A visual line is a line as drawn on the screen. Folding, for // example, can cause multiple logical lines to appear on the same // visual line. This finds the start of the visual line that the // given line is part of (usually that is the line itself). function visualLine(line) { var merged; while (merged = collapsedSpanAtStart(line)) line = merged.find(-1, true).line; return line; } // Returns an array of logical lines that continue the visual line // started by the argument, or undefined if there are no such lines. function visualLineContinued(line) { var merged, lines; while (merged = collapsedSpanAtEnd(line)) { line = merged.find(1, true).line; (lines || (lines = [])).push(line); } return lines; } // Get the line number of the start of the visual line that the // given line number is part of. function visualLineNo(doc, lineN) { var line = getLine(doc, lineN), vis = visualLine(line); if (line == vis) return lineN; return lineNo(vis); } // Get the line number of the start of the next visual line after // the given line. function visualLineEndNo(doc, lineN) { if (lineN > doc.lastLine()) return lineN; var line = getLine(doc, lineN), merged; if (!lineIsHidden(doc, line)) return lineN; while (merged = collapsedSpanAtEnd(line)) line = merged.find(1, true).line; return lineNo(line) + 1; } // Compute whether a line is hidden. Lines count as hidden when they // are part of a visual line that starts with another line, or when // they are entirely covered by collapsed, non-widget span. function lineIsHidden(doc, line) { var sps = sawCollapsedSpans && line.markedSpans; if (sps) for (var sp, i = 0; i < sps.length; ++i) { sp = sps[i]; if (!sp.marker.collapsed) continue; if (sp.from == null) return true; if (sp.marker.widgetNode) continue; if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) return true; } } function lineIsHiddenInner(doc, line, span) { if (span.to == null) { var end = span.marker.find(1, true); return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); } if (span.marker.inclusiveRight && span.to == line.text.length) return true; for (var sp, i = 0; i < line.markedSpans.length; ++i) { sp = line.markedSpans[i]; if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && (sp.to == null || sp.to != span.from) && (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && lineIsHiddenInner(doc, line, sp)) return true; } } // LINE WIDGETS // Line widgets are block elements displayed above or below a line. var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { if (options) for (var opt in options) if (options.hasOwnProperty(opt)) this[opt] = options[opt]; this.doc = doc; this.node = node; }; eventMixin(LineWidget); function adjustScrollWhenAboveVisible(cm, line, diff) { if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) addToScrollPos(cm, null, diff); } LineWidget.prototype.clear = function() { var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); if (no == null || !ws) return; for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); if (!ws.length) line.widgets = null; var height = widgetHeight(this); updateLineHeight(line, Math.max(0, line.height - height)); if (cm) runInOp(cm, function() { adjustScrollWhenAboveVisible(cm, line, -height); regLineChange(cm, no, "widget"); }); }; LineWidget.prototype.changed = function() { var oldH = this.height, cm = this.doc.cm, line = this.line; this.height = null; var diff = widgetHeight(this) - oldH; if (!diff) return; updateLineHeight(line, line.height + diff); if (cm) runInOp(cm, function() { cm.curOp.forceUpdate = true; adjustScrollWhenAboveVisible(cm, line, diff); }); }; function widgetHeight(widget) { if (widget.height != null) return widget.height; var cm = widget.doc.cm; if (!cm) return 0; if (!contains(document.body, widget.node)) { var parentStyle = "position: relative;"; if (widget.coverGutter) parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; if (widget.noHScroll) parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); } return widget.height = widget.node.offsetHeight; } function addLineWidget(doc, handle, node, options) { var widget = new LineWidget(doc, node, options); var cm = doc.cm; if (cm && widget.noHScroll) cm.display.alignWidgets = true; changeLine(doc, handle, "widget", function(line) { var widgets = line.widgets || (line.widgets = []); if (widget.insertAt == null) widgets.push(widget); else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); widget.line = line; if (cm && !lineIsHidden(doc, line)) { var aboveVisible = heightAtLine(line) < doc.scrollTop; updateLineHeight(line, line.height + widgetHeight(widget)); if (aboveVisible) addToScrollPos(cm, null, widget.height); cm.curOp.forceUpdate = true; } return true; }); return widget; } // LINE DATA STRUCTURE // Line objects. These hold state related to a line, including // highlighting info (the styles array). var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { this.text = text; attachMarkedSpans(this, markedSpans); this.height = estimateHeight ? estimateHeight(this) : 1; }; eventMixin(Line); Line.prototype.lineNo = function() { return lineNo(this); }; // Change the content (text, markers) of a line. Automatically // invalidates cached information and tries to re-estimate the // line's height. function updateLine(line, text, markedSpans, estimateHeight) { line.text = text; if (line.stateAfter) line.stateAfter = null; if (line.styles) line.styles = null; if (line.order != null) line.order = null; detachMarkedSpans(line); attachMarkedSpans(line, markedSpans); var estHeight = estimateHeight ? estimateHeight(line) : 1; if (estHeight != line.height) updateLineHeight(line, estHeight); } // Detach a line from the document tree and its markers. function cleanUpLine(line) { line.parent = null; detachMarkedSpans(line); } function extractLineClasses(type, output) { if (type) for (;;) { var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); if (!lineClass) break; type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); var prop = lineClass[1] ? "bgClass" : "textClass"; if (output[prop] == null) output[prop] = lineClass[2]; else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) output[prop] += " " + lineClass[2]; } return type; } function callBlankLine(mode, state) { if (mode.blankLine) return mode.blankLine(state); if (!mode.innerMode) return; var inner = CodeMirror.innerMode(mode, state); if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); } function readToken(mode, stream, state, inner) { for (var i = 0; i < 10; i++) { if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; var style = mode.token(stream, state); if (stream.pos > stream.start) return style; } throw new Error("Mode " + mode.name + " failed to advance stream."); } // Utility for getTokenAt and getLineTokens function takeToken(cm, pos, precise, asArray) { function getObj(copy) { return {start: stream.start, end: stream.pos, string: stream.current(), type: style || null, state: copy ? copyState(doc.mode, state) : state}; } var doc = cm.doc, mode = doc.mode, style; pos = clipPos(doc, pos); var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); var stream = new StringStream(line.text, cm.options.tabSize), tokens; if (asArray) tokens = []; while ((asArray || stream.pos < pos.ch) && !stream.eol()) { stream.start = stream.pos; style = readToken(mode, stream, state); if (asArray) tokens.push(getObj(true)); } return asArray ? tokens : getObj(); } // Run the given mode's parser over a line, calling f for each token. function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { var flattenSpans = mode.flattenSpans; if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; var curStart = 0, curStyle = null; var stream = new StringStream(text, cm.options.tabSize), style; var inner = cm.options.addModeClass && [null]; if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); while (!stream.eol()) { if (stream.pos > cm.options.maxHighlightLength) { flattenSpans = false; if (forceToEnd) processLine(cm, text, state, stream.pos); stream.pos = text.length; style = null; } else { style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); } if (inner) { var mName = inner[0].name; if (mName) style = "m-" + (style ? mName + " " + style : mName); } if (!flattenSpans || curStyle != style) { while (curStart < stream.start) { curStart = Math.min(stream.start, curStart + 50000); f(curStart, curStyle); } curStyle = style; } stream.start = stream.pos; } while (curStart < stream.pos) { // Webkit seems to refuse to render text nodes longer than 57444 characters var pos = Math.min(stream.pos, curStart + 50000); f(pos, curStyle); curStart = pos; } } // Compute a style array (an array starting with a mode generation // -- for invalidation -- followed by pairs of end positions and // style strings), which is used to highlight the tokens on the // line. function highlightLine(cm, line, state, forceToEnd) { // A styles array always starts with a number identifying the // mode/overlays that it is based on (for easy invalidation). var st = [cm.state.modeGen], lineClasses = {}; // Compute the base array of styles runMode(cm, line.text, cm.doc.mode, state, function(end, style) { st.push(end, style); }, lineClasses, forceToEnd); // Run overlays, adjust style array. for (var o = 0; o < cm.state.overlays.length; ++o) { var overlay = cm.state.overlays[o], i = 1, at = 0; runMode(cm, line.text, overlay.mode, true, function(end, style) { var start = i; // Ensure there's a token end at the current position, and that i points at it while (at < end) { var i_end = st[i]; if (i_end > end) st.splice(i, 1, end, st[i+1], i_end); i += 2; at = Math.min(end, i_end); } if (!style) return; if (overlay.opaque) { st.splice(start, i - start, end, "cm-overlay " + style); i = start + 2; } else { for (; start < i; start += 2) { var cur = st[start+1]; st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; } } }, lineClasses); } return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; } function getLineStyles(cm, line, updateFrontier) { if (!line.styles || line.styles[0] != cm.state.modeGen) { var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); line.styles = result.styles; if (result.classes) line.styleClasses = result.classes; else if (line.styleClasses) line.styleClasses = null; if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; } return line.styles; } // Lightweight form of highlight -- proceed over this line and // update state, but don't save a style array. Used for lines that // aren't currently visible. function processLine(cm, text, state, startAt) { var mode = cm.doc.mode; var stream = new StringStream(text, cm.options.tabSize); stream.start = stream.pos = startAt || 0; if (text == "") callBlankLine(mode, state); while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { readToken(mode, stream, state); stream.start = stream.pos; } } // Convert a style as returned by a mode (either null, or a string // containing one or more styles) to a CSS style. This is cached, // and also looks for line-wide styles. var styleToClassCache = {}, styleToClassCacheWithMode = {}; function interpretTokenStyle(style, options) { if (!style || /^\s*$/.test(style)) return null; var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; return cache[style] || (cache[style] = style.replace(/\S+/g, "cm-$&")); } // Render the DOM representation of the text of a line. Also builds // up a 'line map', which points at the DOM nodes that represent // specific stretches of text, and is used by the measuring code. // The returned object contains the DOM node, this map, and // information about line-wide styles that were set by the mode. function buildLineContent(cm, lineView) { // The padding-right forces the element to have a 'border', which // is needed on Webkit to be able to get line-level bounding // rectangles for it (in measureChar). var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); var builder = {pre: elt("pre", [content]), content: content, col: 0, pos: 0, cm: cm, splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; lineView.measure = {}; // Iterate over the logical lines that make up this visual line. for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { var line = i ? lineView.rest[i - 1] : lineView.line, order; builder.pos = 0; builder.addToken = buildToken; // Optionally wire in some hacks into the token-rendering // algorithm, to deal with browser quirks. if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) builder.addToken = buildTokenBadBidi(builder.addToken, order); builder.map = []; var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); if (line.styleClasses) { if (line.styleClasses.bgClass) builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); if (line.styleClasses.textClass) builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); } // Ensure at least a single node is present, for measuring. if (builder.map.length == 0) builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); // Store the map and a cache object for the current logical line if (i == 0) { lineView.measure.map = builder.map; lineView.measure.cache = {}; } else { (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); (lineView.measure.caches || (lineView.measure.caches = [])).push({}); } } // See issue #2901 if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className)) builder.content.className = "cm-tab-wrap-hack"; signal(cm, "renderLine", cm, lineView.line, builder.pre); if (builder.pre.className) builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); return builder; } function defaultSpecialCharPlaceholder(ch) { var token = elt("span", "\u2022", "cm-invalidchar"); token.title = "\\u" + ch.charCodeAt(0).toString(16); token.setAttribute("aria-label", token.title); return token; } // Build up the DOM representation for a single token, and add it to // the line map. Takes care to render special characters separately. function buildToken(builder, text, style, startStyle, endStyle, title, css) { if (!text) return; var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; var special = builder.cm.state.specialChars, mustWrap = false; if (!special.test(text)) { builder.col += text.length; var content = document.createTextNode(displayText); builder.map.push(builder.pos, builder.pos + text.length, content); if (ie && ie_version < 9) mustWrap = true; builder.pos += text.length; } else { var content = document.createDocumentFragment(), pos = 0; while (true) { special.lastIndex = pos; var m = special.exec(text); var skipped = m ? m.index - pos : text.length - pos; if (skipped) { var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); else content.appendChild(txt); builder.map.push(builder.pos, builder.pos + skipped, txt); builder.col += skipped; builder.pos += skipped; } if (!m) break; pos += skipped + 1; if (m[0] == "\t") { var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); txt.setAttribute("role", "presentation"); txt.setAttribute("cm-text", "\t"); builder.col += tabWidth; } else { var txt = builder.cm.options.specialCharPlaceholder(m[0]); txt.setAttribute("cm-text", m[0]); if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); else content.appendChild(txt); builder.col += 1; } builder.map.push(builder.pos, builder.pos + 1, txt); builder.pos++; } } if (style || startStyle || endStyle || mustWrap || css) { var fullStyle = style || ""; if (startStyle) fullStyle += startStyle; if (endStyle) fullStyle += endStyle; var token = elt("span", [content], fullStyle, css); if (title) token.title = title; return builder.content.appendChild(token); } builder.content.appendChild(content); } function splitSpaces(old) { var out = " "; for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; out += " "; return out; } // Work around nonsense dimensions being reported for stretches of // right-to-left text. function buildTokenBadBidi(inner, order) { return function(builder, text, style, startStyle, endStyle, title, css) { style = style ? style + " cm-force-border" : "cm-force-border"; var start = builder.pos, end = start + text.length; for (;;) { // Find the part that overlaps with the start of this text for (var i = 0; i < order.length; i++) { var part = order[i]; if (part.to > start && part.from <= start) break; } if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); startStyle = null; text = text.slice(part.to - start); start = part.to; } }; } function buildCollapsedSpan(builder, size, marker, ignoreWidget) { var widget = !ignoreWidget && marker.widgetNode; if (widget) builder.map.push(builder.pos, builder.pos + size, widget); if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { if (!widget) widget = builder.content.appendChild(document.createElement("span")); widget.setAttribute("cm-marker", marker.id); } if (widget) { builder.cm.display.input.setUneditable(widget); builder.content.appendChild(widget); } builder.pos += size; } // Outputs a number of spans to make up a line, taking highlighting // and marked text into account. function insertLineContent(line, builder, styles) { var spans = line.markedSpans, allText = line.text, at = 0; if (!spans) { for (var i = 1; i < styles.length; i+=2) builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); return; } var len = allText.length, pos = 0, i = 1, text = "", style, css; var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; for (;;) { if (nextChange == pos) { // Update current marker set spanStyle = spanEndStyle = spanStartStyle = title = css = ""; collapsed = null; nextChange = Infinity; var foundBookmarks = []; for (var j = 0; j < spans.length; ++j) { var sp = spans[j], m = sp.marker; if (sp.from <= pos && (sp.to == null || sp.to > pos)) { if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } if (m.className) spanStyle += " " + m.className; if (m.css) css = m.css; if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; if (m.title && !title) title = m.title; if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) collapsed = sp; } else if (sp.from > pos && nextChange > sp.from) { nextChange = sp.from; } if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m); } if (collapsed && (collapsed.from || 0) == pos) { buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, collapsed.marker, collapsed.from == null); if (collapsed.to == null) return; } if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) buildCollapsedSpan(builder, 0, foundBookmarks[j]); } if (pos >= len) break; var upto = Math.min(len, nextChange); while (true) { if (text) { var end = pos + text.length; if (!collapsed) { var tokenText = end > upto ? text.slice(0, upto - pos) : text; builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); } if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} pos = end; spanStartStyle = ""; } text = allText.slice(at, at = styles[i++]); style = interpretTokenStyle(styles[i++], builder.cm.options); } } } // DOCUMENT DATA STRUCTURE // By default, updates that start and end at the beginning of a line // are treated specially, in order to make the association of line // widgets and marker elements with the text behave more intuitive. function isWholeLineUpdate(doc, change) { return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && (!doc.cm || doc.cm.options.wholeLineUpdateBefore); } // Perform a change on the document data structure. function updateDoc(doc, change, markedSpans, estimateHeight) { function spansFor(n) {return markedSpans ? markedSpans[n] : null;} function update(line, text, spans) { updateLine(line, text, spans, estimateHeight); signalLater(line, "change", line, change); } function linesFor(start, end) { for (var i = start, result = []; i < end; ++i) result.push(new Line(text[i], spansFor(i), estimateHeight)); return result; } var from = change.from, to = change.to, text = change.text; var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; // Adjust the line structure if (change.full) { doc.insert(0, linesFor(0, text.length)); doc.remove(text.length, doc.size - text.length); } else if (isWholeLineUpdate(doc, change)) { // This is a whole-line replace. Treated specially to make // sure line objects move the way they are supposed to. var added = linesFor(0, text.length - 1); update(lastLine, lastLine.text, lastSpans); if (nlines) doc.remove(from.line, nlines); if (added.length) doc.insert(from.line, added); } else if (firstLine == lastLine) { if (text.length == 1) { update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { var added = linesFor(1, text.length - 1); added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); doc.insert(from.line + 1, added); } } else if (text.length == 1) { update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); doc.remove(from.line + 1, nlines); } else { update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); var added = linesFor(1, text.length - 1); if (nlines > 1) doc.remove(from.line + 1, nlines - 1); doc.insert(from.line + 1, added); } signalLater(doc, "change", doc, change); } // The document is represented as a BTree consisting of leaves, with // chunk of lines in them, and branches, with up to ten leaves or // other branch nodes below them. The top node is always a branch // node, and is the document object itself (meaning it has // additional methods and properties). // // All nodes have parent links. The tree is used both to go from // line numbers to line objects, and to go from objects to numbers. // It also indexes by height, and is used to convert between height // and line object, and to find the total height of the document. // // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html function LeafChunk(lines) { this.lines = lines; this.parent = null; for (var i = 0, height = 0; i < lines.length; ++i) { lines[i].parent = this; height += lines[i].height; } this.height = height; } LeafChunk.prototype = { chunkSize: function() { return this.lines.length; }, // Remove the n lines at offset 'at'. removeInner: function(at, n) { for (var i = at, e = at + n; i < e; ++i) { var line = this.lines[i]; this.height -= line.height; cleanUpLine(line); signalLater(line, "delete"); } this.lines.splice(at, n); }, // Helper used to collapse a small branch into a single leaf. collapse: function(lines) { lines.push.apply(lines, this.lines); }, // Insert the given array of lines at offset 'at', count them as // having the given height. insertInner: function(at, lines, height) { this.height += height; this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); for (var i = 0; i < lines.length; ++i) lines[i].parent = this; }, // Used to iterate over a part of the tree. iterN: function(at, n, op) { for (var e = at + n; at < e; ++at) if (op(this.lines[at])) return true; } }; function BranchChunk(children) { this.children = children; var size = 0, height = 0; for (var i = 0; i < children.length; ++i) { var ch = children[i]; size += ch.chunkSize(); height += ch.height; ch.parent = this; } this.size = size; this.height = height; this.parent = null; } BranchChunk.prototype = { chunkSize: function() { return this.size; }, removeInner: function(at, n) { this.size -= n; for (var i = 0; i < this.children.length; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var rm = Math.min(n, sz - at), oldHeight = child.height; child.removeInner(at, rm); this.height -= oldHeight - child.height; if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } if ((n -= rm) == 0) break; at = 0; } else at -= sz; } // If the result is smaller than 25 lines, ensure that it is a // single leaf node. if (this.size - n < 25 && (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { var lines = []; this.collapse(lines); this.children = [new LeafChunk(lines)]; this.children[0].parent = this; } }, collapse: function(lines) { for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); }, insertInner: function(at, lines, height) { this.size += lines.length; this.height += height; for (var i = 0; i < this.children.length; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at <= sz) { child.insertInner(at, lines, height); if (child.lines && child.lines.length > 50) { while (child.lines.length > 50) { var spilled = child.lines.splice(child.lines.length - 25, 25); var newleaf = new LeafChunk(spilled); child.height -= newleaf.height; this.children.splice(i + 1, 0, newleaf); newleaf.parent = this; } this.maybeSpill(); } break; } at -= sz; } }, // When a node has grown, check whether it should be split. maybeSpill: function() { if (this.children.length <= 10) return; var me = this; do { var spilled = me.children.splice(me.children.length - 5, 5); var sibling = new BranchChunk(spilled); if (!me.parent) { // Become the parent node var copy = new BranchChunk(me.children); copy.parent = me; me.children = [copy, sibling]; me = copy; } else { me.size -= sibling.size; me.height -= sibling.height; var myIndex = indexOf(me.parent.children, me); me.parent.children.splice(myIndex + 1, 0, sibling); } sibling.parent = me.parent; } while (me.children.length > 10); me.parent.maybeSpill(); }, iterN: function(at, n, op) { for (var i = 0; i < this.children.length; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var used = Math.min(n, sz - at); if (child.iterN(at, used, op)) return true; if ((n -= used) == 0) break; at = 0; } else at -= sz; } } }; var nextDocId = 0; var Doc = CodeMirror.Doc = function(text, mode, firstLine) { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); if (firstLine == null) firstLine = 0; BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); this.first = firstLine; this.scrollTop = this.scrollLeft = 0; this.cantEdit = false; this.cleanGeneration = 1; this.frontier = firstLine; var start = Pos(firstLine, 0); this.sel = simpleSelection(start); this.history = new History(null); this.id = ++nextDocId; this.modeOption = mode; if (typeof text == "string") text = splitLines(text); updateDoc(this, {from: start, to: start, text: text}); setSelection(this, simpleSelection(start), sel_dontScroll); }; Doc.prototype = createObj(BranchChunk.prototype, { constructor: Doc, // Iterate over the document. Supports two forms -- with only one // argument, it calls that for each line in the document. With // three, it iterates over the range given by the first two (with // the second being non-inclusive). iter: function(from, to, op) { if (op) this.iterN(from - this.first, to - from, op); else this.iterN(this.first, this.first + this.size, from); }, // Non-public interface for adding and removing lines. insert: function(at, lines) { var height = 0; for (var i = 0; i < lines.length; ++i) height += lines[i].height; this.insertInner(at - this.first, lines, height); }, remove: function(at, n) { this.removeInner(at - this.first, n); }, // From here, the methods are part of the public interface. Most // are also available from CodeMirror (editor) instances. getValue: function(lineSep) { var lines = getLines(this, this.first, this.first + this.size); if (lineSep === false) return lines; return lines.join(lineSep || "\n"); }, setValue: docMethodOp(function(code) { var top = Pos(this.first, 0), last = this.first + this.size - 1; makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), text: splitLines(code), origin: "setValue", full: true}, true); setSelection(this, simpleSelection(top)); }), replaceRange: function(code, from, to, origin) { from = clipPos(this, from); to = to ? clipPos(this, to) : from; replaceRange(this, code, from, to, origin); }, getRange: function(from, to, lineSep) { var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); if (lineSep === false) return lines; return lines.join(lineSep || "\n"); }, getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, getLineNumber: function(line) {return lineNo(line);}, getLineHandleVisualStart: function(line) { if (typeof line == "number") line = getLine(this, line); return visualLine(line); }, lineCount: function() {return this.size;}, firstLine: function() {return this.first;}, lastLine: function() {return this.first + this.size - 1;}, clipPos: function(pos) {return clipPos(this, pos);}, getCursor: function(start) { var range = this.sel.primary(), pos; if (start == null || start == "head") pos = range.head; else if (start == "anchor") pos = range.anchor; else if (start == "end" || start == "to" || start === false) pos = range.to(); else pos = range.from(); return pos; }, listSelections: function() { return this.sel.ranges; }, somethingSelected: function() {return this.sel.somethingSelected();}, setCursor: docMethodOp(function(line, ch, options) { setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); }), setSelection: docMethodOp(function(anchor, head, options) { setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); }), extendSelection: docMethodOp(function(head, other, options) { extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); }), extendSelections: docMethodOp(function(heads, options) { extendSelections(this, clipPosArray(this, heads, options)); }), extendSelectionsBy: docMethodOp(function(f, options) { extendSelections(this, map(this.sel.ranges, f), options); }), setSelections: docMethodOp(function(ranges, primary, options) { if (!ranges.length) return; for (var i = 0, out = []; i < ranges.length; i++) out[i] = new Range(clipPos(this, ranges[i].anchor), clipPos(this, ranges[i].head)); if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); setSelection(this, normalizeSelection(out, primary), options); }), addSelection: docMethodOp(function(anchor, head, options) { var ranges = this.sel.ranges.slice(0); ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); }), getSelection: function(lineSep) { var ranges = this.sel.ranges, lines; for (var i = 0; i < ranges.length; i++) { var sel = getBetween(this, ranges[i].from(), ranges[i].to()); lines = lines ? lines.concat(sel) : sel; } if (lineSep === false) return lines; else return lines.join(lineSep || "\n"); }, getSelections: function(lineSep) { var parts = [], ranges = this.sel.ranges; for (var i = 0; i < ranges.length; i++) { var sel = getBetween(this, ranges[i].from(), ranges[i].to()); if (lineSep !== false) sel = sel.join(lineSep || "\n"); parts[i] = sel; } return parts; }, replaceSelection: function(code, collapse, origin) { var dup = []; for (var i = 0; i < this.sel.ranges.length; i++) dup[i] = code; this.replaceSelections(dup, collapse, origin || "+input"); }, replaceSelections: docMethodOp(function(code, collapse, origin) { var changes = [], sel = this.sel; for (var i = 0; i < sel.ranges.length; i++) { var range = sel.ranges[i]; changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; } var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); for (var i = changes.length - 1; i >= 0; i--) makeChange(this, changes[i]); if (newSel) setSelectionReplaceHistory(this, newSel); else if (this.cm) ensureCursorVisible(this.cm); }), undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), setExtending: function(val) {this.extend = val;}, getExtending: function() {return this.extend;}, historySize: function() { var hist = this.history, done = 0, undone = 0; for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; return {undo: done, redo: undone}; }, clearHistory: function() {this.history = new History(this.history.maxGeneration);}, markClean: function() { this.cleanGeneration = this.changeGeneration(true); }, changeGeneration: function(forceSplit) { if (forceSplit) this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; return this.history.generation; }, isClean: function (gen) { return this.history.generation == (gen || this.cleanGeneration); }, getHistory: function() { return {done: copyHistoryArray(this.history.done), undone: copyHistoryArray(this.history.undone)}; }, setHistory: function(histData) { var hist = this.history = new History(this.history.maxGeneration); hist.done = copyHistoryArray(histData.done.slice(0), null, true); hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); }, addLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass"; if (!line[prop]) line[prop] = cls; else if (classTest(cls).test(line[prop])) return false; else line[prop] += " " + cls; return true; }); }), removeLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass"; var cur = line[prop]; if (!cur) return false; else if (cls == null) line[prop] = null; else { var found = cur.match(classTest(cls)); if (!found) return false; var end = found.index + found[0].length; line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; } return true; }); }), addLineWidget: docMethodOp(function(handle, node, options) { return addLineWidget(this, handle, node, options); }), removeLineWidget: function(widget) { widget.clear(); }, markText: function(from, to, options) { return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); }, setBookmark: function(pos, options) { var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), insertLeft: options && options.insertLeft, clearWhenEmpty: false, shared: options && options.shared, handleMouseEvents: options && options.handleMouseEvents}; pos = clipPos(this, pos); return markText(this, pos, pos, realOpts, "bookmark"); }, findMarksAt: function(pos) { pos = clipPos(this, pos); var markers = [], spans = getLine(this, pos.line).markedSpans; if (spans) for (var i = 0; i < spans.length; ++i) { var span = spans[i]; if ((span.from == null || span.from <= pos.ch) && (span.to == null || span.to >= pos.ch)) markers.push(span.marker.parent || span.marker); } return markers; }, findMarks: function(from, to, filter) { from = clipPos(this, from); to = clipPos(this, to); var found = [], lineNo = from.line; this.iter(from.line, to.line + 1, function(line) { var spans = line.markedSpans; if (spans) for (var i = 0; i < spans.length; i++) { var span = spans[i]; if (!(lineNo == from.line && from.ch > span.to || span.from == null && lineNo != from.line|| lineNo == to.line && span.from > to.ch) && (!filter || filter(span.marker))) found.push(span.marker.parent || span.marker); } ++lineNo; }); return found; }, getAllMarks: function() { var markers = []; this.iter(function(line) { var sps = line.markedSpans; if (sps) for (var i = 0; i < sps.length; ++i) if (sps[i].from != null) markers.push(sps[i].marker); }); return markers; }, posFromIndex: function(off) { var ch, lineNo = this.first; this.iter(function(line) { var sz = line.text.length + 1; if (sz > off) { ch = off; return true; } off -= sz; ++lineNo; }); return clipPos(this, Pos(lineNo, ch)); }, indexFromPos: function (coords) { coords = clipPos(this, coords); var index = coords.ch; if (coords.line < this.first || coords.ch < 0) return 0; this.iter(this.first, coords.line, function (line) { index += line.text.length + 1; }); return index; }, copy: function(copyHistory) { var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; doc.sel = this.sel; doc.extend = false; if (copyHistory) { doc.history.undoDepth = this.history.undoDepth; doc.setHistory(this.getHistory()); } return doc; }, linkedDoc: function(options) { if (!options) options = {}; var from = this.first, to = this.first + this.size; if (options.from != null && options.from > from) from = options.from; if (options.to != null && options.to < to) to = options.to; var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); if (options.sharedHist) copy.history = this.history; (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; copySharedMarkers(copy, findSharedMarkers(this)); return copy; }, unlinkDoc: function(other) { if (other instanceof CodeMirror) other = other.doc; if (this.linked) for (var i = 0; i < this.linked.length; ++i) { var link = this.linked[i]; if (link.doc != other) continue; this.linked.splice(i, 1); other.unlinkDoc(this); detachSharedMarkers(findSharedMarkers(this)); break; } // If the histories were shared, split them again if (other.history == this.history) { var splitIds = [other.id]; linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); other.history = new History(null); other.history.done = copyHistoryArray(this.history.done, splitIds); other.history.undone = copyHistoryArray(this.history.undone, splitIds); } }, iterLinkedDocs: function(f) {linkedDocs(this, f);}, getMode: function() {return this.mode;}, getEditor: function() {return this.cm;} }); // Public alias. Doc.prototype.eachLine = Doc.prototype.iter; // Set up methods on CodeMirror's prototype to redirect to the editor's document. var dontDelegate = "iter insert remove copy getEditor".split(" "); for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) CodeMirror.prototype[prop] = (function(method) { return function() {return method.apply(this.doc, arguments);}; })(Doc.prototype[prop]); eventMixin(Doc); // Call f for all linked documents. function linkedDocs(doc, f, sharedHistOnly) { function propagate(doc, skip, sharedHist) { if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { var rel = doc.linked[i]; if (rel.doc == skip) continue; var shared = sharedHist && rel.sharedHist; if (sharedHistOnly && !shared) continue; f(rel.doc, shared); propagate(rel.doc, doc, shared); } } propagate(doc, null, true); } // Attach a document to an editor. function attachDoc(cm, doc) { if (doc.cm) throw new Error("This document is already in use."); cm.doc = doc; doc.cm = cm; estimateLineHeights(cm); loadMode(cm); if (!cm.options.lineWrapping) findMaxLine(cm); cm.options.mode = doc.modeOption; regChange(cm); } // LINE UTILITIES // Find the line object corresponding to the given line number. function getLine(doc, n) { n -= doc.first; if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); for (var chunk = doc; !chunk.lines;) { for (var i = 0;; ++i) { var child = chunk.children[i], sz = child.chunkSize(); if (n < sz) { chunk = child; break; } n -= sz; } } return chunk.lines[n]; } // Get the part of a document between two positions, as an array of // strings. function getBetween(doc, start, end) { var out = [], n = start.line; doc.iter(start.line, end.line + 1, function(line) { var text = line.text; if (n == end.line) text = text.slice(0, end.ch); if (n == start.line) text = text.slice(start.ch); out.push(text); ++n; }); return out; } // Get the lines between from and to, as array of strings. function getLines(doc, from, to) { var out = []; doc.iter(from, to, function(line) { out.push(line.text); }); return out; } // Update the height of a line, propagating the height change // upwards to parent nodes. function updateLineHeight(line, height) { var diff = height - line.height; if (diff) for (var n = line; n; n = n.parent) n.height += diff; } // Given a line object, find its line number by walking up through // its parent links. function lineNo(line) { if (line.parent == null) return null; var cur = line.parent, no = indexOf(cur.lines, line); for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { for (var i = 0;; ++i) { if (chunk.children[i] == cur) break; no += chunk.children[i].chunkSize(); } } return no + cur.first; } // Find the line at the given vertical position, using the height // information in the document tree. function lineAtHeight(chunk, h) { var n = chunk.first; outer: do { for (var i = 0; i < chunk.children.length; ++i) { var child = chunk.children[i], ch = child.height; if (h < ch) { chunk = child; continue outer; } h -= ch; n += child.chunkSize(); } return n; } while (!chunk.lines); for (var i = 0; i < chunk.lines.length; ++i) { var line = chunk.lines[i], lh = line.height; if (h < lh) break; h -= lh; } return n + i; } // Find the height above the given line. function heightAtLine(lineObj) { lineObj = visualLine(lineObj); var h = 0, chunk = lineObj.parent; for (var i = 0; i < chunk.lines.length; ++i) { var line = chunk.lines[i]; if (line == lineObj) break; else h += line.height; } for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { for (var i = 0; i < p.children.length; ++i) { var cur = p.children[i]; if (cur == chunk) break; else h += cur.height; } } return h; } // Get the bidi ordering for the given line (and cache it). Returns // false for lines that are fully left-to-right, and an array of // BidiSpan objects otherwise. function getOrder(line) { var order = line.order; if (order == null) order = line.order = bidiOrdering(line.text); return order; } // HISTORY function History(startGen) { // Arrays of change events and selections. Doing something adds an // event to done and clears undo. Undoing moves events from done // to undone, redoing moves them in the other direction. this.done = []; this.undone = []; this.undoDepth = Infinity; // Used to track when changes can be merged into a single undo // event this.lastModTime = this.lastSelTime = 0; this.lastOp = this.lastSelOp = null; this.lastOrigin = this.lastSelOrigin = null; // Used by the isClean() method this.generation = this.maxGeneration = startGen || 1; } // Create a history change event from an updateDoc-style change // object. function historyChangeFromChange(doc, change) { var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); return histChange; } // Pop all selection events off the end of a history array. Stop at // a change event. function clearSelectionEvents(array) { while (array.length) { var last = lst(array); if (last.ranges) array.pop(); else break; } } // Find the top change event in the history. Pop off selection // events that are in the way. function lastChangeEvent(hist, force) { if (force) { clearSelectionEvents(hist.done); return lst(hist.done); } else if (hist.done.length && !lst(hist.done).ranges) { return lst(hist.done); } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { hist.done.pop(); return lst(hist.done); } } // Register a change in the history. Merges changes that are within // a single operation, ore are close together with an origin that // allows merging (starting with "+") into a single event. function addChangeToHistory(doc, change, selAfter, opId) { var hist = doc.history; hist.undone.length = 0; var time = +new Date, cur; if ((hist.lastOp == opId || hist.lastOrigin == change.origin && change.origin && ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || change.origin.charAt(0) == "*")) && (cur = lastChangeEvent(hist, hist.lastOp == opId))) { // Merge this change into the last event var last = lst(cur.changes); if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { // Optimized case for simple insertion -- don't want to add // new changesets for every character typed last.to = changeEnd(change); } else { // Add new sub-event cur.changes.push(historyChangeFromChange(doc, change)); } } else { // Can not be merged, start a new event. var before = lst(hist.done); if (!before || !before.ranges) pushSelectionToHistory(doc.sel, hist.done); cur = {changes: [historyChangeFromChange(doc, change)], generation: hist.generation}; hist.done.push(cur); while (hist.done.length > hist.undoDepth) { hist.done.shift(); if (!hist.done[0].ranges) hist.done.shift(); } } hist.done.push(selAfter); hist.generation = ++hist.maxGeneration; hist.lastModTime = hist.lastSelTime = time; hist.lastOp = hist.lastSelOp = opId; hist.lastOrigin = hist.lastSelOrigin = change.origin; if (!last) signal(doc, "historyAdded"); } function selectionEventCanBeMerged(doc, origin, prev, sel) { var ch = origin.charAt(0); return ch == "*" || ch == "+" && prev.ranges.length == sel.ranges.length && prev.somethingSelected() == sel.somethingSelected() && new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); } // Called whenever the selection changes, sets the new selection as // the pending selection in the history, and pushes the old pending // selection into the 'done' array when it was significantly // different (in number of selected ranges, emptiness, or time). function addSelectionToHistory(doc, sel, opId, options) { var hist = doc.history, origin = options && options.origin; // A new event is started when the previous origin does not match // the current, or the origins don't allow matching. Origins // starting with * are always merged, those starting with + are // merged when similar and close together in time. if (opId == hist.lastSelOp || (origin && hist.lastSelOrigin == origin && (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) hist.done[hist.done.length - 1] = sel; else pushSelectionToHistory(sel, hist.done); hist.lastSelTime = +new Date; hist.lastSelOrigin = origin; hist.lastSelOp = opId; if (options && options.clearRedo !== false) clearSelectionEvents(hist.undone); } function pushSelectionToHistory(sel, dest) { var top = lst(dest); if (!(top && top.ranges && top.equals(sel))) dest.push(sel); } // Used to store marked span information in the history. function attachLocalSpans(doc, change, from, to) { var existing = change["spans_" + doc.id], n = 0; doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { if (line.markedSpans) (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; ++n; }); } // When un/re-doing restores text containing marked spans, those // that have been explicitly cleared should not be restored. function removeClearedSpans(spans) { if (!spans) return null; for (var i = 0, out; i < spans.length; ++i) { if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } else if (out) out.push(spans[i]); } return !out ? spans : out.length ? out : null; } // Retrieve and filter the old marked spans stored in a change event. function getOldSpans(doc, change) { var found = change["spans_" + doc.id]; if (!found) return null; for (var i = 0, nw = []; i < change.text.length; ++i) nw.push(removeClearedSpans(found[i])); return nw; } // Used both to provide a JSON-safe object in .getHistory, and, when // detaching a document, to split the history in two function copyHistoryArray(events, newGroup, instantiateSel) { for (var i = 0, copy = []; i < events.length; ++i) { var event = events[i]; if (event.ranges) { copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); continue; } var changes = event.changes, newChanges = []; copy.push({changes: newChanges}); for (var j = 0; j < changes.length; ++j) { var change = changes[j], m; newChanges.push({from: change.from, to: change.to, text: change.text}); if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { if (indexOf(newGroup, Number(m[1])) > -1) { lst(newChanges)[prop] = change[prop]; delete change[prop]; } } } } return copy; } // Rebasing/resetting history to deal with externally-sourced changes function rebaseHistSelSingle(pos, from, to, diff) { if (to < pos.line) { pos.line += diff; } else if (from < pos.line) { pos.line = from; pos.ch = 0; } } // Tries to rebase an array of history events given a change in the // document. If the change touches the same lines as the event, the // event, and everything 'behind' it, is discarded. If the change is // before the event, the event's positions are updated. Uses a // copy-on-write scheme for the positions, to avoid having to // reallocate them all on every rebase, but also avoid problems with // shared position objects being unsafely updated. function rebaseHistArray(array, from, to, diff) { for (var i = 0; i < array.length; ++i) { var sub = array[i], ok = true; if (sub.ranges) { if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } for (var j = 0; j < sub.ranges.length; j++) { rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); } continue; } for (var j = 0; j < sub.changes.length; ++j) { var cur = sub.changes[j]; if (to < cur.from.line) { cur.from = Pos(cur.from.line + diff, cur.from.ch); cur.to = Pos(cur.to.line + diff, cur.to.ch); } else if (from <= cur.to.line) { ok = false; break; } } if (!ok) { array.splice(0, i + 1); i = 0; } } } function rebaseHist(hist, change) { var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; rebaseHistArray(hist.done, from, to, diff); rebaseHistArray(hist.undone, from, to, diff); } // EVENT UTILITIES // Due to the fact that we still support jurassic IE versions, some // compatibility wrappers are needed. var e_preventDefault = CodeMirror.e_preventDefault = function(e) { if (e.preventDefault) e.preventDefault(); else e.returnValue = false; }; var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { if (e.stopPropagation) e.stopPropagation(); else e.cancelBubble = true; }; function e_defaultPrevented(e) { return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; } var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; function e_target(e) {return e.target || e.srcElement;} function e_button(e) { var b = e.which; if (b == null) { if (e.button & 1) b = 1; else if (e.button & 2) b = 3; else if (e.button & 4) b = 2; } if (mac && e.ctrlKey && b == 1) b = 3; return b; } // EVENT HANDLING // Lightweight event framework. on/off also work on DOM nodes, // registering native DOM handlers. var on = CodeMirror.on = function(emitter, type, f) { if (emitter.addEventListener) emitter.addEventListener(type, f, false); else if (emitter.attachEvent) emitter.attachEvent("on" + type, f); else { var map = emitter._handlers || (emitter._handlers = {}); var arr = map[type] || (map[type] = []); arr.push(f); } }; var off = CodeMirror.off = function(emitter, type, f) { if (emitter.removeEventListener) emitter.removeEventListener(type, f, false); else if (emitter.detachEvent) emitter.detachEvent("on" + type, f); else { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; for (var i = 0; i < arr.length; ++i) if (arr[i] == f) { arr.splice(i, 1); break; } } }; var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; var args = Array.prototype.slice.call(arguments, 2); for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); }; var orphanDelayedCallbacks = null; // Often, we want to signal events at a point where we are in the // middle of some work, but don't want the handler to start calling // other methods on the editor, which might be in an inconsistent // state or simply not expect any other events to happen. // signalLater looks whether there are any handlers, and schedules // them to be executed when the last operation ends, or, if no // operation is active, when a timeout fires. function signalLater(emitter, type /*, values...*/) { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; var args = Array.prototype.slice.call(arguments, 2), list; if (operationGroup) { list = operationGroup.delayedCallbacks; } else if (orphanDelayedCallbacks) { list = orphanDelayedCallbacks; } else { list = orphanDelayedCallbacks = []; setTimeout(fireOrphanDelayed, 0); } function bnd(f) {return function(){f.apply(null, args);};}; for (var i = 0; i < arr.length; ++i) list.push(bnd(arr[i])); } function fireOrphanDelayed() { var delayed = orphanDelayedCallbacks; orphanDelayedCallbacks = null; for (var i = 0; i < delayed.length; ++i) delayed[i](); } // The DOM events that CodeMirror handles can be overridden by // registering a (non-DOM) handler on the editor for the event name, // and preventDefault-ing the event in that handler. function signalDOMEvent(cm, e, override) { if (typeof e == "string") e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; signal(cm, override || e.type, cm, e); return e_defaultPrevented(e) || e.codemirrorIgnore; } function signalCursorActivity(cm) { var arr = cm._handlers && cm._handlers.cursorActivity; if (!arr) return; var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) set.push(arr[i]); } function hasHandler(emitter, type) { var arr = emitter._handlers && emitter._handlers[type]; return arr && arr.length > 0; } // Add on and off methods to a constructor's prototype, to make // registering events on such objects more convenient. function eventMixin(ctor) { ctor.prototype.on = function(type, f) {on(this, type, f);}; ctor.prototype.off = function(type, f) {off(this, type, f);}; } // MISC UTILITIES // Number of pixels added to scroller and sizer to hide scrollbar var scrollerGap = 30; // Returned or thrown by various protocols to signal 'I'm not // handling this'. var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; // Reused option objects for setSelection & friends var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; function Delayed() {this.id = null;} Delayed.prototype.set = function(ms, f) { clearTimeout(this.id); this.id = setTimeout(f, ms); }; // Counts the column offset in a string, taking tabs into account. // Used mostly to find indentation. var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { if (end == null) { end = string.search(/[^\s\u00a0]/); if (end == -1) end = string.length; } for (var i = startIndex || 0, n = startValue || 0;;) { var nextTab = string.indexOf("\t", i); if (nextTab < 0 || nextTab >= end) return n + (end - i); n += nextTab - i; n += tabSize - (n % tabSize); i = nextTab + 1; } }; // The inverse of countColumn -- find the offset that corresponds to // a particular column. function findColumn(string, goal, tabSize) { for (var pos = 0, col = 0;;) { var nextTab = string.indexOf("\t", pos); if (nextTab == -1) nextTab = string.length; var skipped = nextTab - pos; if (nextTab == string.length || col + skipped >= goal) return pos + Math.min(skipped, goal - col); col += nextTab - pos; col += tabSize - (col % tabSize); pos = nextTab + 1; if (col >= goal) return pos; } } var spaceStrs = [""]; function spaceStr(n) { while (spaceStrs.length <= n) spaceStrs.push(lst(spaceStrs) + " "); return spaceStrs[n]; } function lst(arr) { return arr[arr.length-1]; } var selectInput = function(node) { node.select(); }; if (ios) // Mobile Safari apparently has a bug where select() is broken. selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; else if (ie) // Suppress mysterious IE10 errors selectInput = function(node) { try { node.select(); } catch(_e) {} }; function indexOf(array, elt) { for (var i = 0; i < array.length; ++i) if (array[i] == elt) return i; return -1; } function map(array, f) { var out = []; for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); return out; } function nothing() {} function createObj(base, props) { var inst; if (Object.create) { inst = Object.create(base); } else { nothing.prototype = base; inst = new nothing(); } if (props) copyObj(props, inst); return inst; }; function copyObj(obj, target, overwrite) { if (!target) target = {}; for (var prop in obj) if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) target[prop] = obj[prop]; return target; } function bind(f) { var args = Array.prototype.slice.call(arguments, 1); return function(){return f.apply(null, args);}; } var nonASCIISingleCaseWordChar = /[\u00df\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; var isWordCharBasic = CodeMirror.isWordChar = function(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); }; function isWordChar(ch, helper) { if (!helper) return isWordCharBasic(ch); if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; return helper.test(ch); } function isEmpty(obj) { for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; return true; } // Extending unicode characters. A series of a non-extending char + // any number of extending chars is treated as a single unit as far // as editing and measuring is concerned. This is not fully correct, // since some scripts/fonts/browsers also treat other configurations // of code points as a group. var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } // DOM UTILITIES function elt(tag, content, className, style) { var e = document.createElement(tag); if (className) e.className = className; if (style) e.style.cssText = style; if (typeof content == "string") e.appendChild(document.createTextNode(content)); else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); return e; } var range; if (document.createRange) range = function(node, start, end, endNode) { var r = document.createRange(); r.setEnd(endNode || node, end); r.setStart(node, start); return r; }; else range = function(node, start, end) { var r = document.body.createTextRange(); try { r.moveToElementText(node.parentNode); } catch(e) { return r; } r.collapse(true); r.moveEnd("character", end); r.moveStart("character", start); return r; }; function removeChildren(e) { for (var count = e.childNodes.length; count > 0; --count) e.removeChild(e.firstChild); return e; } function removeChildrenAndAdd(parent, e) { return removeChildren(parent).appendChild(e); } var contains = CodeMirror.contains = function(parent, child) { if (child.nodeType == 3) // Android browser always returns false when child is a textnode child = child.parentNode; if (parent.contains) return parent.contains(child); do { if (child.nodeType == 11) child = child.host; if (child == parent) return true; } while (child = child.parentNode); }; function activeElt() { return document.activeElement; } // Older versions of IE throws unspecified error when touching // document.activeElement in some cases (during loading, in iframe) if (ie && ie_version < 11) activeElt = function() { try { return document.activeElement; } catch(e) { return document.body; } }; function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } var rmClass = CodeMirror.rmClass = function(node, cls) { var current = node.className; var match = classTest(cls).exec(current); if (match) { var after = current.slice(match.index + match[0].length); node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); } }; var addClass = CodeMirror.addClass = function(node, cls) { var current = node.className; if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; }; function joinClasses(a, b) { var as = a.split(" "); for (var i = 0; i < as.length; i++) if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; return b; } // WINDOW-WIDE EVENTS // These must be handled carefully, because naively registering a // handler for each editor will cause the editors to never be // garbage collected. function forEachCodeMirror(f) { if (!document.body.getElementsByClassName) return; var byClass = document.body.getElementsByClassName("CodeMirror"); for (var i = 0; i < byClass.length; i++) { var cm = byClass[i].CodeMirror; if (cm) f(cm); } } var globalsRegistered = false; function ensureGlobalHandlers() { if (globalsRegistered) return; registerGlobalHandlers(); globalsRegistered = true; } function registerGlobalHandlers() { // When the window resizes, we need to refresh active editors. var resizeTimer; on(window, "resize", function() { if (resizeTimer == null) resizeTimer = setTimeout(function() { resizeTimer = null; forEachCodeMirror(onResize); }, 100); }); // When the window loses focus, we want to show the editor as blurred on(window, "blur", function() { forEachCodeMirror(onBlur); }); } // FEATURE DETECTION // Detect drag-and-drop var dragAndDrop = function() { // There is *some* kind of drag-and-drop support in IE6-8, but I // couldn't get it to work yet. if (ie && ie_version < 9) return false; var div = elt('div'); return "draggable" in div || "dragDrop" in div; }(); var zwspSupported; function zeroWidthElement(measure) { if (zwspSupported == null) { var test = elt("span", "\u200b"); removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); if (measure.firstChild.offsetHeight != 0) zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); } var node = zwspSupported ? elt("span", "\u200b") : elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); node.setAttribute("cm-text", ""); return node; } // Feature-detect IE's crummy client rect reporting for bidi text var badBidiRects; function hasBadBidiRects(measure) { if (badBidiRects != null) return badBidiRects; var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); var r0 = range(txt, 0, 1).getBoundingClientRect(); if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) var r1 = range(txt, 1, 2).getBoundingClientRect(); return badBidiRects = (r1.right - r0.right < 3); } // See if "".split is the broken IE version, if so, provide an // alternative way to split lines. var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { var pos = 0, result = [], l = string.length; while (pos <= l) { var nl = string.indexOf("\n", pos); if (nl == -1) nl = string.length; var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); var rt = line.indexOf("\r"); if (rt != -1) { result.push(line.slice(0, rt)); pos += rt + 1; } else { result.push(line); pos = nl + 1; } } return result; } : function(string){return string.split(/\r\n?|\n/);}; var hasSelection = window.getSelection ? function(te) { try { return te.selectionStart != te.selectionEnd; } catch(e) { return false; } } : function(te) { try {var range = te.ownerDocument.selection.createRange();} catch(e) {} if (!range || range.parentElement() != te) return false; return range.compareEndPoints("StartToEnd", range) != 0; }; var hasCopyEvent = (function() { var e = elt("div"); if ("oncopy" in e) return true; e.setAttribute("oncopy", "return;"); return typeof e.oncopy == "function"; })(); var badZoomedRects = null; function hasBadZoomedRects(measure) { if (badZoomedRects != null) return badZoomedRects; var node = removeChildrenAndAdd(measure, elt("span", "x")); var normal = node.getBoundingClientRect(); var fromRange = range(node, 0, 1).getBoundingClientRect(); return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; } // KEY NAMES var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; CodeMirror.keyNames = keyNames; (function() { // Number keys for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); // Alphabetic keys for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); // Function keys for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; })(); // BIDI HELPERS function iterateBidiSections(order, from, to, f) { if (!order) return f(from, to, "ltr"); var found = false; for (var i = 0; i < order.length; ++i) { var part = order[i]; if (part.from < to && part.to > from || from == to && part.to == from) { f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); found = true; } } if (!found) f(from, to, "ltr"); } function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } function bidiRight(part) { return part.level % 2 ? part.from : part.to; } function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } function lineRight(line) { var order = getOrder(line); if (!order) return line.text.length; return bidiRight(lst(order)); } function lineStart(cm, lineN) { var line = getLine(cm.doc, lineN); var visual = visualLine(line); if (visual != line) lineN = lineNo(visual); var order = getOrder(visual); var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); return Pos(lineN, ch); } function lineEnd(cm, lineN) { var merged, line = getLine(cm.doc, lineN); while (merged = collapsedSpanAtEnd(line)) { line = merged.find(1, true).line; lineN = null; } var order = getOrder(line); var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); return Pos(lineN == null ? lineNo(line) : lineN, ch); } function lineStartSmart(cm, pos) { var start = lineStart(cm, pos.line); var line = getLine(cm.doc, start.line); var order = getOrder(line); if (!order || order[0].level == 0) { var firstNonWS = Math.max(0, line.text.search(/\S/)); var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; return Pos(start.line, inWS ? 0 : firstNonWS); } return start; } function compareBidiLevel(order, a, b) { var linedir = order[0].level; if (a == linedir) return true; if (b == linedir) return false; return a < b; } var bidiOther; function getBidiPartAt(order, pos) { bidiOther = null; for (var i = 0, found; i < order.length; ++i) { var cur = order[i]; if (cur.from < pos && cur.to > pos) return i; if ((cur.from == pos || cur.to == pos)) { if (found == null) { found = i; } else if (compareBidiLevel(order, cur.level, order[found].level)) { if (cur.from != cur.to) bidiOther = found; return i; } else { if (cur.from != cur.to) bidiOther = i; return found; } } } return found; } function moveInLine(line, pos, dir, byUnit) { if (!byUnit) return pos + dir; do pos += dir; while (pos > 0 && isExtendingChar(line.text.charAt(pos))); return pos; } // This is needed in order to move 'visually' through bi-directional // text -- i.e., pressing left should make the cursor go left, even // when in RTL text. The tricky part is the 'jumps', where RTL and // LTR text touch each other. This often requires the cursor offset // to move more than one unit, in order to visually move one unit. function moveVisually(line, start, dir, byUnit) { var bidi = getOrder(line); if (!bidi) return moveLogically(line, start, dir, byUnit); var pos = getBidiPartAt(bidi, start), part = bidi[pos]; var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); for (;;) { if (target > part.from && target < part.to) return target; if (target == part.from || target == part.to) { if (getBidiPartAt(bidi, target) == pos) return target; part = bidi[pos += dir]; return (dir > 0) == part.level % 2 ? part.to : part.from; } else { part = bidi[pos += dir]; if (!part) return null; if ((dir > 0) == part.level % 2) target = moveInLine(line, part.to, -1, byUnit); else target = moveInLine(line, part.from, 1, byUnit); } } } function moveLogically(line, start, dir, byUnit) { var target = start + dir; if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; return target < 0 || target > line.text.length ? null : target; } // Bidirectional ordering algorithm // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm // that this (partially) implements. // One-char codes used for character types: // L (L): Left-to-Right // R (R): Right-to-Left // r (AL): Right-to-Left Arabic // 1 (EN): European Number // + (ES): European Number Separator // % (ET): European Number Terminator // n (AN): Arabic Number // , (CS): Common Number Separator // m (NSM): Non-Spacing Mark // b (BN): Boundary Neutral // s (B): Paragraph Separator // t (S): Segment Separator // w (WS): Whitespace // N (ON): Other Neutrals // Returns null if characters are ordered as they appear // (left-to-right), or an array of sections ({from, to, level} // objects) in the order in which they occur visually. var bidiOrdering = (function() { // Character types for codepoints 0 to 0xff var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; // Character types for codepoints 0x600 to 0x6ff var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; function charType(code) { if (code <= 0xf7) return lowTypes.charAt(code); else if (0x590 <= code && code <= 0x5f4) return "R"; else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); else if (0x6ee <= code && code <= 0x8ac) return "r"; else if (0x2000 <= code && code <= 0x200b) return "w"; else if (code == 0x200c) return "b"; else return "L"; } var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; // Browsers seem to always treat the boundaries of block elements as being L. var outerType = "L"; function BidiSpan(level, from, to) { this.level = level; this.from = from; this.to = to; } return function(str) { if (!bidiRE.test(str)) return false; var len = str.length, types = []; for (var i = 0, type; i < len; ++i) types.push(type = charType(str.charCodeAt(i))); // W1. Examine each non-spacing mark (NSM) in the level run, and // change the type of the NSM to the type of the previous // character. If the NSM is at the start of the level run, it will // get the type of sor. for (var i = 0, prev = outerType; i < len; ++i) { var type = types[i]; if (type == "m") types[i] = prev; else prev = type; } // W2. Search backwards from each instance of a European number // until the first strong type (R, L, AL, or sor) is found. If an // AL is found, change the type of the European number to Arabic // number. // W3. Change all ALs to R. for (var i = 0, cur = outerType; i < len; ++i) { var type = types[i]; if (type == "1" && cur == "r") types[i] = "n"; else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } } // W4. A single European separator between two European numbers // changes to a European number. A single common separator between // two numbers of the same type changes to that type. for (var i = 1, prev = types[0]; i < len - 1; ++i) { var type = types[i]; if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; else if (type == "," && prev == types[i+1] && (prev == "1" || prev == "n")) types[i] = prev; prev = type; } // W5. A sequence of European terminators adjacent to European // numbers changes to all European numbers. // W6. Otherwise, separators and terminators change to Other // Neutral. for (var i = 0; i < len; ++i) { var type = types[i]; if (type == ",") types[i] = "N"; else if (type == "%") { for (var end = i + 1; end < len && types[end] == "%"; ++end) {} var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; for (var j = i; j < end; ++j) types[j] = replace; i = end - 1; } } // W7. Search backwards from each instance of a European number // until the first strong type (R, L, or sor) is found. If an L is // found, then change the type of the European number to L. for (var i = 0, cur = outerType; i < len; ++i) { var type = types[i]; if (cur == "L" && type == "1") types[i] = "L"; else if (isStrong.test(type)) cur = type; } // N1. A sequence of neutrals takes the direction of the // surrounding strong text if the text on both sides has the same // direction. European and Arabic numbers act as if they were R in // terms of their influence on neutrals. Start-of-level-run (sor) // and end-of-level-run (eor) are used at level run boundaries. // N2. Any remaining neutrals take the embedding direction. for (var i = 0; i < len; ++i) { if (isNeutral.test(types[i])) { for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} var before = (i ? types[i-1] : outerType) == "L"; var after = (end < len ? types[end] : outerType) == "L"; var replace = before || after ? "L" : "R"; for (var j = i; j < end; ++j) types[j] = replace; i = end - 1; } } // Here we depart from the documented algorithm, in order to avoid // building up an actual levels array. Since there are only three // levels (0, 1, 2) in an implementation that doesn't take // explicit embedding into account, we can build up the order on // the fly, without following the level-based algorithm. var order = [], m; for (var i = 0; i < len;) { if (countsAsLeft.test(types[i])) { var start = i; for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} order.push(new BidiSpan(0, start, i)); } else { var pos = i, at = order.length; for (++i; i < len && types[i] != "L"; ++i) {} for (var j = pos; j < i;) { if (countsAsNum.test(types[j])) { if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); var nstart = j; for (++j; j < i && countsAsNum.test(types[j]); ++j) {} order.splice(at, 0, new BidiSpan(2, nstart, j)); pos = j; } else ++j; } if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); } } if (order[0].level == 1 && (m = str.match(/^\s+/))) { order[0].from = m[0].length; order.unshift(new BidiSpan(0, 0, m[0].length)); } if (lst(order).level == 1 && (m = str.match(/\s+$/))) { lst(order).to -= m[0].length; order.push(new BidiSpan(0, len - m[0].length, len)); } if (order[0].level != lst(order).level) order.push(new BidiSpan(order[0].level, len, len)); return order; }; })(); // THE END CodeMirror.version = "5.1.0"; return CodeMirror; }); three.js-r73/editor/js/libs/codemirror/addon/0000755000175500017550000000000012610076566021041 5ustar debacledebaclethree.js-r73/editor/js/libs/codemirror/addon/tern.js0000644000175500017550000005742112610076566022360 0ustar debacledebacle// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE // Glue code between CodeMirror and Tern. // // Create a CodeMirror.TernServer to wrap an actual Tern server, // register open documents (CodeMirror.Doc instances) with it, and // call its methods to activate the assisting functions that Tern // provides. // // Options supported (all optional): // * defs: An array of JSON definition data structures. // * plugins: An object mapping plugin names to configuration // options. // * getFile: A function(name, c) that can be used to access files in // the project that haven't been loaded yet. Simply do c(null) to // indicate that a file is not available. // * fileFilter: A function(value, docName, doc) that will be applied // to documents before passing them on to Tern. // * switchToDoc: A function(name, doc) that should, when providing a // multi-file view, switch the view or focus to the named file. // * showError: A function(editor, message) that can be used to // override the way errors are displayed. // * completionTip: Customize the content in tooltips for completions. // Is passed a single argument—the completion's data as returned by // Tern—and may return a string, DOM node, or null to indicate that // no tip should be shown. By default the docstring is shown. // * typeTip: Like completionTip, but for the tooltips shown for type // queries. // * responseFilter: A function(doc, query, request, error, data) that // will be applied to the Tern responses before treating them // * caseInsensitive: boolean to send case insensitive querys to tern // // // It is possible to run the Tern server in a web worker by specifying // these additional options: // * useWorker: Set to true to enable web worker mode. You'll probably // want to feature detect the actual value you use here, for example // !!window.Worker. // * workerScript: The main script of the worker. Point this to // wherever you are hosting worker.js from this directory. // * workerDeps: An array of paths pointing (relative to workerScript) // to the Acorn and Tern libraries and any Tern plugins you want to // load. Or, if you minified those into a single script and included // them in the workerScript, simply leave this undefined. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { "use strict"; // declare global: tern CodeMirror.TernServer = function(options) { var self = this; this.options = options || {}; var plugins = this.options.plugins || (this.options.plugins = {}); if (!plugins.doc_comment) plugins.doc_comment = true; if (this.options.useWorker) { this.server = new WorkerServer(this); } else { this.server = new tern.Server({ getFile: function(name, c) { return getFile(self, name, c); }, async: true, defs: this.options.defs || [], plugins: plugins }); } this.docs = Object.create(null); this.trackChange = function(doc, change) { trackChange(self, doc, change); }; this.cachedArgHints = null; this.activeArgHints = null; this.jumpStack = []; this.getHint = function(cm, c) { return hint(self, cm, c); }; this.getHint.async = true; }; CodeMirror.TernServer.prototype = { addDoc: function(name, doc) { var data = {doc: doc, name: name, changed: null}; this.server.addFile(name, docValue(this, data)); CodeMirror.on(doc, "change", this.trackChange); return this.docs[name] = data; }, delDoc: function(id) { var found = resolveDoc(this, id); if (!found) return; CodeMirror.off(found.doc, "change", this.trackChange); delete this.docs[found.name]; this.server.delFile(found.name); }, hideDoc: function(id) { closeArgHints(this); var found = resolveDoc(this, id); if (found && found.changed) sendDoc(this, found); }, complete: function(cm) { cm.showHint({hint: this.getHint}); }, showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); }, showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); }, updateArgHints: function(cm) { updateArgHints(this, cm); }, jumpToDef: function(cm) { jumpToDef(this, cm); }, jumpBack: function(cm) { jumpBack(this, cm); }, rename: function(cm) { rename(this, cm); }, selectName: function(cm) { selectName(this, cm); }, request: function (cm, query, c, pos) { var self = this; var doc = findDoc(this, cm.getDoc()); var request = buildRequest(this, doc, query, pos); this.server.request(request, function (error, data) { if (!error && self.options.responseFilter) data = self.options.responseFilter(doc, query, request, error, data); c(error, data); }); }, destroy: function () { if (this.worker) { this.worker.terminate(); this.worker = null; } } }; var Pos = CodeMirror.Pos; var cls = "CodeMirror-Tern-"; var bigDoc = 250; function getFile(ts, name, c) { var buf = ts.docs[name]; if (buf) c(docValue(ts, buf)); else if (ts.options.getFile) ts.options.getFile(name, c); else c(null); } function findDoc(ts, doc, name) { for (var n in ts.docs) { var cur = ts.docs[n]; if (cur.doc == doc) return cur; } if (!name) for (var i = 0;; ++i) { n = "[doc" + (i || "") + "]"; if (!ts.docs[n]) { name = n; break; } } return ts.addDoc(name, doc); } function resolveDoc(ts, id) { if (typeof id == "string") return ts.docs[id]; if (id instanceof CodeMirror) id = id.getDoc(); if (id instanceof CodeMirror.Doc) return findDoc(ts, id); } function trackChange(ts, doc, change) { var data = findDoc(ts, doc); var argHints = ts.cachedArgHints; if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0) ts.cachedArgHints = null; var changed = data.changed; if (changed == null) data.changed = changed = {from: change.from.line, to: change.from.line}; var end = change.from.line + (change.text.length - 1); if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end); if (end >= changed.to) changed.to = end + 1; if (changed.from > change.from.line) changed.from = change.from.line; if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() { if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data); }, 200); } function sendDoc(ts, doc) { ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) { if (error) window.console.error(error); else doc.changed = null; }); } // Completion function hint(ts, cm, c) { ts.request(cm, {type: "completions", types: true, docs: true, urls: true, caseInsensitive: ts.options.caseInsensitive}, function(error, data) { if (error) return showError(ts, cm, error); var completions = [], after = ""; var from = data.start, to = data.end; if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" && cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]") after = "\"]"; for (var i = 0; i < data.completions.length; ++i) { var completion = data.completions[i], className = typeToIcon(completion.type); if (data.guess) className += " " + cls + "guess"; completions.push({text: completion.name + after, displayText: completion.name, className: className, data: completion}); } var obj = {from: from, to: to, list: completions}; var tooltip = null; CodeMirror.on(obj, "close", function() { remove(tooltip); }); CodeMirror.on(obj, "update", function() { remove(tooltip); }); CodeMirror.on(obj, "select", function(cur, node) { remove(tooltip); var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc; if (content) { tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset, node.getBoundingClientRect().top + window.pageYOffset, content); tooltip.className += " " + cls + "hint-doc"; } }); c(obj); }); } function typeToIcon(type) { var suffix; if (type == "?") suffix = "unknown"; else if (type == "number" || type == "string" || type == "bool") suffix = type; else if (/^fn\(/.test(type)) suffix = "fn"; else if (/^\[/.test(type)) suffix = "array"; else suffix = "object"; return cls + "completion " + cls + "completion-" + suffix; } // Type queries function showContextInfo(ts, cm, pos, queryName, c) { ts.request(cm, queryName, function(error, data) { if (error) return showError(ts, cm, error); if (ts.options.typeTip) { var tip = ts.options.typeTip(data); } else { var tip = elt("span", null, elt("strong", null, data.type || "not found")); if (data.doc) tip.appendChild(document.createTextNode(" — " + data.doc)); if (data.url) { tip.appendChild(document.createTextNode(" ")); var child = tip.appendChild(elt("a", null, "[docs]")); child.href = data.url; child.target = "_blank"; } } tempTooltip(cm, tip); if (c) c(); }, pos); } // Maintaining argument hints function updateArgHints(ts, cm) { closeArgHints(ts); if (cm.somethingSelected()) return; var state = cm.getTokenAt(cm.getCursor()).state; var inner = CodeMirror.innerMode(cm.getMode(), state); if (inner.mode.name != "javascript") return; var lex = inner.state.lexical; if (lex.info != "call") return; var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize"); for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { var str = cm.getLine(line), extra = 0; for (var pos = 0;;) { var tab = str.indexOf("\t", pos); if (tab == -1) break; extra += tabSize - (tab + extra) % tabSize - 1; pos = tab + 1; } ch = lex.column - extra; if (str.charAt(ch) == "(") {found = true; break;} } if (!found) return; var start = Pos(line, ch); var cache = ts.cachedArgHints; if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0) return showArgHints(ts, cm, argPos); ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { if (error || !data.type || !(/^fn\(/).test(data.type)) return; ts.cachedArgHints = { start: pos, type: parseFnType(data.type), name: data.exprName || data.name || "fn", guess: data.guess, doc: cm.getDoc() }; showArgHints(ts, cm, argPos); }); } function showArgHints(ts, cm, pos) { closeArgHints(ts); var cache = ts.cachedArgHints, tp = cache.type; var tip = elt("span", cache.guess ? cls + "fhint-guess" : null, elt("span", cls + "fname", cache.name), "("); for (var i = 0; i < tp.args.length; ++i) { if (i) tip.appendChild(document.createTextNode(", ")); var arg = tp.args[i]; tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?")); if (arg.type != "?") { tip.appendChild(document.createTextNode(":\u00a0")); tip.appendChild(elt("span", cls + "type", arg.type)); } } tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")")); if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype)); var place = cm.cursorCoords(null, "page"); ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip); } function parseFnType(text) { var args = [], pos = 3; function skipMatching(upto) { var depth = 0, start = pos; for (;;) { var next = text.charAt(pos); if (upto.test(next) && !depth) return text.slice(start, pos); if (/[{\[\(]/.test(next)) ++depth; else if (/[}\]\)]/.test(next)) --depth; ++pos; } } // Parse arguments if (text.charAt(pos) != ")") for (;;) { var name = text.slice(pos).match(/^([^, \(\[\{]+): /); if (name) { pos += name[0].length; name = name[1]; } args.push({name: name, type: skipMatching(/[\),]/)}); if (text.charAt(pos) == ")") break; pos += 2; } var rettype = text.slice(pos).match(/^\) -> (.*)$/); return {args: args, rettype: rettype && rettype[1]}; } // Moving to the definition of something function jumpToDef(ts, cm) { function inner(varName) { var req = {type: "definition", variable: varName || null}; var doc = findDoc(ts, cm.getDoc()); ts.server.request(buildRequest(ts, doc, req), function(error, data) { if (error) return showError(ts, cm, error); if (!data.file && data.url) { window.open(data.url); return; } if (data.file) { var localDoc = ts.docs[data.file], found; if (localDoc && (found = findContext(localDoc.doc, data))) { ts.jumpStack.push({file: doc.name, start: cm.getCursor("from"), end: cm.getCursor("to")}); moveTo(ts, doc, localDoc, found.start, found.end); return; } } showError(ts, cm, "Could not find a definition."); }); } if (!atInterestingExpression(cm)) dialog(cm, "Jump to variable", function(name) { if (name) inner(name); }); else inner(); } function jumpBack(ts, cm) { var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file]; if (!doc) return; moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end); } function moveTo(ts, curDoc, doc, start, end) { doc.doc.setSelection(start, end); if (curDoc != doc && ts.options.switchToDoc) { closeArgHints(ts); ts.options.switchToDoc(doc.name, doc.doc); } } // The {line,ch} representation of positions makes this rather awkward. function findContext(doc, data) { var before = data.context.slice(0, data.contextOffset).split("\n"); var startLine = data.start.line - (before.length - 1); var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length); var text = doc.getLine(startLine).slice(start.ch); for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur) text += "\n" + doc.getLine(cur); if (text.slice(0, data.context.length) == data.context) return data; var cursor = doc.getSearchCursor(data.context, 0, false); var nearest, nearestDist = Infinity; while (cursor.findNext()) { var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000; if (!dist) dist = Math.abs(from.ch - start.ch); if (dist < nearestDist) { nearest = from; nearestDist = dist; } } if (!nearest) return null; if (before.length == 1) nearest.ch += before[0].length; else nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length); if (data.start.line == data.end.line) var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch)); else var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch); return {start: nearest, end: end}; } function atInterestingExpression(cm) { var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos); if (tok.start < pos.ch && (tok.type == "comment" || tok.type == "string")) return false; return /[\w)\]]/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1)); } // Variable renaming function rename(ts, cm) { var token = cm.getTokenAt(cm.getCursor()); if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable"); dialog(cm, "New name for " + token.string, function(newName) { ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { if (error) return showError(ts, cm, error); applyChanges(ts, data.changes); }); }); } function selectName(ts, cm) { var name = findDoc(ts, cm.doc).name; ts.request(cm, {type: "refs"}, function(error, data) { if (error) return showError(ts, cm, error); var ranges = [], cur = 0; for (var i = 0; i < data.refs.length; i++) { var ref = data.refs[i]; if (ref.file == name) { ranges.push({anchor: ref.start, head: ref.end}); if (cmpPos(cur, ref.start) >= 0 && cmpPos(cur, ref.end) <= 0) cur = ranges.length - 1; } } cm.setSelections(ranges, cur); }); } var nextChangeOrig = 0; function applyChanges(ts, changes) { var perFile = Object.create(null); for (var i = 0; i < changes.length; ++i) { var ch = changes[i]; (perFile[ch.file] || (perFile[ch.file] = [])).push(ch); } for (var file in perFile) { var known = ts.docs[file], chs = perFile[file];; if (!known) continue; chs.sort(function(a, b) { return cmpPos(b.start, a.start); }); var origin = "*rename" + (++nextChangeOrig); for (var i = 0; i < chs.length; ++i) { var ch = chs[i]; known.doc.replaceRange(ch.text, ch.start, ch.end, origin); } } } // Generic request-building helper function buildRequest(ts, doc, query, pos) { var files = [], offsetLines = 0, allowFragments = !query.fullDocs; if (!allowFragments) delete query.fullDocs; if (typeof query == "string") query = {type: query}; query.lineCharPositions = true; if (query.end == null) { query.end = pos || doc.doc.getCursor("end"); if (doc.doc.somethingSelected()) query.start = doc.doc.getCursor("start"); } var startPos = query.start || query.end; if (doc.changed) { if (doc.doc.lineCount() > bigDoc && allowFragments !== false && doc.changed.to - doc.changed.from < 100 && doc.changed.from <= startPos.line && doc.changed.to > query.end.line) { files.push(getFragmentAround(doc, startPos, query.end)); query.file = "#0"; var offsetLines = files[0].offsetLines; if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch); query.end = Pos(query.end.line - offsetLines, query.end.ch); } else { files.push({type: "full", name: doc.name, text: docValue(ts, doc)}); query.file = doc.name; doc.changed = null; } } else { query.file = doc.name; } for (var name in ts.docs) { var cur = ts.docs[name]; if (cur.changed && cur != doc) { files.push({type: "full", name: cur.name, text: docValue(ts, cur)}); cur.changed = null; } } return {query: query, files: files}; } function getFragmentAround(data, start, end) { var doc = data.doc; var minIndent = null, minLine = null, endLine, tabSize = 4; for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) { var line = doc.getLine(p), fn = line.search(/\bfunction\b/); if (fn < 0) continue; var indent = CodeMirror.countColumn(line, null, tabSize); if (minIndent != null && minIndent <= indent) continue; minIndent = indent; minLine = p; } if (minLine == null) minLine = min; var max = Math.min(doc.lastLine(), end.line + 20); if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize)) endLine = max; else for (endLine = end.line + 1; endLine < max; ++endLine) { var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize); if (indent <= minIndent) break; } var from = Pos(minLine, 0); return {type: "part", name: data.name, offsetLines: from.line, text: doc.getRange(from, Pos(endLine, 0))}; } // Generic utilities var cmpPos = CodeMirror.cmpPos; function elt(tagname, cls /*, ... elts*/) { var e = document.createElement(tagname); if (cls) e.className = cls; for (var i = 2; i < arguments.length; ++i) { var elt = arguments[i]; if (typeof elt == "string") elt = document.createTextNode(elt); e.appendChild(elt); } return e; } function dialog(cm, text, f) { if (cm.openDialog) cm.openDialog(text + ": ", f); else f(prompt(text, "")); } // Tooltips function tempTooltip(cm, content) { if (cm.state.ternTooltip) remove(cm.state.ternTooltip); var where = cm.cursorCoords(); var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content); function maybeClear() { old = true; if (!mouseOnTip) clear(); } function clear() { cm.state.ternTooltip = null; if (!tip.parentNode) return; cm.off("cursorActivity", clear); cm.off('blur', clear); cm.off('scroll', clear); fadeOut(tip); } var mouseOnTip = false, old = false; CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; }); CodeMirror.on(tip, "mouseout", function(e) { if (!CodeMirror.contains(tip, e.relatedTarget || e.toElement)) { if (old) clear(); else mouseOnTip = false; } }); setTimeout(maybeClear, 1700); cm.on("cursorActivity", clear); cm.on('blur', clear); cm.on('scroll', clear); } function makeTooltip(x, y, content) { var node = elt("div", cls + "tooltip", content); node.style.left = x + "px"; node.style.top = y + "px"; document.body.appendChild(node); return node; } function remove(node) { var p = node && node.parentNode; if (p) p.removeChild(node); } function fadeOut(tooltip) { tooltip.style.opacity = "0"; setTimeout(function() { remove(tooltip); }, 1100); } function showError(ts, cm, msg) { if (ts.options.showError) ts.options.showError(cm, msg); else tempTooltip(cm, String(msg)); } function closeArgHints(ts) { if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; } } function docValue(ts, doc) { var val = doc.doc.getValue(); if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc); return val; } // Worker wrapper function WorkerServer(ts) { var worker = ts.worker = new Worker(ts.options.workerScript); worker.postMessage({type: "init", defs: ts.options.defs, plugins: ts.options.plugins, scripts: ts.options.workerDeps}); var msgId = 0, pending = {}; function send(data, c) { if (c) { data.id = ++msgId; pending[msgId] = c; } worker.postMessage(data); } worker.onmessage = function(e) { var data = e.data; if (data.type == "getFile") { getFile(ts, data.name, function(err, text) { send({type: "getFile", err: String(err), text: text, id: data.id}); }); } else if (data.type == "debug") { window.console.log(data.message); } else if (data.id && pending[data.id]) { pending[data.id](data.err, data.body); delete pending[data.id]; } }; worker.onerror = function(e) { for (var id in pending) pending[id](e); pending = {}; }; this.addFile = function(name, text) { send({type: "add", name: name, text: text}); }; this.delFile = function(name) { send({type: "del", name: name}); }; this.request = function(body, c) { send({type: "req", body: body}, c); }; } }); three.js-r73/editor/js/libs/codemirror/addon/show-hint.js0000644000175500017550000003352712610076566023331 0ustar debacledebacle// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { "use strict"; var HINT_ELEMENT_CLASS = "CodeMirror-hint"; var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; // This is the old interface, kept around for now to stay // backwards-compatible. CodeMirror.showHint = function(cm, getHints, options) { if (!getHints) return cm.showHint(options); if (options && options.async) getHints.async = true; var newOpts = {hint: getHints}; if (options) for (var prop in options) newOpts[prop] = options[prop]; return cm.showHint(newOpts); }; CodeMirror.defineExtension("showHint", function(options) { // We want a single cursor position. if (this.listSelections().length > 1 || this.somethingSelected()) return; if (this.state.completionActive) this.state.completionActive.close(); var completion = this.state.completionActive = new Completion(this, options); if (!completion.options.hint) return; CodeMirror.signal(this, "startCompletion", this); completion.update(true); }); function Completion(cm, options) { this.cm = cm; this.options = this.buildOptions(options); this.widget = null; this.debounce = 0; this.tick = 0; this.startPos = this.cm.getCursor(); this.startLen = this.cm.getLine(this.startPos.line).length; var self = this; cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); } var requestAnimationFrame = window.requestAnimationFrame || function(fn) { return setTimeout(fn, 1000/60); }; var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; Completion.prototype = { close: function() { if (!this.active()) return; this.cm.state.completionActive = null; this.tick = null; this.cm.off("cursorActivity", this.activityFunc); if (this.widget && this.data) CodeMirror.signal(this.data, "close"); if (this.widget) this.widget.close(); CodeMirror.signal(this.cm, "endCompletion", this.cm); }, active: function() { return this.cm.state.completionActive == this; }, pick: function(data, i) { var completion = data.list[i]; if (completion.hint) completion.hint(this.cm, data, completion); else this.cm.replaceRange(getText(completion), completion.from || data.from, completion.to || data.to, "complete"); CodeMirror.signal(data, "pick", completion); this.close(); }, cursorActivity: function() { if (this.debounce) { cancelAnimationFrame(this.debounce); this.debounce = 0; } var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || pos.ch < this.startPos.ch || this.cm.somethingSelected() || (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { this.close(); } else { var self = this; this.debounce = requestAnimationFrame(function() {self.update();}); if (this.widget) this.widget.disable(); } }, update: function(first) { if (this.tick == null) return; if (this.data) CodeMirror.signal(this.data, "update"); if (!this.options.hint.async) { this.finishUpdate(this.options.hint(this.cm, this.options), first); } else { var myTick = ++this.tick, self = this; this.options.hint(this.cm, function(data) { if (self.tick == myTick) self.finishUpdate(data, first); }, this.options); } }, finishUpdate: function(data, first) { this.data = data; var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); if (this.widget) this.widget.close(); if (data && data.list.length) { if (picked && data.list.length == 1) { this.pick(data, 0); } else { this.widget = new Widget(this, data); CodeMirror.signal(data, "shown"); } } }, buildOptions: function(options) { var editor = this.cm.options.hintOptions; var out = {}; for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; if (editor) for (var prop in editor) if (editor[prop] !== undefined) out[prop] = editor[prop]; if (options) for (var prop in options) if (options[prop] !== undefined) out[prop] = options[prop]; return out; } }; function getText(completion) { if (typeof completion == "string") return completion; else return completion.text; } function buildKeyMap(completion, handle) { var baseMap = { Up: function() {handle.moveFocus(-1);}, Down: function() {handle.moveFocus(1);}, PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, Home: function() {handle.setFocus(0);}, End: function() {handle.setFocus(handle.length - 1);}, Enter: handle.pick, Tab: handle.pick, Esc: handle.close }; var custom = completion.options.customKeys; var ourMap = custom ? {} : baseMap; function addBinding(key, val) { var bound; if (typeof val != "string") bound = function(cm) { return val(cm, handle); }; // This mechanism is deprecated else if (baseMap.hasOwnProperty(val)) bound = baseMap[val]; else bound = val; ourMap[key] = bound; } if (custom) for (var key in custom) if (custom.hasOwnProperty(key)) addBinding(key, custom[key]); var extra = completion.options.extraKeys; if (extra) for (var key in extra) if (extra.hasOwnProperty(key)) addBinding(key, extra[key]); return ourMap; } function getHintElement(hintsElement, el) { while (el && el != hintsElement) { if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; el = el.parentNode; } } function Widget(completion, data) { this.completion = completion; this.data = data; this.picked = false; var widget = this, cm = completion.cm; var hints = this.hints = document.createElement("ul"); hints.className = "CodeMirror-hints"; this.selectedHint = data.selectedHint || 0; var completions = data.list; for (var i = 0; i < completions.length; ++i) { var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); if (cur.className != null) className = cur.className + " " + className; elt.className = className; if (cur.render) cur.render(elt, data, cur); else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); elt.hintId = i; } var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); var left = pos.left, top = pos.bottom, below = true; hints.style.left = left + "px"; hints.style.top = top + "px"; // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); (completion.options.container || document.body).appendChild(hints); var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; if (overlapY > 0) { var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); if (curTop - height > 0) { // Fits above cursor hints.style.top = (top = pos.top - height) + "px"; below = false; } else if (height > winH) { hints.style.height = (winH - 5) + "px"; hints.style.top = (top = pos.bottom - box.top) + "px"; var cursor = cm.getCursor(); if (data.from.ch != cursor.ch) { pos = cm.cursorCoords(cursor); hints.style.left = (left = pos.left) + "px"; box = hints.getBoundingClientRect(); } } } var overlapX = box.right - winW; if (overlapX > 0) { if (box.right - box.left > winW) { hints.style.width = (winW - 5) + "px"; overlapX -= (box.right - box.left) - winW; } hints.style.left = (left = pos.left - overlapX) + "px"; } cm.addKeyMap(this.keyMap = buildKeyMap(completion, { moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, setFocus: function(n) { widget.changeActive(n); }, menuSize: function() { return widget.screenAmount(); }, length: completions.length, close: function() { completion.close(); }, pick: function() { widget.pick(); }, data: data })); if (completion.options.closeOnUnfocus) { var closingOnBlur; cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); } var startScroll = cm.getScrollInfo(); cm.on("scroll", this.onScroll = function() { var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); var newTop = top + startScroll.top - curScroll.top; var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); if (!below) point += hints.offsetHeight; if (point <= editor.top || point >= editor.bottom) return completion.close(); hints.style.top = newTop + "px"; hints.style.left = (left + startScroll.left - curScroll.left) + "px"; }); CodeMirror.on(hints, "dblclick", function(e) { var t = getHintElement(hints, e.target || e.srcElement); if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} }); CodeMirror.on(hints, "click", function(e) { var t = getHintElement(hints, e.target || e.srcElement); if (t && t.hintId != null) { widget.changeActive(t.hintId); if (completion.options.completeOnSingleClick) widget.pick(); } }); CodeMirror.on(hints, "mousedown", function() { setTimeout(function(){cm.focus();}, 20); }); CodeMirror.signal(data, "select", completions[0], hints.firstChild); return true; } Widget.prototype = { close: function() { if (this.completion.widget != this) return; this.completion.widget = null; this.hints.parentNode.removeChild(this.hints); this.completion.cm.removeKeyMap(this.keyMap); var cm = this.completion.cm; if (this.completion.options.closeOnUnfocus) { cm.off("blur", this.onBlur); cm.off("focus", this.onFocus); } cm.off("scroll", this.onScroll); }, disable: function() { this.completion.cm.removeKeyMap(this.keyMap); var widget = this; this.keyMap = {Enter: function() { widget.picked = true; }}; this.completion.cm.addKeyMap(this.keyMap); }, pick: function() { this.completion.pick(this.data, this.selectedHint); }, changeActive: function(i, avoidWrap) { if (i >= this.data.list.length) i = avoidWrap ? this.data.list.length - 1 : 0; else if (i < 0) i = avoidWrap ? 0 : this.data.list.length - 1; if (this.selectedHint == i) return; var node = this.hints.childNodes[this.selectedHint]; node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); node = this.hints.childNodes[this.selectedHint = i]; node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; if (node.offsetTop < this.hints.scrollTop) this.hints.scrollTop = node.offsetTop - 3; else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); }, screenAmount: function() { return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; } }; CodeMirror.registerHelper("hint", "auto", function(cm, options) { var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; if (helpers.length) { for (var i = 0; i < helpers.length; i++) { var cur = helpers[i](cm, options); if (cur && cur.list.length) return cur; } } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { if (words) return CodeMirror.hint.fromList(cm, {words: words}); } else if (CodeMirror.hint.anyword) { return CodeMirror.hint.anyword(cm, options); } }); CodeMirror.registerHelper("hint", "fromList", function(cm, options) { var cur = cm.getCursor(), token = cm.getTokenAt(cur); var found = []; for (var i = 0; i < options.words.length; i++) { var word = options.words[i]; if (word.slice(0, token.string.length) == token.string) found.push(word); } if (found.length) return { list: found, from: CodeMirror.Pos(cur.line, token.start), to: CodeMirror.Pos(cur.line, token.end) }; }); CodeMirror.commands.autocomplete = CodeMirror.showHint; var defaultOptions = { hint: CodeMirror.hint.auto, completeSingle: true, alignWithWord: true, closeCharacters: /[\s()\[\]{};:>,]/, closeOnUnfocus: true, completeOnSingleClick: false, container: null, customKeys: null, extraKeys: null }; CodeMirror.defineOption("hintOptions", null); }); three.js-r73/editor/js/libs/codemirror/addon/dialog.js0000644000175500017550000001151212610076566022636 0ustar debacledebacle// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE // Open simple dialogs on top of an editor. Relies on dialog.css. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { function dialogDiv(cm, template, bottom) { var wrap = cm.getWrapperElement(); var dialog; dialog = wrap.appendChild(document.createElement("div")); if (bottom) dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; else dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; if (typeof template == "string") { dialog.innerHTML = template; } else { // Assuming it's a detached DOM element. dialog.appendChild(template); } return dialog; } function closeNotification(cm, newVal) { if (cm.state.currentNotificationClose) cm.state.currentNotificationClose(); cm.state.currentNotificationClose = newVal; } CodeMirror.defineExtension("openDialog", function(template, callback, options) { if (!options) options = {}; closeNotification(this, null); var dialog = dialogDiv(this, template, options.bottom); var closed = false, me = this; function close(newVal) { if (typeof newVal == 'string') { inp.value = newVal; } else { if (closed) return; closed = true; dialog.parentNode.removeChild(dialog); me.focus(); if (options.onClose) options.onClose(dialog); } } var inp = dialog.getElementsByTagName("input")[0], button; if (inp) { if (options.value) { inp.value = options.value; if (options.selectValueOnOpen !== false) { inp.select(); } } if (options.onInput) CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); if (options.onKeyUp) CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); CodeMirror.on(inp, "keydown", function(e) { if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { inp.blur(); CodeMirror.e_stop(e); close(); } if (e.keyCode == 13) callback(inp.value, e); }); if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); inp.focus(); } else if (button = dialog.getElementsByTagName("button")[0]) { CodeMirror.on(button, "click", function() { close(); me.focus(); }); if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); button.focus(); } return close; }); CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { closeNotification(this, null); var dialog = dialogDiv(this, template, options && options.bottom); var buttons = dialog.getElementsByTagName("button"); var closed = false, me = this, blurring = 1; function close() { if (closed) return; closed = true; dialog.parentNode.removeChild(dialog); me.focus(); } buttons[0].focus(); for (var i = 0; i < buttons.length; ++i) { var b = buttons[i]; (function(callback) { CodeMirror.on(b, "click", function(e) { CodeMirror.e_preventDefault(e); close(); if (callback) callback(me); }); })(callbacks[i]); CodeMirror.on(b, "blur", function() { --blurring; setTimeout(function() { if (blurring <= 0) close(); }, 200); }); CodeMirror.on(b, "focus", function() { ++blurring; }); } }); /* * openNotification * Opens a notification, that can be closed with an optional timer * (default 5000ms timer) and always closes on click. * * If a notification is opened while another is opened, it will close the * currently opened one and open the new one immediately. */ CodeMirror.defineExtension("openNotification", function(template, options) { closeNotification(this, close); var dialog = dialogDiv(this, template, options && options.bottom); var closed = false, doneTimer; var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; function close() { if (closed) return; closed = true; clearTimeout(doneTimer); dialog.parentNode.removeChild(dialog); } CodeMirror.on(dialog, 'click', function(e) { CodeMirror.e_preventDefault(e); close(); }); if (duration) doneTimer = setTimeout(close, duration); return close; }); }); three.js-r73/editor/js/libs/codemirror/addon/show-hint.css0000644000175500017550000000122612610076566023474 0ustar debacledebacle.CodeMirror-hints { position: absolute; z-index: 10; overflow: hidden; list-style: none; margin: 0; padding: 2px; -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); box-shadow: 2px 3px 5px rgba(0,0,0,.2); border-radius: 3px; border: 1px solid silver; background: white; font-size: 90%; font-family: monospace; max-height: 20em; overflow-y: auto; } .CodeMirror-hint { margin: 0; padding: 0 4px; border-radius: 2px; max-width: 19em; overflow: hidden; white-space: pre; color: black; cursor: pointer; } li.CodeMirror-hint-active { background: #08f; color: white; } three.js-r73/editor/js/libs/codemirror/addon/dialog.css0000644000175500017550000000077312610076566023021 0ustar debacledebacle.CodeMirror-dialog { position: absolute; left: 0; right: 0; background: inherit; z-index: 15; padding: .1em .8em; overflow: hidden; color: inherit; } .CodeMirror-dialog-top { border-bottom: 1px solid #eee; top: 0; } .CodeMirror-dialog-bottom { border-top: 1px solid #eee; bottom: 0; } .CodeMirror-dialog input { border: none; outline: none; background: transparent; width: 20em; color: inherit; font-family: monospace; } .CodeMirror-dialog button { font-size: 70%; } three.js-r73/editor/js/libs/codemirror/addon/tern.css0000644000175500017550000000347412610076566022533 0ustar debacledebacle.CodeMirror-Tern-completion { padding-left: 22px; position: relative; } .CodeMirror-Tern-completion:before { position: absolute; left: 2px; bottom: 2px; border-radius: 50%; font-size: 12px; font-weight: bold; height: 15px; width: 15px; line-height: 16px; text-align: center; color: white; -moz-box-sizing: border-box; box-sizing: border-box; } .CodeMirror-Tern-completion-unknown:before { content: "?"; background: #4bb; } .CodeMirror-Tern-completion-object:before { content: "O"; background: #77c; } .CodeMirror-Tern-completion-fn:before { content: "F"; background: #7c7; } .CodeMirror-Tern-completion-array:before { content: "A"; background: #c66; } .CodeMirror-Tern-completion-number:before { content: "1"; background: #999; } .CodeMirror-Tern-completion-string:before { content: "S"; background: #999; } .CodeMirror-Tern-completion-bool:before { content: "B"; background: #999; } .CodeMirror-Tern-completion-guess { color: #999; } .CodeMirror-Tern-tooltip { border: 1px solid silver; border-radius: 3px; color: #444; padding: 2px 5px; font-size: 90%; font-family: monospace; background-color: white; white-space: pre-wrap; max-width: 40em; position: absolute; z-index: 10; -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); box-shadow: 2px 3px 5px rgba(0,0,0,.2); transition: opacity 1s; -moz-transition: opacity 1s; -webkit-transition: opacity 1s; -o-transition: opacity 1s; -ms-transition: opacity 1s; } .CodeMirror-Tern-hint-doc { max-width: 25em; margin-top: -3px; } .CodeMirror-Tern-fname { color: black; } .CodeMirror-Tern-farg { color: #70a; } .CodeMirror-Tern-farg-current { text-decoration: underline; } .CodeMirror-Tern-type { color: #07c; } .CodeMirror-Tern-fhint-guess { opacity: .7; } three.js-r73/editor/js/libs/codemirror/theme/0000755000175500017550000000000012610076566021056 5ustar debacledebaclethree.js-r73/editor/js/libs/codemirror/theme/monokai.css0000644000175500017550000000276412610076566023236 0ustar debacledebacle/* Based on Sublime Text's Monokai theme */ .cm-s-monokai.CodeMirror {background: #272822; color: #f8f8f2;} .cm-s-monokai div.CodeMirror-selected {background: #49483E !important;} .cm-s-monokai.CodeMirror ::selection { background: rgba(73, 72, 62, .99); } .cm-s-monokai.CodeMirror ::-moz-selection { background: rgba(73, 72, 62, .99); } .cm-s-monokai .CodeMirror-gutters {background: #272822; border-right: 0px;} .cm-s-monokai .CodeMirror-guttermarker { color: white; } .cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } .cm-s-monokai .CodeMirror-linenumber {color: #d0d0d0;} .cm-s-monokai .CodeMirror-cursor {border-left: 1px solid #f8f8f0 !important;} .cm-s-monokai span.cm-comment {color: #75715e;} .cm-s-monokai span.cm-atom {color: #ae81ff;} .cm-s-monokai span.cm-number {color: #ae81ff;} .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {color: #a6e22e;} .cm-s-monokai span.cm-keyword {color: #f92672;} .cm-s-monokai span.cm-string {color: #e6db74;} .cm-s-monokai span.cm-variable {color: #a6e22e;} .cm-s-monokai span.cm-variable-2 {color: #9effff;} .cm-s-monokai span.cm-def {color: #fd971f;} .cm-s-monokai span.cm-bracket {color: #f8f8f2;} .cm-s-monokai span.cm-tag {color: #f92672;} .cm-s-monokai span.cm-link {color: #ae81ff;} .cm-s-monokai span.cm-error {background: #f92672; color: #f8f8f0;} .cm-s-monokai .CodeMirror-activeline-background {background: #373831 !important;} .cm-s-monokai .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } three.js-r73/editor/js/libs/ui.three.js0000644000175500017550000001372212610076566017675 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ UI.Texture = function ( mapping ) { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'span' ); var input = document.createElement( 'input' ); input.type = 'file'; input.addEventListener( 'change', function ( event ) { loadFile( event.target.files[ 0 ] ); } ); var canvas = document.createElement( 'canvas' ); canvas.width = 32; canvas.height = 16; canvas.style.cursor = 'pointer'; canvas.style.marginRight = '5px'; canvas.style.border = '1px solid #888'; canvas.addEventListener( 'click', function ( event ) { input.click(); }, false ); canvas.addEventListener( 'drop', function ( event ) { event.preventDefault(); event.stopPropagation(); loadFile( event.dataTransfer.files[ 0 ] ); }, false ); dom.appendChild( canvas ); var name = document.createElement( 'input' ); name.disabled = true; name.style.width = '64px'; name.style.border = '1px solid #ccc'; dom.appendChild( name ); var loadFile = function ( file ) { if ( file.type.match( 'image.*' ) ) { var reader = new FileReader(); reader.addEventListener( 'load', function ( event ) { var image = document.createElement( 'img' ); image.addEventListener( 'load', function( event ) { var texture = new THREE.Texture( this, mapping ); texture.sourceFile = file.name; texture.needsUpdate = true; scope.setValue( texture ); if ( scope.onChangeCallback ) scope.onChangeCallback(); }, false ); image.src = event.target.result; }, false ); reader.readAsDataURL( file ); } } this.dom = dom; this.texture = null; this.onChangeCallback = null; return this; }; UI.Texture.prototype = Object.create( UI.Element.prototype ); UI.Texture.prototype.constructor = UI.Texture; UI.Texture.prototype.getValue = function () { return this.texture; }; UI.Texture.prototype.setValue = function ( texture ) { var canvas = this.dom.children[ 0 ]; var name = this.dom.children[ 1 ]; var context = canvas.getContext( '2d' ); if ( texture !== null ) { var image = texture.image; if ( image !== undefined && image.width > 0 ) { name.value = texture.sourceFile; var scale = canvas.width / image.width; context.drawImage( image, 0, 0, image.width * scale, image.height * scale ); } else { name.value = texture.sourceFile + ' (error)'; context.clearRect( 0, 0, canvas.width, canvas.height ); } } else { name.value = ''; context.clearRect( 0, 0, canvas.width, canvas.height ); } this.texture = texture; }; UI.Texture.prototype.onChange = function ( callback ) { this.onChangeCallback = callback; return this; }; // Outliner UI.Outliner = function ( editor ) { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'div' ); dom.className = 'Outliner'; dom.tabIndex = 0; // keyup event is ignored without setting tabIndex var scene = editor.scene; var sortable = Sortable.create( dom, { draggable: '.draggable', onUpdate: function ( event ) { var item = event.item; var object = scene.getObjectById( item.value ); if ( item.nextSibling === null ) { editor.moveObject( object, editor.scene ); } else { var nextObject = scene.getObjectById( item.nextSibling.value ); editor.moveObject( object, nextObject.parent, nextObject ); } } } ); // Broadcast for object selection after arrow navigation var changeEvent = document.createEvent('HTMLEvents'); changeEvent.initEvent( 'change', true, true ); // Prevent native scroll behavior dom.addEventListener( 'keydown', function (event) { switch ( event.keyCode ) { case 38: // up case 40: // down event.preventDefault(); event.stopPropagation(); break; } }, false); // Keybindings to support arrow navigation dom.addEventListener( 'keyup', function (event) { switch ( event.keyCode ) { case 38: // up case 40: // down scope.selectedIndex += ( event.keyCode == 38 ) ? -1 : 1; if ( scope.selectedIndex >= 0 && scope.selectedIndex < scope.options.length ) { // Highlight selected dom elem and scroll parent if needed scope.setValue( scope.options[ scope.selectedIndex ].value ); scope.dom.dispatchEvent( changeEvent ); } break; } }, false); this.dom = dom; this.options = []; this.selectedIndex = -1; this.selectedValue = null; return this; }; UI.Outliner.prototype = Object.create( UI.Element.prototype ); UI.Outliner.prototype.constructor = UI.Outliner; UI.Outliner.prototype.setOptions = function ( options ) { var scope = this; var changeEvent = document.createEvent( 'HTMLEvents' ); changeEvent.initEvent( 'change', true, true ); while ( scope.dom.children.length > 0 ) { scope.dom.removeChild( scope.dom.firstChild ); } scope.options = []; for ( var i = 0; i < options.length; i ++ ) { var option = options[ i ]; var div = document.createElement( 'div' ); div.className = 'option ' + ( option.static === true ? '': 'draggable' ); div.innerHTML = option.html; div.value = option.value; scope.dom.appendChild( div ); scope.options.push( div ); div.addEventListener( 'click', function ( event ) { scope.setValue( this.value ); scope.dom.dispatchEvent( changeEvent ); }, false ); } return scope; }; UI.Outliner.prototype.getValue = function () { return this.selectedValue; }; UI.Outliner.prototype.setValue = function ( value ) { for ( var i = 0; i < this.options.length; i ++ ) { var element = this.options[ i ]; if ( element.value === value ) { element.classList.add( 'active' ); // scroll into view var y = element.offsetTop - this.dom.offsetTop; var bottomY = y + element.offsetHeight; var minScroll = bottomY - this.dom.offsetHeight; if ( this.dom.scrollTop > y ) { this.dom.scrollTop = y } else if ( this.dom.scrollTop < minScroll ) { this.dom.scrollTop = minScroll; } this.selectedIndex = i; } else { element.classList.remove( 'active' ); } } this.selectedValue = value; return this; }; three.js-r73/editor/js/libs/acorn/0000755000175500017550000000000012640552061016701 5ustar debacledebaclethree.js-r73/editor/js/libs/tern-threejs/0000755000175500017550000000000012640552114020210 5ustar debacledebaclethree.js-r73/editor/js/libs/app.js0000644000175500017550000001313212610076566016725 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var APP = { Player: function () { var scope = this; var loader = new THREE.ObjectLoader(); var camera, scene, renderer; var vr, controls, effect; var events = {}; this.dom = undefined; this.width = 500; this.height = 500; this.load = function ( json ) { vr = json.project.vr; renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setClearColor( 0x000000 ); renderer.setPixelRatio( window.devicePixelRatio ); if ( json.project.shadows ) renderer.shadowMap.enabled = true; this.dom = renderer.domElement; this.setScene( loader.parse( json.scene ) ); this.setCamera( loader.parse( json.camera ) ); events = { init: [], start: [], stop: [], keydown: [], keyup: [], mousedown: [], mouseup: [], mousemove: [], touchstart: [], touchend: [], touchmove: [], update: [] }; var scriptWrapParams = 'player,renderer,scene'; var scriptWrapResultObj = {}; for ( var eventKey in events ) { scriptWrapParams += ',' + eventKey; scriptWrapResultObj[ eventKey ] = eventKey; } var scriptWrapResult = JSON.stringify( scriptWrapResultObj ).replace( /\"/g, '' ); for ( var uuid in json.scripts ) { var object = scene.getObjectByProperty( 'uuid', uuid, true ); var scripts = json.scripts[ uuid ]; for ( var i = 0; i < scripts.length; i ++ ) { var script = scripts[ i ]; var functions = ( new Function( scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult+ ';' ).bind( object ) )( this, renderer, scene ); for ( var name in functions ) { if ( functions[ name ] === undefined ) continue; if ( events[ name ] === undefined ) { console.warn( 'APP.Player: event type not supported (', name, ')' ); continue; } events[ name ].push( functions[ name ].bind( object ) ); } } } dispatch( events.init, arguments ); }; this.setCamera = function ( value ) { camera = value; camera.aspect = this.width / this.height; camera.updateProjectionMatrix(); if ( vr === true ) { if ( camera.parent === null ) { // camera needs to be in the scene so camera2 matrix updates scene.add( camera ); } var camera2 = camera.clone(); camera.add( camera2 ); camera = camera2; controls = new THREE.VRControls( camera ); effect = new THREE.VREffect( renderer ); document.addEventListener( 'keyup', function ( event ) { switch ( event.keyCode ) { case 90: controls.zeroSensor(); break; } } ); this.dom.addEventListener( 'dblclick', function () { effect.setFullScreen( true ); } ); } }; this.setScene = function ( value ) { scene = value; }, this.setSize = function ( width, height ) { if ( renderer._fullScreen ) return; this.width = width; this.height = height; camera.aspect = this.width / this.height; camera.updateProjectionMatrix(); renderer.setSize( width, height ); }; function dispatch( array, event ) { for ( var i = 0, l = array.length; i < l; i ++ ) { try { array[ i ]( event ); } catch (e) { console.error( ( e.message || e ), ( e.stack || "" ) ); } } } var prevTime, request; function animate( time ) { request = requestAnimationFrame( animate ); dispatch( events.update, { time: time, delta: time - prevTime } ); if ( vr === true ) { controls.update(); effect.render( scene, camera ); } else { renderer.render( scene, camera ); } prevTime = time; } this.play = function () { document.addEventListener( 'keydown', onDocumentKeyDown ); document.addEventListener( 'keyup', onDocumentKeyUp ); document.addEventListener( 'mousedown', onDocumentMouseDown ); document.addEventListener( 'mouseup', onDocumentMouseUp ); document.addEventListener( 'mousemove', onDocumentMouseMove ); document.addEventListener( 'touchstart', onDocumentTouchStart ); document.addEventListener( 'touchend', onDocumentTouchEnd ); document.addEventListener( 'touchmove', onDocumentTouchMove ); dispatch( events.start, arguments ); request = requestAnimationFrame( animate ); prevTime = ( window.performance || Date ).now(); }; this.stop = function () { document.removeEventListener( 'keydown', onDocumentKeyDown ); document.removeEventListener( 'keyup', onDocumentKeyUp ); document.removeEventListener( 'mousedown', onDocumentMouseDown ); document.removeEventListener( 'mouseup', onDocumentMouseUp ); document.removeEventListener( 'mousemove', onDocumentMouseMove ); document.removeEventListener( 'touchstart', onDocumentTouchStart ); document.removeEventListener( 'touchend', onDocumentTouchEnd ); document.removeEventListener( 'touchmove', onDocumentTouchMove ); dispatch( events.stop, arguments ); cancelAnimationFrame( request ); }; // function onDocumentKeyDown( event ) { dispatch( events.keydown, event ); } function onDocumentKeyUp( event ) { dispatch( events.keyup, event ); } function onDocumentMouseDown( event ) { dispatch( events.mousedown, event ); } function onDocumentMouseUp( event ) { dispatch( events.mouseup, event ); } function onDocumentMouseMove( event ) { dispatch( events.mousemove, event ); } function onDocumentTouchStart( event ) { dispatch( events.touchstart, event ); } function onDocumentTouchEnd( event ) { dispatch( events.touchend, event ); } function onDocumentTouchMove( event ) { dispatch( events.touchmove, event ); } } }; three.js-r73/editor/js/libs/esprima.js0000644000175500017550000040466112610076566017620 0ustar debacledebacle/* Copyright (C) 2013 Ariya Hidayat Copyright (C) 2013 Thaddee Tyl Copyright (C) 2013 Mathias Bynens Copyright (C) 2012 Ariya Hidayat Copyright (C) 2012 Mathias Bynens Copyright (C) 2012 Joost-Wim Boekesteijn Copyright (C) 2012 Kris Kowal Copyright (C) 2012 Yusuke Suzuki Copyright (C) 2012 Arpad Borsos Copyright (C) 2011 Ariya Hidayat Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function (root, factory) { 'use strict'; // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, // Rhino, and plain browser loading. /* istanbul ignore next */ if (typeof define === 'function' && define.amd) { define(['exports'], factory); } else if (typeof exports !== 'undefined') { factory(exports); } else { factory((root.esprima = {})); } }(this, function (exports) { 'use strict'; var Token, TokenName, FnExprTokens, Syntax, PlaceHolders, PropertyKind, Messages, Regex, source, strict, index, lineNumber, lineStart, length, lookahead, state, extra; Token = { BooleanLiteral: 1, EOF: 2, Identifier: 3, Keyword: 4, NullLiteral: 5, NumericLiteral: 6, Punctuator: 7, StringLiteral: 8, RegularExpression: 9 }; TokenName = {}; TokenName[Token.BooleanLiteral] = 'Boolean'; TokenName[Token.EOF] = ''; TokenName[Token.Identifier] = 'Identifier'; TokenName[Token.Keyword] = 'Keyword'; TokenName[Token.NullLiteral] = 'Null'; TokenName[Token.NumericLiteral] = 'Numeric'; TokenName[Token.Punctuator] = 'Punctuator'; TokenName[Token.StringLiteral] = 'String'; TokenName[Token.RegularExpression] = 'RegularExpression'; // A function following one of those tokens is an expression. FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', 'return', 'case', 'delete', 'throw', 'void', // assignment operators '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', '&=', '|=', '^=', ',', // binary/unary operators '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', '<=', '<', '>', '!=', '!==']; Syntax = { AssignmentExpression: 'AssignmentExpression', ArrayExpression: 'ArrayExpression', ArrowFunctionExpression: 'ArrowFunctionExpression', BlockStatement: 'BlockStatement', BinaryExpression: 'BinaryExpression', BreakStatement: 'BreakStatement', CallExpression: 'CallExpression', CatchClause: 'CatchClause', ConditionalExpression: 'ConditionalExpression', ContinueStatement: 'ContinueStatement', DoWhileStatement: 'DoWhileStatement', DebuggerStatement: 'DebuggerStatement', EmptyStatement: 'EmptyStatement', ExpressionStatement: 'ExpressionStatement', ForStatement: 'ForStatement', ForInStatement: 'ForInStatement', FunctionDeclaration: 'FunctionDeclaration', FunctionExpression: 'FunctionExpression', Identifier: 'Identifier', IfStatement: 'IfStatement', Literal: 'Literal', LabeledStatement: 'LabeledStatement', LogicalExpression: 'LogicalExpression', MemberExpression: 'MemberExpression', NewExpression: 'NewExpression', ObjectExpression: 'ObjectExpression', Program: 'Program', Property: 'Property', ReturnStatement: 'ReturnStatement', SequenceExpression: 'SequenceExpression', SwitchStatement: 'SwitchStatement', SwitchCase: 'SwitchCase', ThisExpression: 'ThisExpression', ThrowStatement: 'ThrowStatement', TryStatement: 'TryStatement', UnaryExpression: 'UnaryExpression', UpdateExpression: 'UpdateExpression', VariableDeclaration: 'VariableDeclaration', VariableDeclarator: 'VariableDeclarator', WhileStatement: 'WhileStatement', WithStatement: 'WithStatement' }; PlaceHolders = { ArrowParameterPlaceHolder: { type: 'ArrowParameterPlaceHolder' } }; PropertyKind = { Data: 1, Get: 2, Set: 4 }; // Error messages should be identical to V8. Messages = { UnexpectedToken: 'Unexpected token %0', UnexpectedNumber: 'Unexpected number', UnexpectedString: 'Unexpected string', UnexpectedIdentifier: 'Unexpected identifier', UnexpectedReserved: 'Unexpected reserved word', UnexpectedEOS: 'Unexpected end of input', NewlineAfterThrow: 'Illegal newline after throw', InvalidRegExp: 'Invalid regular expression', UnterminatedRegExp: 'Invalid regular expression: missing /', InvalidLHSInAssignment: 'Invalid left-hand side in assignment', InvalidLHSInForIn: 'Invalid left-hand side in for-in', MultipleDefaultsInSwitch: 'More than one default clause in switch statement', NoCatchOrFinally: 'Missing catch or finally after try', UnknownLabel: 'Undefined label \'%0\'', Redeclaration: '%0 \'%1\' has already been declared', IllegalContinue: 'Illegal continue statement', IllegalBreak: 'Illegal break statement', IllegalReturn: 'Illegal return statement', StrictModeWith: 'Strict mode code may not include a with statement', StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', StrictVarName: 'Variable name may not be eval or arguments in strict mode', StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', StrictParamDupe: 'Strict mode function may not have duplicate parameter names', StrictFunctionName: 'Function name may not be eval or arguments in strict mode', StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', StrictDelete: 'Delete of an unqualified identifier in strict mode.', StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', StrictReservedWord: 'Use of future reserved word in strict mode' }; // See also tools/generate-unicode-regex.py. Regex = { NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'), NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') }; // Ensure the condition is true, otherwise throw an error. // This is only to have a better contract semantic, i.e. another safety net // to catch a logic error. The condition shall be fulfilled in normal case. // Do NOT use this to enforce a certain condition on any user input. function assert(condition, message) { /* istanbul ignore if */ if (!condition) { throw new Error('ASSERT: ' + message); } } function isDecimalDigit(ch) { return (ch >= 0x30 && ch <= 0x39); // 0..9 } function isHexDigit(ch) { return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; } function isOctalDigit(ch) { return '01234567'.indexOf(ch) >= 0; } // 7.2 White Space function isWhiteSpace(ch) { return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); } // 7.3 Line Terminators function isLineTerminator(ch) { return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); } // 7.6 Identifier Names and Identifiers function isIdentifierStart(ch) { return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) (ch >= 0x41 && ch <= 0x5A) || // A..Z (ch >= 0x61 && ch <= 0x7A) || // a..z (ch === 0x5C) || // \ (backslash) ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); } function isIdentifierPart(ch) { return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) (ch >= 0x41 && ch <= 0x5A) || // A..Z (ch >= 0x61 && ch <= 0x7A) || // a..z (ch >= 0x30 && ch <= 0x39) || // 0..9 (ch === 0x5C) || // \ (backslash) ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); } // 7.6.1.2 Future Reserved Words function isFutureReservedWord(id) { switch (id) { case 'class': case 'enum': case 'export': case 'extends': case 'import': case 'super': return true; default: return false; } } function isStrictModeReservedWord(id) { switch (id) { case 'implements': case 'interface': case 'package': case 'private': case 'protected': case 'public': case 'static': case 'yield': case 'let': return true; default: return false; } } function isRestrictedWord(id) { return id === 'eval' || id === 'arguments'; } // 7.6.1.1 Keywords function isKeyword(id) { if (strict && isStrictModeReservedWord(id)) { return true; } // 'const' is specialized as Keyword in V8. // 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next. // Some others are from future reserved words. switch (id.length) { case 2: return (id === 'if') || (id === 'in') || (id === 'do'); case 3: return (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try') || (id === 'let'); case 4: return (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with') || (id === 'enum'); case 5: return (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw') || (id === 'const') || (id === 'yield') || (id === 'class') || (id === 'super'); case 6: return (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch') || (id === 'export') || (id === 'import'); case 7: return (id === 'default') || (id === 'finally') || (id === 'extends'); case 8: return (id === 'function') || (id === 'continue') || (id === 'debugger'); case 10: return (id === 'instanceof'); default: return false; } } // 7.4 Comments function addComment(type, value, start, end, loc) { var comment; assert(typeof start === 'number', 'Comment must have valid position'); // Because the way the actual token is scanned, often the comments // (if any) are skipped twice during the lexical analysis. // Thus, we need to skip adding a comment if the comment array already // handled it. if (state.lastCommentStart >= start) { return; } state.lastCommentStart = start; comment = { type: type, value: value }; if (extra.range) { comment.range = [start, end]; } if (extra.loc) { comment.loc = loc; } extra.comments.push(comment); if (extra.attachComment) { extra.leadingComments.push(comment); extra.trailingComments.push(comment); } } function skipSingleLineComment(offset) { var start, loc, ch, comment; start = index - offset; loc = { start: { line: lineNumber, column: index - lineStart - offset } }; while (index < length) { ch = source.charCodeAt(index); ++index; if (isLineTerminator(ch)) { if (extra.comments) { comment = source.slice(start + offset, index - 1); loc.end = { line: lineNumber, column: index - lineStart - 1 }; addComment('Line', comment, start, index - 1, loc); } if (ch === 13 && source.charCodeAt(index) === 10) { ++index; } ++lineNumber; lineStart = index; return; } } if (extra.comments) { comment = source.slice(start + offset, index); loc.end = { line: lineNumber, column: index - lineStart }; addComment('Line', comment, start, index, loc); } } function skipMultiLineComment() { var start, loc, ch, comment; if (extra.comments) { start = index - 2; loc = { start: { line: lineNumber, column: index - lineStart - 2 } }; } while (index < length) { ch = source.charCodeAt(index); if (isLineTerminator(ch)) { if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) { ++index; } ++lineNumber; ++index; lineStart = index; if (index >= length) { throwUnexpectedToken(); } } else if (ch === 0x2A) { // Block comment ends with '*/'. if (source.charCodeAt(index + 1) === 0x2F) { ++index; ++index; if (extra.comments) { comment = source.slice(start + 2, index - 2); loc.end = { line: lineNumber, column: index - lineStart }; addComment('Block', comment, start, index, loc); } return; } ++index; } else { ++index; } } throwUnexpectedToken(); } function skipComment() { var ch, start; start = (index === 0); while (index < length) { ch = source.charCodeAt(index); if (isWhiteSpace(ch)) { ++index; } else if (isLineTerminator(ch)) { ++index; if (ch === 0x0D && source.charCodeAt(index) === 0x0A) { ++index; } ++lineNumber; lineStart = index; start = true; } else if (ch === 0x2F) { // U+002F is '/' ch = source.charCodeAt(index + 1); if (ch === 0x2F) { ++index; ++index; skipSingleLineComment(2); start = true; } else if (ch === 0x2A) { // U+002A is '*' ++index; ++index; skipMultiLineComment(); } else { break; } } else if (start && ch === 0x2D) { // U+002D is '-' // U+003E is '>' if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) { // '-->' is a single-line comment index += 3; skipSingleLineComment(3); } else { break; } } else if (ch === 0x3C) { // U+003C is '<' if (source.slice(index + 1, index + 4) === '!--') { ++index; // `<` ++index; // `!` ++index; // `-` ++index; // `-` skipSingleLineComment(4); } else { break; } } else { break; } } } function scanHexEscape(prefix) { var i, len, ch, code = 0; len = (prefix === 'u') ? 4 : 2; for (i = 0; i < len; ++i) { if (index < length && isHexDigit(source[index])) { ch = source[index++]; code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); } else { return ''; } } return String.fromCharCode(code); } function scanUnicodeCodePointEscape() { var ch, code, cu1, cu2; ch = source[index]; code = 0; // At least, one hex digit is required. if (ch === '}') { throwUnexpectedToken(); } while (index < length) { ch = source[index++]; if (!isHexDigit(ch)) { break; } code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); } if (code > 0x10FFFF || ch !== '}') { throwUnexpectedToken(); } // UTF-16 Encoding if (code <= 0xFFFF) { return String.fromCharCode(code); } cu1 = ((code - 0x10000) >> 10) + 0xD800; cu2 = ((code - 0x10000) & 1023) + 0xDC00; return String.fromCharCode(cu1, cu2); } function getEscapedIdentifier() { var ch, id; ch = source.charCodeAt(index++); id = String.fromCharCode(ch); // '\u' (U+005C, U+0075) denotes an escaped character. if (ch === 0x5C) { if (source.charCodeAt(index) !== 0x75) { throwUnexpectedToken(); } ++index; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { throwUnexpectedToken(); } id = ch; } while (index < length) { ch = source.charCodeAt(index); if (!isIdentifierPart(ch)) { break; } ++index; id += String.fromCharCode(ch); // '\u' (U+005C, U+0075) denotes an escaped character. if (ch === 0x5C) { id = id.substr(0, id.length - 1); if (source.charCodeAt(index) !== 0x75) { throwUnexpectedToken(); } ++index; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { throwUnexpectedToken(); } id += ch; } } return id; } function getIdentifier() { var start, ch; start = index++; while (index < length) { ch = source.charCodeAt(index); if (ch === 0x5C) { // Blackslash (U+005C) marks Unicode escape sequence. index = start; return getEscapedIdentifier(); } if (isIdentifierPart(ch)) { ++index; } else { break; } } return source.slice(start, index); } function scanIdentifier() { var start, id, type; start = index; // Backslash (U+005C) starts an escaped character. id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier(); // There is no keyword or literal with only one character. // Thus, it must be an identifier. if (id.length === 1) { type = Token.Identifier; } else if (isKeyword(id)) { type = Token.Keyword; } else if (id === 'null') { type = Token.NullLiteral; } else if (id === 'true' || id === 'false') { type = Token.BooleanLiteral; } else { type = Token.Identifier; } return { type: type, value: id, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } // 7.7 Punctuators function scanPunctuator() { var start = index, code = source.charCodeAt(index), code2, ch1 = source[index], ch2, ch3, ch4; switch (code) { // Check for most common single-character punctuators. case 0x2E: // . dot case 0x28: // ( open bracket case 0x29: // ) close bracket case 0x3B: // ; semicolon case 0x2C: // , comma case 0x7B: // { open curly brace case 0x7D: // } close curly brace case 0x5B: // [ case 0x5D: // ] case 0x3A: // : case 0x3F: // ? case 0x7E: // ~ ++index; if (extra.tokenize) { if (code === 0x28) { extra.openParenToken = extra.tokens.length; } else if (code === 0x7B) { extra.openCurlyToken = extra.tokens.length; } } return { type: Token.Punctuator, value: String.fromCharCode(code), lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; default: code2 = source.charCodeAt(index + 1); // '=' (U+003D) marks an assignment or comparison operator. if (code2 === 0x3D) { switch (code) { case 0x2B: // + case 0x2D: // - case 0x2F: // / case 0x3C: // < case 0x3E: // > case 0x5E: // ^ case 0x7C: // | case 0x25: // % case 0x26: // & case 0x2A: // * index += 2; return { type: Token.Punctuator, value: String.fromCharCode(code) + String.fromCharCode(code2), lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; case 0x21: // ! case 0x3D: // = index += 2; // !== and === if (source.charCodeAt(index) === 0x3D) { ++index; } return { type: Token.Punctuator, value: source.slice(start, index), lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } } } // 4-character punctuator: >>>= ch4 = source.substr(index, 4); if (ch4 === '>>>=') { index += 4; return { type: Token.Punctuator, value: ch4, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } // 3-character punctuators: === !== >>> <<= >>= ch3 = ch4.substr(0, 3); if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { index += 3; return { type: Token.Punctuator, value: ch3, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } // Other 2-character punctuators: ++ -- << >> && || ch2 = ch3.substr(0, 2); if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') { index += 2; return { type: Token.Punctuator, value: ch2, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } // 1-character punctuators: < > = ! + - * % & | ^ / if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { ++index; return { type: Token.Punctuator, value: ch1, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } throwUnexpectedToken(); } // 7.8.3 Numeric Literals function scanHexLiteral(start) { var number = ''; while (index < length) { if (!isHexDigit(source[index])) { break; } number += source[index++]; } if (number.length === 0) { throwUnexpectedToken(); } if (isIdentifierStart(source.charCodeAt(index))) { throwUnexpectedToken(); } return { type: Token.NumericLiteral, value: parseInt('0x' + number, 16), lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } function scanBinaryLiteral(start) { var ch, number; number = ''; while (index < length) { ch = source[index]; if (ch !== '0' && ch !== '1') { break; } number += source[index++]; } if (number.length === 0) { // only 0b or 0B throwUnexpectedToken(); } if (index < length) { ch = source.charCodeAt(index); /* istanbul ignore else */ if (isIdentifierStart(ch) || isDecimalDigit(ch)) { throwUnexpectedToken(); } } return { type: Token.NumericLiteral, value: parseInt(number, 2), lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } function scanOctalLiteral(prefix, start) { var number, octal; if (isOctalDigit(prefix)) { octal = true; number = '0' + source[index++]; } else { octal = false; ++index; number = ''; } while (index < length) { if (!isOctalDigit(source[index])) { break; } number += source[index++]; } if (!octal && number.length === 0) { // only 0o or 0O throwUnexpectedToken(); } if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { throwUnexpectedToken(); } return { type: Token.NumericLiteral, value: parseInt(number, 8), octal: octal, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } function isImplicitOctalLiteral() { var i, ch; // Implicit octal, unless there is a non-octal digit. // (Annex B.1.1 on Numeric Literals) for (i = index + 1; i < length; ++i) { ch = source[i]; if (ch === '8' || ch === '9') { return false; } if (!isOctalDigit(ch)) { return true; } } return true; } function scanNumericLiteral() { var number, start, ch; ch = source[index]; assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), 'Numeric literal must start with a decimal digit or a decimal point'); start = index; number = ''; if (ch !== '.') { number = source[index++]; ch = source[index]; // Hex number starts with '0x'. // Octal number starts with '0'. // Octal number in ES6 starts with '0o'. // Binary number in ES6 starts with '0b'. if (number === '0') { if (ch === 'x' || ch === 'X') { ++index; return scanHexLiteral(start); } if (ch === 'b' || ch === 'B') { ++index; return scanBinaryLiteral(start); } if (ch === 'o' || ch === 'O') { return scanOctalLiteral(ch, start); } if (isOctalDigit(ch)) { if (isImplicitOctalLiteral()) { return scanOctalLiteral(ch, start); } } } while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } ch = source[index]; } if (ch === '.') { number += source[index++]; while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } ch = source[index]; } if (ch === 'e' || ch === 'E') { number += source[index++]; ch = source[index]; if (ch === '+' || ch === '-') { number += source[index++]; } if (isDecimalDigit(source.charCodeAt(index))) { while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } } else { throwUnexpectedToken(); } } if (isIdentifierStart(source.charCodeAt(index))) { throwUnexpectedToken(); } return { type: Token.NumericLiteral, value: parseFloat(number), lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } // 7.8.4 String Literals function scanStringLiteral() { var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart; startLineNumber = lineNumber; startLineStart = lineStart; quote = source[index]; assert((quote === '\'' || quote === '"'), 'String literal must starts with a quote'); start = index; ++index; while (index < length) { ch = source[index++]; if (ch === quote) { quote = ''; break; } else if (ch === '\\') { ch = source[index++]; if (!ch || !isLineTerminator(ch.charCodeAt(0))) { switch (ch) { case 'u': case 'x': if (source[index] === '{') { ++index; str += scanUnicodeCodePointEscape(); } else { restore = index; unescaped = scanHexEscape(ch); if (unescaped) { str += unescaped; } else { index = restore; str += ch; } } break; case 'n': str += '\n'; break; case 'r': str += '\r'; break; case 't': str += '\t'; break; case 'b': str += '\b'; break; case 'f': str += '\f'; break; case 'v': str += '\x0B'; break; default: if (isOctalDigit(ch)) { code = '01234567'.indexOf(ch); // \0 is not octal escape sequence if (code !== 0) { octal = true; } if (index < length && isOctalDigit(source[index])) { octal = true; code = code * 8 + '01234567'.indexOf(source[index++]); // 3 digits are only allowed when string starts // with 0, 1, 2, 3 if ('0123'.indexOf(ch) >= 0 && index < length && isOctalDigit(source[index])) { code = code * 8 + '01234567'.indexOf(source[index++]); } } str += String.fromCharCode(code); } else { str += ch; } break; } } else { ++lineNumber; if (ch === '\r' && source[index] === '\n') { ++index; } lineStart = index; } } else if (isLineTerminator(ch.charCodeAt(0))) { break; } else { str += ch; } } if (quote !== '') { throwUnexpectedToken(); } return { type: Token.StringLiteral, value: str, octal: octal, startLineNumber: startLineNumber, startLineStart: startLineStart, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } function testRegExp(pattern, flags) { var tmp = pattern, value; if (flags.indexOf('u') >= 0) { // Replace each astral symbol and every Unicode code point // escape sequence with a single ASCII symbol to avoid throwing on // regular expressions that are only valid in combination with the // `/u` flag. // Note: replacing with the ASCII symbol `x` might cause false // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a // perfectly valid pattern that is equivalent to `[a-b]`, but it // would be replaced by `[x-b]` which throws an error. tmp = tmp .replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) { if (parseInt($1, 16) <= 0x10FFFF) { return 'x'; } throwError(Messages.InvalidRegExp); }) .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x'); } // First, detect invalid regular expressions. try { value = new RegExp(tmp); } catch (e) { throwError(Messages.InvalidRegExp); } // Return a regular expression object for this pattern-flag pair, or // `null` in case the current environment doesn't support the flags it // uses. try { return new RegExp(pattern, flags); } catch (exception) { return null; } } function scanRegExpBody() { var ch, str, classMarker, terminated, body; ch = source[index]; assert(ch === '/', 'Regular expression literal must start with a slash'); str = source[index++]; classMarker = false; terminated = false; while (index < length) { ch = source[index++]; str += ch; if (ch === '\\') { ch = source[index++]; // ECMA-262 7.8.5 if (isLineTerminator(ch.charCodeAt(0))) { throwError(Messages.UnterminatedRegExp); } str += ch; } else if (isLineTerminator(ch.charCodeAt(0))) { throwError(Messages.UnterminatedRegExp); } else if (classMarker) { if (ch === ']') { classMarker = false; } } else { if (ch === '/') { terminated = true; break; } else if (ch === '[') { classMarker = true; } } } if (!terminated) { throwError(Messages.UnterminatedRegExp); } // Exclude leading and trailing slash. body = str.substr(1, str.length - 2); return { value: body, literal: str }; } function scanRegExpFlags() { var ch, str, flags, restore; str = ''; flags = ''; while (index < length) { ch = source[index]; if (!isIdentifierPart(ch.charCodeAt(0))) { break; } ++index; if (ch === '\\' && index < length) { ch = source[index]; if (ch === 'u') { ++index; restore = index; ch = scanHexEscape('u'); if (ch) { flags += ch; for (str += '\\u'; restore < index; ++restore) { str += source[restore]; } } else { index = restore; flags += 'u'; str += '\\u'; } tolerateUnexpectedToken(); } else { str += '\\'; tolerateUnexpectedToken(); } } else { flags += ch; str += ch; } } return { value: flags, literal: str }; } function scanRegExp() { var start, body, flags, value; lookahead = null; skipComment(); start = index; body = scanRegExpBody(); flags = scanRegExpFlags(); value = testRegExp(body.value, flags.value); if (extra.tokenize) { return { type: Token.RegularExpression, value: value, regex: { pattern: body.value, flags: flags.value }, lineNumber: lineNumber, lineStart: lineStart, start: start, end: index }; } return { literal: body.literal + flags.literal, value: value, regex: { pattern: body.value, flags: flags.value }, start: start, end: index }; } function collectRegex() { var pos, loc, regex, token; skipComment(); pos = index; loc = { start: { line: lineNumber, column: index - lineStart } }; regex = scanRegExp(); loc.end = { line: lineNumber, column: index - lineStart }; /* istanbul ignore next */ if (!extra.tokenize) { // Pop the previous token, which is likely '/' or '/=' if (extra.tokens.length > 0) { token = extra.tokens[extra.tokens.length - 1]; if (token.range[0] === pos && token.type === 'Punctuator') { if (token.value === '/' || token.value === '/=') { extra.tokens.pop(); } } } extra.tokens.push({ type: 'RegularExpression', value: regex.literal, regex: regex.regex, range: [pos, index], loc: loc }); } return regex; } function isIdentifierName(token) { return token.type === Token.Identifier || token.type === Token.Keyword || token.type === Token.BooleanLiteral || token.type === Token.NullLiteral; } function advanceSlash() { var prevToken, checkToken; // Using the following algorithm: // https://github.com/mozilla/sweet.js/wiki/design prevToken = extra.tokens[extra.tokens.length - 1]; if (!prevToken) { // Nothing before that: it cannot be a division. return collectRegex(); } if (prevToken.type === 'Punctuator') { if (prevToken.value === ']') { return scanPunctuator(); } if (prevToken.value === ')') { checkToken = extra.tokens[extra.openParenToken - 1]; if (checkToken && checkToken.type === 'Keyword' && (checkToken.value === 'if' || checkToken.value === 'while' || checkToken.value === 'for' || checkToken.value === 'with')) { return collectRegex(); } return scanPunctuator(); } if (prevToken.value === '}') { // Dividing a function by anything makes little sense, // but we have to check for that. if (extra.tokens[extra.openCurlyToken - 3] && extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { // Anonymous function. checkToken = extra.tokens[extra.openCurlyToken - 4]; if (!checkToken) { return scanPunctuator(); } } else if (extra.tokens[extra.openCurlyToken - 4] && extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { // Named function. checkToken = extra.tokens[extra.openCurlyToken - 5]; if (!checkToken) { return collectRegex(); } } else { return scanPunctuator(); } // checkToken determines whether the function is // a declaration or an expression. if (FnExprTokens.indexOf(checkToken.value) >= 0) { // It is an expression. return scanPunctuator(); } // It is a declaration. return collectRegex(); } return collectRegex(); } if (prevToken.type === 'Keyword' && prevToken.value !== 'this') { return collectRegex(); } return scanPunctuator(); } function advance() { var ch; skipComment(); if (index >= length) { return { type: Token.EOF, lineNumber: lineNumber, lineStart: lineStart, start: index, end: index }; } ch = source.charCodeAt(index); if (isIdentifierStart(ch)) { return scanIdentifier(); } // Very common: ( and ) and ; if (ch === 0x28 || ch === 0x29 || ch === 0x3B) { return scanPunctuator(); } // String literal starts with single quote (U+0027) or double quote (U+0022). if (ch === 0x27 || ch === 0x22) { return scanStringLiteral(); } // Dot (.) U+002E can also start a floating-point number, hence the need // to check the next character. if (ch === 0x2E) { if (isDecimalDigit(source.charCodeAt(index + 1))) { return scanNumericLiteral(); } return scanPunctuator(); } if (isDecimalDigit(ch)) { return scanNumericLiteral(); } // Slash (/) U+002F can also start a regex. if (extra.tokenize && ch === 0x2F) { return advanceSlash(); } return scanPunctuator(); } function collectToken() { var loc, token, value, entry; skipComment(); loc = { start: { line: lineNumber, column: index - lineStart } }; token = advance(); loc.end = { line: lineNumber, column: index - lineStart }; if (token.type !== Token.EOF) { value = source.slice(token.start, token.end); entry = { type: TokenName[token.type], value: value, range: [token.start, token.end], loc: loc }; if (token.regex) { entry.regex = { pattern: token.regex.pattern, flags: token.regex.flags }; } extra.tokens.push(entry); } return token; } function lex() { var token; token = lookahead; index = token.end; lineNumber = token.lineNumber; lineStart = token.lineStart; lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); index = token.end; lineNumber = token.lineNumber; lineStart = token.lineStart; return token; } function peek() { var pos, line, start; pos = index; line = lineNumber; start = lineStart; lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); index = pos; lineNumber = line; lineStart = start; } function Position() { this.line = lineNumber; this.column = index - lineStart; } function SourceLocation() { this.start = new Position(); this.end = null; } function WrappingSourceLocation(startToken) { if (startToken.type === Token.StringLiteral) { this.start = { line: startToken.startLineNumber, column: startToken.start - startToken.startLineStart }; } else { this.start = { line: startToken.lineNumber, column: startToken.start - startToken.lineStart }; } this.end = null; } function Node() { // Skip comment. index = lookahead.start; if (lookahead.type === Token.StringLiteral) { lineNumber = lookahead.startLineNumber; lineStart = lookahead.startLineStart; } else { lineNumber = lookahead.lineNumber; lineStart = lookahead.lineStart; } if (extra.range) { this.range = [index, 0]; } if (extra.loc) { this.loc = new SourceLocation(); } } function WrappingNode(startToken) { if (extra.range) { this.range = [startToken.start, 0]; } if (extra.loc) { this.loc = new WrappingSourceLocation(startToken); } } WrappingNode.prototype = Node.prototype = { processComment: function () { var lastChild, leadingComments, trailingComments, bottomRight = extra.bottomRightStack, i, comment, last = bottomRight[bottomRight.length - 1]; if (this.type === Syntax.Program) { if (this.body.length > 0) { return; } } if (extra.trailingComments.length > 0) { trailingComments = []; for (i = extra.trailingComments.length - 1; i >= 0; --i) { comment = extra.trailingComments[i]; if (comment.range[0] >= this.range[1]) { trailingComments.unshift(comment); extra.trailingComments.splice(i, 1); } } extra.trailingComments = []; } else { if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) { trailingComments = last.trailingComments; delete last.trailingComments; } } // Eating the stack. if (last) { while (last && last.range[0] >= this.range[0]) { lastChild = last; last = bottomRight.pop(); } } if (lastChild) { if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= this.range[0]) { this.leadingComments = lastChild.leadingComments; lastChild.leadingComments = undefined; } } else if (extra.leadingComments.length > 0) { leadingComments = []; for (i = extra.leadingComments.length - 1; i >= 0; --i) { comment = extra.leadingComments[i]; if (comment.range[1] <= this.range[0]) { leadingComments.unshift(comment); extra.leadingComments.splice(i, 1); } } } if (leadingComments && leadingComments.length > 0) { this.leadingComments = leadingComments; } if (trailingComments && trailingComments.length > 0) { this.trailingComments = trailingComments; } bottomRight.push(this); }, finish: function () { if (extra.range) { this.range[1] = index; } if (extra.loc) { this.loc.end = new Position(); if (extra.source) { this.loc.source = extra.source; } } if (extra.attachComment) { this.processComment(); } }, finishArrayExpression: function (elements) { this.type = Syntax.ArrayExpression; this.elements = elements; this.finish(); return this; }, finishArrowFunctionExpression: function (params, defaults, body, expression) { this.type = Syntax.ArrowFunctionExpression; this.id = null; this.params = params; this.defaults = defaults; this.body = body; this.rest = null; this.generator = false; this.expression = expression; this.finish(); return this; }, finishAssignmentExpression: function (operator, left, right) { this.type = Syntax.AssignmentExpression; this.operator = operator; this.left = left; this.right = right; this.finish(); return this; }, finishBinaryExpression: function (operator, left, right) { this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression; this.operator = operator; this.left = left; this.right = right; this.finish(); return this; }, finishBlockStatement: function (body) { this.type = Syntax.BlockStatement; this.body = body; this.finish(); return this; }, finishBreakStatement: function (label) { this.type = Syntax.BreakStatement; this.label = label; this.finish(); return this; }, finishCallExpression: function (callee, args) { this.type = Syntax.CallExpression; this.callee = callee; this.arguments = args; this.finish(); return this; }, finishCatchClause: function (param, body) { this.type = Syntax.CatchClause; this.param = param; this.body = body; this.finish(); return this; }, finishConditionalExpression: function (test, consequent, alternate) { this.type = Syntax.ConditionalExpression; this.test = test; this.consequent = consequent; this.alternate = alternate; this.finish(); return this; }, finishContinueStatement: function (label) { this.type = Syntax.ContinueStatement; this.label = label; this.finish(); return this; }, finishDebuggerStatement: function () { this.type = Syntax.DebuggerStatement; this.finish(); return this; }, finishDoWhileStatement: function (body, test) { this.type = Syntax.DoWhileStatement; this.body = body; this.test = test; this.finish(); return this; }, finishEmptyStatement: function () { this.type = Syntax.EmptyStatement; this.finish(); return this; }, finishExpressionStatement: function (expression) { this.type = Syntax.ExpressionStatement; this.expression = expression; this.finish(); return this; }, finishForStatement: function (init, test, update, body) { this.type = Syntax.ForStatement; this.init = init; this.test = test; this.update = update; this.body = body; this.finish(); return this; }, finishForInStatement: function (left, right, body) { this.type = Syntax.ForInStatement; this.left = left; this.right = right; this.body = body; this.each = false; this.finish(); return this; }, finishFunctionDeclaration: function (id, params, defaults, body) { this.type = Syntax.FunctionDeclaration; this.id = id; this.params = params; this.defaults = defaults; this.body = body; this.rest = null; this.generator = false; this.expression = false; this.finish(); return this; }, finishFunctionExpression: function (id, params, defaults, body) { this.type = Syntax.FunctionExpression; this.id = id; this.params = params; this.defaults = defaults; this.body = body; this.rest = null; this.generator = false; this.expression = false; this.finish(); return this; }, finishIdentifier: function (name) { this.type = Syntax.Identifier; this.name = name; this.finish(); return this; }, finishIfStatement: function (test, consequent, alternate) { this.type = Syntax.IfStatement; this.test = test; this.consequent = consequent; this.alternate = alternate; this.finish(); return this; }, finishLabeledStatement: function (label, body) { this.type = Syntax.LabeledStatement; this.label = label; this.body = body; this.finish(); return this; }, finishLiteral: function (token) { this.type = Syntax.Literal; this.value = token.value; this.raw = source.slice(token.start, token.end); if (token.regex) { this.regex = token.regex; } this.finish(); return this; }, finishMemberExpression: function (accessor, object, property) { this.type = Syntax.MemberExpression; this.computed = accessor === '['; this.object = object; this.property = property; this.finish(); return this; }, finishNewExpression: function (callee, args) { this.type = Syntax.NewExpression; this.callee = callee; this.arguments = args; this.finish(); return this; }, finishObjectExpression: function (properties) { this.type = Syntax.ObjectExpression; this.properties = properties; this.finish(); return this; }, finishPostfixExpression: function (operator, argument) { this.type = Syntax.UpdateExpression; this.operator = operator; this.argument = argument; this.prefix = false; this.finish(); return this; }, finishProgram: function (body) { this.type = Syntax.Program; this.body = body; this.finish(); return this; }, finishProperty: function (kind, key, value, method, shorthand) { this.type = Syntax.Property; this.key = key; this.value = value; this.kind = kind; this.method = method; this.shorthand = shorthand; this.finish(); return this; }, finishReturnStatement: function (argument) { this.type = Syntax.ReturnStatement; this.argument = argument; this.finish(); return this; }, finishSequenceExpression: function (expressions) { this.type = Syntax.SequenceExpression; this.expressions = expressions; this.finish(); return this; }, finishSwitchCase: function (test, consequent) { this.type = Syntax.SwitchCase; this.test = test; this.consequent = consequent; this.finish(); return this; }, finishSwitchStatement: function (discriminant, cases) { this.type = Syntax.SwitchStatement; this.discriminant = discriminant; this.cases = cases; this.finish(); return this; }, finishThisExpression: function () { this.type = Syntax.ThisExpression; this.finish(); return this; }, finishThrowStatement: function (argument) { this.type = Syntax.ThrowStatement; this.argument = argument; this.finish(); return this; }, finishTryStatement: function (block, guardedHandlers, handlers, finalizer) { this.type = Syntax.TryStatement; this.block = block; this.guardedHandlers = guardedHandlers; this.handlers = handlers; this.finalizer = finalizer; this.finish(); return this; }, finishUnaryExpression: function (operator, argument) { this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression; this.operator = operator; this.argument = argument; this.prefix = true; this.finish(); return this; }, finishVariableDeclaration: function (declarations, kind) { this.type = Syntax.VariableDeclaration; this.declarations = declarations; this.kind = kind; this.finish(); return this; }, finishVariableDeclarator: function (id, init) { this.type = Syntax.VariableDeclarator; this.id = id; this.init = init; this.finish(); return this; }, finishWhileStatement: function (test, body) { this.type = Syntax.WhileStatement; this.test = test; this.body = body; this.finish(); return this; }, finishWithStatement: function (object, body) { this.type = Syntax.WithStatement; this.object = object; this.body = body; this.finish(); return this; } }; // Return true if there is a line terminator before the next token. function peekLineTerminator() { var pos, line, start, found; pos = index; line = lineNumber; start = lineStart; skipComment(); found = lineNumber !== line; index = pos; lineNumber = line; lineStart = start; return found; } function createError(line, pos, description) { var error = new Error('Line ' + line + ': ' + description); error.index = pos; error.lineNumber = line; error.column = pos - lineStart + 1; error.description = description; return error; } // Throw an exception function throwError(messageFormat) { var args, msg; args = Array.prototype.slice.call(arguments, 1); msg = messageFormat.replace(/%(\d)/g, function (whole, idx) { assert(idx < args.length, 'Message reference must be in range'); return args[idx]; } ); throw createError(lineNumber, index, msg); } function tolerateError(messageFormat) { var args, msg, error; args = Array.prototype.slice.call(arguments, 1); /* istanbul ignore next */ msg = messageFormat.replace(/%(\d)/g, function (whole, idx) { assert(idx < args.length, 'Message reference must be in range'); return args[idx]; } ); error = createError(lineNumber, index, msg); if (extra.errors) { extra.errors.push(error); } else { throw error; } } // Throw an exception because of the token. function unexpectedTokenError(token, message) { var msg = Messages.UnexpectedToken; if (token) { msg = message ? message : (token.type === Token.EOF) ? Messages.UnexpectedEOS : (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier : (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber : (token.type === Token.StringLiteral) ? Messages.UnexpectedString : Messages.UnexpectedToken; if (token.type === Token.Keyword) { if (isFutureReservedWord(token.value)) { msg = Messages.UnexpectedReserved; } else if (strict && isStrictModeReservedWord(token.value)) { msg = Messages.StrictReservedWord; } } } msg = msg.replace('%0', token ? token.value : 'ILLEGAL'); return (token && typeof token.lineNumber === 'number') ? createError(token.lineNumber, token.start, msg) : createError(lineNumber, index, msg); } function throwUnexpectedToken(token, message) { throw unexpectedTokenError(token, message); } function tolerateUnexpectedToken(token, message) { var error = unexpectedTokenError(token, message); if (extra.errors) { extra.errors.push(error); } else { throw error; } } // Expect the next token to match the specified punctuator. // If not, an exception will be thrown. function expect(value) { var token = lex(); if (token.type !== Token.Punctuator || token.value !== value) { throwUnexpectedToken(token); } } /** * @name expectCommaSeparator * @description Quietly expect a comma when in tolerant mode, otherwise delegates * to expect(value) * @since 2.0 */ function expectCommaSeparator() { var token; if (extra.errors) { token = lookahead; if (token.type === Token.Punctuator && token.value === ',') { lex(); } else if (token.type === Token.Punctuator && token.value === ';') { lex(); tolerateUnexpectedToken(token); } else { tolerateUnexpectedToken(token, Messages.UnexpectedToken); } } else { expect(','); } } // Expect the next token to match the specified keyword. // If not, an exception will be thrown. function expectKeyword(keyword) { var token = lex(); if (token.type !== Token.Keyword || token.value !== keyword) { throwUnexpectedToken(token); } } // Return true if the next token matches the specified punctuator. function match(value) { return lookahead.type === Token.Punctuator && lookahead.value === value; } // Return true if the next token matches the specified keyword function matchKeyword(keyword) { return lookahead.type === Token.Keyword && lookahead.value === keyword; } // Return true if the next token is an assignment operator function matchAssign() { var op; if (lookahead.type !== Token.Punctuator) { return false; } op = lookahead.value; return op === '=' || op === '*=' || op === '/=' || op === '%=' || op === '+=' || op === '-=' || op === '<<=' || op === '>>=' || op === '>>>=' || op === '&=' || op === '^=' || op === '|='; } function consumeSemicolon() { var line, oldIndex = index, oldLineNumber = lineNumber, oldLineStart = lineStart, oldLookahead = lookahead; // Catch the very common case first: immediately a semicolon (U+003B). if (source.charCodeAt(index) === 0x3B || match(';')) { lex(); return; } line = lineNumber; skipComment(); if (lineNumber !== line) { index = oldIndex; lineNumber = oldLineNumber; lineStart = oldLineStart; lookahead = oldLookahead; return; } if (lookahead.type !== Token.EOF && !match('}')) { throwUnexpectedToken(lookahead); } } // Return true if provided expression is LeftHandSideExpression function isLeftHandSide(expr) { return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; } // 11.1.4 Array Initialiser function parseArrayInitialiser() { var elements = [], node = new Node(); expect('['); while (!match(']')) { if (match(',')) { lex(); elements.push(null); } else { elements.push(parseAssignmentExpression()); if (!match(']')) { expect(','); } } } lex(); return node.finishArrayExpression(elements); } // 11.1.5 Object Initialiser function parsePropertyFunction(param, first) { var previousStrict, body, node = new Node(); previousStrict = strict; body = parseFunctionSourceElements(); if (first && strict && isRestrictedWord(param[0].name)) { tolerateUnexpectedToken(first, Messages.StrictParamName); } strict = previousStrict; return node.finishFunctionExpression(null, param, [], body); } function parsePropertyMethodFunction() { var previousStrict, param, method; previousStrict = strict; strict = true; param = parseParams(); method = parsePropertyFunction(param.params); strict = previousStrict; return method; } function parseObjectPropertyKey() { var token, node = new Node(); token = lex(); // Note: This function is called only from parseObjectProperty(), where // EOF and Punctuator tokens are already filtered out. if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { if (strict && token.octal) { tolerateUnexpectedToken(token, Messages.StrictOctalLiteral); } return node.finishLiteral(token); } return node.finishIdentifier(token.value); } function parseObjectProperty() { var token, key, id, value, param, node = new Node(); token = lookahead; if (token.type === Token.Identifier) { id = parseObjectPropertyKey(); // Property Assignment: Getter and Setter. if (token.value === 'get' && !(match(':') || match('('))) { key = parseObjectPropertyKey(); expect('('); expect(')'); value = parsePropertyFunction([]); return node.finishProperty('get', key, value, false, false); } if (token.value === 'set' && !(match(':') || match('('))) { key = parseObjectPropertyKey(); expect('('); token = lookahead; if (token.type !== Token.Identifier) { expect(')'); tolerateUnexpectedToken(token); value = parsePropertyFunction([]); } else { param = [ parseVariableIdentifier() ]; expect(')'); value = parsePropertyFunction(param, token); } return node.finishProperty('set', key, value, false, false); } if (match(':')) { lex(); value = parseAssignmentExpression(); return node.finishProperty('init', id, value, false, false); } if (match('(')) { value = parsePropertyMethodFunction(); return node.finishProperty('init', id, value, true, false); } value = id; return node.finishProperty('init', id, value, false, true); } if (token.type === Token.EOF || token.type === Token.Punctuator) { throwUnexpectedToken(token); } else { key = parseObjectPropertyKey(); if (match(':')) { lex(); value = parseAssignmentExpression(); return node.finishProperty('init', key, value, false, false); } if (match('(')) { value = parsePropertyMethodFunction(); return node.finishProperty('init', key, value, true, false); } throwUnexpectedToken(lex()); } } function parseObjectInitialiser() { var properties = [], property, name, key, kind, map = {}, toString = String, node = new Node(); expect('{'); while (!match('}')) { property = parseObjectProperty(); if (property.key.type === Syntax.Identifier) { name = property.key.name; } else { name = toString(property.key.value); } kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; key = '$' + name; if (Object.prototype.hasOwnProperty.call(map, key)) { if (map[key] === PropertyKind.Data) { if (strict && kind === PropertyKind.Data) { tolerateError(Messages.StrictDuplicateProperty); } else if (kind !== PropertyKind.Data) { tolerateError(Messages.AccessorDataProperty); } } else { if (kind === PropertyKind.Data) { tolerateError(Messages.AccessorDataProperty); } else if (map[key] & kind) { tolerateError(Messages.AccessorGetSet); } } map[key] |= kind; } else { map[key] = kind; } properties.push(property); if (!match('}')) { expectCommaSeparator(); } } expect('}'); return node.finishObjectExpression(properties); } // 11.1.6 The Grouping Operator function parseGroupExpression() { var expr; expect('('); if (match(')')) { lex(); return PlaceHolders.ArrowParameterPlaceHolder; } ++state.parenthesisCount; expr = parseExpression(); expect(')'); return expr; } // 11.1 Primary Expressions function parsePrimaryExpression() { var type, token, expr, node; if (match('(')) { return parseGroupExpression(); } if (match('[')) { return parseArrayInitialiser(); } if (match('{')) { return parseObjectInitialiser(); } type = lookahead.type; node = new Node(); if (type === Token.Identifier) { expr = node.finishIdentifier(lex().value); } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { if (strict && lookahead.octal) { tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral); } expr = node.finishLiteral(lex()); } else if (type === Token.Keyword) { if (matchKeyword('function')) { return parseFunctionExpression(); } if (matchKeyword('this')) { lex(); expr = node.finishThisExpression(); } else { throwUnexpectedToken(lex()); } } else if (type === Token.BooleanLiteral) { token = lex(); token.value = (token.value === 'true'); expr = node.finishLiteral(token); } else if (type === Token.NullLiteral) { token = lex(); token.value = null; expr = node.finishLiteral(token); } else if (match('/') || match('/=')) { if (typeof extra.tokens !== 'undefined') { expr = node.finishLiteral(collectRegex()); } else { expr = node.finishLiteral(scanRegExp()); } peek(); } else { throwUnexpectedToken(lex()); } return expr; } // 11.2 Left-Hand-Side Expressions function parseArguments() { var args = []; expect('('); if (!match(')')) { while (index < length) { args.push(parseAssignmentExpression()); if (match(')')) { break; } expectCommaSeparator(); } } expect(')'); return args; } function parseNonComputedProperty() { var token, node = new Node(); token = lex(); if (!isIdentifierName(token)) { throwUnexpectedToken(token); } return node.finishIdentifier(token.value); } function parseNonComputedMember() { expect('.'); return parseNonComputedProperty(); } function parseComputedMember() { var expr; expect('['); expr = parseExpression(); expect(']'); return expr; } function parseNewExpression() { var callee, args, node = new Node(); expectKeyword('new'); callee = parseLeftHandSideExpression(); args = match('(') ? parseArguments() : []; return node.finishNewExpression(callee, args); } function parseLeftHandSideExpressionAllowCall() { var expr, args, property, startToken, previousAllowIn = state.allowIn; startToken = lookahead; state.allowIn = true; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); for (;;) { if (match('.')) { property = parseNonComputedMember(); expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); } else if (match('(')) { args = parseArguments(); expr = new WrappingNode(startToken).finishCallExpression(expr, args); } else if (match('[')) { property = parseComputedMember(); expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); } else { break; } } state.allowIn = previousAllowIn; return expr; } function parseLeftHandSideExpression() { var expr, property, startToken; assert(state.allowIn, 'callee of new expression always allow in keyword.'); startToken = lookahead; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); for (;;) { if (match('[')) { property = parseComputedMember(); expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); } else if (match('.')) { property = parseNonComputedMember(); expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); } else { break; } } return expr; } // 11.3 Postfix Expressions function parsePostfixExpression() { var expr, token, startToken = lookahead; expr = parseLeftHandSideExpressionAllowCall(); if (lookahead.type === Token.Punctuator) { if ((match('++') || match('--')) && !peekLineTerminator()) { // 11.3.1, 11.3.2 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { tolerateError(Messages.StrictLHSPostfix); } if (!isLeftHandSide(expr)) { tolerateError(Messages.InvalidLHSInAssignment); } token = lex(); expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr); } } return expr; } // 11.4 Unary Operators function parseUnaryExpression() { var token, expr, startToken; if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { expr = parsePostfixExpression(); } else if (match('++') || match('--')) { startToken = lookahead; token = lex(); expr = parseUnaryExpression(); // 11.4.4, 11.4.5 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { tolerateError(Messages.StrictLHSPrefix); } if (!isLeftHandSide(expr)) { tolerateError(Messages.InvalidLHSInAssignment); } expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); } else if (match('+') || match('-') || match('~') || match('!')) { startToken = lookahead; token = lex(); expr = parseUnaryExpression(); expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { startToken = lookahead; token = lex(); expr = parseUnaryExpression(); expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { tolerateError(Messages.StrictDelete); } } else { expr = parsePostfixExpression(); } return expr; } function binaryPrecedence(token, allowIn) { var prec = 0; if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { return 0; } switch (token.value) { case '||': prec = 1; break; case '&&': prec = 2; break; case '|': prec = 3; break; case '^': prec = 4; break; case '&': prec = 5; break; case '==': case '!=': case '===': case '!==': prec = 6; break; case '<': case '>': case '<=': case '>=': case 'instanceof': prec = 7; break; case 'in': prec = allowIn ? 7 : 0; break; case '<<': case '>>': case '>>>': prec = 8; break; case '+': case '-': prec = 9; break; case '*': case '/': case '%': prec = 11; break; default: break; } return prec; } // 11.5 Multiplicative Operators // 11.6 Additive Operators // 11.7 Bitwise Shift Operators // 11.8 Relational Operators // 11.9 Equality Operators // 11.10 Binary Bitwise Operators // 11.11 Binary Logical Operators function parseBinaryExpression() { var marker, markers, expr, token, prec, stack, right, operator, left, i; marker = lookahead; left = parseUnaryExpression(); if (left === PlaceHolders.ArrowParameterPlaceHolder) { return left; } token = lookahead; prec = binaryPrecedence(token, state.allowIn); if (prec === 0) { return left; } token.prec = prec; lex(); markers = [marker, lookahead]; right = parseUnaryExpression(); stack = [left, token, right]; while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { // Reduce: make a binary expression from the three topmost entries. while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { right = stack.pop(); operator = stack.pop().value; left = stack.pop(); markers.pop(); expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right); stack.push(expr); } // Shift. token = lex(); token.prec = prec; stack.push(token); markers.push(lookahead); expr = parseUnaryExpression(); stack.push(expr); } // Final reduce to clean-up the stack. i = stack.length - 1; expr = stack[i]; markers.pop(); while (i > 1) { expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr); i -= 2; } return expr; } // 11.12 Conditional Operator function parseConditionalExpression() { var expr, previousAllowIn, consequent, alternate, startToken; startToken = lookahead; expr = parseBinaryExpression(); if (expr === PlaceHolders.ArrowParameterPlaceHolder) { return expr; } if (match('?')) { lex(); previousAllowIn = state.allowIn; state.allowIn = true; consequent = parseAssignmentExpression(); state.allowIn = previousAllowIn; expect(':'); alternate = parseAssignmentExpression(); expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate); } return expr; } // [ES6] 14.2 Arrow Function function parseConciseBody() { if (match('{')) { return parseFunctionSourceElements(); } return parseAssignmentExpression(); } function reinterpretAsCoverFormalsList(expressions) { var i, len, param, params, defaults, defaultCount, options, rest, token; params = []; defaults = []; defaultCount = 0; rest = null; options = { paramSet: {} }; for (i = 0, len = expressions.length; i < len; i += 1) { param = expressions[i]; if (param.type === Syntax.Identifier) { params.push(param); defaults.push(null); validateParam(options, param, param.name); } else if (param.type === Syntax.AssignmentExpression) { params.push(param.left); defaults.push(param.right); ++defaultCount; validateParam(options, param.left, param.left.name); } else { return null; } } if (options.message === Messages.StrictParamDupe) { token = strict ? options.stricted : options.firstRestricted; throwUnexpectedToken(token, options.message); } if (defaultCount === 0) { defaults = []; } return { params: params, defaults: defaults, rest: rest, stricted: options.stricted, firstRestricted: options.firstRestricted, message: options.message }; } function parseArrowFunctionExpression(options, node) { var previousStrict, body; expect('=>'); previousStrict = strict; body = parseConciseBody(); if (strict && options.firstRestricted) { throwUnexpectedToken(options.firstRestricted, options.message); } if (strict && options.stricted) { tolerateUnexpectedToken(options.stricted, options.message); } strict = previousStrict; return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement); } // 11.13 Assignment Operators function parseAssignmentExpression() { var oldParenthesisCount, token, expr, right, list, startToken; oldParenthesisCount = state.parenthesisCount; startToken = lookahead; token = lookahead; expr = parseConditionalExpression(); if (expr === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) { if (state.parenthesisCount === oldParenthesisCount || state.parenthesisCount === (oldParenthesisCount + 1)) { if (expr.type === Syntax.Identifier) { list = reinterpretAsCoverFormalsList([ expr ]); } else if (expr.type === Syntax.AssignmentExpression) { list = reinterpretAsCoverFormalsList([ expr ]); } else if (expr.type === Syntax.SequenceExpression) { list = reinterpretAsCoverFormalsList(expr.expressions); } else if (expr === PlaceHolders.ArrowParameterPlaceHolder) { list = reinterpretAsCoverFormalsList([]); } if (list) { return parseArrowFunctionExpression(list, new WrappingNode(startToken)); } } } if (matchAssign()) { // LeftHandSideExpression if (!isLeftHandSide(expr)) { tolerateError(Messages.InvalidLHSInAssignment); } // 11.13.1 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { tolerateUnexpectedToken(token, Messages.StrictLHSAssignment); } token = lex(); right = parseAssignmentExpression(); expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right); } return expr; } // 11.14 Comma Operator function parseExpression() { var expr, startToken = lookahead, expressions; expr = parseAssignmentExpression(); if (match(',')) { expressions = [expr]; while (index < length) { if (!match(',')) { break; } lex(); expressions.push(parseAssignmentExpression()); } expr = new WrappingNode(startToken).finishSequenceExpression(expressions); } return expr; } // 12.1 Block function parseStatementList() { var list = [], statement; while (index < length) { if (match('}')) { break; } statement = parseSourceElement(); if (typeof statement === 'undefined') { break; } list.push(statement); } return list; } function parseBlock() { var block, node = new Node(); expect('{'); block = parseStatementList(); expect('}'); return node.finishBlockStatement(block); } // 12.2 Variable Statement function parseVariableIdentifier() { var token, node = new Node(); token = lex(); if (token.type !== Token.Identifier) { if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) { tolerateUnexpectedToken(token, Messages.StrictReservedWord); } else { throwUnexpectedToken(token); } } return node.finishIdentifier(token.value); } function parseVariableDeclaration(kind) { var init = null, id, node = new Node(); id = parseVariableIdentifier(); // 12.2.1 if (strict && isRestrictedWord(id.name)) { tolerateError(Messages.StrictVarName); } if (kind === 'const') { expect('='); init = parseAssignmentExpression(); } else if (match('=')) { lex(); init = parseAssignmentExpression(); } return node.finishVariableDeclarator(id, init); } function parseVariableDeclarationList(kind) { var list = []; do { list.push(parseVariableDeclaration(kind)); if (!match(',')) { break; } lex(); } while (index < length); return list; } function parseVariableStatement(node) { var declarations; expectKeyword('var'); declarations = parseVariableDeclarationList(); consumeSemicolon(); return node.finishVariableDeclaration(declarations, 'var'); } // kind may be `const` or `let` // Both are experimental and not in the specification yet. // see http://wiki.ecmascript.org/doku.php?id=harmony:const // and http://wiki.ecmascript.org/doku.php?id=harmony:let function parseConstLetDeclaration(kind) { var declarations, node = new Node(); expectKeyword(kind); declarations = parseVariableDeclarationList(kind); consumeSemicolon(); return node.finishVariableDeclaration(declarations, kind); } // 12.3 Empty Statement function parseEmptyStatement() { var node = new Node(); expect(';'); return node.finishEmptyStatement(); } // 12.4 Expression Statement function parseExpressionStatement(node) { var expr = parseExpression(); consumeSemicolon(); return node.finishExpressionStatement(expr); } // 12.5 If statement function parseIfStatement(node) { var test, consequent, alternate; expectKeyword('if'); expect('('); test = parseExpression(); expect(')'); consequent = parseStatement(); if (matchKeyword('else')) { lex(); alternate = parseStatement(); } else { alternate = null; } return node.finishIfStatement(test, consequent, alternate); } // 12.6 Iteration Statements function parseDoWhileStatement(node) { var body, test, oldInIteration; expectKeyword('do'); oldInIteration = state.inIteration; state.inIteration = true; body = parseStatement(); state.inIteration = oldInIteration; expectKeyword('while'); expect('('); test = parseExpression(); expect(')'); if (match(';')) { lex(); } return node.finishDoWhileStatement(body, test); } function parseWhileStatement(node) { var test, body, oldInIteration; expectKeyword('while'); expect('('); test = parseExpression(); expect(')'); oldInIteration = state.inIteration; state.inIteration = true; body = parseStatement(); state.inIteration = oldInIteration; return node.finishWhileStatement(test, body); } function parseForVariableDeclaration() { var token, declarations, node = new Node(); token = lex(); declarations = parseVariableDeclarationList(); return node.finishVariableDeclaration(declarations, token.value); } function parseForStatement(node) { var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn; init = test = update = null; expectKeyword('for'); expect('('); if (match(';')) { lex(); } else { if (matchKeyword('var') || matchKeyword('let')) { state.allowIn = false; init = parseForVariableDeclaration(); state.allowIn = previousAllowIn; if (init.declarations.length === 1 && matchKeyword('in')) { lex(); left = init; right = parseExpression(); init = null; } } else { state.allowIn = false; init = parseExpression(); state.allowIn = previousAllowIn; if (matchKeyword('in')) { // LeftHandSideExpression if (!isLeftHandSide(init)) { tolerateError(Messages.InvalidLHSInForIn); } lex(); left = init; right = parseExpression(); init = null; } } if (typeof left === 'undefined') { expect(';'); } } if (typeof left === 'undefined') { if (!match(';')) { test = parseExpression(); } expect(';'); if (!match(')')) { update = parseExpression(); } } expect(')'); oldInIteration = state.inIteration; state.inIteration = true; body = parseStatement(); state.inIteration = oldInIteration; return (typeof left === 'undefined') ? node.finishForStatement(init, test, update, body) : node.finishForInStatement(left, right, body); } // 12.7 The continue statement function parseContinueStatement(node) { var label = null, key; expectKeyword('continue'); // Optimize the most common form: 'continue;'. if (source.charCodeAt(index) === 0x3B) { lex(); if (!state.inIteration) { throwError(Messages.IllegalContinue); } return node.finishContinueStatement(null); } if (peekLineTerminator()) { if (!state.inIteration) { throwError(Messages.IllegalContinue); } return node.finishContinueStatement(null); } if (lookahead.type === Token.Identifier) { label = parseVariableIdentifier(); key = '$' + label.name; if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError(Messages.UnknownLabel, label.name); } } consumeSemicolon(); if (label === null && !state.inIteration) { throwError(Messages.IllegalContinue); } return node.finishContinueStatement(label); } // 12.8 The break statement function parseBreakStatement(node) { var label = null, key; expectKeyword('break'); // Catch the very common case first: immediately a semicolon (U+003B). if (source.charCodeAt(index) === 0x3B) { lex(); if (!(state.inIteration || state.inSwitch)) { throwError(Messages.IllegalBreak); } return node.finishBreakStatement(null); } if (peekLineTerminator()) { if (!(state.inIteration || state.inSwitch)) { throwError(Messages.IllegalBreak); } return node.finishBreakStatement(null); } if (lookahead.type === Token.Identifier) { label = parseVariableIdentifier(); key = '$' + label.name; if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError(Messages.UnknownLabel, label.name); } } consumeSemicolon(); if (label === null && !(state.inIteration || state.inSwitch)) { throwError(Messages.IllegalBreak); } return node.finishBreakStatement(label); } // 12.9 The return statement function parseReturnStatement(node) { var argument = null; expectKeyword('return'); if (!state.inFunctionBody) { tolerateError(Messages.IllegalReturn); } // 'return' followed by a space and an identifier is very common. if (source.charCodeAt(index) === 0x20) { if (isIdentifierStart(source.charCodeAt(index + 1))) { argument = parseExpression(); consumeSemicolon(); return node.finishReturnStatement(argument); } } if (peekLineTerminator()) { return node.finishReturnStatement(null); } if (!match(';')) { if (!match('}') && lookahead.type !== Token.EOF) { argument = parseExpression(); } } consumeSemicolon(); return node.finishReturnStatement(argument); } // 12.10 The with statement function parseWithStatement(node) { var object, body; if (strict) { // TODO(ikarienator): Should we update the test cases instead? skipComment(); tolerateError(Messages.StrictModeWith); } expectKeyword('with'); expect('('); object = parseExpression(); expect(')'); body = parseStatement(); return node.finishWithStatement(object, body); } // 12.10 The swith statement function parseSwitchCase() { var test, consequent = [], statement, node = new Node(); if (matchKeyword('default')) { lex(); test = null; } else { expectKeyword('case'); test = parseExpression(); } expect(':'); while (index < length) { if (match('}') || matchKeyword('default') || matchKeyword('case')) { break; } statement = parseStatement(); consequent.push(statement); } return node.finishSwitchCase(test, consequent); } function parseSwitchStatement(node) { var discriminant, cases, clause, oldInSwitch, defaultFound; expectKeyword('switch'); expect('('); discriminant = parseExpression(); expect(')'); expect('{'); cases = []; if (match('}')) { lex(); return node.finishSwitchStatement(discriminant, cases); } oldInSwitch = state.inSwitch; state.inSwitch = true; defaultFound = false; while (index < length) { if (match('}')) { break; } clause = parseSwitchCase(); if (clause.test === null) { if (defaultFound) { throwError(Messages.MultipleDefaultsInSwitch); } defaultFound = true; } cases.push(clause); } state.inSwitch = oldInSwitch; expect('}'); return node.finishSwitchStatement(discriminant, cases); } // 12.13 The throw statement function parseThrowStatement(node) { var argument; expectKeyword('throw'); if (peekLineTerminator()) { throwError(Messages.NewlineAfterThrow); } argument = parseExpression(); consumeSemicolon(); return node.finishThrowStatement(argument); } // 12.14 The try statement function parseCatchClause() { var param, body, node = new Node(); expectKeyword('catch'); expect('('); if (match(')')) { throwUnexpectedToken(lookahead); } param = parseVariableIdentifier(); // 12.14.1 if (strict && isRestrictedWord(param.name)) { tolerateError(Messages.StrictCatchVariable); } expect(')'); body = parseBlock(); return node.finishCatchClause(param, body); } function parseTryStatement(node) { var block, handlers = [], finalizer = null; expectKeyword('try'); block = parseBlock(); if (matchKeyword('catch')) { handlers.push(parseCatchClause()); } if (matchKeyword('finally')) { lex(); finalizer = parseBlock(); } if (handlers.length === 0 && !finalizer) { throwError(Messages.NoCatchOrFinally); } return node.finishTryStatement(block, [], handlers, finalizer); } // 12.15 The debugger statement function parseDebuggerStatement(node) { expectKeyword('debugger'); consumeSemicolon(); return node.finishDebuggerStatement(); } // 12 Statements function parseStatement() { var type = lookahead.type, expr, labeledBody, key, node; if (type === Token.EOF) { throwUnexpectedToken(lookahead); } if (type === Token.Punctuator && lookahead.value === '{') { return parseBlock(); } node = new Node(); if (type === Token.Punctuator) { switch (lookahead.value) { case ';': return parseEmptyStatement(node); case '(': return parseExpressionStatement(node); default: break; } } else if (type === Token.Keyword) { switch (lookahead.value) { case 'break': return parseBreakStatement(node); case 'continue': return parseContinueStatement(node); case 'debugger': return parseDebuggerStatement(node); case 'do': return parseDoWhileStatement(node); case 'for': return parseForStatement(node); case 'function': return parseFunctionDeclaration(node); case 'if': return parseIfStatement(node); case 'return': return parseReturnStatement(node); case 'switch': return parseSwitchStatement(node); case 'throw': return parseThrowStatement(node); case 'try': return parseTryStatement(node); case 'var': return parseVariableStatement(node); case 'while': return parseWhileStatement(node); case 'with': return parseWithStatement(node); default: break; } } expr = parseExpression(); // 12.12 Labelled Statements if ((expr.type === Syntax.Identifier) && match(':')) { lex(); key = '$' + expr.name; if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError(Messages.Redeclaration, 'Label', expr.name); } state.labelSet[key] = true; labeledBody = parseStatement(); delete state.labelSet[key]; return node.finishLabeledStatement(expr, labeledBody); } consumeSemicolon(); return node.finishExpressionStatement(expr); } // 13 Function Definition function parseFunctionSourceElements() { var sourceElement, sourceElements = [], token, directive, firstRestricted, oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount, node = new Node(); expect('{'); while (index < length) { if (lookahead.type !== Token.StringLiteral) { break; } token = lookahead; sourceElement = parseSourceElement(); sourceElements.push(sourceElement); if (sourceElement.expression.type !== Syntax.Literal) { // this is not directive break; } directive = source.slice(token.start + 1, token.end - 1); if (directive === 'use strict') { strict = true; if (firstRestricted) { tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); } } else { if (!firstRestricted && token.octal) { firstRestricted = token; } } } oldLabelSet = state.labelSet; oldInIteration = state.inIteration; oldInSwitch = state.inSwitch; oldInFunctionBody = state.inFunctionBody; oldParenthesisCount = state.parenthesizedCount; state.labelSet = {}; state.inIteration = false; state.inSwitch = false; state.inFunctionBody = true; state.parenthesizedCount = 0; while (index < length) { if (match('}')) { break; } sourceElement = parseSourceElement(); if (typeof sourceElement === 'undefined') { break; } sourceElements.push(sourceElement); } expect('}'); state.labelSet = oldLabelSet; state.inIteration = oldInIteration; state.inSwitch = oldInSwitch; state.inFunctionBody = oldInFunctionBody; state.parenthesizedCount = oldParenthesisCount; return node.finishBlockStatement(sourceElements); } function validateParam(options, param, name) { var key = '$' + name; if (strict) { if (isRestrictedWord(name)) { options.stricted = param; options.message = Messages.StrictParamName; } if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { options.stricted = param; options.message = Messages.StrictParamDupe; } } else if (!options.firstRestricted) { if (isRestrictedWord(name)) { options.firstRestricted = param; options.message = Messages.StrictParamName; } else if (isStrictModeReservedWord(name)) { options.firstRestricted = param; options.message = Messages.StrictReservedWord; } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { options.firstRestricted = param; options.message = Messages.StrictParamDupe; } } options.paramSet[key] = true; } function parseParam(options) { var token, param, def; token = lookahead; param = parseVariableIdentifier(); validateParam(options, token, token.value); if (match('=')) { lex(); def = parseAssignmentExpression(); ++options.defaultCount; } options.params.push(param); options.defaults.push(def); return !match(')'); } function parseParams(firstRestricted) { var options; options = { params: [], defaultCount: 0, defaults: [], firstRestricted: firstRestricted }; expect('('); if (!match(')')) { options.paramSet = {}; while (index < length) { if (!parseParam(options)) { break; } expect(','); } } expect(')'); if (options.defaultCount === 0) { options.defaults = []; } return { params: options.params, defaults: options.defaults, stricted: options.stricted, firstRestricted: options.firstRestricted, message: options.message }; } function parseFunctionDeclaration() { var id, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, node = new Node(); expectKeyword('function'); token = lookahead; id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { tolerateUnexpectedToken(token, Messages.StrictFunctionName); } } else { if (isRestrictedWord(token.value)) { firstRestricted = token; message = Messages.StrictFunctionName; } else if (isStrictModeReservedWord(token.value)) { firstRestricted = token; message = Messages.StrictReservedWord; } } tmp = parseParams(firstRestricted); params = tmp.params; defaults = tmp.defaults; stricted = tmp.stricted; firstRestricted = tmp.firstRestricted; if (tmp.message) { message = tmp.message; } previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { throwUnexpectedToken(firstRestricted, message); } if (strict && stricted) { tolerateUnexpectedToken(stricted, message); } strict = previousStrict; return node.finishFunctionDeclaration(id, params, defaults, body); } function parseFunctionExpression() { var token, id = null, stricted, firstRestricted, message, tmp, params = [], defaults = [], body, previousStrict, node = new Node(); expectKeyword('function'); if (!match('(')) { token = lookahead; id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { tolerateUnexpectedToken(token, Messages.StrictFunctionName); } } else { if (isRestrictedWord(token.value)) { firstRestricted = token; message = Messages.StrictFunctionName; } else if (isStrictModeReservedWord(token.value)) { firstRestricted = token; message = Messages.StrictReservedWord; } } } tmp = parseParams(firstRestricted); params = tmp.params; defaults = tmp.defaults; stricted = tmp.stricted; firstRestricted = tmp.firstRestricted; if (tmp.message) { message = tmp.message; } previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { throwUnexpectedToken(firstRestricted, message); } if (strict && stricted) { tolerateUnexpectedToken(stricted, message); } strict = previousStrict; return node.finishFunctionExpression(id, params, defaults, body); } // 14 Program function parseSourceElement() { if (lookahead.type === Token.Keyword) { switch (lookahead.value) { case 'const': case 'let': return parseConstLetDeclaration(lookahead.value); case 'function': return parseFunctionDeclaration(); default: return parseStatement(); } } if (lookahead.type !== Token.EOF) { return parseStatement(); } } function parseSourceElements() { var sourceElement, sourceElements = [], token, directive, firstRestricted; while (index < length) { token = lookahead; if (token.type !== Token.StringLiteral) { break; } sourceElement = parseSourceElement(); sourceElements.push(sourceElement); if (sourceElement.expression.type !== Syntax.Literal) { // this is not directive break; } directive = source.slice(token.start + 1, token.end - 1); if (directive === 'use strict') { strict = true; if (firstRestricted) { tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); } } else { if (!firstRestricted && token.octal) { firstRestricted = token; } } } while (index < length) { sourceElement = parseSourceElement(); /* istanbul ignore if */ if (typeof sourceElement === 'undefined') { break; } sourceElements.push(sourceElement); } return sourceElements; } function parseProgram() { var body, node; skipComment(); peek(); node = new Node(); strict = false; body = parseSourceElements(); return node.finishProgram(body); } function filterTokenLocation() { var i, entry, token, tokens = []; for (i = 0; i < extra.tokens.length; ++i) { entry = extra.tokens[i]; token = { type: entry.type, value: entry.value }; if (entry.regex) { token.regex = { pattern: entry.regex.pattern, flags: entry.regex.flags }; } if (extra.range) { token.range = entry.range; } if (extra.loc) { token.loc = entry.loc; } tokens.push(token); } extra.tokens = tokens; } function tokenize(code, options) { var toString, tokens; toString = String; if (typeof code !== 'string' && !(code instanceof String)) { code = toString(code); } source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; lineStart = 0; length = source.length; lookahead = null; state = { allowIn: true, labelSet: {}, inFunctionBody: false, inIteration: false, inSwitch: false, lastCommentStart: -1 }; extra = {}; // Options matching. options = options || {}; // Of course we collect tokens here. options.tokens = true; extra.tokens = []; extra.tokenize = true; // The following two fields are necessary to compute the Regex tokens. extra.openParenToken = -1; extra.openCurlyToken = -1; extra.range = (typeof options.range === 'boolean') && options.range; extra.loc = (typeof options.loc === 'boolean') && options.loc; if (typeof options.comment === 'boolean' && options.comment) { extra.comments = []; } if (typeof options.tolerant === 'boolean' && options.tolerant) { extra.errors = []; } try { peek(); if (lookahead.type === Token.EOF) { return extra.tokens; } lex(); while (lookahead.type !== Token.EOF) { try { lex(); } catch (lexError) { if (extra.errors) { extra.errors.push(lexError); // We have to break on the first error // to avoid infinite loops. break; } else { throw lexError; } } } filterTokenLocation(); tokens = extra.tokens; if (typeof extra.comments !== 'undefined') { tokens.comments = extra.comments; } if (typeof extra.errors !== 'undefined') { tokens.errors = extra.errors; } } catch (e) { throw e; } finally { extra = {}; } return tokens; } function parse(code, options) { var program, toString; toString = String; if (typeof code !== 'string' && !(code instanceof String)) { code = toString(code); } source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; lineStart = 0; length = source.length; lookahead = null; state = { allowIn: true, labelSet: {}, parenthesisCount: 0, inFunctionBody: false, inIteration: false, inSwitch: false, lastCommentStart: -1 }; extra = {}; if (typeof options !== 'undefined') { extra.range = (typeof options.range === 'boolean') && options.range; extra.loc = (typeof options.loc === 'boolean') && options.loc; extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; if (extra.loc && options.source !== null && options.source !== undefined) { extra.source = toString(options.source); } if (typeof options.tokens === 'boolean' && options.tokens) { extra.tokens = []; } if (typeof options.comment === 'boolean' && options.comment) { extra.comments = []; } if (typeof options.tolerant === 'boolean' && options.tolerant) { extra.errors = []; } if (extra.attachComment) { extra.range = true; extra.comments = []; extra.bottomRightStack = []; extra.trailingComments = []; extra.leadingComments = []; } } try { program = parseProgram(); if (typeof extra.comments !== 'undefined') { program.comments = extra.comments; } if (typeof extra.tokens !== 'undefined') { filterTokenLocation(); program.tokens = extra.tokens; } if (typeof extra.errors !== 'undefined') { program.errors = extra.errors; } } catch (e) { throw e; } finally { extra = {}; } return program; } // Sync with *.json manifests. exports.version = '2.0.0'; exports.tokenize = tokenize; exports.parse = parse; // Deep copy. /* istanbul ignore next */ exports.Syntax = (function () { var name, types = {}; if (typeof Object.create === 'function') { types = Object.create(null); } for (name in Syntax) { if (Syntax.hasOwnProperty(name)) { types[name] = Syntax[name]; } } if (typeof Object.freeze === 'function') { Object.freeze(types); } return types; }()); })); /* vim: set sw=4 ts=4 et tw=80 : */ three.js-r73/editor/js/libs/ui.js0000644000175500017550000004316212610076566016570 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var UI = {}; UI.Element = function ( dom ) { this.dom = dom; }; UI.Element.prototype = { add: function () { for ( var i = 0; i < arguments.length; i ++ ) { var argument = arguments[ i ]; if ( argument instanceof UI.Element ) { this.dom.appendChild( argument.dom ); } else { console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' ) } } return this; }, remove: function () { for ( var i = 0; i < arguments.length; i ++ ) { var argument = arguments[ i ]; if ( argument instanceof UI.Element ) { this.dom.removeChild( argument.dom ); } else { console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' ) } } return this; }, clear: function () { while ( this.dom.children.length ) { this.dom.removeChild( this.dom.lastChild ); } }, setId: function ( id ) { this.dom.id = id; return this; }, setClass: function ( name ) { this.dom.className = name; return this; }, setStyle: function ( style, array ) { for ( var i = 0; i < array.length; i ++ ) { this.dom.style[ style ] = array[ i ]; } return this; }, setDisabled: function ( value ) { this.dom.disabled = value; return this; }, setTextContent: function ( value ) { this.dom.textContent = value; return this; } } // properties var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft', 'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color', 'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ]; properties.forEach( function ( property ) { var method = 'set' + property.substr( 0, 1 ).toUpperCase() + property.substr( 1, property.length ); UI.Element.prototype[ method ] = function () { this.setStyle( property, arguments ); return this; }; } ); // events var events = [ 'KeyUp', 'KeyDown', 'MouseOver', 'MouseOut', 'Click', 'DblClick', 'Change' ]; events.forEach( function ( event ) { var method = 'on' + event; UI.Element.prototype[ method ] = function ( callback ) { this.dom.addEventListener( event.toLowerCase(), callback.bind( this ), false ); return this; }; } ); // Span UI.Span = function () { UI.Element.call( this ); this.dom = document.createElement( 'span' ); return this; }; UI.Span.prototype = Object.create( UI.Element.prototype ); UI.Span.prototype.constructor = UI.Span; // Panel UI.Panel = function () { UI.Element.call( this ); var dom = document.createElement( 'div' ); dom.className = 'Panel'; this.dom = dom; return this; }; UI.Panel.prototype = Object.create( UI.Element.prototype ); UI.Panel.prototype.constructor = UI.Panel; // Collapsible Panel UI.CollapsiblePanel = function () { UI.Panel.call( this ); this.setClass( 'Panel Collapsible' ); var scope = this; this.static = new UI.Panel(); this.static.setClass( 'Static' ); this.static.onClick( function () { scope.toggle(); } ); this.dom.appendChild( this.static.dom ); this.contents = new UI.Panel(); this.contents.setClass( 'Content' ); this.dom.appendChild( this.contents.dom ); var button = new UI.Panel(); button.setClass( 'Button' ); this.static.add( button ); this.isCollapsed = false; return this; }; UI.CollapsiblePanel.prototype = Object.create( UI.Panel.prototype ); UI.CollapsiblePanel.prototype.constructor = UI.CollapsiblePanel; UI.CollapsiblePanel.prototype.addStatic = function () { this.static.add.apply( this.static, arguments ); return this; }; UI.CollapsiblePanel.prototype.removeStatic = function () { this.static.remove.apply( this.static, arguments ); return this; }; UI.CollapsiblePanel.prototype.clearStatic = function () { this.static.clear(); return this; }; UI.CollapsiblePanel.prototype.add = function () { this.contents.add.apply( this.contents, arguments ); return this; }; UI.CollapsiblePanel.prototype.remove = function () { this.contents.remove.apply( this.contents, arguments ); return this; }; UI.CollapsiblePanel.prototype.clear = function () { this.contents.clear(); return this; }; UI.CollapsiblePanel.prototype.toggle = function() { this.setCollapsed( !this.isCollapsed ); }; UI.CollapsiblePanel.prototype.collapse = function() { this.setCollapsed( true ); }; UI.CollapsiblePanel.prototype.expand = function() { this.setCollapsed( false ); }; UI.CollapsiblePanel.prototype.setCollapsed = function( boolean ) { if ( boolean ) { this.dom.classList.add( 'collapsed' ); } else { this.dom.classList.remove( 'collapsed' ); } this.isCollapsed = boolean; if ( this.onCollapsedChangeCallback !== undefined ) { this.onCollapsedChangeCallback( boolean ); } }; UI.CollapsiblePanel.prototype.onCollapsedChange = function ( callback ) { this.onCollapsedChangeCallback = callback; }; // Text UI.Text = function ( text ) { UI.Element.call( this ); var dom = document.createElement( 'span' ); dom.className = 'Text'; dom.style.cursor = 'default'; dom.style.display = 'inline-block'; dom.style.verticalAlign = 'middle'; this.dom = dom; this.setValue( text ); return this; }; UI.Text.prototype = Object.create( UI.Element.prototype ); UI.Text.prototype.constructor = UI.Text; UI.Text.prototype.getValue = function () { return this.dom.textContent; }; UI.Text.prototype.setValue = function ( value ) { if ( value !== undefined ) { this.dom.textContent = value; } return this; }; // Input UI.Input = function ( text ) { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'input' ); dom.className = 'Input'; dom.style.padding = '2px'; dom.style.border = '1px solid transparent'; dom.addEventListener( 'keydown', function ( event ) { event.stopPropagation(); }, false ); this.dom = dom; this.setValue( text ); return this; }; UI.Input.prototype = Object.create( UI.Element.prototype ); UI.Input.prototype.constructor = UI.Input; UI.Input.prototype.getValue = function () { return this.dom.value; }; UI.Input.prototype.setValue = function ( value ) { this.dom.value = value; return this; }; // TextArea UI.TextArea = function () { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'textarea' ); dom.className = 'TextArea'; dom.style.padding = '2px'; dom.spellcheck = false; dom.addEventListener( 'keydown', function ( event ) { event.stopPropagation(); if ( event.keyCode === 9 ) { event.preventDefault(); var cursor = dom.selectionStart; dom.value = dom.value.substring( 0, cursor ) + '\t' + dom.value.substring( cursor ); dom.selectionStart = cursor + 1; dom.selectionEnd = dom.selectionStart; } }, false ); this.dom = dom; return this; }; UI.TextArea.prototype = Object.create( UI.Element.prototype ); UI.TextArea.prototype.constructor = UI.TextArea; UI.TextArea.prototype.getValue = function () { return this.dom.value; }; UI.TextArea.prototype.setValue = function ( value ) { this.dom.value = value; return this; }; // Select UI.Select = function () { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'select' ); dom.className = 'Select'; dom.style.padding = '2px'; this.dom = dom; return this; }; UI.Select.prototype = Object.create( UI.Element.prototype ); UI.Select.prototype.constructor = UI.Select; UI.Select.prototype.setMultiple = function ( boolean ) { this.dom.multiple = boolean; return this; }; UI.Select.prototype.setOptions = function ( options ) { var selected = this.dom.value; while ( this.dom.children.length > 0 ) { this.dom.removeChild( this.dom.firstChild ); } for ( var key in options ) { var option = document.createElement( 'option' ); option.value = key; option.innerHTML = options[ key ]; this.dom.appendChild( option ); } this.dom.value = selected; return this; }; UI.Select.prototype.getValue = function () { return this.dom.value; }; UI.Select.prototype.setValue = function ( value ) { value = String( value ); if ( this.dom.value !== value ) { this.dom.value = value; } return this; }; // Checkbox UI.Checkbox = function ( boolean ) { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'input' ); dom.className = 'Checkbox'; dom.type = 'checkbox'; this.dom = dom; this.setValue( boolean ); return this; }; UI.Checkbox.prototype = Object.create( UI.Element.prototype ); UI.Checkbox.prototype.constructor = UI.Checkbox; UI.Checkbox.prototype.getValue = function () { return this.dom.checked; }; UI.Checkbox.prototype.setValue = function ( value ) { if ( value !== undefined ) { this.dom.checked = value; } return this; }; // Color UI.Color = function () { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'input' ); dom.className = 'Color'; dom.style.width = '64px'; dom.style.height = '16px'; dom.style.border = '0px'; dom.style.padding = '0px'; dom.style.backgroundColor = 'transparent'; try { dom.type = 'color'; dom.value = '#ffffff'; } catch ( exception ) {} this.dom = dom; return this; }; UI.Color.prototype = Object.create( UI.Element.prototype ); UI.Color.prototype.constructor = UI.Color; UI.Color.prototype.getValue = function () { return this.dom.value; }; UI.Color.prototype.getHexValue = function () { return parseInt( this.dom.value.substr( 1 ), 16 ); }; UI.Color.prototype.setValue = function ( value ) { this.dom.value = value; return this; }; UI.Color.prototype.setHexValue = function ( hex ) { this.dom.value = '#' + ( '000000' + hex.toString( 16 ) ).slice( -6 ); return this; }; // Number UI.Number = function ( number ) { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'input' ); dom.className = 'Number'; dom.value = '0.00'; dom.addEventListener( 'keydown', function ( event ) { event.stopPropagation(); if ( event.keyCode === 13 ) dom.blur(); }, false ); this.min = - Infinity; this.max = Infinity; this.precision = 2; this.step = 1; this.dom = dom; this.setValue( number ); var changeEvent = document.createEvent( 'HTMLEvents' ); changeEvent.initEvent( 'change', true, true ); var distance = 0; var onMouseDownValue = 0; var pointer = [ 0, 0 ]; var prevPointer = [ 0, 0 ]; var onMouseDown = function ( event ) { event.preventDefault(); distance = 0; onMouseDownValue = parseFloat( dom.value ); prevPointer = [ event.clientX, event.clientY ]; document.addEventListener( 'mousemove', onMouseMove, false ); document.addEventListener( 'mouseup', onMouseUp, false ); }; var onMouseMove = function ( event ) { var currentValue = dom.value; pointer = [ event.clientX, event.clientY ]; distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] ); var number = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step; dom.value = Math.min( scope.max, Math.max( scope.min, number ) ).toFixed( scope.precision ); if ( currentValue !== dom.value ) dom.dispatchEvent( changeEvent ); prevPointer = [ event.clientX, event.clientY ]; }; var onMouseUp = function ( event ) { document.removeEventListener( 'mousemove', onMouseMove, false ); document.removeEventListener( 'mouseup', onMouseUp, false ); if ( Math.abs( distance ) < 2 ) { dom.focus(); dom.select(); } }; var onChange = function ( event ) { var value = 0; try { value = eval( dom.value ); } catch ( error ) { console.error( error.message ); } dom.value = parseFloat( value ); }; var onFocus = function ( event ) { dom.style.backgroundColor = ''; dom.style.borderColor = '#ccc'; dom.style.cursor = ''; }; var onBlur = function ( event ) { dom.style.backgroundColor = 'transparent'; dom.style.borderColor = 'transparent'; dom.style.cursor = 'col-resize'; }; dom.addEventListener( 'mousedown', onMouseDown, false ); dom.addEventListener( 'change', onChange, false ); dom.addEventListener( 'focus', onFocus, false ); dom.addEventListener( 'blur', onBlur, false ); return this; }; UI.Number.prototype = Object.create( UI.Element.prototype ); UI.Number.prototype.constructor = UI.Number; UI.Number.prototype.getValue = function () { return parseFloat( this.dom.value ); }; UI.Number.prototype.setValue = function ( value ) { if ( value !== undefined ) { this.dom.value = value.toFixed( this.precision ); } return this; }; UI.Number.prototype.setRange = function ( min, max ) { this.min = min; this.max = max; return this; }; UI.Number.prototype.setPrecision = function ( precision ) { this.precision = precision; return this; }; // Integer UI.Integer = function ( number ) { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'input' ); dom.className = 'Number'; dom.value = '0.00'; dom.addEventListener( 'keydown', function ( event ) { event.stopPropagation(); }, false ); this.min = - Infinity; this.max = Infinity; this.step = 1; this.dom = dom; this.setValue( number ); var changeEvent = document.createEvent( 'HTMLEvents' ); changeEvent.initEvent( 'change', true, true ); var distance = 0; var onMouseDownValue = 0; var pointer = [ 0, 0 ]; var prevPointer = [ 0, 0 ]; var onMouseDown = function ( event ) { event.preventDefault(); distance = 0; onMouseDownValue = parseFloat( dom.value ); prevPointer = [ event.clientX, event.clientY ]; document.addEventListener( 'mousemove', onMouseMove, false ); document.addEventListener( 'mouseup', onMouseUp, false ); }; var onMouseMove = function ( event ) { var currentValue = dom.value; pointer = [ event.clientX, event.clientY ]; distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] ); var number = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step; dom.value = Math.min( scope.max, Math.max( scope.min, number ) ) | 0; if ( currentValue !== dom.value ) dom.dispatchEvent( changeEvent ); prevPointer = [ event.clientX, event.clientY ]; }; var onMouseUp = function ( event ) { document.removeEventListener( 'mousemove', onMouseMove, false ); document.removeEventListener( 'mouseup', onMouseUp, false ); if ( Math.abs( distance ) < 2 ) { dom.focus(); dom.select(); } }; var onChange = function ( event ) { var value = 0; try { value = eval( dom.value ); } catch ( error ) { console.error( error.message ); } dom.value = parseInt( value ); }; var onFocus = function ( event ) { dom.style.backgroundColor = ''; dom.style.borderColor = '#ccc'; dom.style.cursor = ''; }; var onBlur = function ( event ) { dom.style.backgroundColor = 'transparent'; dom.style.borderColor = 'transparent'; dom.style.cursor = 'col-resize'; }; dom.addEventListener( 'mousedown', onMouseDown, false ); dom.addEventListener( 'change', onChange, false ); dom.addEventListener( 'focus', onFocus, false ); dom.addEventListener( 'blur', onBlur, false ); return this; }; UI.Integer.prototype = Object.create( UI.Element.prototype ); UI.Integer.prototype.constructor = UI.Integer; UI.Integer.prototype.getValue = function () { return parseInt( this.dom.value ); }; UI.Integer.prototype.setValue = function ( value ) { if ( value !== undefined ) { this.dom.value = value | 0; } return this; }; UI.Integer.prototype.setRange = function ( min, max ) { this.min = min; this.max = max; return this; }; // Break UI.Break = function () { UI.Element.call( this ); var dom = document.createElement( 'br' ); dom.className = 'Break'; this.dom = dom; return this; }; UI.Break.prototype = Object.create( UI.Element.prototype ); UI.Break.prototype.constructor = UI.Break; // HorizontalRule UI.HorizontalRule = function () { UI.Element.call( this ); var dom = document.createElement( 'hr' ); dom.className = 'HorizontalRule'; this.dom = dom; return this; }; UI.HorizontalRule.prototype = Object.create( UI.Element.prototype ); UI.HorizontalRule.prototype.constructor = UI.HorizontalRule; // Button UI.Button = function ( value ) { UI.Element.call( this ); var scope = this; var dom = document.createElement( 'button' ); dom.className = 'Button'; this.dom = dom; this.dom.textContent = value; return this; }; UI.Button.prototype = Object.create( UI.Element.prototype ); UI.Button.prototype.constructor = UI.Button; UI.Button.prototype.setLabel = function ( value ) { this.dom.textContent = value; return this; }; // Modal UI.Modal = function ( value ) { var scope = this; var dom = document.createElement( 'div' ); dom.style.position = 'absolute'; dom.style.width = '100%'; dom.style.height = '100%'; dom.style.backgroundColor = 'rgba(0,0,0,0.5)'; dom.style.display = 'none'; dom.style.alignItems = 'center'; dom.style.justifyContent = 'center'; dom.addEventListener( 'click', function ( event ) { scope.hide(); } ); this.dom = dom; this.container = new UI.Panel(); this.container.dom.style.width = '200px'; this.container.dom.style.padding = '20px'; this.container.dom.style.backgroundColor = '#ffffff'; this.container.dom.style.boxShadow = '0px 5px 10px rgba(0,0,0,0.5)'; this.add( this.container ); return this; }; UI.Modal.prototype = Object.create( UI.Element.prototype ); UI.Modal.prototype.constructor = UI.Modal; UI.Modal.prototype.show = function ( content ) { this.container.clear(); this.container.add( content ); this.dom.style.display = 'flex'; return this; }; UI.Modal.prototype.hide = function () { this.dom.style.display = 'none'; return this; }; three.js-r73/editor/js/Menubar.Play.js0000644000175500017550000000115112610076566017507 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.Play = function ( editor ) { var signals = editor.signals; var container = new UI.Panel(); container.setClass( 'menu' ); var isPlaying = false; var title = new UI.Panel(); title.setClass( 'title' ); title.setTextContent( 'Play' ); title.onClick( function () { if ( isPlaying === false ) { isPlaying = true; title.setTextContent( 'Stop' ); signals.startPlayer.dispatch(); } else { isPlaying = false; title.setTextContent( 'Play' ); signals.stopPlayer.dispatch(); } } ); container.add( title ); return container; }; three.js-r73/editor/js/Menubar.View.js0000644000175500017550000000274712610076566017530 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ Menubar.View = function ( editor ) { var container = new UI.Panel(); container.setClass( 'menu' ); var title = new UI.Panel(); title.setClass( 'title' ); title.setTextContent( 'View' ); container.add( title ); var options = new UI.Panel(); options.setClass( 'options' ); container.add( options ); // Light theme var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Light theme' ); option.onClick( function () { editor.setTheme( 'css/light.css' ); editor.config.setKey( 'theme', 'css/light.css' ); } ); options.add( option ); // Dark theme var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Dark theme' ); option.onClick( function () { editor.setTheme( 'css/dark.css' ); editor.config.setKey( 'theme', 'css/dark.css' ); } ); options.add( option ); // options.add( new UI.HorizontalRule() ); // fullscreen var option = new UI.Panel(); option.setClass( 'option' ); option.setTextContent( 'Fullscreen' ); option.onClick( function () { var element = document.body; if ( element.requestFullscreen ) { element.requestFullscreen(); } else if ( element.mozRequestFullScreen ) { element.mozRequestFullScreen(); } else if ( element.webkitRequestFullscreen ) { element.webkitRequestFullscreen(); } else if ( element.msRequestFullscreen ) { element.msRequestFullscreen(); } } ); options.add( option ); return container; }; three.js-r73/editor/js/Menubar.js0000644000175500017550000000104412610076566016604 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var Menubar = function ( editor ) { var container = new UI.Panel(); container.setId( 'menubar' ); container.add( new Menubar.File( editor ) ); container.add( new Menubar.Edit( editor ) ); container.add( new Menubar.Add( editor ) ); container.add( new Menubar.Play( editor ) ); container.add( new Menubar.Examples( editor ) ); container.add( new Menubar.View( editor ) ); container.add( new Menubar.Help( editor ) ); container.add( new Menubar.Status( editor ) ); return container; }; three.js-r73/editor/css/0000755000175500017550000000000012610076566015032 5ustar debacledebaclethree.js-r73/editor/css/main.css0000644000175500017550000000357012610076566016475 0ustar debacledebaclebody { font-family: Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; overflow: hidden; } hr { border: 0px; border-top: 1px solid #ccc; } button { position: relative; } textarea { tab-size: 4; white-space: pre; word-wrap: normal; } textarea.success { border-color: #8b8 !important; } textarea.fail { border-color: #f00 !important; background-color: rgba(255,0,0,0.05); } textarea, input { outline: none; } /* osx */ .Panel { -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; /* No support for these yet */ -o-user-select: none; user-select: none; } .Panel.Collapsible .Static { margin: 0px; } .Panel.Collapsible .Static .Button { float: left; margin-right: 6px; width: 0px; height: 0px; border: 6px solid transparent; } .Panel.Collapsible.collapsed .Static .Button { margin-top: 2px; border-left-color: #bbb; } .Panel.Collapsible:not(.collapsed) .Static .Button { margin-top: 6px; border-top-color: #bbb; } .Panel.Collapsible.collapsed .Content { display: none; } /* CodeMirror */ .CodeMirror { position: absolute !important; top: 37px; width: 100% !important; height: calc(100% - 37px) !important; } .CodeMirror .errorLine { background: rgba(255,0,0,0.25); } .CodeMirror .esprima-error { color: #f00; text-align: right; padding: 0px 20px; } /* scene types */ .type { position:relative; top:-2px; padding: 0px 2px; color: #ddd; } .type:after { content: 'â– '; } .Scene { color: #ccccff; } .Object3D { color: #aaaaee; } .Mesh { color: #8888ee; } .Line { color: #88ee88; } .LineSegments { color: #88ee88; } .Points { color: #ee8888; } /* */ .PointLight { color: #dddd00; } /* */ .Geometry { color: #88ff88; } .BoxGeometry { color: #bbeebb; } .TorusGeometry { color: #aaeeaa; } /* */ .Material { color: #ff8888; } .MeshPhongMaterial { color: #ffaa88; } three.js-r73/editor/css/light.css0000644000175500017550000000525112610076566016656 0ustar debacledebacle.Outliner { color: #444; background: #fff; padding: 0; width: 100%; height: 140px; font-size: 12px; cursor: default; overflow: auto; outline: none; } .Outliner .option { padding: 4px; color: #666; white-space: nowrap; } .Outliner .option.active { background-color: #f8f8f8; } input.Number { color: #0080f0!important; font-size: 12px; /** TODO: Use of !imporant is not ideal **/ background-color: transparent!important; /* For now this is a quick fix a rendering issue due to inherited background */ border: 1px solid transparent; padding: 2px; cursor: col-resize; } #viewport { position: absolute; top: 32px; left: 0px; right: 300px; bottom: 32px; } #viewport #info { text-shadow: 1px 1px 0px rgba(0,0,0,0.25); pointer-events: none; } #script { position: absolute; top: 32px; left: 0px; right: 300px; bottom: 32px; opacity: 0.9; } #player { position: absolute; top: 32px; left: 0px; right: 300px; bottom: 32px; } #menubar { position: absolute; width: 100%; height: 32px; background: #eee; padding: 0px; margin: 0px; right: 0px; top: 0px; } #menubar .menu { float: left; cursor: pointer; padding-right: 8px; } #menubar .menu.right { float: right; cursor: auto; padding-right: 0px; text-align: right; } #menubar .menu .title { display: inline-block; color: #888; margin: 0px; padding: 8px; } #menubar .menu .options { position: absolute; display: none; padding: 5px 0px; background: #eee; width: 150px; } #menubar .menu:hover .options { display: block; } #menubar .menu .options hr { border-color: #ddd; } #menubar .menu .options .option { color: #666; background-color: transparent; padding: 5px 10px; margin: 0px !important; } #menubar .menu .options .option:hover { color: #fff; background-color: #08f; } #menubar .menu .options .option:active { color: #666; background: transparent; } #sidebar { position: absolute; right: 0px; top: 32px; bottom: 0px; width: 300px; background: #eee; overflow: auto; } #sidebar * { vertical-align: middle; } #sidebar input, #sidebar textarea, #sidebar select { border: 1px solid transparent; color: #444; } #sidebar .Panel { margin-bottom: 10px; } #sidebar .Panel.collapsed { margin-bottom: 0px; } #sidebar > .Panel { color: #888; padding: 10px; border-top: 1px solid #ccc; } #toolbar { position: absolute; left: 0px; right: 300px; bottom: 0px; height: 32px; background: #eee; color: #333; } #toolbar * { vertical-align: middle; } #toolbar .Panel { padding: 4px; color: #888; } #toolbar button { margin-right: 6px; } three.js-r73/editor/css/dark.css0000644000175500017550000000561612610076566016475 0ustar debacledebacle.Outliner { color: #868686; background: #222; padding: 0; width: 100%; height: 140px; font-size: 12px; cursor: default; overflow: auto; outline: none; } .Outliner .option { padding: 4px; white-space: nowrap; } .Outliner .option.active { background-color: #153C5E; } .Panel.Collapsible.collapsed .Static .Button { border-left-color: #444; } .Panel.Collapsible:not(.collapsed) .Static .Button { border-top-color: #444; } input.Number { color: #2A75B7!important; font-size: 12px; /** TODO: Use of !imporant is not ideal **/ background-color: transparent!important; /* For now this is a quick fix a rendering issue due to inherited background */ border: 1px solid transparent; padding: 2px; cursor: col-resize; } #viewport { position: absolute; top: 32px; left: 0px; right: 300px; bottom: 32px; } #viewport #info { text-shadow: 1px 1px 0px rgba(0,0,0,0.25); pointer-events: none; } #script { position: absolute; top: 32px; left: 0px; right: 300px; bottom: 32px; opacity: 0.9; } #player { position: absolute; top: 32px; left: 0px; right: 300px; bottom: 32px; } #menubar { position: absolute; width: 100%; height: 32px; background: #111; padding: 0px; margin: 0px; right: 0px; top: 0px; } #menubar .menu { float: left; cursor: pointer; padding-right: 8px; } #menubar .menu.right { float: right; cursor: auto; padding-right: 0px; text-align: right; } #menubar .menu .title { display: inline-block; color: #888; margin: 0px; padding: 8px; } #menubar .menu .options { position: absolute; display: none; padding: 5px 0px; background: #111; width: 150px; } #menubar .menu:hover .options { display: block; } #menubar .menu .options hr { border-color: #333; } #menubar .menu .options .option { color: #888; background-color: transparent; padding: 5px 10px; margin: 0px !important; } #menubar .menu .options .option:hover { color: #fff; background-color: #08f; } #menubar .menu .options .option:active { background: transparent; } #sidebar { position: absolute; right: 0px; top: 32px; bottom: 0px; width: 300px; background-color: #111; overflow: auto; } #sidebar * { vertical-align: middle; } #sidebar input, #sidebar textarea, #sidebar select { background: #222; border: 1px solid transparent; color: #888; } #sidebar .Panel { margin-bottom: 10px; } #sidebar .Panel.collapsed { margin-bottom: 0px; } #sidebar > .Panel { color: #888; padding: 10px; border-top: 1px solid #333; } #sidebar .Panel.Material canvas { border: solid 1px #5A5A5A; } #toolbar { position: absolute; left: 0px; right: 300px; bottom: 0px; height: 32px; background-color: #111; color: #333; } #toolbar * { vertical-align: middle; } #toolbar .Panel { padding: 4px; color: #888; } #toolbar button { margin-right: 6px; } three.js-r73/docs/0000755000175500017550000000000012610076566013704 5ustar debacledebaclethree.js-r73/docs/manual/0000755000175500017550000000000012610076566015161 5ustar debacledebaclethree.js-r73/docs/manual/introduction/0000755000175500017550000000000012610076566017702 5ustar debacledebaclethree.js-r73/docs/manual/introduction/Matrix-transformations.html0000644000175500017550000000657612610076566025301 0ustar debacledebacle

      [name]

      Three.js uses *matrices* to encode 3D transformations---translations (position), rotations, and scaling. Every instance of [page:Object3D] has a [page:Object3D.matrix matrix] which stores that object's position, rotation, and scale. This page describes how to update an object's transformation.

      Convenience properties and *matrixAutoUpdate*

      There are two ways to update an object's transformation:
      1. Modify the object's *position*, *quaternion*, and *scale* properties, and let Three.js recompute the object's matrix from these properties: object.position.copy(start_position); object.quaternion.copy(quaternion); By default, the *matrixAutoUpdate* property is set true, and the matrix will be automatically recalculated. If the object is static, or you wish to manually control when recalculation occurs, better performance can be obtained by setting the property false: object.matrixAutoUpdate = false; And after changing any properties, manually update the matrix: object.updateMatrix();
      2. Modify the object's matrix directly. The [page:Matrix4] class has various methods for modifying the matrix: object.matrix.setRotationFromQuaternion(quaternion); object.matrix.setPosition(start_position); object.matrixAutoUpdate = false; Note that *matrixAutoUpdate* must be set to *false* in this case, and you should make sure not to call *updateMatrix*. Calling *updateMatrix* will clobber the manual changes made to the matrix, recalculating the matrix from *position*, *scale*, and so on.

      Object and world matrices

      An object's [page:Object3D.matrix matrix] stores the object's transformation relative to the object's [page:Object3D.parent parent]; to get the object's transformation in world coordinates, you must access the object's [page:Object3D.matrixWorld].

      When either the parent or the child object's transformation changes, you can request that the child object's [page:Object3D.matrixWorld matrixWorld] be updated by calling [page:Object3D.updateMatrixWorld updateMatrixWorld]().

      Rotation and Quaternion

      Three.js provides two ways of representing 3D rotations: [page:Euler Euler angles] and [page:Quaternion Quaternions], as well as methods for converting between the two. Euler angles are subject to a problem called "gimbal lock," where certain configurations can lose a degree of freedom (preventing the object from being rotated about one axis). For this reason, object rotations are always stored in the object's [page:Object3D.quaternion quaternion].

      Previous versions of the library included a *useQuaternion* property which, when set to false, would cause the object's [page:Object3D.matrix matrix] to be calculated from an Euler angle. This practice is deprecated---instead, you should use the [page:Object3D.setRotationFromEuler setRotationFromEuler] method, which will update the quaternion.

      three.js-r73/docs/manual/introduction/Creating-a-scene.html0000644000175500017550000002133112610076566023635 0ustar debacledebacle

      [name]

      The goal of this section is to give a brief introduction to Three.js. We will start by setting up a scene, with a spinning cube. A working example is provided at the bottom of the page in case you get stuck and need help.

      What is Three.js?

      Let's try to describe it briefly:
      Three.js is a library that makes WebGL - 3D in the browser - easy to use. While a simple cube in raw WebGL would turn out hundreds of lines of Javascript and shader code, a Three.js equivalent is only a fraction of that.

      Before we start

      Before you can use Three.js, you need somewhere to display it. Save the following HTML to a file on your computer, along with a copy of three.min.js in the js/ directory, and open it in your browser.
      <!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>My first Three.js app</title> <style> body { margin: 0; } canvas { width: 100%; height: 100% } </style> </head> <body> <script src="js/three.min.js"></script> <script> // Our Javascript will go here. </script> </body> </html>
      That's all. All the code below goes into the empty <script> tag.

      Creating the scene

      To actually be able to display anything with Three.js, we need three things: A scene, a camera, and a renderer so we can render the scene with the camera.
      var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement );
      Let's take a moment to explain what's going on here. We have now set up the scene, our camera and the renderer. There are a few different cameras in Three.js. For now, let's use a PerspectiveCamera. The first attribute is the field of view.
      The second one is the aspect ratio. You almost always want to use the width of the element divided by the height, or you'll get the same result as when you play old movies on a widescreen TV - the image looks squished.
      The next two attributes are the near and far clipping plane. What that means, is that objects further away from the camera than the value of far or closer than near won't be rendered. You don't have to worry about this now, but you may want to use other values in your apps to get better performance.
      Next up is the renderer. This is where the magic happens. In addition to the WebGLRenderer we use here, Three.js comes with a few others, often used as fallbacks for users with older browsers or for those who don't have WebGL support for some reason.
      In addition to creating the renderer instance, we also need to set the size at which we want it to render our app. It's a good idea to use the width and height of the area we want to fill with our app - in this case, the width and height of the browser window. For performance intensive apps, you can also give setSize smaller values, like window.innerWidth/2 and window.innerHeight/2, which will make the app render at half size.
      If you wish to keep the size of your app but render it at a lower resolution, you can do so by calling setSize with false as updateStyle. For example, setSize(window.innerWidth/2, window.innerHeight/2, false) will render your app at half resolution, given that your <canvas> has 100% width and height.
      Last but not least, we add the renderer element to our HTML document. This is a <canvas> element the renderer uses to display the scene to us.
      "That's all good, but where's that cube you promised?" Let's add it now.
      var geometry = new THREE.BoxGeometry( 1, 1, 1 ); var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); var cube = new THREE.Mesh( geometry, material ); scene.add( cube ); camera.position.z = 5;
      To create a cube, we need a BoxGeometry. This is an object that contains all the points (vertices) and fill (faces) of the cube. We'll explore this more in the future.
      In addition to the geometry, we need a material to color it. Three.js comes with several materials, but we'll stick to the MeshBasicMaterial for now. All materials take an object of properties which will be applied to them. To keep things very simple, we only supply a color attribute of 0x00ff00, which is green. This works the same way that colors work in CSS or Photoshop (hex colors).
      The third thing we need is a Mesh. A mesh is an object that takes a geometry, and applies a material to it, which we then can insert to our scene, and move freely around.
      By default, when we call scene.add(), the thing we add will be added to the coordinates (0,0,0). This would cause both the camera and the cube to be inside each other. To avoid this, we simply move the camera out a bit.

      Rendering the scene

      If you copied the code from above into the HTML file we created earlier, you wouldn't be able to see anything. This is because we're not actually rendering anything yet. For that, we need what's called a render loop.
      function render() { requestAnimationFrame( render ); renderer.render( scene, camera ); } render();
      This will create a loop that causes the renderer to draw the scene 60 times per second. If you're new to writing games in the browser, you might say "why don't we just create a setInterval? The thing is - we could, but requestAnimationFrame has a number of advantages. Perhaps the most important one is that it pauses when the user navigates to another browser tab, hence not wasting their precious processing power and battery life.

      Animating the cube

      If you insert all the code above into the file you created before we began, you should see a green box. Let's make it all a little more interesting by rotating it.
      Add the following right above the renderer.render call in your render function:
      cube.rotation.x += 0.1; cube.rotation.y += 0.1;
      This will be run every frame (60 times per second), and give the cube a nice rotation animation. Basically, anything you want to move or change while the app is running has to go through the render loop. You can of course call other functions from there, so that you don't end up with a render function that's hundreds of lines.

      The result

      Congratulations! You have now completed your first Three.js application. It's simple, you have to start somewhere.
      The full code is available below. Play around with it to get a better understanding of how it works.
      <html> <head> <title>My first Three.js app</title> <style> body { margin: 0; } canvas { width: 100%; height: 100% } </style> </head> <body> <script src="js/three.min.js"></script> <script> var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); var geometry = new THREE.BoxGeometry( 1, 1, 1 ); var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); var cube = new THREE.Mesh( geometry, material ); scene.add( cube ); camera.position.z = 5; var render = function () { requestAnimationFrame( render ); cube.rotation.x += 0.1; cube.rotation.y += 0.1; renderer.render(scene, camera); }; render(); </script> </body> </html> three.js-r73/docs/api/0000755000175500017550000000000012610076566014455 5ustar debacledebaclethree.js-r73/docs/api/extras/0000755000175500017550000000000012610076566015763 5ustar debacledebaclethree.js-r73/docs/api/extras/core/0000755000175500017550000000000012610076566016713 5ustar debacledebaclethree.js-r73/docs/api/extras/core/Gyroscope.html0000644000175500017550000000156512610076566021562 0ustar debacledebacle [page:Object3D] →

      [name]

      An Object3d that rotates independently of its parent objects, but keeps the position and scale.
      var root = new THREE.Group(); var gyro = new THREE.Gyroscope(); var cube = new THREE.Mesh( geometry, material ); root.add( gyro ) gyro.add( cube ) cube.position.x = 10; root.rotation.y = Math.PI; // The cube will have changed its position but maintained its orientation

      Constructor

      [name]()

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/core/Path.html0000644000175500017550000001157412610076566020505 0ustar debacledebacle [page:CurvePath] →

      [name]

      A 2d path representation, comprising of points, lines, and cubes, similar to the html5 2d canvas api. It extends [page:CurvePath].

      Constructor

      [name]([page:Array points])

      points -- array of Vector2
      Creates a Path from the points. The first vector defines the offset. After that the lines get defined.

      Properties

      [property:array actions]

      The possible actions that define the path.

      Methods

      [method:null fromPoints]( [page:Array vector2s] )

      Adds to the Path from the points. The first vector defines the offset. After that the lines get defined.

      [method:null moveTo]( [page:Float x], [page:Float y] )

      This moves the offset to x and y

      [method:null lineTo]( [page:Float x], [page:Float y] )

      This creates a line from the offset to X and Y and updates the offset to X and Y.

      [method:null quadraticCurveTo]( [page:Float cpX], [page:Float cpY], [page:Float x], [page:Float y] )

      This creates a quadratic curve from the offset to x and y with cpX and cpY as control point and updates the offset to x and y.

      [method:null bezierCurveTo]( [page:Float cp1X], [page:Float cp1Y], [page:Float cp2X], [page:Float cp2Y], [page:Float x], [page:Float y] )

      This creates a bezier curve from the last offset to x and y with cp1X, cp1Y and cp1X, cp1Y as control points and updates the offset to x and y.

      [method:null splineThru] ( [page:Array points] )

      points - An array of [page:Vector2]s
      Connects a new [page:SplineCurve] onto the path.

      [method:null arc]( [page:Float x], [page:Float y], [page:Float radius], [page:Float startAngle], [page:Float endAngle], [page:Float clockwise] )

      x, y -- The center of the arc offset from the last call radius -- The radius of the arc startAngle -- The start angle in radians endAngle -- The end angle in radians clockwise -- Sweep the arc clockwise. Defaults to false
      Draw an arc offset from the last call

      [method:null absarc]( [page:Float x], [page:Float y], [page:Float radius], [page:Float startAngle], [page:Float endAngle], [page:Float clockwise] )

      x, y -- The absolute center of the arc radius -- The radius of the arc startAngle -- The start angle in radians endAngle -- The end angle in radians clockwise -- Sweep the arc clockwise. Defaults to false
      Draw an arc absolutely positioned

      [method:null ellipse]( [page:Float x], [page:Float y], [page:Float xRadius], [page:Float yRadius], [page:Float startAngle], [page:Float endAngle], [page:Float clockwise], [page:Float rotation] )

      x, y -- The center of the ellipse offset from the last call xRadius -- The radius of the ellipse in the x axis yRadius -- The radius of the ellipse in the y axis startAngle -- The start angle in radians endAngle -- The end angle in radians clockwise -- Sweep the ellipse clockwise. Defaults to false rotation -- The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. Optional, defaults to 0
      Draw an ellipse offset from the last call

      [method:null absellipse]( [page:Float x], [page:Float y], [page:Float xRadius], [page:Float yRadius], [page:Float startAngle], [page:Float endAngle], [page:Float clockwise], [page:Float rotation] )

      x, y -- The absolute center of the ellipse xRadius -- The radius of the ellipse in the x axis yRadius -- The radius of the ellipse in the y axis startAngle -- The start angle in radians endAngle -- The end angle in radians clockwise -- Sweep the ellipse clockwise. Defaults to false rotation -- The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. Optional, defaults to 0
      Draw an ellipse absolutely positioned

      [method:Array toShapes]( [page:Boolean isCCW], [page:Boolean noHoles] )

      isCCW -- Changes how solids and holes are generated
      noHoles -- Whether or not to generate holes
      Converts the Path into an array of Shapes. By default solid shapes are defined clockwise (CW) and holes are defined counterclockwise (CCW). If isCCW is set to true, then those are flipped. If the paramater noHoles is set to true then all paths are set as solid shapes and isCCW is ignored.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/core/CurvePath.html0000644000175500017550000000743112610076566021507 0ustar debacledebacle [page:Curve] →

      [name]

      An abstract base class further extending [page:Curve]. A CurvePath is simply an array of connected curves, but retains the api of a curve.

      Constructor

      [name]()

      The constructor take no parameters.

      Properties

      [property:array curves]

      The array of [page:Curve]s

      [property:array bends]

      An array of [page:Curve]s used to transform and bend the curve using [page:CurvePath.getWrapPoints].

      [property:boolean autoClose]

      Whether or not to automatically close the path.

      Methods

      [method:Array getWrapPoints]([page:Array vertices], [page:Curve curve])

      vertices -- An array of [page:Vector2]s to modify
      curve -- An array of 2d [page:Curve]s
      Modifies the array of vertices by warping it by the curve. The curve parameter also accepts objects with similar interfaces such as [page:CurvePath], [page:Path], [page:SplineCurve], etc. Returns the original vertices after modification.

      [method:null addWrapPath]([page:Curve curve])

      curve -- A [page:Curve] or object with a similar interface.
      Pushes a curve onto the bends array.

      [method:Geometry createGeometry]([page:Vector3 points])

      points -- An array of [page:Vector3]s
      Creates a geometry from points

      [method:Geometry createPointsGeometry]([page:Integer divisions])

      divisions -- How many segments to create with [page:Vector3]s. Defaults to 12.
      Creates a [page:Geometry] object comprised of [page:Vector3]s

      [method:Geometry createSpacedPointsGeometry]([page:Integer divisions])

      divisions -- How many segments to create with [page:Vector3]s. Defaults to 12.
      Creates a [page:Geometry] object comprised of [page:Vector3]s that are equidistant.

      [method:null add]([page:Curve curve])

      curve -- The [page:Curve curve] to add
      Pushes a curve onto the curves array.

      [method:null closePath]()

      Adds a curve to close the path.

      [method:Object getBoundingBox]()

      Returns an object with the keys minX, minY, maxX, maxY, (if 3d: maxZ, minZ)

      [method:Float getCurveLengths]()

      Adds together the length of the curves

      [method:Array getTransformedPoints]([page:Integer segments], [page:Array bends])

      segments -- The number of segments to create using the getPoints()
      bends -- (optional) An array of [page:Curve]s used to transform the points. Defaults to this.bends if blank.
      Uses this CurvePath to generate a series of points transformed by the curves in the bends array. Returns an array of [page:Vector2]s.

      [method:Array getTransformedSpacedPoints]([page:Integer segments], [page:Array bends])

      segments -- The number of segments to create using the getPoints()
      bends -- (optional) Defaults to this.bends if blank. An array of [page:Curve]s used to transform the points.
      Uses this CurvePath to generate a series equidistant points that are then transformed by the curves in the bends. Returns an array of [page:Vector2]s.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/core/Shape.html0000644000175500017550000000711112610076566020641 0ustar debacledebacle [page:Path] →

      [name]

      Defines an arbitrary 2d shape plane using paths with optional holes. It can be used with [page:ExtrudeGeometry], [page:ShapeGeometry], to get points, or to get triangulated faces.
      var heartShape = new THREE.Shape(); heartShape.moveTo( 25, 25 ); heartShape.bezierCurveTo( 25, 25, 20, 0, 0, 0 ); heartShape.bezierCurveTo( 30, 0, 30, 35,30,35 ); heartShape.bezierCurveTo( 30, 55, 10, 77, 25, 95 ); heartShape.bezierCurveTo( 60, 77, 80, 55, 80, 35 ); heartShape.bezierCurveTo( 80, 35, 80, 0, 50, 0 ); heartShape.bezierCurveTo( 35, 0, 25, 25, 25, 25 ); var extrudeSettings = { amount: 8, bevelEnabled: true, bevelSegments: 2, steps: 2, bevelSize: 1, bevelThickness: 1 }; var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings ); var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );

      Examples

      [example:webgl_geometry_shapes geometry / shapes ]
      [example:webgl_geometry_extrude_shapes geometry / extrude / shapes ]
      [example:webgl_geometry_extrude_shapes2 geometry / extrude / shapes2 ]
      [example:webgl_particles_shapes particles / shapes ]

      Constructor

      [name]()

      Properties

      [property:array holes]

      An array of [page:Path paths] that define the holes in the shape.

      Methods

      [method:ShapeGeometry makeGeometry]([page:Object options])

      options -- This is passed as the second argument to [page:ShapeGeometry ShapeGeometry]
      Convenience method to return ShapeGeometry

      [method:Array extractAllPoints]([page:Integer divisions])

      divisions -- The number of divisions to create on the shape
      Get points of shape and holes (keypoints based on segments parameter)

      [method:ExtrudeGeometry extrude]([page:Object options])

      options -- This is passed as the second argument to [page:ExtrudeGeometry ExtrudeGeometry]
      Convenience method to return ExtrudeGeometry

      [method:Object extractPoints]([page:Integer divisions])

      divisions -- The number of divisions to create on the shape
      Returns an object with a *shape* and *holes* property that each reference an array of [page:Vector2 Vector2s].

      [method:Object extractAllSpacedPoints]([page:Integer divisions])

      divisions -- The number of divisions to create on the shape
      Returns an object with a *shape* and *holes* property that each reference an array of [page:Vector2 Vector2s]. The points will all be equally spaced along the shape.

      [method:Array getPointsHoles]([page:Integer divisions])

      divisions -- The number of divisions to create on the shape
      Get an array of [page Vector2 Vector2s] that represent the holes in the shape.

      [method:Array getSpacedPointsHoles]([page:Integer divisions])

      divisions -- The number of divisions to create on the shape
      Get an array of equally spaced [page Vector2 Vector2s] that represent the holes in the shape.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/core/Curve.html0000644000175500017550000000412612610076566020670 0ustar debacledebacle

      [name]

      An abstract base class for creating a curve object that contains methods for interpolation. For an array of Curves see [page:CurvePath].

      Examples

      [example:webgl_geometry_extrude_splines geometry / extrude / splines ]

      Constructor

      [name]()

      This constructor creates a new [name].

      Methods

      [method:Vector getPoint]( t )

      Returns a vector for point t of the curve where t is between 0 and 1. Must be implemented in the extending class.

      [method:Vector getPointAt]( u )

      Returns a vector for point at relative position in curve according to arc length

      [method:Array getPoints]( divisions )

      Get sequence of points using getPoint( t )

      [method:Array getSpacedPoints]( divisions )

      Get sequence of equi-spaced points using getPointAt( u )

      [method:Float getLength]()

      Get total curve arc length

      [method:Array getLengths]( divisions )

      Get list of cumulative segment lengths

      [method:null updateArcLengths]()

      Update the cumlative segment distance cache

      [method:Float getUtoTmapping]( u, distance )

      Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant

      [method:Vector getTangent]( t )

      Returns a unit vector tangent at t. If the subclassed curve do not implement its tangent derivation, 2 points a small delta apart will be used to find its gradient which seems to give a reasonable approximation

      [method:Vector getTangentAt]( u )

      Returns tangent at equidistant point u on the curve

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/FontUtils.html0000644000175500017550000000607112610076566020604 0ustar debacledebacle

      [name]

      A class for text operations in three.js (See [page:TextGeometry])

      Properties

      [property:number divisions]

      The amount of segments in a curve. Default is 10.

      [property:string style]

      The style of the used font. Default is "normal".

      [property:string weight]

      The weight of the used font. Default is "normal".

      [property:string face]

      The name of the font. Default is "helvetiker".

      [property:object faces]

      All Fonts which are already loaded in.

      [property:number size]

      The size of the used Font. Default is 150.

      Methods

      [method:Object drawText]([page:string text])

      text -- The text to draw.
      Calculates the path and offset of the text in the used font. It returns an object like { paths : fontPaths, offset : width }.

      [method:Array Triangulate]([page:Array contour], [page:Boolean indices])

      contour -- Array of vector2 to define an contour
      indices -- A boolean indicating if you need to return indices.
      Triangulates a contour into an array of faces.

      [method:Object extractGlyphPoints]([page:string c], [page:string face], [page:number scale], [page:number offset], [page:Path path])

      c -- The character to extract.
      face -- The face to use.
      scale -- The scale of the character.
      offset -- The offset of the character compared to begin of the path.
      path -- The path to which to add the character points.
      This ectracts the glyphPoints of the character of the face and returns an object containing the path and the new offset.

      [method:Array generateShapes]([page:string text], [page:Object parameters])

      text -- The text to generate the shapes from.
      parameters -- The parameter containing
      size -- Default is 100. curveSegments -- Default is 4. font -- Default is "helvetiker". weight -- Default is "normal". style -- Default is "normal".
      Generates shapes from the text and return them as an Array of [page:Shape].

      [method:Object loadFace]([page:Object data])

      data -- The data of the face.
      This loads and saves the data of the face and return the data. When you add the font Data as javascriptfile, then this automatically get called. So there is no need to do this yourself.

      [method:Object getFace]()

      Returns the used font its data based on its style and weight.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/0000755000175500017550000000000012610076566020126 5ustar debacledebaclethree.js-r73/docs/api/extras/geometries/BoxGeometry.html0000644000175500017550000000401112610076566023254 0ustar debacledebacle [page:Geometry] →

      [name]

      BoxGeometry is the quadrilateral primitive geometry class. It is typically used for creating a cube or irregular quadrilateral of the dimensions provided with the 'width', 'height', and 'depth' constructor arguments.

      Example

      var geometry = new THREE.BoxGeometry( 1, 1, 1 ); var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} ); var cube = new THREE.Mesh( geometry, material ); scene.add( cube );

      Constructor

      [name]([page:Float width], [page:Float height], [page:Float depth], [page:Integer widthSegments], [page:Integer heightSegments], [page:Integer depthSegments])

      width — Width of the sides on the X axis.
      height — Height of the sides on the Y axis.
      depth — Depth of the sides on the Z axis.
      widthSegments — Optional. Number of segmented faces along the width of the sides. Default is 1.
      heightSegments — Optional. Number of segmented faces along the height of the sides. Default is 1.
      depthSegments — Optional. Number of segmented faces along the depth of the sides. Default is 1.

      Properties

      .parameters

      Using the above example code above as our basis:

      geometry.parameters; // outputs an object {width: 1, height: 1, depth: 1, widthSegments: undefined, heightSegments: undefined} cube.geometry.parameters; // as above cube.geometry.parameters.width; // === 1 cube.geometry.parameters.widthSegments // === undefined.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/TextGeometry.html0000644000175500017550000000640212610076566023456 0ustar debacledebacle [page:ExtrudeGeometry] →

      [name]

      This object creates a 3D object of text as a single object.

      Example

      [example:webgl_geometry_text geometry / text ]
      [example:webgl_geometry_text2 geometry / text2 ]

      Constructor

      [name]([page:String text], [page:Object parameters])

      text — The text that needs to be shown.
      parameters — Object that can contains the following parameters.
      • size — Float. Size of the text.
      • height — Float. Thickness to extrude text. Default is 50.
      • curveSegments — Integer. Number of points on the curves. Default is 12.
      • font — String. Font name.
      • weight — String. Font weight (normal, bold).
      • style — String. Font style (normal, italics).
      • bevelEnabled — Boolean. Turn on bevel. Default is False.
      • bevelThickness — Float. How deep into text bevel goes. Default is 10.
      • bevelSize — Float. How far from text outline is bevel. Default is 8.

      Available Fonts

      TextGeometry uses typeface.js generated fonts. Some existing fonts can be found located in /examples/fonts and must be included in the page.
      Font Weight Style File Path
      helvetiker normal normal /examples/fonts/helvetiker_regular.typeface.js
      helvetiker bold normal /examples/fonts/helvetiker_bold.typeface.js
      optimer normal normal /examples/fonts/optimer_regular.typeface.js
      optimer bold normal /examples/fonts/optimer_bold.typeface.js
      gentilis normal normal /examples/fonts/gentilis_regular.typeface.js
      gentilis bold normal /examples/fonts/gentilis_bold.typeface.js
      droid sans normal normal /examples/fonts/droid/droid_sans_regular.typeface.js
      droid sans bold normal /examples/fonts/droid/droid_sans_bold.typeface.js
      droid serif normal normal /examples/fonts/droid/droid_serif_regular.typeface.js
      droid serif bold normal /examples/fonts/droid/droid_serif_bold.typeface.js

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/CubeGeometry.html0000644000175500017550000000073512610076566023413 0ustar debacledebacle [page:Geometry] →

      [name]

      Renamed CubeGeometry to BoxGeometry. see [page:BoxGeometry].
      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/TorusGeometry.html0000644000175500017550000000257412610076566023654 0ustar debacledebacle [page:Geometry] →

      [name]

      A class for generating torus geometries

      Example

      var geometry = new THREE.TorusGeometry( 10, 3, 16, 100 ); var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); var torus = new THREE.Mesh( geometry, material ); scene.add( torus );

      Constructor

      [name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Float arc])

      radius — Default is 100.
      tube — Diameter of the tube. Default is 40.
      radialSegments — Default is 8
      tubularSegments — Default is 6.
      arc — Central angle. Default is Math.PI * 2.

      Properties

      Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/ParametricGeometry.html0000644000175500017550000000157712610076566024631 0ustar debacledebacle [page:Geometry] →

      [name]

      Generate geometry representing a parametric surface.

      Constructor

      [name]([page:Function func], [page:Integer slices], [page:Integer stacks])

      func — A function that takes in a [page:Float u] and [page:Float v] value each between 0 and 1 and returns a [page:Vector3]
      slices — The count of slices to use for the parametric function
      stacks — The count of stacks to use for the parametric function

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/CylinderGeometry.html0000644000175500017550000000401312610076566024277 0ustar debacledebacle [page:Geometry] →

      [name]

      A class for generating cylinder geometries

      Example

      var geometry = new THREE.CylinderGeometry( 5, 5, 20, 32 ); var material = new THREE.MeshBasicMaterial( {color: 0xffff00} ); var cylinder = new THREE.Mesh( geometry, material ); scene.add( cylinder );

      Constructor

      [name]([page:Float radiusTop], [page:Float radiusBottom], [page:Float height], [page:Integer radiusSegments], [page:Integer heightSegments], [page:Boolean openEnded], [page:Float thetaStart], [page:Float thetaLength])

      radiusTop — Radius of the cylinder at the top. Default is 20.
      radiusBottom — Radius of the cylinder at the bottom. Default is 20.
      height — Height of the cylinder. Default is 100.
      radiusSegments — Number of segmented faces around the circumference of the cylinder. Default is 8
      heightSegments — Number of rows of faces along the height of the cylinder. Default is 1.
      openEnded — A Boolean indicating whether the ends of the cylinder are open or capped. Default is false, meaning capped.
      thetaStart — Start angle for first segment, default = 0 (three o'clock position).
      thetaLength — The central angle, often called theta, of the circular sector. The default is 2*Pi, which makes for a complete cylinder.

      Properties

      Each of the constructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/ShapeGeometry.html0000644000175500017550000000371312610076566023574 0ustar debacledebacle [page:Geometry] →

      [name]

      Creates a one-sided polygonal geometry from one or more path shapes. Similar to [page:ExtrudeGeometry]

      Example

      var rectLength = 120, rectWidth = 40; var rectShape = new THREE.Shape(); rectShape.moveTo( 0,0 ); rectShape.lineTo( 0, rectWidth ); rectShape.lineTo( rectLength, rectWidth ); rectShape.lineTo( rectLength, 0 ); rectShape.lineTo( 0, 0 ); var rectGeom = new THREE.ShapeGeometry( rectShape ); var rectMesh = new THREE.Mesh( rectGeom, new THREE.MeshBasicMaterial( { color: 0xff0000 } ) ) ; scene.add( rectMesh );

      Constructor

      [name]([page:Array shapes], [page:Object options])

      shapes — [page:Array] of shapes, or a single [page:Shape shape]
      options — Optional options [page:Object object]
      • curveSegments - [page:Integer] - Not used at the moment - defaults to 12
      • material - [page:Integer] - index of the material in a material list
      • UVGenerator - A UV generator, defaults to [page:ExtrudeGeometry]'s WorldUVGenerator

      Methods

      .addShapeList([page:Array shapes], [page:Object options]) [page:this]

      shapes — [page:Array] of [page:Shape shapes]
      options — See options in constructor
      Adds a list of shapes to the geometry.

      [method:null addShape]([page:Shape shape], [page:Object options])

      shape — [page:Shape]
      options — See options in constructor
      Adds a single shape to the geometry

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/TubeGeometry.html0000644000175500017550000000523312610076566023432 0ustar debacledebacle [page:Geometry] →

      [name]

      Creates a tube that extrudes along a 3d curve

      Example

      var CustomSinCurve = THREE.Curve.create( function ( scale ) { //custom curve constructor this.scale = (scale === undefined) ? 1 : scale; }, function ( t ) { //getPoint: t is between 0-1 var tx = t * 3 - 1.5, ty = Math.sin( 2 * Math.PI * t ), tz = 0; return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale); } ); var path = new CustomSinCurve( 10 ); var geometry = new THREE.TubeGeometry( path, //path 20, //segments 2, //radius 8, //radiusSegments false //closed );

      Constructor

      [name]([page:Curve path], [page:Integer segments], [page:Float radius], [page:Integer radiusSegments], [page:Boolean closed])

      path — [page:Curve] - A path that inherits from the [page:Curve] base class
      segments — [page:Integer] - The number of segments that make up the tube, default is 64
      radius — [page:Float] - The radius of the tube, default is 1
      radiusSegments — [page:Integer] - The number of segments that make up the cross-section, default is 8
      closed — [page:Float] Is the tube open or closed, default is false

      Properties

      [property:Object parameters]

      An object with all of the parameters that were used to generate the geometry.

      [property:Array tangents]

      An array of [page:Vector3] tangents

      [property:Array normals]

      An array of [page:Vector3] normals

      [property:Array binormals]

      An array of [page:Vector3] binormals

      Methods

      THREE.TubeGeometry.FrenetFrames([page:Curve path], [page:Integer segments], [page:Boolean closed])

      path — A path that inherits from the [page:Curve] base class
      segments — The number of segments that make up the tube
      closed — Is the tube open or closed
      A static method that generates the Frenet Frames. This is internally run on any new TubeGeometry and then the generated tangents, normals, and binormals are exposed as properties on the TubeGeometry object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/CircleGeometry.html0000644000175500017550000000325712610076566023740 0ustar debacledebacle [page:Geometry] →

      [name]

      CircleGeometry is a simple shape of Euclidean geometry. It is contructed from a number of triangular segments that are oriented around a central point and extend as far out as a given radius. It is built counter-clockwise from a start angle and a given central angle. It can also be used to create regular polygons, where the number of segments determines the number of sides.

      Example

      var material = new THREE.MeshBasicMaterial({ color: 0x0000ff }); var radius = 5; var segments = 32; var circleGeometry = new THREE.CircleGeometry( radius, segments ); var circle = new THREE.Mesh( circleGeometry, material ); scene.add( circle );

      Constructor

      [name]([page:Float radius], [page:Integer segments], [page:Float thetaStart], [page:Float thetaLength])

      radius — Radius of the circle, default = 50.
      segments — Number of segments (triangles), minimum = 3, default = 8.
      thetaStart — Start angle for first segment, default = 0 (three o'clock position).
      thetaLength — The central angle, often called theta, of the circular sector. The default is 2*Pi, which makes for a complete circle.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/TetrahedronGeometry.html0000644000175500017550000000176512610076566025020 0ustar debacledebacle [page:PolyhedronGeometry] →

      [name]

      A class for generating a tetrahedron geometries.

      Constructor

      [name]([page:Float radius], [page:Integer detail])

      radius — Radius of the tetrahedron. Default is 1.
      detail — Default is 0. Setting this to a value greater than 0 adds vertices making it no longer a tetrahedron.

      Properties

      [property:Object parameters]

      An object with all of the parameters that were used to generate the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/DodecahedronGeometry.html0000644000175500017550000000177112610076566025115 0ustar debacledebacle [page:PolyhedronGeometry] →

      [name]

      A class for generating a dodecahedron geometries.

      Constructor

      [name]([page:Float radius], [page:Integer detail])

      radius — Radius of the dodecahedron. Default is 1.
      detail — Default is 0. Setting this to a value greater than 0 adds vertices making it no longer a dodecahedron.

      Properties

      [property:Object parameters]

      An object with all of the parameters that were used to generate the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/ExtrudeGeometry.html0000644000175500017550000001002212610076566024143 0ustar debacledebacle [page:Geometry] →

      [name]

      Creates extruded geometry from a path shape

      Constructor

      [name]([page:Array shapes], [page:Object options])

      shapes — Shape or an array of shapes.
      options — Object that can contain the following parameters.
      • curveSegments — int. number of points on the curves
      • steps — int. number of points used for subdividing segements of extrude spline
      • amount — int. Depth to extrude the shape
      • bevelEnabled — bool. turn on bevel
      • bevelThickness — float. how deep into the original shape bevel goes
      • bevelSize — float. how far from shape outline is bevel
      • bevelSegments — int. number of bevel layers
      • extrudePath — THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)
      • frames — THREE.TubeGeometry.FrenetFrames. containing arrays of tangents, normals, binormals
      • material — int. material index for front and back faces
      • extrudeMaterial — int. material index for extrusion and beveled faces
      • uvGenerator — Object. object that provides UV generator functions
      This object extrudes an 2D shape to an 3D geometry.

      Properties

      Methods

      [method:null addShapeList]([page:Array shapes], [page:Object options])

      shapes — An Array of shapes to add.
      options — Object that can contain the following parameters.
      • curveSegments — int. number of points on the curves
      • steps — int. number of points used for subdividing segements of extrude spline
      • amount — int. Depth to extrude the shape
      • bevelEnabled — bool. turn on bevel
      • bevelThickness — float. how deep into the original shape bevel goes
      • bevelSize — float. how far from shape outline is bevel
      • bevelSegments — int. number of bevel layers
      • extrudePath — THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)
      • frames — THREE.TubeGeometry.FrenetFrames. containing arrays of tangents, normals, binormals
      • material — int. material index for front and back faces
      • extrudeMaterial — int. material index for extrusion and beveled faces
      • uvGenerator — Object. object that provides UV generator functions
      Adds the shapes to the list to extrude.

      [method:null addShape]([page:Shape shape], [page:Object options])

      shape — A shape to add.
      options — Object that can contain the following parameters.
      • curveSegments — int. number of points on the curves
      • steps — int. number of points used for subdividing segements of extrude spline
      • amount — int. Depth to extrude the shape
      • bevelEnabled — bool. turn on bevel
      • bevelThickness — float. how deep into the original shape bevel goes
      • bevelSize — float. how far from shape outline is bevel
      • bevelSegments — int. number of bevel layers
      • extrudePath — THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)
      • frames — THREE.TubeGeometry.FrenetFrames. containing arrays of tangents, normals, binormals
      • material — int. material index for front and back faces
      • extrudeMaterial — int. material index for extrusion and beveled faces
      • uvGenerator — Object. object that provides UV generator functions
      Add the shape to the list to extrude.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/RingGeometry.html0000644000175500017550000000267112610076566023435 0ustar debacledebacle [page:Geometry] →

      [name]

      A class for generating a two-dimensional ring geometry.

      Example

      var geometry = new THREE.RingGeometry( 1, 5, 32 ); var material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ); var mesh = new THREE.Mesh( geometry, material ); scene.add( mesh );

      Constructor

      [name]([page:Float innerRadius], [page:Float outerRadius], [page:Integer thetaSegments], [page:Integer phiSegments], [page:Float thetaStart], [page:Float thetaLength])

      innerRadius — Default is 0, but it doesn't work right when innerRadius is set to 0.
      outerRadius — Default is 50.
      thetaSegments — Number of segments. A higher number means the ring will be more round. Minimum is 3. Default is 8.
      phiSegments — Minimum is 1. Default is 8.
      thetaStart — Starting angle. Default is 0.
      thetaLength — Central angle. Default is Math.PI * 2.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/IcosahedronGeometry.html0000644000175500017550000000203212610076566024763 0ustar debacledebacle [page:PolyhedronGeometry] →

      [name]

      A class for generating an icosahedron geometry.

      Constructor

      [name]([page:Float radius], [page:Integer detail])

      radius — Default is 1.
      detail — Default is 0. Setting this to a value greater than 0 adds more vertices making it no longer an icosahedron. When detail is greater than 1, it's effectively a sphere.

      Properties

      [property:Object parameters]

      An object with all of the parameters that were used to generate the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/TorusKnotGeometry.html0000644000175500017550000000311312610076566024476 0ustar debacledebacle [page:Geometry] →

      [name]

      Creates a torus knot, the particular shape of which is defined by a pair of coprime integers, p and q. If p and q are not coprime, the result will be a torus link.

      Example

      var geometry = new THREE.TorusKnotGeometry( 10, 3, 100, 16 ); var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); var torusKnot = new THREE.Mesh( geometry, material ); scene.add( torusKnot );

      Constructor

      [name]([page:Float radius], [page:Float tube], [page:Integer radialSegments], [page:Integer tubularSegments], [page:Integer p], [page:Integer q], [page:Float heightScale])

      radius — Default is 100.
      tube — Default is 40.
      radialSegments — Default is 64.
      tubularSegments — Default is 8.
      p — Default is 2.
      q — Default is 3.
      heightScale — Default is 1.

      Properties

      Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/SphereGeometry.html0000644000175500017550000000420612610076566023760 0ustar debacledebacle [page:Geometry] →

      [name]

      A class for generating sphere geometries

      Example

      var geometry = new THREE.SphereGeometry( 5, 32, 32 ); var material = new THREE.MeshBasicMaterial( {color: 0xffff00} ); var sphere = new THREE.Mesh( geometry, material ); scene.add( sphere );

      Constructor

      [name]([page:Float radius], [page:Integer widthSegments], [page:Integer heightSegments], [page:Float phiStart], [page:Float phiLength], [page:Float thetaStart], [page:Float thetaLength])

      radius — sphere radius. Default is 50.
      widthSegments — number of horizontal segments. Minimum value is 3, and the default is 8.
      heightSegments — number of vertical segments. Minimum value is 2, and the default is 6.
      phiStart — specify horizontal starting angle. Default is 0.
      phiLength — specify horizontal sweep angle size. Default is Math.PI * 2.
      thetaStart — specify vertical starting angle. Default is 0.
      thetaLength — specify vertical sweep angle size. Default is Math.PI.
      The geometry is created by sweeping and calculating vertexes around the Y axis (horizontal sweep) and the Z axis (vertical sweep). Thus, incomplete spheres (akin to 'sphere slices') can be created through the use of different values of phiStart, phiLength, thetaStart and thetaLength, in order to define the points in which we start (or end) calculating those vertices.

      Properties

      Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/OctahedronGeometry.html0000644000175500017550000000176112610076566024623 0ustar debacledebacle [page:PolyhedronGeometry] →

      [name]

      A class for generating an octahedron geometry.

      Constructor

      [name]([page:Float radius], [page:Integer detail])

      radius — Radius of the octahedron. Default is 1.
      detail — Default is 0. Setting this to a value greater than zero add vertices making it no longer an octahedron.

      Properties

      [property:Object parameters]

      An object with all of the parameters that were used to generate the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/PolyhedronGeometry.html0000644000175500017550000000353612610076566024662 0ustar debacledebacle [page:Geometry] →

      [name]

      A polyhedron is a solid in three dimensions with flat faces. This class will take an array of vertices, project them onto a sphere, and then divide them up to the desired level of detail. This class is used by [page:DodecahedronGeometry], [page:IcosahedronGeometry], [page:OctahedronGeometry], and [page:TetrahedronGeometry] to generate their respective geometries.

      Example

      var verticesOfCube = [ -1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1, -1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1, ]; var indicesOfFaces = [ 2,1,0, 0,3,2, 0,4,7, 7,3,0, 0,1,5, 5,4,0, 1,2,6, 6,5,1, 2,3,7, 7,6,2, 4,5,6, 6,7,4 ]; var geometry = new THREE.PolyhedronGeometry( verticesOfCube, indicesOfFaces, 6, 2 );

      Constructor

      [name]([page:Array vertices], [page:Array faces], [page:Float radius], [page:Integer detail])

      vertices — [page:Array] of points of the form [1,1,1, -1,-1,-1, ... ]
      faces — [page:Array] of indices that make up the faces of the form [0,1,2, 2,3,0, ... ]
      radius — [page:Float] - The radius of the final shape
      detail — [page:Integer] - How many levels to subdivide the geometry. The more detail, the smoother the shape.

      Properties

      [property:Object parameters]

      An object with all of the parameters that were used to generate the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/PlaneGeometry.html0000644000175500017550000000251712610076566023574 0ustar debacledebacle [page:Geometry] →

      [name]

      A class for generating plane geometries

      Example

      var geometry = new THREE.PlaneGeometry( 5, 20, 32 ); var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} ); var plane = new THREE.Mesh( geometry, material ); scene.add( plane );

      Constructor

      [name]([page:Float width], [page:Float height], [page:Integer widthSegments], [page:Integer heightSegments])

      width — Width along the X axis.
      height — Height along the Y axis.
      widthSegments — Optional. Default is 1.
      heightSegments — Optional. Default is 1.

      Properties

      Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/geometries/LatheGeometry.html0000644000175500017550000000303712610076566023570 0ustar debacledebacle [page:Geometry] →

      [name]

      Class for generating meshes with axial symmetry. Possible uses include donuts, pipes, vases etc. The lathe rotate around the Z axis.

      Example

      var points = []; for ( var i = 0; i < 10; i ++ ) { points.push( new THREE.Vector3( Math.sin( i * 0.2 ) * 15 + 50, 0, ( i - 5 ) * 2 ) ); } var geometry = new THREE.LatheGeometry( points ); var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); var lathe = new THREE.Mesh( geometry, material ); scene.add( lathe );

      Constructor

      [name]([page:Array points], [page:Integer segments], [page:Float phiStart], [page:Float phiLength])

      points — Array of Vector3s. Since this rotates around Z axis, the y-values can be set to 0
      segments — the number of circumference segments to generate. Default is 12.
      phiStart — the starting angle in radians. Default is 0.
      phiLength — the radian (0 to 2*PI) range of the lathed section 2*PI is a closed lathe, less than 2PI is a portion. Default is 2*PI
      This creates a LatheGeometry based on the parameters.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/SceneUtils.html0000644000175500017550000000377712610076566020745 0ustar debacledebacle

      [name]

      A class containing useful utility functions for scene manipulation.

      Methods

      [method:Object3D createMultiMaterialObject]([page:Geometry geometry], [page:Array materials])

      geometry -- The geometry for the Object.
      materials -- The materials for the object.
      Creates an new Object3D an new mesh for each material defined in materials. Beware that this is not the same as Meshfacematerial which defines multiple material for 1 mesh.
      This is mostly useful for object that need a material and a wireframe implementation.

      [method:null attach]([page:Object3D child], [page:Object3D scene], [page:Object3D parent])

      child -- The object to add to the parent
      scene -- The scene to detach the object on.
      parent -- The parent to attach the object from.
      Attaches the object to the parent without the moving the object in the worldspace. Beware that to do this the matrixWorld needs to be updated, this can be done by calling the updateMatrixWorld method on the parent object.

      [method:null detach]([page:Object3D child], [page:Object3D parent], [page:Object3D scene])

      child -- The object to remove from the parent
      scene -- The scene to attach the object on.
      parent -- The parent to detach the object from.
      Detaches the object from the parent and adds it back to the scene without moving in worldspace. Beware that to do this the matrixWorld needs to be updated, this can be done by calling the updateMatrixWorld method on the parent object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/ImageUtils.html0000644000175500017550000000611512610076566020717 0ustar debacledebacle

      [name]

      A Helper class to ease the loading of images of different types.

      Properties

      [property:string crossOrigin]

      The crossOrigin string to implement CORS for loading the image from a different domain that allows CORS.

      Methods

      [method:DataTexture generateDataTexture]([page:Number width], [page:Number height], [page:Number color])

      width -- The width of the texture.
      height -- The height of the texture.
      color -- The hexadecimal value of the color.
      Generates a texture of a single color. It is a DataTexture with format, RGBFormat.

      [method:CompressedTexture parseDDS]([page:String buffer], [page:boolean loadMipmaps])

      buffer -- A string containing the data of the dds.
      loadMipmaps -- A boolean to indicate if you need to load the mipmaps. Default is True.
      Parses a DDS Image from the string into a CompressedTexture.

      [method:Texture loadTexture]([page:String url], [page:UVMapping mapping], [page:Function onLoad], [page:Function onError])

      url -- the url of the texture
      mapping -- Can be an instance of [page:UVMapping THREE.UVMapping], [page:CubeReflectionMapping THREE.CubeReflectionMapping] or [page:SphericalReflectionMapping THREE.SphericalReflectionMapping]. Describes how the image is applied to the object.
      Use undefined instead of null as a default value. See mapping property of [page:Texture texture] for more details.
      onLoad -- callback function
      onError -- callback function
      A helper function to generates a [page:Texture THREE.Texture] from an image URL. Provides a load and error callback.

      [method:canvas getNormalMap]([page:Image image], [page:Float depth])

      image -- A loaded image element
      depth -- The depth of the normal map. Defaults to between -1 and 1.
      Translates an image element into a normal map with the range (-1, -1, -1) to (1, 1, 1) multiplied by the depth. Returns a canvas element.

      [method:CubeTexture loadTextureCube]([page:Array array], [page:Textures mapping], [page:function onLoad], [page:function onError])

      array -- An array of 6 images
      mapping -- Either [page:Textures THREE.CubeReflectionMapping] or [page:Textures THREE.CubeRefractionMapping]
      onLoad -- callback
      onError -- callback
      Creates a [page:CubeTexture] from 6 images.

      The images are loaded in the following order where p is positiive and n is negative: [ px, nx, py, ny, pz, nz ]. See [page:CubeTexture] for an example in code.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/GeometryUtils.html0000644000175500017550000000263012610076566021466 0ustar debacledebacle

      [name]

      Contains handy functions geometry manipulations.

      Methods

      .merge( [page:Geometry geometry1] , [page:Geometry geometry2], [page:Integer materialIndexOffset] )

      geometry1 — Parent geometry element
      geometry2 — Geometry that need to be added in parent
      materialIndexOffset — Offset applied to the materialIndex of all the new faces in the merged geometry. Default : 0

      .randomPointInTriangle( [page:Vector VectorA] , [page:Vector VectorB] , [page:Vector VectorC])

      VectorA — Vector
      VectorB — Vector
      VectorC — Vector
      returns [page:Int Point]

      .center ( [page:Vector VectorA] , [page:Vector VectorB] , [page:Vector VectorC])

      VectorA — Vector
      VectorB — Vector
      VectorC — Vector
      returns [page:Int Area]

      .center ( [page:Geometry geometry] )

      Geometry — Geometry to Center position

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/animation/0000755000175500017550000000000012610076566017742 5ustar debacledebaclethree.js-r73/docs/api/extras/animation/Animation.html0000644000175500017550000000660312610076566022554 0ustar debacledebacle

      [name]

      This class animates an object based on an hierarchy. This hierarchy can be Object3ds or bones.

      Constructor

      [name]([page:Object3d root], [page:String name])

      root -- The mesh to animate.
      name -- The name of the animation
      Creates an animation for root. The animation data is gathered from AnimationHandler based on its name.

      Properties

      [property:Object3d root]

      The root object of the animation.

      [property:Object data]

      The data containing the animation

      [property:Array hierarchy]

      The objects that are influenced by the animation.

      [property:number currentTime]

      The time elapsed since the last start/restart of the animation.

      [property:number timeScale]

      How much to scale the speed of the animation. Defaults to 1.

      [property:boolean isPlaying]

      Indicates whether the animation is playing. This shouldn't be adapted by user code.

      [property:boolean isPaused]

      Indicates whether the animation is paused. This shouldn't be adapted by user code.

      [property:boolean loop]

      Set to make the animation restart when the animation ends.

      [property:number interpolationType]

      The type to indicate how to interpolate between 2 data points.

      Methods

      [method:null play]([page:Number startTime])

      Starts the animation at the startTime (in seconds) of the animation.

      [method:null stop]()

      Stops the animation.

      [method:Boolean update]([page:Number deltaTimeMS])

      deltaTimeMS -- The time of the between the previous frame and this frame in miliseconds.
      Updates the animation in time. This shouldn't be called by user code. The animationHandler calls this method.

      [method:array interpolateCatmullRom]([page:Array points], [page:Number scale])

      points -- The 4 control point to calculate CatMullRom
      scale -- The scale between the previous key and the nex key
      Interpolates the point based on the key. Is used in update.

      [method:Object getNextKeyWith]([page:String type], [page:Object h], [page:Number key])

      type -- The animationtype for the key. Can be "pos", "rot" and "scl".
      h -- The object of the hierarchy that catins the key
      key -- The index of the next possible key.
      Gets the next key. Is used in Update.

      [method:Object getPrevKeyWith]([page:String type], [page:Object h], [page:Number key])

      type -- The animationtype for the key. Can be "pos", "rot" and "scl".
      h -- The object of the hierarchy that contains the key.
      key -- The index of the prev possible key.
      Gets the previous key. Is used in Update.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/animation/KeyFrameAnimation.html0000644000175500017550000000540212610076566024174 0ustar debacledebacle

      [name]

      Runs a keyframe animation as imported from the [page:ColladaLoader].

      Examples

      [example:webgl_loader_collada_keyframe loader / collada / keyframe ]

      Constructor

      [name]([page:Object data])

      data -- An individual animation object from a the [page:ColladaLoader], e.g. loadedColladaObj.animations[0]
      Creates a new keyframe animation and initializes it to the first keyframes.

      Properties

      [property:Object3D root]

      The root object of the animation

      [property:Object data]

      The data containing the animation

      [property:Array hierarchy]

      The objects that are influenced by the animation.

      [property:number currentTime]

      The time elapsed since the last start/restart of the animation.

      [property:number timeScale]

      How much to scale the speed of the animation. Defaults to 1.

      [property:boolean isPlaying]

      Indicates whether the animation is playing. This shouldn't be adapted by user code.

      [property:boolean isPaused]

      Indicates whether the animation is paused. This shouldn't be adapted by user code.

      [property:boolean loop]

      Set to make the animation restart when the animation ends.

      Methods

      [method:null play]([page:Number startTime])

      Starts the animation at the startTime (in seconds) of the animation.

      [method:null stop]()

      Stops the animation.

      [method:null update]([page:Float deltaTime])

      deltaTime -- The change in time in seconds
      Updates the keyframe animation

      [method:Object getNextKeyWith]([page:String sid], [page:Integer h], [page:Integer key])

      sid -- The string id
      h -- The index in the heirarchy to use
      key -- The index of which key to start from
      Used internally to traverse the animation

      [method:Object getPrevKeyWith]([page:String sid], [page:Integer h], [page:Integer key])

      sid -- The string id
      h -- The index in the heirarchy to use
      key -- The index of which key to start from
      Used internally to traverse the animation
      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/animation/AnimationHandler.html0000644000175500017550000000470612610076566024054 0ustar debacledebacle

      [name]

      The AnimationHandler handles the initialisation of the Animation data and the animations itself. It keeps track of every animation and if it's active or not. It also update all animations which are active if its method *update* is called.

      Constructor

      [name]()

      The animationHandler can't be called as constructor.

      Properties

      [property:number CATMULLROM]

      Enum Value to indicate that the animation needs to be interpolated as CATMULLROM.

      [property:number CATMULLROM_FORWARD]

      Enum Value to indicate that the animation needs to be interpolated as CATMULLROM_FORWARD.

      [property:number LINEAR]

      Enum Value to indicate that the animation needs to be interpolated as LINEAR.

      Methods

      [method:null removeFromUpdate]([page:Animation animation])

      animation -- The Animation to remove from the update.
      Removes the animation from the update cycle. This gets called when the animation stops. This shouldn't be called by usercode.

      [method:Object get]([page:String name])

      name -- The name of the animationData
      Gets the animationData from its library.

      [method:null update]([page:Number deltaTimeMS])

      deltaTimeMS -- Time elapsed since last update in milliseconds.
      Updates all active animations with deltaTime.

      [method:null parse]([page:Object root])

      root -- object
      Parses the object to get the hierachy.

      [method:null add]([page:object data])

      data -- The animationData
      Adds the animationData from its library.

      [method:null addToUpdate]([page:Animation animation])

      animation -- The Animation to add from the update.
      Adds the animation from the update cycle. This gets called when the animation starts. This shouldn't be called by user code.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/0000755000175500017550000000000012610076566017272 5ustar debacledebaclethree.js-r73/docs/api/extras/curves/CubicBezierCurve3.html0000644000175500017550000000313512610076566023440 0ustar debacledebacle [page:Curve] →

      [name]

      Create a smooth 3d cubic bezier curve.

      Example

      var curve = new THREE.CubicBezierCurve3( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( -5, 15, 0 ), new THREE.Vector3( 20, 15, 0 ), new THREE.Vector3( 10, 0, 0 ) ); var geometry = new THREE.Geometry(); geometry.vertices = curve.getPoints( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); // Create the final Object3d to add to the scene var curveObject = new THREE.Line( geometry, material );

      Constructor

      [name]( [page:Vector3 v0], [page:Vector3 v1], [page:Vector3 v2], [page:Vector3 v3] )

      [page:Vector3 v0] – The starting point
      [page:Vector3 v1] – The first control point
      [page:Vector3 v2] – The second control point
      [page:Vector3 v3] – The ending point

      Properties

      [property:Vector3 v0]

      [property:Vector3 v1]

      [property:Vector3 v2]

      [property:Vector3 v3]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/QuadraticBezierCurve.html0000644000175500017550000000276312610076566024253 0ustar debacledebacle [page:Curve] →

      [name]

      Create a smooth 2d quadratic bezier curve.

      Example

      var curve = new THREE.QuadraticBezierCurve( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( 20, 15, 0 ), new THREE.Vector3( 10, 0, 0 ) ); var path = new THREE.Path( curve.getPoints( 50 ) ); var geometry = path.createPointsGeometry( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); //Create the final Object3d to add to the scene var curveObject = new THREE.Line( geometry, material );

      Constructor

      [name]( [page:Vector2 v0], [page:Vector2 v1], [page:Vector2 v2] )

      [page:Vector2 v0] – The starting point
      [page:Vector2 v1] – The middle control point
      [page:Vector2 v2] – The ending point

      Properties

      [property:Vector2 v0]

      [property:Vector2 v1]

      [property:Vector2 v2]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/EllipseCurve.html0000644000175500017550000000450312610076566022564 0ustar debacledebacle [page:Curve] →

      [name]

      Creates a 2d curve in the shape of an ellipse.

      Example

      var curve = new THREE.EllipseCurve( 0, 0, // ax, aY 10, 10, // xRadius, yRadius 0, 2 * Math.PI, // aStartAngle, aEndAngle false, // aClockwise 0 // aRotation ); var path = new THREE.Path( curve.getPoints( 50 ) ); var geometry = path.createPointsGeometry( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); // Create the final Object3d to add to the scene var ellipse = new THREE.Line( geometry, material );

      Constructor

      [name]( [page:Float aX], [page:Float aY], [page:Float xRadius], [page:Float yRadius], [page:Radians aStartAngle], [page:Radians aEndAngle], [page:Boolean aClockwise], [page:Radians aRotation] )

      aX – The X center of the ellipse
      aY – The Y center of the ellipse
      xRadius – The radius of the ellipse in the x direction
      yRadius – The radius of the ellipse in the y direction
      aStartAngle – The start angle of the curve in radians starting from the middle right side
      aEndAngle – The end angle of the curve in radians starting from the middle right side
      aClockwise – Whether the ellipse is clockwise
      aRotation – The rotation angle of the ellipse in radians, counterclockwise from the positive X axis (optional)

      Note: When going clockwise it's best to set the start angle to (Math.PI * 2) and then work towards lower numbers.

      Properties

      [property:Float aX]

      [property:Float aY]

      [property:Radians xRadius]

      [property:Radians yRadius]

      [property:Float aStartAngle]

      [property:Float aEndAngle]

      [property:Boolean aClockwise]

      [property:Float aRotation]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/QuadraticBezierCurve3.html0000644000175500017550000000274112610076566024332 0ustar debacledebacle [page:Curve] →

      [name]

      Create a smooth 3d quadratic bezier curve.

      Example

      var curve = new THREE.QuadraticBezierCurve3( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( 20, 15, 0 ), new THREE.Vector3( 10, 0, 0 ) ); var geometry = new THREE.Geometry(); geometry.vertices = curve.getPoints( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); // Create the final Object3d to add to the scene var curveObject = new THREE.Line( geometry, material );

      Constructor

      [name]( [page:Vector3 v0], [page:Vector3 v1], [page:Vector3 v2] )

      [page:Vector3 v0] – The starting point
      [page:Vector3 v1] – The middle control point
      [page:Vector3 v2] – The ending point

      Properties

      [property:Vector3 v0]

      [property:Vector3 v1]

      [property:Vector3 v2]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/LineCurve.html0000644000175500017550000000142412610076566022055 0ustar debacledebacle [page:Curve] →

      [name]

      A curve representing a 2d line segment

      Constructor

      [name]( [page:Vector2 v1], [page:Vector2 v2] )

      v1 – The start point
      v2 - The end point

      Properties

      [property:Vector2 v1]

      [property:Vector2 v2]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/CubicBezierCurve.html0000644000175500017550000000316112610076566023354 0ustar debacledebacle [page:Curve] →

      [name]

      Create a smooth 2d cubic bezier curve.

      Example

      var curve = new THREE.CubicBezierCurve( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( -5, 15, 0 ), new THREE.Vector3( 20, 15, 0 ), new THREE.Vector3( 10, 0, 0 ) ); var path = new THREE.Path( curve.getPoints( 50 ) ); var geometry = path.createPointsGeometry( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); // Create the final Object3d to add to the scene var curveObject = new THREE.Line( geometry, material );

      Constructor

      [name] ( [page:Vector2 v0], [page:Vector2 v1], [page:Vector2 v2], [page:Vector2 v3] )

      [page:Vector2 v0] – The starting point
      [page:Vector2 v1] – The first control point
      [page:Vector2 v2] – The second control point
      [page:Vector2 v3] – The ending point

      Properties

      [property:Vector2 v0]

      [property:Vector2 v1]

      [property:Vector2 v2]

      [property:Vector2 v3]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/SplineCurve.html0000644000175500017550000000236512610076566022425 0ustar debacledebacle [page:Curve] →

      [name]

      Create a smooth 2d spline curve from a series of points

      Example

      // Create a sine-like wave var curve = new THREE.SplineCurve( [ new THREE.Vector2( -10, 0 ), new THREE.Vector2( -5, 5 ), new THREE.Vector2( 0, 0 ), new THREE.Vector2( 5, -5 ), new THREE.Vector2( 10, 0 ) ] ); var path = new THREE.Path( curve.getPoints( 50 ) ); var geometry = path.createPointsGeometry( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); // Create the final Object3d to add to the scene var splineObject = new THREE.Line( geometry, material );

      Constructor

      [name]( [page:Array points] )

      points – An array of [page:Vector2] points

      Properties

      [property:Array points]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/SplineCurve3.html0000644000175500017550000000252412610076566022505 0ustar debacledebacle [page:Curve] →

      [name]

      Create a smooth 3d spline curve from a series of points

      Example

      //Create a closed bent a sine-like wave var curve = new THREE.SplineCurve3( [ new THREE.Vector3( -10, 0, 10 ), new THREE.Vector3( -5, 5, 5 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 5, -5, 5 ), new THREE.Vector3( 10, 0, 10 ) ] ); var geometry = new THREE.Geometry(); geometry.vertices = curve.getPoints( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } ); //Create the final Object3d to add to the scene var splineObject = new THREE.Line( geometry, material );

      [example:webgl_geometry_extrude_splines geometry / extrude / splines ] (choose PipeSpline)

      Constructor

      [name]( [page:Array points] )

      points – An array of [page:Vector3] points

      Properties

      [property:Array points]

      Methods

      See [page:Curve] for inherited methods

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/LineCurve3.html0000644000175500017550000000142312610076566022137 0ustar debacledebacle [page:Curve] →

      [name]

      A curve representing a 3d line segment

      Constructor

      [name]( [page:Vector3 v1], [page:Vector3 v2] )

      v1 – The start point
      v2 - The end point

      Properties

      [property:Vector3 v1]

      [property:Vector3 v2]

      Methods

      See [page:Curve] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/ArcCurve.html0000644000175500017550000000072412610076566021675 0ustar debacledebacle [page:EllipseCurve] →

      [name]

      Alias for [page:EllipseCurve]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/curves/ClosedSplineCurve3.html0000644000175500017550000000241012610076566023631 0ustar debacledebacle [page:Curve] →

      [name]

      Create a smooth 3d spline curve from a series of points that loops back onto itself

      Example

      //Create a closed wavey loop var curve = new THREE.ClosedSplineCurve3( [ new THREE.Vector3( -10, 0, 10 ), new THREE.Vector3( -5, 5, 5 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 5, -5, 5 ), new THREE.Vector3( 10, 0, 10 ) ] ); var geometry = new THREE.Geometry(); geometry.vertices = curve.getPoints( 50 ); var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );

      [example:webgl_geometry_extrude_splines geometry / extrude / splines] (choose SampleClosedSpline)

      Constructor

      [name]( [page:Array points] )

      points – An array of [page:Vector3] points

      Properties

      [property:Array points]

      Methods

      See [page:Curve] for inherited methods

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/objects/0000755000175500017550000000000012610076566017414 5ustar debacledebaclethree.js-r73/docs/api/extras/objects/ImmediateRenderObject.html0000644000175500017550000000155412610076566024474 0ustar debacledebacle [page:Object3D] →

      [name]

      base class for immediate rendering objects.

      Constructor

      [name]()

      This creates a new [name].

      Methods

      [method:null render]([page:Function renderCallback])

      renderCallback -- A function to render the generated object.
      This function needs to be overridden to start the creation of the object and should call renderCallback when finished.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/objects/MorphBlendMesh.html0000644000175500017550000001160212610076566023151 0ustar debacledebacle [page:Mesh] →

      [name]

      A mesh that can blend together multiple animated morph targets.

      Example

      [example:webgl_morphtargets_md2_control morphtargets / md2 / controll]

      Constructor

      [name]([page:Geometry geometry], [page:Material material])

      geometry — An instance of [page:Geometry].
      material — An instance of [page:Material] (optional).

      Properties

      [property:object animationsMap]

      An object of named animations as added by [page:MorphBlendMesh.createAnimation].

      [property:array animationsList]

      The list of animations as added by [page:MorphBlendMesh.createAnimation].

      Methods

      [method:null setAnimationWeight]([page:String name], [page:Float weight])

      name -- The name of the animation
      weight -- Weight of the animation, typically 0-1
      Set the weight of how much this animation will apply to the overall morph. 0 is off, 1 is full weight.

      [method:null setAnimationFPS]([page:String name], [page:Float fps])

      name -- The name of the animation
      fps -- The number of frames (morphTargets) per second
      A frame is typically 1 morph target.

      [method:null createAnimation]([page:String name], [page:Integer start], [page:Integer end], [page:Float fps])

      name -- The name of the animation
      start -- The starting frame (morph)
      end -- The ending frame (morph)
      fps -- How many frames (morphs) to play per second
      Creates an animation object that gets added to both the [page:MorphBlendMesh.animationsMap animationsMap] and [page:MorphBlendMesh.animationsList animationsList].

      Animation object:

      startFrame -- Starting frame
      endFrame -- Ending frame
      length -- The number of frames
      fps -- The frames per second
      duration -- The length of the animation in seconds
      lastFrame -- The previous frame that was played
      currentFrame -- The current frame
      active -- Whether or not the animation is being played
      time -- The time in seconds of the animation
      direction -- Which way to play the animation
      weight -- The weight of the animation
      directionBackwards -- Is playing backwards
      mirroredLoop -- Loop back and forth

      [method:null playAnimation]([page:String name])

      name -- The name of the animation
      Sets the animation to active and animation time to 0

      [method:null update]([page:Float delta])

      delta -- Time in seconds
      Updates and plays the animation

      [method:null autoCreateAnimations]([page:Float fps])

      fps -- Frames per second
      Goes through the geometry's morphTargets and generates animations based on the morphTargets' names. Names are of the form "walk_01", "walk_02", "walk_03", etc or "run001", "run002", "run003".

      [method:null setAnimationDuration]([page:String name], [page:Float duration])

      name -- The name of the animation
      duration -- How long in seconds to play the animation
      Updates the animation object with proper values to update the duration.

      [method:null setAnimationDirectionForward]([page:String name])

      name -- The name of the animation
      Sets the animation to play forwards

      [method:null setAnimationDirectionBackward]([page:String name])

      name -- The name of the animation
      Sets the animation to play backwards

      [method:Float getAnimationDuration]([page:String name])

      name -- The name of the animation
      Returns the duration in seconds of the animation. Returns -1 if it can't be found.

      [method:Float getAnimationTime]([page:String name])

      name -- The name of the animation
      Returns the current time position of the animation.

      [method:null setAnimationTime]([page:String name], [page:Float time])

      name -- The name of the animation
      time -- The time in seconds
      Sets the current time position of the animation

      [method:null stopAnimation]([page:String name])

      name -- The name of the animation
      Stops the playback of the animation

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/0000755000175500017550000000000012610076566017425 5ustar debacledebaclethree.js-r73/docs/api/extras/helpers/AxisHelper.html0000644000175500017550000000161512610076566022362 0ustar debacledebacle [page:Line] →

      [name]

      An axis object to visualize the the 3 axes in a simple way.
      The X axis is red. The Y axis is green. The Z axis is blue.

      Example

      var axisHelper = new THREE.AxisHelper( 5 ); scene.add( axisHelper );

      Constructor

      [name]([page:Number size])

      size -- Define the size of the line representing the axes.
      Creates an axisHelper with lines of length size.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/GridHelper.html0000644000175500017550000000263412610076566022345 0ustar debacledebacle [page:Line] →

      [name]

      The GridHelper is an object to define grids. Grids are two-dimensional arrays of lines.

      Example

      var size = 10; var step = 1; var gridHelper = new THREE.GridHelper( size, step ); scene.add( gridHelper ); [example:webgl_helpers Example using various helpers]

      Constructor

      [name]([page:number size], [page:Number step])

      size -- The size of the grid
      step -- The size of the step between 2 lines
      Creates a new [name] of size 'size' and with steps of size 'step'.

      Methods

      [method:null setColors]([page:number colorCenterLine], [page:Number colorGrid])

      colorCenterLine -- The color of the centerline. This can be a [page:Color], a hexadecimal value and an CSS-Color name.
      colorGrid -- The color of the lines of the grid. This can be a [page:Color], a hexadecimal value and an CSS-Color name.
      Updates the color of the grid lines.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/BoxHelper.html0000644000175500017550000000217612610076566022211 0ustar debacledebacle [page:Line] →

      [name]

      Helper object to show a wireframe box (with no face diagonals) around an object

      Example

      var sphere = new THREE.SphereGeometry(); var object = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial(0xff0000) ); var box = new THREE.BoxHelper( object ); scene.add( box );

      Constructor

      [name]( [page:Object3D object] )

      Creates a new wireframe box matching the size of the passed box.

      Properties

      (none)

      Methods

      [method:null update]( [page:Object3D object] )

      Updates the helper's geometry to match the dimensions of the [page:Geometry.boundingBox bounding box] of the passed object's geometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/ArrowHelper.html0000644000175500017550000000434612610076566022554 0ustar debacledebacle [page:Object3D] →

      [name]

      An 3D arrow Object.

      Example

      var dir = new THREE.Vector3( 1, 0, 0 ); var origin = new THREE.Vector3( 0, 0, 0 ); var length = 1; var hex = 0xffff00; var arrowHelper = new THREE.ArrowHelper( dir, origin, length, hex ); scene.add( arrowHelper );

      Constructor

      [name]([page:Vector3 dir], [page:Vector3 origin], [page:Number length], [page:Number hex], [page:Number headLength], [page:Number headWidth] )

      dir -- Vector3 -- direction from origin. Must be a unit vector.
      origin -- Vector3
      length -- scalar
      hex -- hexadecimal value to define color ex:0xffff00
      headLength -- The length of the head of the arrow
      headWidth -- The length of the width of the arrow
      This creates an arrow starting in origin in the direction dir for a certain length. It is also possible to change color.

      Properties

      [property:Line line]

      Contains the line part of the arrowHelper.

      [property:Mesh cone]

      Contains the cone part of the arrowHelper.

      Methods

      [method:null setColor]([page:Number hex])

      hex -- The hexadicmal value of the color
      Sets the color of the arrowHelper.

      [method:null setLength]([page:Number length], [page:Number headLength], [page:Number headWidth])

      length -- The desired length
      headLength -- The length of the head of the arrow
      headWidth -- The length of the width of the arrow
      Sets the length of the arrowhelper.

      [method:null setDirection]([page:Vector3 dir])

      dir -- The desired direction. Must be a unit vector.
      Sets the direction of the arrowhelper.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/SpotLightHelper.html0000644000175500017550000000207712610076566023376 0ustar debacledebacle [page:Object3D] →

      [name]

      This displays a cylinder helper object for a [page:SpotLight]

      Example

      var spotLight = new THREE.SpotLight( 0xffffff ); spotLight.position.set( 10, 10, 10 ); scene.add( spotLight ); var spotLightHelper = new THREE.SpotLightHelper( spotLight ); scene.add( spotLightHelper );

      Constructor

      [name]([page:SpotLight light])

      light -- The [page:SpotLight] to display

      Properties

      [property:SpotLight light]

      The [page:SpotLight]

      Methods

      [method:null update]()

      Updates the light helper.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/WireframeHelper.html0000644000175500017550000000266412610076566023404 0ustar debacledebacle [page:Line] →

      [name]

      Creates a wireframe object that shows the edges of another object's geometry. To draw a wireframe image showing only "hard" edges (edges between non-coplanar faces), see [page:EdgesHelper].

      Example

      geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); object = new THREE.Mesh( geometry, material ); wireframe = new THREE.WireframeHelper( object, 0x00ff00 ); scene.add( object ); scene.add( wireframe ); [example:webgl_helpers Example using various helpers], [example:webgl_materials_wireframe Alternative approach using a shader.]

      Constructor

      [name]( [page:Object3D object], [page:Color color] )

      object -- Object of which to draw edges
      color -- Color of the edges.
      Creates a [page:Line], showing only the edges between vertices of an object.

      Properties

      none

      Methods

      none

      Source

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/VertexNormalsHelper.html0000644000175500017550000000313012610076566024261 0ustar debacledebacle [page:Line] →

      [name]

      Renders [page:ArrowHelper arrows] to visualize an object's vertex normal vectors. Requires that normals have been specified in a [page:BufferAttribute custom attribute] or have been calculated using [page:Geometry.computeVertexNormals computeVertexNormals].

      Example

      geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); object = new THREE.Mesh( geometry, material ); edges = new THREE.VertexNormalsHelper( object, 2, 0x00ff00, 1 ); scene.add( object ); scene.add( edges ); [example:webgl_helpers Example using various helpers]

      Constructor

      [name]( [page:Object3D object], [page:Number size], [page:Color color], [page:Number linewidth] )

      object -- object for which to render vertex normals size -- size (length) of the arrows color -- color of the arrows linewidth -- width of the arrow lines

      Properties

      [property:Object3D object]

      The attached object

      Methods

      [method:null update]()

      Updates the vertex normal preview based on movement of the object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/PointLightHelper.html0000644000175500017550000000240512610076566023535 0ustar debacledebacle [page:Mesh] →

      [name]

      This displays a helper object for a [page:PointLight]

      Example

      var pointLight = new THREE.PointLight( 0xff0000, 1, 100 ); pointLight.position.set( 10, 10, 10 ); scene.add( pointLight ); var sphereSize = 1; var pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize ); scene.add( pointLightHelper ); [example:webgl_helpers Example using various helpers]

      Constructor

      [name]([page:PointLight light], [page:Float sphereSize])

      light -- The [page:PointLight] to display.
      sphereSize -- The size of the sphere helper

      Properties

      [property:PointLight light]

      The [page:PointLight] that is being represented.

      Methods

      [method:null update]()

      Updates the light helper.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/BoundingBoxHelper.html0000644000175500017550000000342612610076566023676 0ustar debacledebacle [page:Mesh] →

      [name]

      A helper object to show the world-axis-aligned bounding box for an object.

      Example

      var hex = 0xff0000; var sphereMaterial = new THREE.MeshLambertMaterial( {color: 0x00ff00} ); var sphere = new THREE.Mesh( new THREE.SphereGeometry( 30, 12, 12), sphereMaterial ); scene.add( sphere ); var bbox = new THREE.BoundingBoxHelper( sphere, hex ); bbox.update(); scene.add( bbox );
      Note that this helper will create a wireframe [page:Mesh] object with a [page:BoxGeometry]; the resulting bounding box object will therefore have face diagonals. You may want to use [page:BoxHelper], which generates a [page:Line] object without face diagonals.

      Constructor

      [name]([page:Object3D object], [page:Number hex])

      object -- Object3D -- the object3D to show the world-axis-aligned boundingbox.
      hex -- hexadecimal value to define color ex:0x888888
      This creates an line object to the boundingbox.

      Properties

      [property:Object3D object]

      Contains the object3D to show the world-axis-aligned boundingbox.

      [property:Box3 box]

      Contains the bounding box of the object.

      Methods

      [method:null update]()

      Updates the BoundingBoxHelper based on the object property.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/HemisphereLightHelper.html0000644000175500017550000000223112610076566024532 0ustar debacledebacle [page:Object3D] →

      [name]

      Creates a visual aid for a [page:HemisphereLight HemisphereLight].

      Constructor

      [name]([page:HemisphereLight light], [page:Number sphereSize])

      light -- The HemisphereLight.
      sphereSize -- The size of the sphere that shows the location.
      Creates an helper for the hemispherelight.

      Properties

      [property:Mesh lightSphere]

      The sphere mesh that shows the location of the hemispherelight.

      [property:HemisphereLight light]

      Contains the HemisphereLight.

      Methods

      [method:null update]()

      Updates the helper to match the position and direction of the [page:.light].

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/FaceNormalsHelper.html0000644000175500017550000000324512610076566023651 0ustar debacledebacle [page:Line] →

      [name]

      Renders [page:ArrowHelper arrows] to visualize an object's [page:Face3 face] normals. Requires that the object's geometry be an instance of [page:Geometry] (does not work with [page:BufferGeometry]), and that face normals have been specified on all [page:Face3 faces] or calculated with [page:Geometry.computeFaceNormals computeFaceNormals].

      Example

      geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); object = new THREE.Mesh( geometry, material ); edges = new THREE.FaceNormalsHelper( object, 2, 0x00ff00, 1 ); scene.add( object ); scene.add( edges ); [example:webgl_helpers Example using various helpers]

      Constructor

      [name]( [page:Object3D object], [page:Number size], [page:Color color], [page:Number linewidth] )

      object -- object for which to render face normals size -- size (length) of the arrows color -- color of the arrows linewidth -- width of the arrow lines

      Properties

      [property:Object3D object]

      The attached object

      Methods

      [method:null update]()

      Updates the face normal preview based on movement of the object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/DirectionalLightHelper.html0000644000175500017550000000244512610076566024705 0ustar debacledebacle [page:Object3D] →

      [name]

      Visualize a [page:DirectionalLight]'s effect on the scene

      Constructor

      [name]([page:DirectionalLight light], [page:Number size])

      light -- [page:DirectionalLight] -- Light to visualize
      size -- dimensions of the plane
      Creates a line and plane to visualize the light's position and direction

      Properties

      [property:Line lightPlane]

      Contains the line mesh showing the location of the directional light.

      [property:DirectionalLight light]

      Contains the directionalLight.

      [property:Line targetLine]

      Contains the line mesh that shows the direction of the light.

      Methods

      .[method:null update]()

      Updates the helper to match the position and direction of the [page:.light].

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/EdgesHelper.html0000644000175500017550000000302012610076566022475 0ustar debacledebacle [page:Line] →

      [name]

      Creates a wireframe object that shows the "hard" edges of another object's geometry. To draw a full wireframe image of an object, see [page:WireframeHelper].

      Example

      geometry = new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 ); material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); object = new THREE.Mesh( geometry, material ); edges = new THREE.EdgesHelper( object, 0x00ff00 ); scene.add( object ); scene.add( edges );

      Constructor

      [name]( [page:Object3D object], [page:Color color], [page:Float thresholdAngle] )

      object -- Object of which to draw edges
      color -- Color of the edges.
      thresholdAngle -- the minimim angle (in degrees), between the face normals of adjacent faces, that is required to render an edge. Default is 0.1.
      Creates a [page:Line], showing only the "hard" edges of the passed object; specifically, no edge will be drawn between faces which are adjacent and coplanar (or nearly coplanar).

      Properties

      none

      Methods

      none

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/extras/helpers/CameraHelper.html0000644000175500017550000000216112610076566022643 0ustar debacledebacle [page:Line] →

      [name]

      The camera Helper is an Object3D which helps visualizing what a camera contains in its frustum.
      It visualizes the frustum with an line Geometry.

      Constructor

      [name]([page:Camera camera])

      camera -- The camera to visualize.
      This create a new [Name] for the specified camera.

      Properties

      [property:object pointMap]

      This contains the points to viualize the cameraHelper

      [property:Camera camera]

      The camera to visualize.

      Methods

      [method:null update]()

      Updates the helper based on the projectionMatrix of the camera.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/cameras/0000755000175500017550000000000012610076566016070 5ustar debacledebaclethree.js-r73/docs/api/cameras/Camera.html0000644000175500017550000000332312610076566020147 0ustar debacledebacle [page:Object3D] →

      [name]

      Abstract base class for cameras. This class should always be inherited when you build a new camera.

      Constructor

      [name]()

      This constructor sets the following properties to the correct type: matrixWorldInverse and projectionMatrix.

      Properties

      [property:Matrix4 matrixWorldInverse]

      This is the inverse of matrixWorld. MatrixWorld contains the Matrix which has the world transform of the Camera.

      [property:Matrix4 projectionMatrix]

      This is the matrix which contains the projection.

      Methods

      [method:Vector3 getWorldDirection]([page:Vector3 vector])

      vector — (optional)

      It returns a vector representing the direction in which the camera is looking, in world space.

      [method:null lookAt]( [page:Vector3 vector] )

      vector — point to look at

      This makes the camera look at the vector position in the global space as long as the parent of this camera is the scene or at position (0,0,0).

      [method:Camera clone]( [page:Camera camera] )

      camera — camera to clone

      It returns a clone of camera.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/cameras/CubeCamera.html0000644000175500017550000000414212610076566020746 0ustar debacledebacle [page:Object3D] →

      [name]

      Creates 6 cameras that render to a [page:WebGLRenderTargetCube].

      Examples

      [example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]
      [example:webgl_materials_cubemap_dynamic2 materials / cubemap / dynamic2 ]
      [example:webgl_shading_physical shading / physical ]
      //Create cube camera var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 ); scene.add( cubeCamera ); //Create car var chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeCamera.renderTarget } ); var car = new Mesh( carGeometry, chromeMaterial ); scene.add( car ); //Update the render target cube car.setVisible( false ); cubeCamera.position.copy( car.position ); cubeCamera.updateCubeMap( renderer, scene ); //Render the scene car.setVisible( true ); renderer.render( scene, camera );

      Constructor

      [name]([page:number near], [page:number far], [page:number cubeResolution])

      near -- The near clipping distance.
      far -- The far clipping distance
      cubeResolution -- Sets the width of the cube.
      Constructs a CubeCamera that contains 6 [page:PerspectiveCamera PerspectiveCameras] that then render to a [page:WebGLRenderTargetCube]

      Properties

      [property:WebGLRenderTargetCube renderTarget]

      The cube texture that gets generated.

      Methods

      [method:null updateCubeMap]([page:WebGLRenderer renderer], [page:Scene scene])

      renderer -- The current WebGL renderer
      scene -- The current scene
      Call this to update the renderTarget.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/cameras/PerspectiveCamera.html0000644000175500017550000001013212610076566022355 0ustar debacledebacle [page:Object3D] → [page:Camera] →

      [name]

      Camera with perspective projection.

      Example

      [example:canvas_effects_stereo effects / stereo ]
      [example:canvas_geometry_birds geometry / birds ]
      [example:canvas_geometry_cube geometry / cube ]
      [example:webgl_animation_skinning_blending animation / skinning / blending ]
      [example:webgl_animation_skinning_morph animation / skinning / blending ]
      [example:webgl_interactive_cubes interactive / cubes ]
      [example:webgl_loader_collada_skinning loader / collada / skinning ]
      var camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 ); scene.add( camera );

      Constructor

      [name]( [page:Float fov], [page:Float aspect], [page:Float near], [page:Float far] )

      fov — Camera frustum vertical field of view.
      aspect — Camera frustum aspect ratio.
      near — Camera frustum near plane.
      far — Camera frustum far plane.

      Properties

      [property:number zoom]

      Gets or sets the zoom factor of the camera.

      [property:Float fov]

      Camera frustum vertical field of view, from bottom to top of view, in degrees.

      [property:Float aspect]

      Camera frustum aspect ratio, window width divided by window height.

      [property:Float near]

      Camera frustum near plane.

      [property:Float far]

      Camera frustum far plane.

      Methods

      [method:null setLens]( [page:Float focalLength], [page:Float frameSize] )

      focalLength — focal length
      frameSize — frame size
      Uses focal length (in mm) to estimate and set FOV 35mm (fullframe) camera is used if frame size is not specified.
      Formula based on [link:http://www.bobatkins.com/photography/technical/field_of_view.html]

      [method:null setViewOffset]( [page:Float fullWidth], [page:Float fullHeight], [page:Float x], [page:Float y], [page:Float width], [page:Float height] )

      fullWidth — full width of multiview setup
      fullHeight — full height of multiview setup
      x — horizontal offset of subcamera
      y — vertical offset of subcamera
      width — width of subcamera
      height — height of subcamera
      Sets an offset in a larger frustum. This is useful for multi-window or multi-monitor/multi-machine setups.
      For example, if you have 3x2 monitors and each monitor is 1920x1080 and the monitors are in grid like this:
      +---+---+---+
      | A | B | C |
      +---+---+---+
      | D | E | F |
      +---+---+---+
      then for each monitor you would call it like this:
      var w = 1920; var h = 1080; var fullWidth = w * 3; var fullHeight = h * 2; // A camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); // B camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); // C camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); // D camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); // E camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); // F camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); Note there is no reason monitors have to be the same size or in a grid.

      [method:null updateProjectionMatrix]()

      Updates the camera projection matrix. Must be called after change of parameters.

      [method:PerspectiveCamera clone]()


      It returns a clone of PerspectiveCamera.

      [method:JSON toJSON]()

      Return camera data in JSON format.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/cameras/OrthographicCamera.html0000644000175500017550000000544012610076566022523 0ustar debacledebacle [page:Object3D] → [page:Camera] →

      [name]

      Camera with orthographic projection.

      Example

      [example:canvas_camera_orthographic camera / orthographic ]
      [example:canvas_camera_orthographic2 camera / orthographic2 ]
      [example:webgl_camera camera ]
      [example:webgl_interactive_cubes_ortho interactive / cubes / ortho ]
      [example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]
      [example:webgl_postprocessing_advanced postprocessing / advanced ]
      [example:webgl_postprocessing_dof2 postprocessing / dof2 ]
      [example:webgl_postprocessing_godrays postprocessing / godrays ]
      [example:webgl_rtt rtt ]
      [example:webgl_shaders_tonemapping shaders / tonemapping ]
      [example:webgl_shadowmap shadowmap ]
      [example:webgl_terrain_dynamic terrain / dynamic ]
      var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 ); scene.add( camera );

      Constructor

      [name]( [page:Float left], [page:Float right], [page:Float top], [page:Float bottom], [page:Float near], [page:Float far] )

      left — Camera frustum left plane.
      right — Camera frustum right plane.
      top — Camera frustum top plane.
      bottom — Camera frustum bottom plane.
      near — Camera frustum near plane.
      far — Camera frustum far plane.

      Properties

      [property:number zoom]

      Gets or sets the zoom factor of the camera.

      [property:Float left]

      Camera frustum left plane.

      [property:Float right]

      Camera frustum right plane.

      [property:Float top]

      Camera frustum top plane.

      [property:Float bottom]

      Camera frustum bottom plane.

      [property:Float near]

      Camera frustum near plane.

      [property:Float far]

      Camera frustum far plane.

      Methods

      [method:null updateProjectionMatrix]()

      Updates the camera projection matrix. Must be called after change of parameters.

      [method:OrthographicCamera clone]()


      It returns a clone of OrthographicCamera.

      [method:JSON toJSON]()

      Return camera data in JSON format.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/examples/0000755000175500017550000000000012610076566016273 5ustar debacledebaclethree.js-r73/docs/api/examples/cameras/0000755000175500017550000000000012610076566017706 5ustar debacledebaclethree.js-r73/docs/api/examples/cameras/CombinedCamera.html0000644000175500017550000001226012610076566023426 0ustar debacledebacle [page:Camera] →

      [name]

      A general purpose camera, for setting FOV, Lens Focal Length, and switching between perspective and orthographic views easily. Use this only if you do not wish to manage both an Orthographic and Perspective Camera

      Examples

      [example:canvas_camera_orthographic2 camera / orthographic2 ]
      //Create combined camera camera = new THREE.CombinedCamera( window.innerWidth / 2, window.innerHeight / 2, 70, 1, 1000, - 500, 1000 );

      Constructor

      [name]([page:Number width], [page:Number height], [page:Number fov], [page:Number near], [page:Number far], [page:Number orthoNear], [page:Number orthoFar])

      width -- Camera frustum width.
      height -- Camera frustum height.
      fov — Camera frustum vertical field of view in perspective view.
      near — Camera frustum near plane in perspective view.
      far — Camera frustum far plane in perspective view.
      orthoNear — Camera frustum near plane in orthographic view.
      orthoFar — Camera frustum far plane in orthographic view.
      Creates a [name]. This initializes 2 cameras, an OrthographicCamera and a PerspectiveCamera. The default is the perspective Camera.

      Properties

      [property:Number fov]

      Gets or sets the camera frustum vertical field of view in perspective view.

      [property:number left]

      Gets or sets the camera frustum left plane in orthographic view.

      [property:Number right]

      Gets or sets the camera frustum right plane in orthographic view.

      [property:number top]

      Gets or sets the camera frustum top plane in orthographic view.

      [property:Number bottom]

      Gets or sets the camera frustum bottom plane in orthographic view.

      [property:number zoom]

      Gets or sets the zoom factor of the camera.

      [property:number near]

      Gets camera frustum near plane.

      [property:number far]

      Gets camera frustum far plane.

      [property:Matrix4 projectionMatrix]

      This is the matrix which contains the projection.

      [property:OrthographicCamera cameraO]

      Gets or sets the internal OrthographicCamera used as camera.

      [property:PerspectiveCamera cameraP]

      Gets or sets the internal PerspectiveCamera used as camera.

      [property:boolean inOrthographicMode]

      Gets whether the combinedCamera is in Orthographic Mode.

      [property:boolean inPerspectiveMode]

      Gets whether the combinedCamera is in Perspective Mode.

      Methods

      [method:null setFov]([page:Number fov])

      fov -- Camera frustum vertical field of view in perspective view.
      sets the camera frustum vertical field of view in perspective view.

      [method:null setZoom]([page:Number zoom])

      zoom -- The zoom factor.
      Sets the zoomfactor.

      [method:null setLens]([page:number focalLength], [page:Number frameHeight])

      focalLength -- The focal length of a lens is defined as the distance from the optical center of a lens (or, the secondary principal point for a complex lens like a camera lens) to the focal point (sensor) when the lens is focused on an object at infinity.
      frameHeight -- the size of the frame in mm. (default is *35*)
      Sets the fov based on lens data.

      [method:null toFrontView]()

      Sets the camera to view the front of the target.

      [method:null toBackView]()

      Sets the camera to view the back of the target.

      [method:null toLeftView]()

      Sets the camera to view the left of the target.

      [method:null toRightView]()

      Sets the camera to view the right of the target.

      [method:null toTopView]()

      Sets the camera to view the top.

      [method:null toBottomView]()

      Sets the camera to view the bottom.

      [method:null setSize]([page:Number width], [page:Number height])

      width -- The width of the orthographic view.
      height -- The height of the orthographic view.
      Sets the size of the orthographic view.

      [method:null toOrthographic]()

      Change the camera to orthographic view.

      [method:null toPerspective]()

      Change the camera to Perspective view.

      [method:null updateProjectionMatrix]()

      Updates the ProjectionMatrix.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/cameras/CombinedCamera.js examples/cameras/CombinedCamera.js] three.js-r73/docs/api/examples/Lut.html0000644000175500017550000001013112610076566017721 0ustar debacledebacle

      [name]

      Represents a lookup table for colormaps. It is used to determine the color values from a range of data values.

      Example

      var lut = new THREE.Lut( "rainbow", 512 ); var data = [0, 10.1, 4.2, 3.4, 63, 28]; lut.setMax(63); color = lut.getColor(10);

      Constructor

      [name]( colormap, numberOfColors )

      colormap - optional argument that sets a colormap from predefined colormaps. Available colormaps are : "rainbow", "cooltowarm", "blackbody". numberOfColors - optional argument that sets the number of colors used to represent the data array.

      Properties

      [property:Float minV]

      The minimum value to be represented with the lookup table. Default is 0.

      [property:Float maxV]

      The maximum value to be represented with the lookup table. Default is 1.

      .[legend]

      The legend of the lookup table.

      Methods

      [method:null copy]( [page:Lut lut] ) [page:Lut this]

      color — Lut to copy.
      Copies given lut.

      .setLegendOn [parameters]

      parameters - { layout: value, position: { x: value, y: value, z: value }, dimensions: { width: value, height: value } } layout — Horizontal or vertical layout. Default is vertical.
      position — The position x,y,z of the legend.
      dimensions — The dimensions (width and height) of the legend.
      Sets this Lut with the legend on.

      .setLegendOff

      Sets this Lut with the legend off.

      .setLegendLabels [parameters, callback]

      parameters - { fontsize: value, fontface: value, title: value, um: value, ticks: value, decimal: value, notation: value } fontsize — Font size to be used for labels.
      fontface — Font type to be used for labels.
      title — The title of the legend.
      um — The unit of measurements of the legend.
      ticks — The number of ticks to be displayed.
      decimal — The number of decimals to be used for legend values.
      notation — Legend notation: standard (default) or scientific.
      callback — An optional callback to be used to format the legend labels.
      Sets the labels of the legend of this Lut.

      [method:Lut setminV]( [page:Float minV] )

      minV — The minimum value to be represented with the lookup table.
      Sets this Lut with the minimum value to be represented.

      [method:Lut setmaxV]( [page:Float maxV] )

      maxV — The maximum value to be represented with the lookup table.
      Sets this Lut with the maximum value to be represented.

      [method:Lut changeNumberOfColors]( [page:Float numberOfColors] )

      numberOfColors — The number of colors to be used to represent the data array.
      Sets this Lut with the number of colors to be used.

      [method:Lut changeColorMap]( [page:Float colorMap] )

      colorMap — The name of the color map to be used to represent the data array.
      Sets this Lut with the colormap to be used.

      [method:Lut addColorMap]( colorMapName, arrayOfColors )

      Insert a new color map into the set of available color maps.

      [method:Lut getColor]( value ) [page:Lut this]

      value -- the data value to be displayed as a color.
      Returns a Three.Color.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/math/[path].js examples/js/math/[path].js] three.js-r73/docs/api/lights/0000755000175500017550000000000012610076566015747 5ustar debacledebaclethree.js-r73/docs/api/lights/HemisphereLight.html0000644000175500017550000000352012610076566021716 0ustar debacledebacle [page:Object3D] → [page:Light] →

      [name]

      A light source positioned directly above the scene.

      Example

      [example:webgl_lights_hemisphere lights / hemisphere ]
      [example:misc_controls_pointerlock controls / pointerlock ]
      [example:webgl_decals decals ]
      [example:webgl_loader_collada_kinematics loader / collada / kinematics ]
      [example:webgl_materials_lightmap materials / lightmap ]
      [example:webgl_shaders_ocean shaders / ocean ]
      var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 ); scene.add( light );

      Constructor

      [name]([page:Integer skyColorHex], [page:Integer groundColorHex], [page:Float intensity])

      [page:Integer skyColorHex] — Numeric value of the RGB sky color.
      [page:Integer groundColorHex] — Numeric value of the RGB ground color.
      [page:Float intensity] — Numeric value of the light's strength/intensity.

      Properties

      [property:Float groundColor]

      Light's ground color.

      [property:Float intensity]

      Light's intensity.
      Default — *1.0*.

      Methods

      [method:HemisphereLight clone]()


      It returns a clone of HemisphereLight.

      [method:JSON toJSON]()

      Return HemisphereLight data in JSON format.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/lights/Light.html0000644000175500017550000000160512610076566017706 0ustar debacledebacle [page:Object3D] →

      [name]

      Abstract base class for lights.

      Constructor

      [name]( [page:Integer hex] )

      [page:Integer hex] — Numeric value of the RGB component of the color.
      This creates a light with color.

      Properties

      [property:Color color]

      Color of the light.

      Methods

      [method:Light clone]()


      It returns a clone of Light.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/lights/DirectionalLight.html0000644000175500017550000001176512610076566022074 0ustar debacledebacle [page:Object3D] → [page:Light] →

      [name]

      Affects objects using [page:MeshLambertMaterial] or [page:MeshPhongMaterial].

      Example

      [example:canvas_morphtargets_horse morphtargets / horse ]
      [example:misc_controls_fly controls / fly ]
      [example:misc_lights_test lights / test ]
      [example:vr_cubes cubes ]
      [example:webgl_effects_parallaxbarrier effects / parallaxbarrier ]
      [example:webgl_effects_stereo effects / stereo ]
      [example:webgl_geometry_extrude_splines geometry / extrude / splines ]
      [example:webgl_materials_bumpmap materials / bumpmap ]
      [example:webgl_materials_cubemap_balls_reflection materials / cubemap / balls / reflection ]
      // White directional light at half intensity shining from the top. var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 ); directionalLight.position.set( 0, 1, 0 ); scene.add( directionalLight );

      Constructor

      [name]([page:Integer hex], [page:Float intensity])

      [page:Integer hex] -- Numeric value of the RGB component of the color.
      [page:Float intensity] -- Numeric value of the light's strength/intensity.
      Creates a light that shines from a specific direction not from a specific position. This light will behave as though it is infinitely far away and the rays produced from it are all parallel. The best analogy would be a light source that acts like the sun: the sun is so far away that all sunlight hitting objects comes from the same angle.

      Properties

      [property:Object3D target]

      Target used for shadow camera orientation.

      [property:Float intensity]

      Light's intensity.
      Default — *1.0*.

      [property:Boolean onlyShadow]

      If set to *true* light will only cast shadow but not contribute any lighting (as if *intensity* was 0 but cheaper to compute).
      Default — *false*.

      [property:Boolean castShadow]

      If set to true light will cast dynamic shadows. Warning: This is expensive and requires tweaking to get shadows looking right.
      Default — *false*.

      [property:Float shadowCameraNear]

      Orthographic shadow camera frustum parameter.
      Default — *50*.

      [property:Float shadowCameraFar]

      Orthographic shadow camera frustum parameter.
      Default — *5000*.

      [property:Float shadowCameraLeft]

      Orthographic shadow camera frustum parameter.
      Default — *-500*.

      [property:Float shadowCameraRight]

      Orthographic shadow camera frustum parameter.
      Default — *500*.

      [property:Float shadowCameraTop]

      Orthographic shadow camera frustum parameter.
      Default — *500*.

      [property:Float shadowCameraBottom]

      Orthographic shadow camera frustum parameter.
      Default — *-500*.

      [property:Boolean shadowCameraVisible]

      Show debug shadow camera frustum.
      Default — *false*.

      [property:Float shadowBias]

      Shadow map bias, how much to add or subtract from the normalized depth when deciding whether a surface is in shadow.
      Default — *0*.

      [property:Integer shadowMapWidth]

      Shadow map texture width in pixels.
      Default — *512*.

      [property:Integer shadowMapHeight]

      Shadow map texture height in pixels.
      Default — *512*.

      [property:Vector2 shadowMapSize]

      The shadowMapWidth and shadowMapHeight stored in a [page:Vector2 THREE.Vector2]. Set internally during rendering.

      [property:OrthographicCamera shadowCamera]

      The shadow's view of the world. Computed internally during rendering from the shadowCamera* settings.

      [property:Matrix4 shadowMatrix]

      Model to shadow camera space, to compute location and depth in shadow map. Computed internally during rendering.

      [property:WebGLRenderTarget shadowMap]

      The depth map generated using the shadowCamera; a location beyond a pixel's depth is in shadow. Computed internally during rendering.

      Methods

      [method:DirectionalLight clone]()

      It returns a clone of DirectionalLight.

      [method:JSON toJSON]()

      Return DirectionalLight data in JSON format.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/lights/AmbientLight.html0000644000175500017550000000274712610076566021216 0ustar debacledebacle [page:Object3D] → [page:Light] →

      [name]

      This light's color gets applied to all the objects in the scene globally.

      Example

      [example:canvas_camera_orthographic camera / orthographic ]
      [example:canvas_interactive_voxelpainter interactive / voxelpainter ]
      [example:canvas_materials materials ]
      [example:canvas_sandbox sandbox ]
      [example:webgl_animation_cloth animation / cloth ]
      [example:webgl_animation_skinning_blending animation / skinning / blending ]
      var light = new THREE.AmbientLight( 0x404040 ); // soft white light scene.add( light );

      Constructor

      [name]( [page:Integer hex] )

      [page:Integer hex] — Numeric value of the RGB component of the color.
      This creates an Ambientlight with a color.

      Methods

      [method:AmbientLight clone]()


      It returns a clone of Ambientlight.

      [method:JSON toJSON]()

      Return Ambientlight data in JSON format.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/lights/SpotLight.html0000644000175500017550000001426712610076566020564 0ustar debacledebacle [page:Object3D] → [page:Light] →

      [name]

      A point light that can cast shadow in one direction.
      Affects objects using [page:MeshLambertMaterial] or [page:MeshPhongMaterial].

      Example

      [example:webgl_interactive_cubes_gpu interactive / cubes / gpu ]
      [example:webgl_interactive_draggablecubes interactive / draggablecubes ]
      [example:webgl_materials_bumpmap_skin materials / bumpmap / skin ]
      [example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]
      [example:webgl_morphtargets_md2 morphtargets / md2 ]
      [example:webgl_shading_physical shading / physical ]
      // white spotlight shining from the side, casting shadow var spotLight = new THREE.SpotLight( 0xffffff ); spotLight.position.set( 100, 1000, 100 ); spotLight.castShadow = true; spotLight.shadowMapWidth = 1024; spotLight.shadowMapHeight = 1024; spotLight.shadowCameraNear = 500; spotLight.shadowCameraFar = 4000; spotLight.shadowCameraFov = 30; scene.add( spotLight );
      [example:webgl_materials_bumpmap materials / bumpmap]
      [example:webgl_shading_physical shading / physical]
      [example:webgl_shadowmap shadowmap]
      [example:webgl_shadowmap_viewer shadowmap / performance]
      [example:webgl_shadowmap_viewer shadowmap / viewer]

      Constructor

      [name]([page:Integer hex], [page:Float intensity], [page:Float distance], [page:Radians angle], [page:Float exponent], [page:Float decay])

      [page:Integer hex] — Numeric value of the RGB component of the color.
      [page:Float intensity] — Numeric value of the light's strength/intensity.
      [page:Float distance] -- Maximum distance from origin where light will shine whose intensity is attenuated linearly based on distance from origin.
      [page:Radians angle] -- Maximum angle of light dispersion from its direction whose upper bound is Math.PI/2.
      [page:Float exponent] -- Rapidity of the falloff of light from its target direction.
      [page:Float decay] -- The amount the light dims along the distance of the light.

      Properties

      [property:Object3D target]

      Spotlight focus points at target.position.
      Default position — *(0,0,0)*.

      [property:Float intensity]

      Light's intensity.
      Default — *1.0*.

      [property:Float distance]

      If non-zero, light will attenuate linearly from maximum intensity at light *position* down to zero at *distance*.
      Default — *0.0*.

      [property:Float angle]

      Maximum extent of the spotlight, in radians, from its direction. Should be no more than *Math.PI/2*.
      Default — *Math.PI/3*.

      [property:Float exponent]

      Rapidity of the falloff of light from its target direction. A lower value spreads out the light, while a higher focuses it towards the center.
      Default — *10.0*.

      [property:Float decay]

      The amount the light dims along the distance of the light
      Default — *1*.

      [property:Boolean castShadow]

      If set to *true* light will cast dynamic shadows. *Warning*: This is expensive and requires tweaking to get shadows looking right.
      Default — *false*.

      [property:Boolean onlyShadow]

      If set to *true* light will only cast shadow but not contribute any lighting (as if *intensity* was 0 but cheaper to compute).
      Default — *false*.

      [property:Float shadowCameraNear]

      Perspective shadow camera frustum near parameter.
      Default — *50*.

      [property:Float shadowCameraFar]

      Perspective shadow camera frustum far parameter.
      Default — *5000*.

      [property:Float shadowCameraFov]

      Perspective shadow camera frustum field of view parameter.
      Default — *50*.

      [property:Boolean shadowCameraVisible]

      Show debug shadow camera frustum.
      Default — *false*.

      [property:Float shadowBias]

      Shadow map bias, how much to add or subtract from the normalized depth when deciding whether a surface is in shadow.
      Default — *0*.

      [property:Integer shadowMapWidth]

      Shadow map texture width in pixels.
      Default — *512*.

      [property:Integer shadowMapHeight]

      Shadow map texture height in pixels.
      Default — *512*.

      [property:Vector2 shadowMapSize]

      The shadowMapWidth and shadowMapHeight stored in a [page:Vector2 THREE.Vector2]. Set internally during rendering.

      [property:PerspectiveCamera shadowCamera]

      The shadow's view of the world. Computed internally during rendering from the shadowCamera* settings.

      [property:Matrix4 shadowMatrix]

      Model to shadow camera space, to compute location and depth in shadow map. Computed internally during rendering.

      [property:WebGLRenderTarget shadowMap]

      The depth map generated using the shadowCamera; a location beyond a pixel's depth is in shadow. Computed internally during rendering.

      Methods

      [method:SpotLight clone]()


      It returns a clone of SpotLight.

      [method:JSON toJSON]()

      Return SpotLight data in JSON format.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/lights/PointLight.html0000644000175500017550000000525312610076566020723 0ustar debacledebacle [page:Object3D] → [page:Light] →

      [name]

      Affects objects using [page:MeshLambertMaterial] or [page:MeshPhongMaterial].

      Example

      [example:canvas_lights_pointlights lights / pointlights ]
      [example:webgl_lights_pointlights lights / pointlights ]
      [example:webgl_lights_pointlights2 lights / pointlights2 ]
      [example:webgldeferred_animation animation ]
      [example:webgldeferred_pointlights pointlights ]
      [example:webgl_effects_anaglyph effects / anaglyph ]
      [example:webgl_geometry_large_mesh geometry / large / mesh ]
      [example:webgl_geometry_text geometry / text ]
      [example:webgl_lensflares lensflares ]
      var light = new THREE.PointLight( 0xff0000, 1, 100 ); light.position.set( 50, 50, 50 ); scene.add( light );

      Constructor

      [name]([page:Integer hex], [page:Float intensity], [page:Number distance], [page:Float decay])

      [page:Integer hex] — Numeric value of the RGB component of the color.
      [page:Float intensity] — Numeric value of the light's strength/intensity.
      [page:Number distance] -- The distance of the light where the intensity is 0. When distance is 0, then the distance is endless.
      [page:Float decay] -- The amount the light dims along the distance of the light.
      Creates a light at a specific position in the scene. The light shines in all directions (roughly similar to a light bulb.)

      Properties

      [property:Float intensity]

      Light's intensity.
      Default - *1.0*.

      [property:Float distance]

      If non-zero, light will attenuate linearly from maximum intensity at light *position* down to zero at *distance*.
      Default — *0.0*.

      [property:Float decay]

      The amount the light dims along the distance of the light
      Default — *1*.

      Methods

      [method:PointLight clone]()


      It returns a clone of PointLight.

      [method:JSON toJSON]()

      Return PointLight data in JSON format.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/0000755000175500017550000000000012610076566016446 5ustar debacledebaclethree.js-r73/docs/api/renderers/CanvasRenderer.html0000644000175500017550000001231512610076566022240 0ustar debacledebacle

      [name]

      The Canvas renderer displays your beautifully crafted scenes not using WebGL, but draws it using the (slower) Canvas 2D Context API.

      This renderer can be a nice fallback from [page:WebGLRenderer] for simple scenes: function webglAvailable() { try { var canvas = document.createElement( 'canvas' ); return !!( window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ) ); } catch ( e ) { return false; } } if ( webglAvailable() ) { renderer = new THREE.WebGLRenderer(); } else { renderer = new THREE.CanvasRenderer(); } Note: both WebGLRenderer and CanvasRenderer are embedded in the web page using an HTML5 <canvas> tag. The "Canvas" in CanvasRenderer means it uses Canvas 2D instead of WebGL.

      Don't confuse either CanvasRenderer with the SoftwareRenderer example, which simulates a screen buffer in a Javascript array.

      Constructor

      [name]([page:object parameters])

      parameters is an optional object with properties defining the renderer's behaviour. The constructor also accepts no parameters at all. In all cases, it will assume sane defaults when parameters are missing.
      canvas — A [page:Canvas] where the renderer draws its output.

      Properties

      [property:Object info]

      An object with a series of statistical information about the graphics board memory and the rendering process. Useful for debugging or just for the sake of curiosity. The object contains the following fields:
      • render:
        • vertices
        • faces

      [property:DOMElement domElement]

      A [page:Canvas] where the renderer draws its output.
      This is automatically created by the renderer in the constructor (if not provided already); you just need to add it to your page.

      [property:Boolean autoClear]

      Defines whether the renderer should automatically clear its output before rendering.

      [property:Boolean sortObjects]

      Defines whether the renderer should sort objects. Default is true.
      Note: Sorting is used to attempt to properly render objects that have some degree of transparency. By definition, sorting objects may not work in all cases. Depending on the needs of application, it may be neccessary to turn off sorting and use other methods to deal with transparency rendering e.g. manually determining the object rendering order.

      [property:boolean sortElements]

      Defines whether the renderer should sort the face of each object. Default is true.

      Methods

      [method:null render]([page:Scene scene], [page:Camera camera])

      scene -- The scene to render.
      camera -- the camera to view the scene.
      Render a scene using a camera.

      [method:null clear]()

      Tells the renderer to clear its color drawing buffer with the clearcolor.

      [method:null setClearColor]([page:Color color], [page:number alpha])

      color -- The color to clear the canvas with.
      alpha -- The alpha channel to clear the canvas with.
      This set the clearColor and the clearAlpha.

      [method:null setSize]([page:Number width], [page:Number height])

      width -- The width of the drawing canvas.
      height -- The height of the drawing canvas.
      This set the size of the drawing canvas and if updateStyle is set, then the css of the canvas is updated too.

      [method:null setClearColorHex]([page:number hex], [page:number alpha])

      hex -- The the hexadecimal value of the color to clear the canvas with.
      alpha -- The alpha channel to clear the canvas with.
      This set the clearColor and the clearAlpha.

      [method:number getClearColorHex]()

      Returns the [page:number hex] color.

      [method:number getClearAlpha]()

      Returns the alpha value.

      Empty Methods to Maintain Compatibility with [page:WebglRenderer]

      [method:null clearColor]()
      [method:null clearDepth]()
      [method:null clearStencil]()
      [method:null setFaceCulling]()
      [method:null supportsVertexTextures]()
      [method:number getMaxAnisotropy]() - returns 1

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/WebGLRenderTargetCube.html0000644000175500017550000000235512610076566023407 0ustar debacledebacle [page:WebGLRenderTarget] →

      [name]

      [page:CubeCamera] uses this as its [page:WebGLRenderTarget]

      Examples

      See [page:CubeCamera] for examples.

      Constructor

      [name]([page:Number width], [page:Number height], [page:Object options])

      width -- The width of the renderTarget.
      height -- The height of the renderTarget.
      options -- The options sets the properties of the render target.

      Properties

      [property:integer activeCubeFace]

      The activeCubeFace property corresponds to a cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) and is used and set internally by the [page:CubeCamera].

      See [page:WebGLRenderTarget] for inherited properties

      Methods

      See [page:WebGLRenderTarget] for inherited methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/shaders/0000755000175500017550000000000012610076566020077 5ustar debacledebaclethree.js-r73/docs/api/renderers/shaders/UniformsLib.html0000644000175500017550000000076312610076566023224 0ustar debacledebacle

      [name]

      Uniforms library for shared webgl shaders

      Properties

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/shaders/ShaderChunk.html0000644000175500017550000000076012610076566023167 0ustar debacledebacle

      [name]

      Shader chunks for WebLG Shader library

      Properties

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/shaders/UniformsUtils.html0000644000175500017550000000101312610076566023603 0ustar debacledebacle

      [name]

      Uniform Utilities. Support merging and cloning of uniform variables

      Properties

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/shaders/ShaderLib.html0000644000175500017550000000075212610076566022626 0ustar debacledebacle

      [name]

      Webgl Shader Library for three.js

      Properties

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/webgl/0000755000175500017550000000000012610076566017546 5ustar debacledebaclethree.js-r73/docs/api/renderers/webgl/WebGLShader.html0000644000175500017550000000253212610076566022525 0ustar debacledebacle

      [name]

      A lower level function to compile either a vertex or fragment shader.

      Example

      var gl = renderer.context; var glVertexShader = new THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexSourceCode ); var glFragmentShader = new THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentSourceCode ); var program = gl.createProgram(); gl.attachShader( program, glVertexShader ); gl.attachShader( program, glFragmentShader ); gl.linkProgram( program );

      Function

      [page:WebGLShader objects]([page:WebGLContext gl], [page:WebGLEnum type], [page:String source])

      gl -- The current WebGL context type -- The WebGL type, either gl.VERTEX_SHADER or gl.FRAGMENT_SHADER source -- The source code for the shader
      This will compile an individual shader, but won't link it to be a complete [page:WebGLProgram]. Note: this is a function so the new operator should not be used.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/webgl/WebGLProgram.html0000644000175500017550000000633012610076566022726 0ustar debacledebacle

      [name]

      Constructor for the GLSL program sent to vertex and fragment shaders, including default uniforms and attributes.

      Built-in uniforms and attributes

      Vertex shader (unconditional):

      // = object.matrixWorld uniform mat4 modelMatrix; // = camera.matrixWorldInverse * object.matrixWorld uniform mat4 modelViewMatrix; // = camera.projectionMatrix uniform mat4 projectionMatrix; // = camera.matrixWorldInverse uniform mat4 viewMatrix; // = inverse transpose of modelViewMatrix uniform mat3 normalMatrix; // = camera position in world space uniform vec3 cameraPosition; // default vertex attributes provided by Geometry and BufferGeometry attribute vec3 position; attribute vec3 normal; attribute vec2 uv; attribute vec2 uv2;

      Note that you can therefore calculate the position of a vertex in the vertex shader by: gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); or alternatively gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );

      Vertex shader (conditional):

      #ifdef USE_COLOR // vertex color attribute attribute vec3 color; #endif #ifdef USE_MORPHTARGETS attribute vec3 morphTarget0; attribute vec3 morphTarget1; attribute vec3 morphTarget2; attribute vec3 morphTarget3; #ifdef USE_MORPHNORMALS attribute vec3 morphNormal0; attribute vec3 morphNormal1; attribute vec3 morphNormal2; attribute vec3 morphNormal3; #else attribute vec3 morphTarget4; attribute vec3 morphTarget5; attribute vec3 morphTarget6; attribute vec3 morphTarget7; #endif #endif #ifdef USE_SKINNING attribute vec4 skinIndex; attribute vec4 skinWeight; #endif

      Fragment shader:

      uniform mat4 viewMatrix; uniform vec3 cameraPosition;

      Constructor

      [name]( [page:WebGLRenderer renderer], [page:Object code], [page:Material material], [page:Object parameters] )

      For parameters see [page:WebGLRenderer WebGLRenderer]

      Properties

      [property:String id]

      [property:String code]

      [property:Integer usedTimes]

      [property:Object program]

      [property:WebGLShader vertexShader]

      [property:WebGLShader fragmentShader]

      Methods

      [method:Object getUniforms]()

      Returns a name-value mapping of all active uniform locations.

      [method:Object getAttributes]()

      Returns a name-value mapping of all active vertex attribute locations.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/webgl/plugins/0000755000175500017550000000000012610076566021227 5ustar debacledebaclethree.js-r73/docs/api/renderers/webgl/plugins/ShadowMapPlugin.html0000644000175500017550000000173712610076566025167 0ustar debacledebacle

      [name]

      The Webglrenderer plugin class that allows shadowmaps to be rendered in the WebglRenderer. This plugin is automatically loaded in the Webglrenderer.

      Constructor

      [name]()

      Creates a new [name].

      Methods

      [method:null render]([page:Scene scene], [page:Camera camera])

      scene -- The scene to render.
      camera -- The camera to render.
      Prepares the shadowmaps to be rendered defined in the scene. This gets automatically called as pre render function to draw the lensflares.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/webgl/plugins/LensFlarePlugin.html0000644000175500017550000000216712610076566025155 0ustar debacledebacle

      [name]

      The Webglrenderer plugin class that allows lensflares to be rendered in the WebglRenderer. This plugin is automatically loaded in the Webglrenderer.

      Constructor

      [name]()

      Creates a new [name].

      Methods

      [method:null render]([page:Scene scene], [page:Camera camera], [page:Number viewportWidth], [page:Number viewportHeight])

      scene -- The scene to render.
      camera -- The camera to render.
      viewportWidth -- The width of the viewport.
      viewportHeight -- The height of the viewport.
      Renders the lensflares defined in the scene. This gets automatically called as post render function to draw the lensflares.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/webgl/plugins/SpritePlugin.html0000644000175500017550000000171212610076566024543 0ustar debacledebacle

      [name]

      The Webglrenderer plugin class that allows Sprites to be rendered in the WebglRenderer. This plugin is automatically loaded in the Webglrenderer.

      Constructor

      [name]()

      Creates a new [name].

      Methods

      [method:null render]([page:Scene scene], [page:Camera camera])

      scene -- The scene to render.
      camera -- The camera to render.
      Renders the sprites defined in the scene. This gets automatically called as post-render function to draw the lensflares.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/webgl/WebGLState.html0000644000175500017550000000511712610076566022401 0ustar debacledebacle

      [name]

      Methods

      [method:null enable]( [page:integer id], [page:boolean boolean] )

      TODO

      [method:null disable]( [page:integer id], [page:boolean boolean] )

      TODO

      [method:null setDepthTest]( [page:boolean depthTest] )

      depthTest -- The boolean to decide if depth of a fragment needs to be tested against the depth buffer .
      This sets, based on depthTest, whether or not the depth data needs to be tested against the depth buffer.

      [method:null setDepthWrite]( [page:boolean depthWrite] )

      depthWrite -- The boolean to decide if depth of a fragment needs to be kept.
      This sets, based on depthWrite, whether or not the depth data needs to be written in the depth buffer.

      [method:null setBlending]( [page:number blending], [page:number blendEquation], [page:number blendSrc], [page:number blendDst] )

      blending -- A number indicating the blending mode. Possible value are THREE.NoBlending, THREE.NormalBlending, THREE.AdditiveBlending, THREE.SubtractiveBlending, THREE.MultiplyBlending or THREE.CustomBlending
      blendEquation -- When blending is THREE.CustomBlending, then you can set the blendEquation. Possible values are THREE.AddEquation, THREE.SubtractEquation or THREE.ReverseSubtractEquation.
      blendSrc -- When blending is THREE.CustomBlending, then you can set the blendSrc. Possible values are THREE.ZeroFactor, THREE.OneFactor,THREE.SrcColorFactor, THREE.OneMinusSrcColorFactor, THREE.SrcAlphaFactor, THREE.OneMinusSrcAlphaFactor, THREE.DstAlphaFactor, THREE.OneMinusDstAlphaFactor, THREE.DstColorFactor,THREE.OneMinusDstColorFactor or THREE.SrcAlphaSaturateFactor
      blendDst -- When blending is THREE.CustomBlending, then you can set the blendDst. Possible values are THREE.ZeroFactor, THREE.OneFactor,THREE.SrcColorFactor, THREE.OneMinusSrcColorFactor, THREE.SrcAlphaFactor, THREE.OneMinusSrcAlphaFactor, THREE.DstAlphaFactor, THREE.OneMinusDstAlphaFactor, THREE.DstColorFactor,THREE.OneMinusDstColorFactor or THREE.SrcAlphaSaturateFactor
      This method sets the correct blending.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/WebGLRenderTarget.html0000644000175500017550000001124012610076566022601 0ustar debacledebacle

      [name]

      A render target is a buffer where the video card draws pixels for a scene that is being rendered in the background. It is used in different effects.

      Constructor

      [name]([page:Number width], [page:Number height], [page:Object options])

      width -- The width of the renderTarget.
      height -- The height of the renderTarget.
      options -- The options sets the properties of the render target.
      Creates a new renderTarget with a certain width and height.

      Properties

      [property:number wrapS]

      The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. The other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.

      [property:number wrapT]

      The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. The other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.

      [property:number magFilter]

      How the texture is sampled when a texel covers more than one pixel. The default is THREE.LinearFilter, which takes the four closest texels and bilinearly interpolates among them. The other option is THREE.NearestFilter, which uses the value of the closest texel.

      [property:number minFilter]

      How the texture is sampled when a texel covers less than one pixel. The default is THREE.LinearMipMapLinearFilter, which uses mipmapping and a trilinear filter. Other choices are THREE.NearestFilter, THREE.NearestMipMapNearestFilter, THREE.NearestMipMapLinearFilter, THREE.LinearFilter, and THREE.LinearMipMapNearestFilter. These vary whether the nearest texel or nearest four texels are retrieved on the nearest mipmap or nearest two mipmaps. Interpolation occurs among the samples retrieved.

      [property:number anisotropy]

      The number of samples taken along the axis through the pixel that has the highest density of texels. By default, this value is 1. A higher value gives a less blurry result than a basic mipmap, at the cost of more texture samples being used. Use renderer.getMaxAnisotropy() to find the maximum valid anisotropy value for the GPU; this value is usually a power of 2.

      [property:Vector2 repeat]

      How many times the texture is repeated across the surface, in each direction U and V.

      [property:Vector2 offset]

      How much a single repetition of the texture is offset from the beginning, in each direction U and V. Typical range is 0.0 to 1.0.

      [property:number format]

      The default is THREE.RGBAFormat for the texture. Other formats are: THREE.AlphaFormat, THREE.RGBFormat, THREE.LuminanceFormat, and THREE.LuminanceAlphaFormat. There are also compressed texture formats, if the S3TC extension is supported: THREE.RGB_S3TC_DXT1_Format, THREE.RGBA_S3TC_DXT1_Format, THREE.RGBA_S3TC_DXT3_Format, and THREE.RGBA_S3TC_DXT5_Format.

      [property:number type]

      The default is THREE.UnsignedByteType. Other valid types (as WebGL allows) are THREE.ByteType, THREE.ShortType, THREE.UnsignedShortType, THREE.IntType, THREE.UnsignedIntType, THREE.HalfFloatType, THREE.FloatType, THREE.UnsignedShort4444Type, THREE.UnsignedShort5551Type, and THREE.UnsignedShort565Type.

      [property:boolean depthBuffer]

      Renders to the depth buffer. Default is true.

      [property:boolean stencilBuffer]

      Renders to the stencil buffer. Default is true.

      [property:boolean generateMipmaps]

      Whether to generate mipmaps (if possible) for a texture. True by default.

      [property:WebGLRenderTarget shareDepthFrom]

      Shares the depth from another WebGLRenderTarget. Default is null.

      Methods

      [method:null setSize]( [page:Number width], [page:Number height] )

      Sets the size of the renderTarget.

      [method:RenderTarget clone]()

      Creates a copy of the render target.

      [method:null dispose]()

      Dispatches a dispose event.

      [page:EventDispatcher EventDispatcher] methods are available on this class.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/renderers/WebGLRenderer.html0000644000175500017550000002761412610076566021775 0ustar debacledebacle

      [name]

      The WebGL renderer displays your beautifully crafted scenes using WebGL, if your device supports it.
      This renderer has way better performance than [page:CanvasRenderer].

      Constructor

      [name]( [page:Object parameters] )

      parameters is an optional object with properties defining the renderer's behaviour. The constructor also accepts no parameters at all. In all cases, it will assume sane defaults when parameters are missing.
      canvas — A [page:Canvas] where the renderer draws its output.
      context — The [page:RenderingContext] context to use.
      precision — Shader precision. Can be *"highp"*, *"mediump"* or *"lowp"*. Defaults to *"highp"* if supported by the device.
      alpha — [page:Boolean], default is *false*.
      premultipliedAlpha — [page:Boolean], default is *true*.
      antialias — [page:Boolean], default is *false*.
      stencil — [page:Boolean], default is *true*.
      preserveDrawingBuffer — [page:Boolean], default is *false*.
      depth — [page:Boolean], default is *true*.
      logarithmicDepthBuffer — [page:Boolean], default is *false*.

      Properties

      [property:DOMElement domElement]

      A [page:Canvas] where the renderer draws its output.
      This is automatically created by the renderer in the constructor (if not provided already); you just need to add it to your page.

      [property:WebGLRenderingContext context]

      The HTML5 Canvas's 'webgl' context obtained from the canvas where the renderer will draw.

      [property:Boolean autoClear]

      Defines whether the renderer should automatically clear its output before rendering.

      [property:Boolean autoClearColor]

      If autoClear is true, defines whether the renderer should clear the color buffer. Default is true.

      [property:Boolean autoClearDepth]

      If autoClear is true, defines whether the renderer should clear the depth buffer. Default is true.

      [property:Boolean autoClearStencil]

      If autoClear is true, defines whether the renderer should clear the stencil buffer. Default is true.

      [property:Boolean sortObjects]

      Defines whether the renderer should sort objects. Default is true.
      Note: Sorting is used to attempt to properly render objects that have some degree of transparency. By definition, sorting objects may not work in all cases. Depending on the needs of application, it may be neccessary to turn off sorting and use other methods to deal with transparency rendering e.g. manually determining the object rendering order.

      [property:Boolean gammaInput]

      Default is false. If set, then it expects that all textures and colors are premultiplied gamma.

      [property:Boolean gammaOutput]

      Default is false. If set, then it expects that all textures and colors need to be outputted in premultiplied gamma.

      [property:Boolean shadowMapEnabled]

      Default is false. If set, use shadow maps in the scene.

      [property:Integer shadowMapType]

      Defines shadow map type (unfiltered, percentage close filtering, percentage close filtering with bilinear filtering in shader)
      Options are THREE.BasicShadowMap, THREE.PCFShadowMap, THREE.PCFSoftShadowMap. Default is THREE.PCFShadowMap.

      [property:Integer shadowMapCullFace]

      Default is THREE.CullFaceFront. The faces that needed to be culled. Possible values: THREE.CullFaceFront and THREE.CullFaceBack

      [page:Boolean shadowMapDebug]

      Default is false. If set, then the shadowmaps get a specific color to identify which shadow is from which shadowmap.

      [property:Boolean shadowMapCascade]

      Default is false. If Set, use cascaded shadowmaps. See [link:http://developer.download.nvidia.com/SDK/10.5/opengl/src/cascaded_shadow_maps/doc/cascaded_shadow_maps.pdf cascaded shadowmaps] for more information.

      [property:Integer maxMorphTargets]

      Default is 8. The maximum number of MorphTargets allowed in a shader. Keep in mind that the standard materials only allow 8 MorphTargets.

      [property:Integer maxMorphNormals]

      Default is 4. The maximum number of MorphNormals allowed in a shader. Keep in mind that the standard materials only allow 4 MorphNormals.

      [property:Boolean autoScaleCubemaps]

      Default is true. If set, then Cubemaps are scaled, when they are bigger than the maximum size, to make sure that they aren't bigger than the maximum size.

      [property:Object info]

      An object with a series of statistical information about the graphics board memory and the rendering process. Useful for debugging or just for the sake of curiosity. The object contains the following fields:
      • memory:
        • programs
        • geometries
        • textures
      • render:
        • calls
        • vertices
        • faces
        • points

      [property:ShadowMapPlugin shadowMapPlugin]

      This contains the reference to the shadowMapPlugin.

      Methods

      [method:WebGLRenderingContext getContext]()

      Return the WebGL context.

      [method:WebGLContextAttributes getContextAttributes]()

      Returns an object that describes the attributes set on the WebGL context when it was created.

      [method:Boolean supportsVertexTextures]()

      Return a [page:Boolean] true if the context supports vertex textures.

      [method:null setSize]( [page:Integer width], [page:Integer height] )

      Resizes the output canvas to (width, height), and also sets the viewport to fit that size, starting in (0, 0).

      [method:null setViewport]( [page:Integer x], [page:Integer y], [page:Integer width], [page:Integer height] )

      Sets the viewport to render from (x, y) to (x + width, y + height).

      [method:null setScissor]( [page:Integer x], [page:Integer y], [page:Integer width], [page:Integer height] )

      Sets the scissor area from (x, y) to (x + width, y + height).

      [method:null enableScissorTest]( [page:Boolean enable] )

      Enable the scissor test. When this is enabled, only the pixels within the defined scissor area will be affected by further renderer actions.

      [method:null setClearColor]( [page:Color color], [page:Float alpha] )

      Sets the clear color and opacity.
      // Creates a renderer with red background var renderer = new THREE.WebGLRenderer(); renderer.setSize( 200, 100 ); renderer.setClearColor( 0xff0000 );

      [method:Color getClearColor]()

      Returns a [page:Color THREE.Color] instance with the current clear color.

      [method:Float getClearAlpha]()

      Returns a [page:Float float] with the current clear alpha. Ranges from 0 to 1.

      [method:null clear]( [page:Boolean color], [page:Boolean depth], [page:Boolean stencil] )

      Tells the renderer to clear its color, depth or stencil drawing buffer(s).
      Arguments default to true.

      [method:null renderBufferImmediate]( [page:Object3D object], [page:shaderprogram program], [page:Material shading] )

      object — an instance of [page:Object3D]]
      program — an instance of shaderProgram
      shading — an instance of Material
      Render an immediate buffer. Gets called by renderImmediateObject.

      [method:null renderBufferDirect]( [page:Camera camera], [page:Array lights], [page:Fog fog], [page:Material material], [page:Object geometryGroup], [page:Object3D object] )

      Render a buffer geometry group using the camera and with the correct material.

      [method:null renderBuffer]( [page:Camera camera], [page:Array lights], [page:Fog fog], [page:Material material], [page:Object geometryGroup], [page:Object3D object] )

      Render a geometry group using the camera and with the correct material.

      [method:null render]( [page:Scene scene], [page:Camera camera], [page:WebGLRenderTarget renderTarget], [page:Boolean forceClear] )

      Render a scene using a camera.
      The render is done to the renderTarget (if specified) or to the canvas as usual.
      If forceClear is true, the depth, stencil and color buffers will be cleared before rendering even if the renderer's autoClear property is false.
      Even with forceClear set to true you can prevent certain buffers being cleared by setting either the .autoClearColor, .autoClearStencil or .autoClearDepth properties to false.

      [method:null renderImmediateObject]( camera, lights, fog, material, object )

      Renders an immediate Object using a camera.

      [method:null setFaceCulling]( cullFace, frontFace )

      [page:String cullFace] —- "back", "front", "front_and_back", or false.
      [page:String frontFace] —- "ccw" or "cw
      Used for setting the gl frontFace, cullFace states in the GPU, thus enabling/disabling face culling when rendering.
      If cullFace is false, culling will be disabled.

      [method:null setTexture]( [page:Texture texture], [page:number slot] )

      texture -- The [page:Texture texture] that needs to be set.
      slot -- The number indicating which slot should be used by the texture.
      This method sets the correct texture to the correct slot for the wegl shader. The slot number can be found as a value of the uniform of the sampler.

      [method:null setRenderTarget]( [page:WebGLRenderTarget renderTarget] )

      renderTarget -- The [page:WebGLRenderTarget renderTarget] that needs to be activated.
      This method sets the active rendertarget.

      [method:boolean supportsCompressedTextureS3TC]()

      This method returns true if the webgl implementation supports compressed textures of the format S3TC.

      [method:number getMaxAnisotropy]()

      This returns the anisotropy level of the textures.

      [method:string getPrecision]()

      This gets the precision used by the shaders. It returns "highp","mediump" or "lowp".

      [method:null setMaterialFaces]([page:Material material])

      material -- The [page:Material material] with side that shouldn't be culled.
      This sets which side needs to be culled in the webgl renderer.

      [method:boolean supportsStandardDerivatives]()

      This method returns true if the webgl implementation supports standard derivatives.

      [method:boolean supportsFloatTextures]()

      This method returns true if the webgl implementation supports float textures.

      [method:null clearTarget]([page:WebGLRenderTarget renderTarget], [page:boolean color], [page:boolean depth], [page:boolean stencil])

      renderTarget -- The [page:WebGLRenderTarget renderTarget] that needs to be cleared.
      color -- If set, then the color gets cleared.
      depth -- If set, then the depth gets cleared.
      stencil -- If set, then the stencil gets cleared.
      This method clears a rendertarget. To do this, it activates the rendertarget.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/0000755000175500017550000000000012610076566015405 5ustar debacledebaclethree.js-r73/docs/api/core/Raycaster.html0000644000175500017550000001521212610076566020231 0ustar debacledebacle

      [name]

      This class makes raycasting easier. Raycasting is used for picking and more.

      Example

      var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2(); function onMouseMove( event ) { // calculate mouse position in normalized device coordinates // (-1 to +1) for both components mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; } function render() { // update the picking ray with the camera and mouse position raycaster.setFromCamera( mouse, camera ); // calculate objects intersecting the picking ray var intersects = raycaster.intersectObjects( scene.children ); for ( var i = 0; i < intersects.length; i++ ) { intersects[ i ].object.material.color.set( 0xff0000 ); } renderer.render( scene, camera ); } window.addEventListener( 'mousemove', onMouseMove, false ); window.requestAnimationFrame(render);
      Examples: [example:webgl_interactive_cubes Raycasting to a Mesh], [example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera], [example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry], [example:webgl_interactive_lines Raycasting to a Line], [example:webgl_interactive_raycasting_pointcloud Raycasting to a Points], [example:webgl_geometry_terrain_raycast Terrain raycasting], [example:webgl_octree_raycasting Raycasting using an octree], [example:webgl_interactive_voxelpainter Raycasting to paint voxels]

      Constructor

      [name]( [page:Vector3 origin], [page:Vector3 direction], [page:Float near], [page:Float far] ) {

      [page:Vector3 origin] — The origin vector where the ray casts from.
      [page:Vector3 direction] — The direction vector that gives direction to the ray. Should be normalized.
      [page:Float near] — All results returned are further away than near. Near can't be negative. Default value is 0.
      [page:Float far] — All results returned are closer then far. Far can't be lower then near . Default value is Infinity.
      This creates a new raycaster object.

      Properties

      [property:Ray ray]

      The Ray used for the raycasting.

      [property:float near]

      The near factor of the raycaster. This value indicates which objects can be discarded based on the distance.
      This value shouldn't be negative and should be smaller than the far property.

      [property:float far]

      The far factor of the raycaster. This value indicates which objects can be discarded based on the distance.
      This value shouldn't be negative and should be larger than the near property.

      .[page:float linePrecision]

      The precision factor of the raycaster when intersecting [page:Line] objects.

      Methods

      [method:null set]( [page:Vector3 origin], [page:Vector3 direction] )

      [page:Vector3 origin] — The origin vector where the ray casts from.
      [page:Vector3 direction] — The normalized direction vector that gives direction to the ray.
      Updates the ray with a new origin and direction.

      [method:null setFromCamera]( [page:Vector2 coords], [page:Camera camera] )

      [page:Vector2 coords] — 2D coordinates of the mouse, in normalized device coordinates (NDC)---X and Y components should be between -1 and 1.
      [page:Camera camera] — camera from which the ray should originate
      Updates the ray with a new origin and direction.

      [method:Array intersectObject]( [page:Object3D object], [page:Boolean recursive] )

      [page:Object3D object] — The object to check for intersection with the ray.
      [page:Boolean recursive] — If set, it also checks all descendants. Otherwise it only checks intersecton with the object.

      Checks all intersection between the ray and the object with or without the descendants. Intersections are returned sorted by distance, closest first. An array of intersections is returned... [ { distance, point, face, faceIndex, indices, object }, ... ]

      [page:Float distance] – distance between the origin of the ray and the intersection
      [page:Vector3 point] – point of intersection, in world coordinates
      [page:Face3 face] – intersected face
      [page:Integer faceIndex] – index of the intersected face
      [page:Array indices] – indices of vertices comprising the intersected face
      [page:Object3D object] – the intersected object

      When intersecting a [page:Mesh] with a [page:BufferGeometry], the *faceIndex* will be *undefined*, and *indices* will be set; when intersecting a [page:Mesh] with a [page:Geometry], *indices* will be *undefined*.

      *Raycaster* delegates to the [page:Object3D.raycast raycast] method of the passed object, when evaluating whether the ray intersects the object or not. This allows [page:Mesh meshes] to respond differently to ray casting than [page:Line lines] and [page:Points pointclouds].

      *Note* that for meshes, faces must be pointed towards the origin of the [page:.ray ray] in order to be detected; intersections of the ray passing through the back of a face will not be detected. To raycast against both faces of an object, you'll want to set the [page:Mesh.material material]'s [page:Material.side side] property to *THREE.DoubleSide*.

      [method:Array intersectObjects]( [page:Array objects], [page:Boolean recursive] )

      [page:Array objects] — The objects to check for intersection with the ray.
      [page:Boolean recursive] — If set, it also checks all descendants of the objects. Otherwise it only checks intersecton with the objects.
      Checks all intersection between the ray and the objects with or without the descendants. Intersections are returned sorted by distance, closest first. Intersections are of the same form as those returned by [page:.intersectObject].

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/Object3D.html0000644000175500017550000001717012610076566017676 0ustar debacledebacle

      [name]

      Base class for scene graph objects.

      Constructor

      [name]()

      The constructor takes no arguments.

      Properties

      [property:Integer id]

      readonly – Unique number for this object instance.

      [property:String uuid]

      [link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this object instance. This gets automatically assigned, so this shouldn't be edited.

      [property:String name]

      Optional name of the object (doesn't need to be unique).

      [property:Object3D parent]

      Object's parent in the scene graph.

      [property:Object3D children]

      Array with object's children.

      [property:Vector3 position]

      Object's local position.

      [property:Euler rotation]

      Object's local rotation (Euler angles), in radians.

      [property:Vector3 scale]

      Object's local scale.

      [property:Vector3 up]

      Up direction. Default is THREE.Vector3( 0, 1, 0 ).

      [property:Matrix4 matrix]

      Local transform.

      [property:Quaternion quaternion]

      Object's local rotation as [page:Quaternion Quaternion].

      [property:Boolean visible]

      Object gets rendered if *true*.
      default – true

      [property:Boolean castShadow]

      Gets rendered into shadow map.
      default – false

      [property:Boolean receiveShadow]

      Material gets baked in shadow receiving.
      default – false

      [property:Boolean frustumCulled]

      When this is set, it checks every frame if the object is in the frustum of the camera. Otherwise the object gets drawn every frame even if it isn't visible.
      default – true

      [property:Boolean matrixAutoUpdate]

      When this is set, it calculates the matrix of position, (rotation or quaternion) and scale every frame and also recalculates the matrixWorld property.
      default – true

      [property:Boolean matrixWorldNeedsUpdate]

      When this is set, it calculates the matrixWorld in that frame and resets this property to false.
      default – false

      [property:Boolean rotationAutoUpdate]

      When this is set, then the rotationMatrix gets calculated every frame.
      default – true

      [property:object userData]

      An object that can be used to store custom data about the Object3d. It should not hold references to functions as these will not be cloned.

      [property:Matrix4 matrixWorld]

      The global transform of the object. If the Object3d has no parent, then it's identical to the local transform.

      Methods

      [page:EventDispatcher EventDispatcher] methods are available on this class.

      [method:null applyMatrix]( [page:Matrix4 matrix])

      matrix - matrix
      This updates the position, rotation and scale with the matrix.

      [method:null translateX]( [page:Float distance] )

      distance - Distance.
      Translates object along x axis by distance.

      [method:null translateY]( [page:Float distance] )

      distance - Distance.
      Translates object along y axis by distance.

      [method:null translateZ]( [page:Float distance] )

      distance - Distance.
      Translates object along z axis by distance.

      [method:Vector3 localToWorld]( [page:Vector3 vector] )

      vector - A local vector.
      Updates the vector from local space to world space.

      [method:Vector3 worldToLocal]( [page:Vector3 vector] )

      vector - A world vector.
      Updates the vector from world space to local space.

      [method:null lookAt]( [page:Vector3 vector] )

      vector - A world vector to look at.
      Rotates object to face point in space.

      [method:null add]( [page:Object3D object], ... )

      object - An object.
      Adds *object* as child of this object. An arbitrary number of objects may be added.

      [method:null remove]( [page:Object3D object], ... )

      object - An object.
      Removes *object* as child of this object. An arbitrary number of objects may be removed.

      [method:null traverse]( [page:Function callback] )

      callback - A function with as first argument an object3D object.
      Executes the callback on this object and all descendants.

      [method:null traverseVisible]( [page:Function callback] )

      callback - A function with as first argument an object3D object.
      Like traverse, but the callback will only be executed for visible objects. Descendants of invisible objects are not traversed.

      [method:null traverseAncestors]( [page:Function callback] )

      callback - A function with as first argument an object3D object.
      Executes the callback on this object and all ancestors.

      [method:null updateMatrix]()

      Updates local transform.

      [method:null updateMatrixWorld]( [page:Boolean force] )

      Updates global transform of the object and its children.

      [method:Object3D clone]()

      Creates a new clone of this object and all descendants.

      [method:Object3D getObjectByName]([page:String name])

      name -- String to match to the children's Object3d.name property.
      Searches through the object's children and returns the first with a matching name.

      [method:Object3D getObjectById]([page:Integer id])

      id -- Unique number of the object instance
      Searches through the object's children and returns the first with a matching id.

      [method:Object3D translateOnAxis]([page:Vector3 axis], [page:Float distance])

      axis -- A normalized vector in object space.
      distance -- The distance to translate.
      Translate an object by distance along an axis in object space. The axis is assumed to be normalized.

      [method:Object3D rotateOnAxis]([page:Vector3 axis], [page:Float angle])

      axis -- A normalized vector in object space.
      angle -- The angle in radians.
      Rotate an object along an axis in object space. The axis is assumed to be normalized.

      [method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])

      Abstract method to get intersections between a casted ray and this object. Subclasses such as [page:Mesh], [page:Line], and [page:Points] implement this method in order to participate in raycasting.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/EventDispatcher.html0000644000175500017550000000321712610076566021366 0ustar debacledebacle

      [name]

      JavaScript events for custom objects.
      https://github.com/mrdoob/eventdispatcher.js

      Constructor

      [name]()

      Creates EventDispatcher object.

      Methods

      [method:null addEventListener]( [page:String type], [page:Function listener] )

      type - The type of event to listen to.
      listener - The function that gets called when the event is fired.
      Adds a listener to an event type.

      [method:Boolean hasEventListener]( [page:String type], [page:Function listener] )

      type - The type of event to listen to.
      listener - The function that gets called when the event is fired.
      Checks if listener is added to an event type.

      [method:null removeEventListener]( [page:String type], [page:Function listener] )

      type - The type of the listener that gets removed.
      listener - The listener function that gets removed.
      Removes a listener from an event type.

      [method:null dispatchEvent]( [page:object event] )

      event - The event that gets fired.
      Fire an event type.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/Clock.html0000644000175500017550000000362712610076566017336 0ustar debacledebacle

      [name]

      Object for keeping track of time.

      Constructor

      [name]( [page:Boolean autoStart] )

      autoStart — Automatically start the clock.

      Properties

      [property:Boolean autoStart]

      If set, starts the clock automatically when the first update is called.

      [property:Float startTime]

      When the clock is running, It holds the start time of the clock.
      This counted from the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.

      [property:Float oldTime]

      When the clock is running, It holds the previous time from a update.
      This counted from the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.

      [property:Float elapsedTime]

      When the clock is running, It holds the time elapsed between the start of the clock to the previous update.
      This counted from the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.

      [property:Boolean running]

      This property keeps track whether the clock is running or not.

      Methods

      [method:null start]()

      Starts clock.

      [method:null stop]()

      Stops clock.

      [method:Float getElapsedTime]()

      Get the seconds passed since the clock started.

      [method:Float getDelta]()

      Get the seconds passed since the last call to this method.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/Geometry.html0000644000175500017550000002214312610076566020070 0ustar debacledebacle

      [name]

      Base class for geometries.
      A geometry holds all data necessary to describe a 3D model.

      Example

      var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3( -10, 10, 0 ), new THREE.Vector3( -10, -10, 0 ), new THREE.Vector3( 10, -10, 0 ) ); geometry.faces.push( new THREE.Face3( 0, 1, 2 ) ); geometry.computeBoundingSphere();

      Constructor

      [name]()

      The constructor takes no arguments.

      Properties

      [property:Integer id]

      Unique number for this geometry instance.

      [property:String name]

      Name for this geometry. Default is an empty string.

      [property:Array vertices]

      Array of [page:Vector3 vertices].
      The array of vertices holds every position of points in the model.
      To signal an update in this array, [page:Geometry Geometry.verticesNeedUpdate] needs to be set to true.

      [property:Array colors]

      Array of vertex [page:Color colors], matching number and order of vertices.
      Used in [page:Points] and [page:Line].
      [page:Mesh Meshes] use per-face-use-of-vertex colors embedded directly in faces.
      To signal an update in this array, [page:Geometry Geometry.colorsNeedUpdate] needs to be set to true.

      [property:Array faces]

      Array of [page:Face3 triangles].
      The array of faces describe how each vertex in the model is connected with each other.
      To signal an update in this array, [page:Geometry Geometry.elementsNeedUpdate] needs to be set to true.

      [property:Array faceVertexUvs]

      Array of face [page:UV] layers.
      Each UV layer is an array of [page:UV]s matching the order and number of vertices in faces.
      To signal an update in this array, [page:Geometry Geometry.uvsNeedUpdate] needs to be set to true.

      [property:Array morphTargets]

      Array of morph targets. Each morph target is a Javascript object: { name: "targetName", vertices: [ new THREE.Vector3(), ... ] } Morph vertices match number and order of primary vertices.

      [property:Array morphNormals]

      Array of morph normals. Morph normals have similar structure as morph targets, each normal set is a Javascript object: morphNormal = { name: "NormalName", normals: [ new THREE.Vector3(), ... ] }

      [property:Array skinWeights]

      Array of [page:Vector4 Vector4s] representing the skinning weights as used in a [page:SkinnedMesh], The weights match the number and order of vertices in the geometry. The weighted values are typically between the values of 0 and 1 and affect the amount that the individuals bones affect a given vertex.

      [property:Array skinIndices]

      Array of [page:Vector4 Vector4s] representing the indices of individual bones in the [page:Skeleton.bones] array, The indices match the number and order of vertices in the geometry. // e.g. geometry.skinIndices[15] = new THREE.Vector4( 0, 5, 9, 0 ); geometry.skinWeights[15] = new THREE.Vector4( 0.2, 0.5, 0.3, 0 ); // corresponds with the following vertex geometry.vertices[15]; // these bones will be used like so: skeleton.bones[0]; // weight of 0.2 skeleton.bones[5]; // weight of 0.5 skeleton.bones[9]; // weight of 0.3 skeleton.bones[0]; // weight of 0

      [property:Object boundingBox]

      Bounding box. { min: new THREE.Vector3(), max: new THREE.Vector3() }

      [property:Object boundingSphere]

      Bounding sphere. { radius: float }

      [property:Boolean dynamic]

      Set to *true* if attribute buffers will need to change in runtime (using "dirty" flags).
      Unless set to true internal typed arrays corresponding to buffers will be deleted once sent to GPU.
      Defaults to true.

      [property:Boolean verticesNeedUpdate]

      Set to *true* if the vertices array has been updated.

      [property:Boolean elementsNeedUpdate]

      Set to *true* if the faces array has been updated.

      [property:Boolean uvsNeedUpdate]

      Set to *true* if the uvs array has been updated.

      [property:Boolean normalsNeedUpdate]

      Set to *true* if the normals array has been updated.

      [property:Boolean colorsNeedUpdate]

      Set to *true* if the colors array has been updated.

      [property:Boolean lineDistancesNeedUpdate]

      Set to *true* if the linedistances array has been updated.

      [property:array lineDistances]

      An array containing distances between vertices for Line geometries. This is required for LinePieces/LineDashedMaterial to render correctly. Line distances can also be generated with computeLineDistances.

      Methods

      [page:EventDispatcher EventDispatcher] methods are available on this class.

      [method:null applyMatrix]( [page:Matrix4 matrix] )

      Bakes matrix transform directly into vertex coordinates.

      [method:null center] ()

      Center the geometry based on the bounding box.

      [method:Geometry rotateX] ( [page:Float radians] )

      Rotate the geometry about the X axis. This is typically done as a one time operation, and not during a loop Use [page:Object3D.rotation] for typical real-time mesh rotation.

      [method:Geometry rotateY] ( [page:Float radians] )

      Rotate the geometry about the Y axis. This is typically done as a one time operation, and not during a loop Use [page:Object3D.rotation] for typical real-time mesh rotation.

      [method:Geometry rotateZ] ( [page:Float radians] )

      Rotate the geometry about the Z axis. This is typically done as a one time operation, and not during a loop Use [page:Object3D.rotation] for typical real-time mesh rotation.

      [method:Geometry translate] ( [page:Float x], [page:Float y], [page:Float z] )

      Translate the geometry. This is typically done as a one time operation, and not during a loop Use [page:Object3D.position] for typical real-time mesh translation.

      [method:Geometry scale] ( [page:Float x], [page:Float y], [page:Float z] )

      Scale the geometry data. This is typically done as a one time operation, and not during a loop Use [page:Object3D.scale] for typical real-time mesh scaling.

      [method:Geometry lookAt] ( [page:Vector3 vector] )

      vector - A world vector to look at.
      Rotates the geometry to face point in space. This is typically done as a one time operation, and not during a loop Use [page:Object3D.lookAt] for typical real-time mesh usage.

      [method:null computeFaceNormals]()

      Computes face normals.

      [method:null computeVertexNormals]()

      Computes vertex normals by averaging face normals.
      Face normals must be existing / computed beforehand.

      [method:null computeMorphNormals]()

      Computes morph normals.

      [method:null computeBoundingBox]()

      Computes bounding box of the geometry, updating [page:Geometry Geometry.boundingBox] attribute.

      [method:null computeBoundingSphere]()

      Computes bounding sphere of the geometry, updating [page:Geometry Geometry.boundingSphere] attribute.
      Neither bounding boxes or bounding spheres are computed by default. They need to be explicitly computed, otherwise they are *null*.

      [method:null merge]( [page:Geometry geometry], [page:Matrix4 matrix], [page:Integer materialIndexOffset] )

      Merge two geometries or geometry and geometry from object (using object's transform)

      [method:null mergeVertices]()

      Checks for duplicate vertices using hashmap.
      Duplicated vertices are removed and faces' vertices are updated.

      [method:null normalize]()

      Normalize the geometry.
      Make the geometry centered and has a bounding sphere whose raidus equals to 1.0.

      [method:Geometry clone]()

      Creates a new clone of the Geometry.

      [method:null dispose]()

      Removes The object from memory.
      Don't forget to call this method when you remove a geometry because it can cause memory leaks.

      [method:null computeLineDistances]()

      Compute distances between vertices for Line geometries.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/BufferGeometry.html0000644000175500017550000003025512610076566021225 0ustar debacledebacle

      [name]

      This class is an efficient alternative to [page:Geometry], because it stores all data, including vertex positions, face indices, normals, colors, UVs, and custom attributes within buffers; this reduces the cost of passing all this data to the GPU. This also makes BufferGeometry harder to work with than [page:Geometry]; rather than accessing position data as [page:Vector3] objects, color data as [page:Color] objects, and so on, you have to access the raw data from the appropriate [page:BufferAttribute attribute] buffer. This makes BufferGeometry best-suited for static objects where you don't need to manipulate the geometry much after instantiating it.

      Example

      var geometry = new THREE.BufferGeometry(); // create a simple square shape. We duplicate the top left and bottom right // vertices because each vertex needs to appear once per triangle. var vertexPositions = [ [-1.0, -1.0, 1.0], [ 1.0, -1.0, 1.0], [ 1.0, 1.0, 1.0], [ 1.0, 1.0, 1.0], [-1.0, 1.0, 1.0], [-1.0, -1.0, 1.0] ]; var vertices = new Float32Array( vertexPositions.length * 3 ); // three components per vertex // components of the position vector for each vertex are stored // contiguously in the buffer. for ( var i = 0; i < vertexPositions.length; i++ ) { vertices[ i*3 + 0 ] = vertexPositions[i][0]; vertices[ i*3 + 1 ] = vertexPositions[i][1]; vertices[ i*3 + 2 ] = vertexPositions[i][2]; } // itemSize = 3 because there are 3 values (components) per vertex geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); var mesh = new THREE.Mesh( geometry, material );

      More examples: [example:webgl_buffergeometry Complex mesh with non-indexed faces], [example:webgl_buffergeometry_uint Complex mesh with indexed faces], [example:webgl_buffergeometry_lines Lines], [example:webgl_buffergeometry_lines_indexed Indexed Lines], [example:webgl_buffergeometry_particles Particles], and [example:webgl_buffergeometry_rawshader Raw Shaders].

      Accessing attributes

      WebGL stores data associated with individual vertices of a geometry in attributes. Examples include the position of the vertex, the normal vector for the vertex, the vertex color, and so on. When using [page:Geometry], the [page:WebGLRenderer renderer] takes care of wrapping up this information into typed array buffers and sending this data to the shader. With BufferGeometry, all of this data is stored in buffers associated with an individual attributes. This means that to get the position data associated with a vertex (for instance), you must call [page:.getAttribute] to access the 'position' [page:BufferAttribute attribute], then access the individual x, y, and z coordinates of the position.

      The following attributes are set by various members of this class:

      [page:BufferAttribute position] (itemSize: 3)

      Stores the x, y, and z coordinates of each vertex in this geometry. Set by [page:.fromGeometry]().

      [page:BufferAttribute normal] (itemSize: 3)

      Stores the x, y, and z components of the face or vertex normal vector of each vertex in this geometry. Set by [page:.fromGeometry]().

      [page:BufferAttribute color] (itemSize: 3)

      Stores the red, green, and blue channels of vertex color of each vertex in this geometry. Set by [page:.fromGeometry]().

      [page:BufferAttribute index] (itemSize: 3)

      Allows for vertices to be re-used across multiple triangles; this is called using "indexed triangles," and works much the same as it does in [page:Geometry]: each triangle is associated with the index of three vertices. This attribute therefore stores the index of each vertex for each triangular face. If this attribute is not set, the [page:WebGLRenderer renderer] assumes that each three contiguous positions represent a single triangle.

      In addition to the the built-in attributes, you can set your own custom attributes using the addAttribute method. With [page:Geometry], these attributes are set and stored on the [page:Material]. In BufferGeometry, the attributes are stored with the geometry itself. Note that you still need to set the attributes information on the material as well, but the value of each attribute is stored in the BufferGeometry.

      Constructor

      [name]()

      This creates a new [name]. It also sets several properties to a default value.

      Properties

      [property:Integer id]

      Unique number for this buffergeometry instance.

      [property:Hashmap attributes]

      This hashmap has as id the name of the attribute to be set and as value the [page:BufferAttribute buffer] to set it to. Rather than accessing this property directly, use addAttribute and getAttribute to access attributes of this geometry.

      [property:Array drawcalls] (previously [property:Array offsets])

      For geometries that use indexed triangles, this Array can be used to split the object into multiple WebGL draw calls. Each draw call will draw some subset of the vertices in this geometry using the configured [page:Material shader]. This may be necessary if, for instance, you have more than 65535 vertices in your object. Each element is an object of the form: { start: Integer, count: Integer, index: Integer } where start specifies the index of the first vertex in this draw call, count specifies how many vertices are included, and index specifies an optional offset. Use addDrawCall to add draw calls, rather than modifying this array directly.

      [property:Box3 boundingBox]

      Bounding box. { min: new THREE.Vector3(), max: new THREE.Vector3() }

      [property:Sphere boundingSphere]

      Bounding sphere. { radius: float }

      [property:Array morphTargets]

      Array of morph targets. Each morph target is a Javascript object: { name: "targetName", vertices: [ new THREE.Vertex(), ... ] } Morph vertices match number and order of primary vertices.

      Methods

      [page:EventDispatcher EventDispatcher] methods are available on this class.

      [property:null addAttribute]( [page:String name], [page:BufferAttribute attribute] )

      Adds an attribute to this geometry. Use this rather than the attributes property, because an internal array of attributes is maintained to speed up iterating over attributes.

      [method:null addDrawCall]( [page:Integer start], [page:Integer count], [page:Integer indexOffset] )

      Adds a draw call to this geometry; see the [page:BufferGeometry.drawcalls drawcalls] property for details.

      [method:null clearDrawCalls]( )

      Clears all draw calls.

      [method:null applyMatrix]( [page:Matrix4 matrix] )

      Bakes matrix transform directly into vertex coordinates.

      [method:null center] ()

      Center the geometry based on the bounding box.

      [method:BufferGeometry rotateX] ( [page:Float radians] )

      Rotate the geometry about the X axis. This is typically done as a one time operation, and not during a loop Use [page:Object3D.rotation] for typical real-time mesh rotation.

      [method:BufferGeometry rotateY] ( [page:Float radians] )

      Rotate the geometry about the Y axis. This is typically done as a one time operation, and not during a loop Use [page:Object3D.rotation] for typical real-time mesh rotation.

      [method:BufferGeometry rotateZ] ( [page:Float radians] )

      Rotate the geometry about the Z axis. This is typically done as a one time operation, and not during a loop Use [page:Object3D.rotation] for typical real-time mesh rotation.

      [method:BufferGeometry translate] ( [page:Float x], [page:Float y], [page:Float z] )

      Translate the geometry. This is typically done as a one time operation, and not during a loop Use [page:Object3D.position] for typical real-time mesh translation.

      [method:BufferGeometry scale] ( [page:Float x], [page:Float y], [page:Float z] )

      Scale the geometry data. This is typically done as a one time operation, and not during a loop Use [page:Object3D.scale] for typical real-time mesh scaling.

      [method:BufferGeometry lookAt] ( [page:Vector3 vector] )

      vector - A world vector to look at.
      Rotates the geometry to face point in space. This is typically done as a one time operation, and not during a loop Use [page:Object3D.lookAt] for typical real-time mesh usage.

      [method:BufferGeometry setFromObject] ( [page:Object3D object] )

      Sets the attributes for this BufferGeometry from an [page:Object3D].

      [method:null computeVertexNormals]()

      Computes vertex normals by averaging face normals.

      [method:null computeBoundingBox]()

      Computes bounding box of the geometry, updating [page:Geometry Geometry.boundingBox] attribute.
      Bounding boxes aren't computed by default. They need to be explicitly computed, otherwise they are *null*.

      [method:null computeBoundingSphere]()

      Computes bounding sphere of the geometry, updating [page:Geometry Geometry.boundingSphere] attribute.
      Bounding spheres aren't computed by default. They need to be explicitly computed, otherwise they are *null*.

      [method:null computeOffsets] ( [page:Integer size] )

      Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. This method will effectively rewrite the index buffer and remap all attributes to match the new indices. WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. size - Defaults to 65535 or 4294967296 if extension OES_element_index_uint supported, but allows for larger or smaller chunks.

      [method:null merge]( [page:BufferGeometry bufferGeometry], [page:Integer offset] )

      Merge in another BufferGeometry with an optional offset of where to start merging in.

      [method:null dispose]()

      Disposes the object from memory.
      You need to call this when you want the bufferGeometry removed while the application is running.

      [method:null fromGeometry]( [page:Geometry] )

      Populates this BufferGeometry with data from a [page:Geometry] object.

      [method:BufferAttribute getAttribute]( [page:String name] )

      Returns the [page:BufferAttribute attribute] with the specified name.

      [method:BufferAttribute removeAttribute]( [page:String name] )

      Removes the [page:BufferAttribute attribute] with the specified name.

      [method:null normalizeNormals]()

      Every normal vector in a geometry will have a magnitude of 1. This will correct lighting on the geometry surfaces.

      [method:Object toJSON]()

      Returns a raw object representation of the BufferGeometry.

      [method:BufferGeometry clone]()

      Creates a clone of this BufferGeometry.

      [method:BufferGeometry copy]( [page:BufferGeometry bufferGeometry] )

      Copies another BufferGeometry to this BufferGeometry.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/BufferAttribute.html0000644000175500017550000000727212610076566021400 0ustar debacledebacle

      [name]

      This class stores data for an attribute associated with a [page:BufferGeometry]. See that page for details and a usage example. This class is used to store builtin attributes such as vertex position, normals, color, etc., but can also be used in your code to store custom attributes in a [page:BufferGeometry].

      Constructor

      [name]([page:Array array], [page:Integer itemSize])

      Instantiates this attribute with data from the associated buffer. The array can either be a regular Array or a Typed Array. itemSize gives the number of values of the array that should be associated with a particular vertex.

      Properties

      [property:Array array]

      Stores the data associated with this attribute; can be an Array or a Typed Array. This element should have itemSize * numVertices elements, where numVertices is the number of vertices in the associated [page:BufferGeometry geometry].

      [property:Integer itemSize]

      Records how many items of the array are associated with a particular vertex. For instance, if this attribute is storing a 3-component vector (such as a position, normal, or color), then itemSize should be 3.

      [property:Integer length]

      Gives the total number of elements in the array.

      [property:Boolean needsUpdate]

      Flag to indicate that this attribute has changed and should be re-send to the GPU. Set this to true when you modify the value of the array.

      [property:Integer version]

      A version number, incremented every time the needsUpdate property is set to true.

      Methods

      [method:null copyAt] ( [page:Integer index1], attribute, [page:Integer index2] )

      Copies itemSize values in the array from the vertex at index2 to the vertex at index1.

      [method:null set] ( [page:Array value] )

      Sets the associated array with values from the passed array.

      [method:null setX]( index, x )

      Sets the value of the array at index * itemSize to x

      [method:null setY]( index, y )

      Sets the value of the array at index * itemSize + 1 to y

      [method:null setZ]( index, z )

      Sets the value of the array at index * itemSize + 2 to z

      [method:null setXY]( index, x, y )

      Sets the value of the array at index * itemSize to x and sets the value of the array at index * itemSize + 1 to y

      [method:null setXYZ]( index, x, y, z )

      Sets the value of the array at index * itemSize to x, the value of the array at index * itemSize + 1 to y, and the value of the array at index * itemSize + 2 to z.

      [method:null setXYZW]( index, x, y, z, w )

      Sets the value of the array at index * itemSize to x, the value of the array at index * itemSize + 1 to y, the value of the array at index * itemSize + 2 to z, and the value of the array at index * itemSize + 3 to w.

      [method:BufferAttribute clone]()

      Copies this attribute.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/core/Face3.html0000644000175500017550000000345612610076566017224 0ustar debacledebacle

      [name]

      Triangle face.

      Example

      var normal = new THREE.Vector3( 0, 1, 0 ); var color = new THREE.Color( 0xffaa00 ); var face = new THREE.Face3( 0, 1, 2, normal, color, 0 );

      Constructor

      [name]( [page:Integer a], [page:Integer b], [page:Integer c], [page:Vector3 normal], [page:Color color], [page:Integer materialIndex] )

      a — Vertex A index.
      b — Vertex B index.
      c — Vertex C index.
      normal — Face normal or array of vertex normals.
      color — Face color or array of vertex colors.
      materialIndex — Material index.

      Properties

      [property:Integer a]

      Vertex A index.

      [property:Integer b]

      Vertex B index.

      [property:Integer c]

      Vertex C index.

      [property:Vector3 normal]

      Face normal.

      [property:Color color]

      Face color.

      [property:Array vertexNormals]

      Array of 3 vertex normals.

      [property:Array vertexColors]

      Array of 3 vertex colors.

      [property:Integer materialIndex]

      Material index (points to [page:MeshFaceMaterial MeshFaceMaterial.materials]).

      Methods

      [method:Face3 clone]()

      Creates a new clone of the Face3 object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/scenes/0000755000175500017550000000000012610076566015735 5ustar debacledebaclethree.js-r73/docs/api/scenes/Scene.html0000644000175500017550000000240412610076566017660 0ustar debacledebacle [page:Object3D] →

      [name]

      Scenes allow you to set up what and where is to be rendered by three.js. This is where you place objects, lights and cameras.

      Constructor

      [name]()

      Create a new scene object.

      Properties

      [property:Fog fog]

      A [page:Fog fog] instance defining the type of fog that affects everything rendered in the scene. Default is null.

      [property:Material overrideMaterial]

      If not null, it will force everything in the scene to be rendered with that material. Default is null.

      [property:boolean autoUpdate]

      Default is true. If set, then the renderer checks every frame if the scene and its objects needs matrix updates. When it isn't, then you have to maintain all matrices in the scene yourself.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/scenes/FogExp2.html0000644000175500017550000000230312610076566020073 0ustar debacledebacle

      [name]

      This class contains the parameters that define exponential fog, i.e., that grows exponentially denser with the distance.

      Constructor

      [name]( [page:Integer hex], [page:Float density])

      The hex parameter is passed to the [page:Color] constructor to set the color property. Hex can be a hexadecimal integer or a CSS-style string.

      Properties

      [property:String name]

      Default is the empty string.

      [property:Color color]

      Fog color. Example: If set to black, far away objects will be rendered black.

      [property:Float density]

      Defines how fast the fog will grow dense.
      Default is 0.00025.

      Methods

      [method:FogExp2 clone]()

      Returns a copy of this.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/scenes/Fog.html0000644000175500017550000000301212610076566017332 0ustar debacledebacle

      [name]

      This class contains the parameters that define linear fog, i.e., that grows linearly denser with the distance.

      Constructor

      [name]( [page:Integer hex], [page:Float near], [page:Float far] )

      The hex parameter is passed to the [page:Color] constructor to set the color property. Hex can be a hexadecimal integer or a CSS-style string.

      Properties

      [property:String name]

      Default is the empty string.

      [property:Color color]

      Fog color. Example: If set to black, far away objects will be rendered black.

      [property:Float near]

      The minimum distance to start applying fog. Objects that are less than 'near' units from the active camera won't be affected by fog.
      Default is 1.

      [property:Float far]

      The maximum distance at which fog stops being calculated and applied. Objects that are more than 'far' units away from the active camera won't be affected by fog.
      Default is 1000.

      Methods

      [method:Fog clone]()

      Returns a copy of this.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/0000755000175500017550000000000012610076566016106 5ustar debacledebaclethree.js-r73/docs/api/loaders/glTFLoader.html0000644000175500017550000000335512610076566020765 0ustar debacledebacle [page:Loader] →

      [name]

      A loader for loading a .gltf resource in JSON format.

      The glTF file format is a JSON file format to enable rapid delivery and loading of 3D content.

      Constructor

      [name]( )

      Creates a new [name].

      Properties

      Methods

      [method:Object3D load]( [page:String url], [page:Function callback] )

      [page:String url] — required
      [page:Function callback] — Will be called when load completes. The argument will be an [page:Object] containing the loaded .[page:Object3D scene], .[page:Array cameras] and .[page:Array animations].
      Begin loading from url and call the callback function with the parsed response content.

      Notes

      This class is often used with [page:glTFAnimator THREE.glTFAnimator] to animate parsed animations.

      Example

      // instantiate a loader var loader = new THREE.glTFLoader(); // load a glTF resource loader.load( // resource URL 'models/gltf/duck/duck.json', // Function when resource is loaded function ( object ) { scene.add( object.scene ); } ); [example:webgl_loader_gltf]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/gltf/glTFLoader.js examples/js/loaders/gltf/glTFLoader.js] three.js-r73/docs/api/loaders/JSONLoader.html0000644000175500017550000000405412610076566020677 0ustar debacledebacle [page:Loader] →

      [name]

      A loader for loading objects in JSON format.

      Constructor

      [name]()

      Creates a new [name].

      Properties

      [property:boolean withCredentials]

      If true, the ajax request will use cookies.

      Methods

      [method:null load]( [page:String url], [page:Function callback], [page:String texturePath] )

      [page:String url] — required
      [page:Function callback] — required. Will be called when load completes. The arguments will be the loaded [page:Object3D] and the loaded [page:Array materials].
      [page:String texturePath] — optional. If not specified, textures will be assumed to be in the same folder as the Javascript model file.

      [method:Object3D parse]( [page:Object json], [page:String texturePath] )

      [page:String json] — JSON object to parse.
      [page:String texturePath] — Base path for textures.
      Parse a JSON structure and return an [page:Object] containing the parsed .[page:Geometry] and .[page:Array materials].

      Example

      // instantiate a loader var loader = new THREE.JSONLoader(); // load a resource loader.load( // resource URL 'models/animated/monster/monster.js', // Function when resource is loaded function ( geometry, materials ) { var material = new THREE.MeshFaceMaterial( materials ); var object = new THREE.Mesh( geometry, material ); scene.add( object ); } ); [example:webgl_loader_json_blender]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/ColladaLoader.html0000644000175500017550000000731512610076566021470 0ustar debacledebacle

      [name]

      A loader for Collada files.

      Constructor

      [name]()

      Creates a new [name].

      Properties

      [property:Array options]

       .[page:Boolean centerGeometry] — Force [page:Geometry] to always be centered at the local origin of the containing [page: Mesh].
       .[page:Boolean convertUpAxis] — Axis conversion is done for geometries, animations, and controllers.
       .[page:Boolean subdivideFaces] — Force subdivision into multiple [page: Face3].
       .[page:String upAxis] — X, Y or Z
       .[page:Boolean defaultEnvMap] — Cubemap to use for reflective or refractive materials.

      [property:Object geometries]

      Parsed .dae geometries.

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress] )

      [page:String url] — required
      [page:function onLoad] — Will be called when load completes. The argument will be an [page:Object object] containing loaded resources.
      [page:function onProgress] — Will be called while load progresses. The argument will be an object containing .[page:Integer total] and .[page:Integer loaded] bytes.
      Begin loading from url and call onLoad with the parsed response content.

      [method:Object parse]( [page:Document doc], [page:Function callBack], [page:String url] )

      [page:Document doc] — The XML document to parse.
      [page:Function callBack] — Will be called when parse completes.
      [page:String url] — The base url from which to find subsequent resources.
      Parse an XML Document and return an [page:Object object] that contain loaded parts: .[page:Scene scene], .[page:Array morphs], .[page:Array skins], .[page:Array animations], .[page:Object dae]

      [method:null setPreferredShading]( [page:Integer shading] )

      [page:Integer shading] — required
      Set the .[page:Integer shading] property on the resource's materials.
      Options are [page:Materials THREE.SmoothShading], [page:Materials THREE.FlatShading].

      [method:null applySkin]( [page:Geometry geometry], [page:Object instanceCtrl], [page:Integer frame] )

      [page:Geometry geometry] — required
      [page:Object instanceCtrl] — required. A collada skinController
      [page:Integer frame] — optionnal. Default is 40
      Apply a skin (vertices, animation, bones) from a collada skin controller, on the given [page:Geometry].

      Example

      // instantiate a loader var loader = new THREE.ColladaLoader(); loader.load( // resource URL 'models/collada/monster/monster.dae', // Function when resource is loaded function ( collada ) { scene.add( collada.scene ); }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); } ); [example:webgl_loader_collada]
      [example:webgl_loader_collada_keyframe]
      [example:webgl_loader_collada_skinning]
      [example:webgl_loader_collada_kinematics]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/ColladaLoader.js examples/js/loaders/ColladaLoader.js] three.js-r73/docs/api/loaders/MTLLoader.html0000644000175500017550000000407212610076566020562 0ustar debacledebacle

      [name]

      A loader for loading an .mtl resource, used internaly by [page:OBJMTLLoader] and [page:UTF8Loader].

      Constructor

      [name]( [page:String baseUrl], [page:Object options], [page:String crossOrigin] )

      [page:String baseUrl] — The base url from which to find subsequent resources.
      [page:Object options] — Options passed to the created material (side, wrap, normalizeRGB, ignoreZeroRGBs, invertTransparency).
      [page:String crossOrigin] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:MTLLoaderMaterialCreator MTLLoader.MaterialCreator] instance.
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and return the loaded material.

      [method:MTLLoaderMaterialCreator parse]( [page:String text] )

      [page:String text] — The textual mtl structure to parse.
      Parse a mtl text structure and return a [page:MTLLoaderMaterialCreator] instance.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/[name].js examples/js/loaders/[name].js] three.js-r73/docs/api/loaders/ImageLoader.html0000644000175500017550000000502012610076566021142 0ustar debacledebacle

      [name]

      A loader for loading an [page:Image].

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      [property:String crossOrigin]

      The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded Imageloader.
      [page:Function onProgress] — Will be called while load progresses. The argument will be the progress event.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and return the [page:Image image] object that will contain the data.

      [method:null setCrossOrigin]( [page:String value] )

      [page:String value] — The crossOrigin string.
      The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.

      Example

      // instantiate a loader var loader = new THREE.ImageLoader(); // load a image resource loader.load( // resource URL 'textures/skyboxsun25degtest.png', // Function when resource is loaded function ( image ) { // do something with it // like drawing a part of it on a canvas var canvas = document.createElement( 'canvas' ); var context = canvas.getContext( '2d' ); context.drawImage( image, 100, 100 ); }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { console.log( 'An error happened' ); } ); [example:webgl_shaders_ocean]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/PDBLoader.html0000644000175500017550000000620212610076566020530 0ustar debacledebacle

      [name]

      A loader for loading a .pdb resource.

      The Protein Data Bank file format is a textual file format describing the three-dimensional structures of molecules.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required. URL to the .pdb file
      [page:Function onLoad] — Will be called when load completes. The arguments will be an [page:Geometry geometryAtoms], [page:Geometry geometryBonds] and the [page:Object JSON] structure.
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and call onLoad with the parsed response content.

      [method:Object parsePDB]( [page:String text] )

      [page:String text] — The textual pdb structure to parse.
      Parse a pdb text and return a JSON structure.

      [method:null createModel]( [page:Object json], [page:Function callback] )

      [page:Object json] — The (JSON) pdb structure to parse.
      [page:Function callback] — Will be called when parse completes, with three arguments: [page:Geometry geometryAtoms], [page:Geometry geometryBonds] and the original [page:Object json].
      Parse a (JSON) pdb structure and return two [page:Geometry]: one for atoms, one for bonds.

      Example

      // instantiate a loader var loader = new THREE.PDBLoader(); // load a PDB resource loader.load( // resource URL 'models/molecules/caffeine.pdb', // Function when resource is loaded function ( geometryAtoms, geometryBonds, json ) { console.log( 'This molecule has ' + json.atoms.length + ' atoms' ); }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { console.log( 'An error happened' ); } ); [example:webgl_loader_pdb]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/PDBLoader.js examples/js/loaders/PDBLoader.js] three.js-r73/docs/api/loaders/ObjectLoader.html0000644000175500017550000000435512610076566021340 0ustar debacledebacle

      [name]

      A loader for loading a JSON resource. Unlike the [page:JSONLoader], this one make use of the .type attributes of objects to map them to their original classes.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Object3D object].
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and call onLoad with the parsed response content.

      [method:Object3D parse]( [page:Object json] )

      [page:Object json] — required. The JSON source to parse
      Parse a JSON content and return a threejs object.

      [method:null setCrossOrigin]( [page:String value] )

      [page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.

      Example

      // instantiate a loader var loader = new THREE.ObjectLoader(); // assuming we loaded a JSON structure from elsewhere var object = loader.parse( a_json_object ); scene.add( object ); [example:webgl_loader_msgpack]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/TGALoader.html0000644000175500017550000000441112610076566020536 0ustar debacledebacle

      [name]

      Class for loading a .tga [page:DataTexture texture].

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Methods

      [method:DataTexture load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:DataTexture].
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and pass the loaded [page:DataTexture texture] to onLoad. The [page:DataTexture texture] is also directly returned for immediate use (but may not be fully loaded).

      Example

      // instantiate a loader var loader = new THREE.TGALoader(); // load a resource var texture = loader.load( // resource URL 'textures/crate_grey8.tga' // Function when resource is loaded function ( texture ) { console.log( 'Texture is loaded' ); }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { console.log( 'An error happened' ); } ); var material = new THREE.MeshPhongMaterial( { color: 0xffffff, map: texture } ); [example:webgl_materials_texture_tga]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/TGALoader.js examples/js/loaders/TGALoader.js] three.js-r73/docs/api/loaders/BufferGeometryLoader.html0000644000175500017550000000450712610076566023056 0ustar debacledebacle

      [name]

      A loader for loading a [page:BufferGeometry].

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:BufferGeometry].
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and call onLoad with the parsed response content.

      [method:BufferGeometry parse]( [page:Object json] )

      [page:Object json] — The JSON structure to parse.
      Parse a JSON structure and return a [page:BufferGeometry].

      Example

      // instantiate a loader var loader = new THREE.BufferGeometryLoader(); // load a resource loader.load( // resource URL 'models/json/pressure.json', // Function when resource is loaded function ( geometry ) { var material = new THREE.MeshLambertMaterial( { color: 0xF5F5F5 } ); var object = new THREE.Mesh( geometry, material ); scene.add( object ); }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { console.log( 'An error happened' ); } );

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/TextureLoader.html0000644000175500017550000000445312610076566021571 0ustar debacledebacle

      [name]

      Class for loading a [page:Texture texture].

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      [property:String crossOrigin]

      default — *null*.
      If set, assigns the *crossOrigin* attribute of the image to the value of *crossOrigin*, prior to starting the load.

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded text response.
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and pass the loaded [page:Texture texture] to onLoad.

      Example

      // instantiate a loader var loader = new THREE.TextureLoader(); // load a resource loader.load( // resource URL 'textures/land_ocean_ice_cloud_2048.jpg', // Function when resource is loaded function ( texture ) { // do something with the texture var material = new THREE.MeshBasicMaterial( { map: texture } ); }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { console.log( 'An error happened' ); } ); [example:canvas_geometry_earth]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/Loader.html0000644000175500017550000000435412610076566020210 0ustar debacledebacle

      [name]

      Base class for implementing loaders.

      Constructor

      [name]()

      Creates a new [name]. This should be called as base class.

      Properties

      [property:Function onLoadStart]

      Will be called when load starts.
      The default is a function with empty body.

      [property:Function onLoadProgress]

      Will be called while load progresses.
      The default is a function with empty body.

      [property:Function onLoadComplete]

      Will be called when load completes.
      The default is a function with empty body.

      [property:string crossOrigin]

      The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.

      Methods

      [method:Material createMaterial]( [page:object m], [page:string texturePath] )

      [page:Object m] — The parameters to create the material.
      [page:String texturePath] — The base path of the textures.
      Creates the Material based on the parameters m.

      [method:Array initMaterials]( [page:Array materials], [page:string texturePath] )

      [page:Array materials] — an array of parameters to create materials.
      [page:String texturePath] — The base path of the textures.
      Creates an array of [page:Material] based on the array of parameters m. The index of the parameters decide the correct index of the materials.

      [method:String extractUrlBase]( [page:string url] )

      [page:String url] — The url to extract the base url from.
      Extract the base from the URL.

      [method:DOMElement addStatusElement]()

      Add a DOM element to indicate the progress and return the DOMElement

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/BabylonLoader.html0000644000175500017550000000471312610076566021516 0ustar debacledebacle

      [name]

      A loader for loading a .babylon resource.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:function onLoad] — Will be called when load completes. The argument will be the loaded [page:Object3D].
      [page:function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:function onError] — Will be called when load errors.
      Begin loading from url and call onLoad with the parsed response content.

      [method:Object3D parse]( [page:Object json] )

      [page:Object json] — The JSON structure to parse.
      Parse a JSON structure and return an [page:Object3D object] or a [page:Scene scene].
      Found objects are converted to [page:Mesh] with a [page:BufferGeometry] and a default [page:MeshPhongMaterial].
      Lights are parsed accordingly.

      Example

      // instantiate a loader var loader = new THREE.BabylonLoader(); // load a Babylon resource loader.load( // resource URL 'models/babylon/skull.babylon', // Function when resource is loaded function ( object ) { scene.add( object ); }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { console.log( 'An error happened' ); } ); [example:webgl_loader_babylon]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/BabylonLoader.js examples/js/loaders/BabylonLoader.js] three.js-r73/docs/api/loaders/OBJLoader.html0000644000175500017550000000420012610076566020531 0ustar debacledebacle

      [name]

      A loader for loading an .obj resource.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Object3D].
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and call onLoad with the parsed response content.

      [method:Object3D parse]( [page:String text] )

      [page:String text] — The textual obj structure to parse.
      Parse an obj text structure and return an [page:Object3D].
      Found objects are converted to [page:Mesh] with a [page:BufferGeometry] and a default [page:MeshLambertMaterial].

      Example

      // instantiate a loader var loader = new THREE.OBJLoader(); // load a resource loader.load( // resource URL 'models/skinned/UCS_config.json', // Function when resource is loaded function ( object ) { scene.add( object ); } ); [example:webgl_loader_obj]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js examples/js/loaders/OBJLoader.js] three.js-r73/docs/api/loaders/SVGLoader.html0000644000175500017550000000272412610076566020567 0ustar debacledebacle

      [name]

      A loader for loading an .svg resource.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:SVGDocument].
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and call onLoad with the response content.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/SVGLoader.js examples/js/loaders/SVGLoader.js] three.js-r73/docs/api/loaders/OBJMTLLoader.html0000644000175500017550000000541312610076566021115 0ustar debacledebacle

      [name]

      A loader for loading a .obj and its .mtl together.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      Methods

      [method:null load]( [page:String objUrl], [page:String mtlUrl], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String objUrl] — required. URL to the .obj resource
      [page:String mtlUrl] — required. URL to the .mtl resource
      [page:Function onLoad] — Will be called when both resources load complete. The argument will be the loaded [page:Object3D].
      [page:Function onProgress] — Will be called while both load progress. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from urls and call onLoad with the parsed response content.

      [method:Object3D parse]( [page:String text], [page:Function mtllibCallback] )

      [page:String text] — required. The textual obj structure to parse.
      [page:Function mtllibCallback] — optional. Callback to handle mtllib declaration.
      Parse an obj text structure and return an [page:Object3D].
      Found objects are converted to a [page:Mesh] and materials are converted to [page:MeshLambertMaterial].

      Example

      // instantiate a loader var loader = new THREE.OBJMTLLoader(); // load an obj / mtl resource pair loader.load( // OBJ resource URL 'obj/male02/male02.obj', // MTL resource URL 'obj/male02/male02_dds.mtl', // Function when both resources are loaded function ( object ) { scene.add( object ); }, // Function called when downloads progress function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when downloads error function ( xhr ) { console.log( 'An error happened' ); } ); [example:webgl_loader_obj_mtl]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJMTLLoader.js examples/js/loaders/OBJMTLLoader.js] three.js-r73/docs/api/loaders/MaterialLoader.html0000644000175500017550000000471412610076566021667 0ustar debacledebacle

      [name]

      A loader for loading a [page:Material] in JSON format.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded [page:Material].
      [page:Function onProgress] — Will be called while load progresses. The argument will be the progress event.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and return the [page:Material] object that will contain the data.

      [method:null setCrossOrigin]( [page:String value] )

      [page:String value] — The crossOrigin string.
      The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.

      [method:Material parse]( [page:Object json] )

      [page:Object json] — The json object containing the parameters of the Material.
      Parse a JSON structure and create a new [page:Material] of the type [page:String json.type] with parameters defined in the json object.

      Example

      // instantiate a loader var loader = new THREE.MaterialLoader(); // load a resource loader.load( // resource URL 'path/to/material.json', // Function when resource is loaded function ( material ) { object.material = material; }, // Function called when download progresses function ( xhr ) { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // Function called when download errors function ( xhr ) { console.log( 'An error happened' ); } );

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/Cache.html0000644000175500017550000000307512610076566020004 0ustar debacledebacle

      [name]

      A simple caching classe, used internaly by [page:XHRLoader].

      Constructor

      [name]()

      Creates a new [name].

      Properties

      [property:Boolean enabled]

      Whether caching is enabled. Default is *false*.

      [property:Object files]

      An [page:Object object] that hold cached values.

      Methods

      [method:null add]( [page:String key], value )

      [page:String key] — required. A string key
      [page:Object] value — A value
      Adds a cache entry with that key to hold the value. If this key already holds a value, it is overwritten.

      [method:null get]( [page:String key] )

      [page:String key] — required. A string key
      Get the value of key. If the key does not exist *undefined* is returned.

      [method:null remove]( [page:String key] )

      [page:String key] — required. A string key
      Remove the cached value associated with the key.

      [method:null clear]()

      Remove all values from the cache.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/LoadingManager.html0000644000175500017550000000447312610076566021654 0ustar debacledebacle

      [name]

      Handles and keeps track of loaded and pending data.
      var manager = new THREE.LoadingManager(); manager.onProgress = function ( item, loaded, total ) { console.log( item, loaded, total ); }; var loader = new THREE.OBJLoader( manager ); loader.load( 'file.obj', function ( object ) { // } );

      Constructor

      [name]( [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:Function onLoad] — The function that needs to be called when all loaders are done.
      [page:Function onProgress] — The function that needs to be called when an item is complete.
      [page:Function onError] — The function that needs to be called when an item is errors.
      Creates a [name].

      Properties

      [property:Function onLoad]

      The function that needs to be called when all loaders are done.

      [property:Function onProgress]

      The function that needs to be called when an item is complete. The arguments are url(The url of the item just loaded),
      loaded(the amount of items already loaded), total( The total amount of items to be loaded.)

      [property:Function onError]

      The function that needs to be called when an item errors.

      Methods

      [method:null itemStart]( [page:String url] )

      [page:String url] — the url to load
      This should be called by any loader used by the manager when the loader starts loading an url. These shouldn't be called outside a loader.

      [method:null itemEnd]( [page:String url] )

      [page:String url] — the loaded url
      This should be called by any loader used by the manager when the loader ended loading an url. These shouldn't be called outside a loader.

      Example

      [example:webgl_loader_obj]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/loaders/XHRLoader.html0000644000175500017550000000457712610076566020601 0ustar debacledebacle

      [name]

      A low level class for loading resources with XmlHttpRequest, used internaly by most loaders.

      Constructor

      [name]( [page:LoadingManager manager] )

      [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
      Creates a new [name].

      Properties

      [property:Cache cache]

      A [page:Cache cache] instance that hold the response from each request made through this loader, so each file is requested once.

      [property:String crossOrigin]

      The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.

      [property:String responseType]

      Can be set to change the response type.

      Methods

      [method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

      [page:String url] — required
      [page:Function onLoad] — Will be called when load completes. The argument will be the loaded text response.
      [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
      [page:Function onError] — Will be called when load errors.
      Begin loading from url and return the [page:String text] response that will contain the data.

      [method:null setCrossOrigin]( [page:String value] )

      [page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.

      [method:null setResponseType]( [page:String value] )

      [page:String value] — the empty string (default), "arraybuffer", "blob", "document", "json", or "text".

      Example

      [example:webgl_morphtargets_human]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/0000755000175500017550000000000012610076566016436 5ustar debacledebaclethree.js-r73/docs/api/materials/LineDashedMaterial.html0000644000175500017550000000501012610076566022777 0ustar debacledebacle [page:Material] →

      [name]

      A material for drawing wireframe-style geometries with dashed lines.

      Constructor

      [name]([page:Object parameters])

      parameters is an object with one or more properties defining the material's appearance.
      color — Line color in hexadecimal. Default is 0xffffff.
      linewidth — Line thickness. Default is 1.
      scale — The scale of the dashed part of a line. Default is 1.
      dashSize — The size of the dash. Default is 3.
      gapSize - The size of the gap. Default is 1.
      vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.
      fog — Define whether the material color is affected by global fog settings. Default is false.

      Properties

      [property:Color color]

      Sets the color of the line. Default is 0xffffff.

      [property:number linewidth]

      Controls line thickness. Default is 1.
      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:number scale]

      The scale of the dashed part of a line.

      [property:number dashSize]

      The size of the dash. This is both the gap with the stroke. Default is 3.

      [property:number gapSize]

      The size of the gap. Default is 1.

      [property:boolean vertexColors]

      Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.
      This setting might not have any effect when used with certain renderers.

      [property:boolean fog]

      Define whether the material color is affected by global fog settings.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/ShaderMaterial.html0000644000175500017550000003174312610076566022221 0ustar debacledebacle [page:Material] →

      [name]

      Material rendered with custom shaders. A shader is a small program written in [link:https://www.opengl.org/documentation/glsl/ GLSL] to run on the GPU. You may want to use a custom shader if you need to:
      • implement an effect not included with any of the built-in [page:Material materials]
      • combine many objects into a single [page:Geometry] or [page:BufferGeometry] in order to improve performance
      There are the following notes to bear in mind when using a *ShaderMaterial*:
      • A *ShaderMaterial* will only be rendered properly by [page:WebGLRenderer], since the GLSL code in the *vertexShader* and *fragmentShader* properties must be compiled and run on the GPU using WebGL.
      • As of THREE r72, directly assigning attributes in a *ShaderMaterial* is no longer supported. A [page:BufferGeometry] instance (instead of a [page:Geometry] instance) must be used instead, using [page:BufferAttribute] instances to define custom attributes.

      Example

      var material = new THREE.ShaderMaterial( { uniforms: { time: { type: "f", value: 1.0 }, resolution: { type: "v2", value: new THREE.Vector2() } }, attributes: { vertexOpacity: { type: 'f', value: [] } }, vertexShader: document.getElementById( 'vertexShader' ).textContent, fragmentShader: document.getElementById( 'fragmentShader' ).textContent } );

      Vertex shaders and fragment shaders

      You can specify two different types of shaders for each material:

      • The *vertex shader* runs first; it recieves *attributes*, calculates/manipulates the position of each individual vertex, and passes additional data (*varying*s) to the fragment shader.
      • The *fragment shader* runs second; it sets the color of each individual "fragment" (pixel) rendered to the screen.

      There are three types of variables in shaders: uniforms, attributes, and varyings:

      • *Uniforms* are variables that have the same value for all vertices---lighting, fog, and shadow maps are examples of data that would be stored in uniforms. Uniforms can be accessed by both the vertex shader and the fragment shader.
      • *Attributes* are variables associated with each vertex---for instance, the vertex position, face normal, and vertex color are all examples of data that would be stored in attributes. Attributes can only be accessed within the vertex shader.
      • *Varyings* are variables that are passed from the vertex shader to the fragment shader. For each fragment, the value of each varying will be smoothly interpolated from the values of adjacent vertices.
      Note that within the shader itself, uniforms and attributes act like constants; you can only modify their values by passing different values to the buffers from your JavaScript code.

      Built-in attributes and uniforms

      [page:WebGLRenderer] provides many attributes and uniforms to shaders by default; definitions of these variables are prepended to your *fragmentShader* and *vertexShader* code by [page:WebGLProgram] when the shader is compiled; you don't need to declare them yourself. These variables are described in [page:WebGLProgram].

      Some of these uniforms or attributes (e.g. those pertaining lighting, fog, etc.) require properties to be set on the material in order for [page:WebGLRenderer] to copy the appropriate values to the GPU---make sure to set these flags if you want to use these features in your own shader.

      If you don't want [page:WebGLProgram] to add anything to your shader code, you can use [page:RawShaderMaterial] instead of this class.

      Custom attributes and uniforms

      Both custom attributes and uniforms must be declared in your GLSL shader code (within *vertexShader* and/or *fragmentShader*). Custom uniforms must be defined in both the *uniforms* property of your *ShaderMaterial*, whereas any custom attributes must be defined via [page:BufferAttribute] instances. Note that *varying*s only need to be declared within the shader code (not within the material).

      To declare a custom attribute, please reference the [page:BufferGeometry] page for an overview, and the [page:BufferAttribute] page for a detailed look at the *BufferAttribute* API.

      When creating your attributes, each typed array that you create to hold your attribute's data must be a multiple of your data type's size. For example, if your attribute is a [page:Vector3 THREE.Vector3] type, and you have 3000 vertices in your [page:BufferGeometry], your typed array value must be created with a length of 3000 * 3, or 9000 (one value per-component). A table of each data type's size is shown below for reference:

      Attribute sizes
      GLSL type JavaScript type Size
      float [page:Number] 1
      vec2 [page:Vector2 THREE.Vector2] 2
      vec3 [page:Vector3 THREE.Vector3] 3
      vec3 [page:Color THREE.Color] 3
      vec4 [page:Vector4 THREE.Vector4] 4
      Note that attribute buffers are not refreshed automatically when their values change. To update custom attributes, set the *needsUpdate* flag to true on the [page:BufferAttribute] of the geometry (see [page:BufferGeometry] for further details).

      To declare a custom uniform, use the *uniforms* property: uniforms: { time: { type: "f", value: 1.0 }, resolution: { type: "v2", value: new THREE.Vector2() } } Each uniform must have a *type* and a *value*:
      Uniform types
      Uniform *type* string GLSL type JavaScript type
      'i', '1i' int [page:Number]
      'f', '1f' float [page:Number]
      'v2' vec2 [page:Vector2 THREE.Vector2]
      'v3' vec3 [page:Vector3 THREE.Vector3]
      'c' vec3 [page:Color THREE.Color]
      'v4' vec4 [page:Vector4 THREE.Vector4]
      'm3' mat3 [page:Matrix3 THREE.Matrix3]
      'm4' mat4 [page:Matrix4 THREE.Matrix4]
      't' sampler2D [page:Texture THREE.Texture]
      't' samplerCube [page:Texture THREE.CubeTexture]

      Constructor

      [name]([page:Object parameters])

      parameters -- An object containing various parameters setting up shaders and their uniforms.
      shading — Define shading type. Default is THREE.SmoothShading.
      fog — Define whether the material color is affected by global fog settings. Default is true.
      wireframe — render geometry as wireframe. Default is false.
      wireframeLinewidth — Line thickness. Default is 1.
      vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.
      skinning — Define whether the material uses skinning. Default is false.
      morphTargets — Define whether the material uses morphTargets. Default is false.

      Properties

      [property:Object uniforms]

      Object specifying the uniforms to be passed to the shader code; keys are uniform names, values are definitions of the form { type: 'f', value: 1.0 } where *type* is a uniform type string, and *value* is the value of the uniform. Names must match the name of the uniform, as defined in the GLSL code. Note that uniforms are refreshed on every frame, so updating the value of the uniform will immediately update the value available to the GLSL code.

      [property:Object defines]

      Defines custom constants using *#define* directives within the GLSL code for both the vertex shader and the fragment shader; each key/value pair yields another directive: defines: { FOO: 15, BAR: true } yields the lines #define FOO 15 #define BAR true in the GLSL code.

      [property:String vertexShader]

      Vertex shader GLSL code. This is the actual code for the shader. In the example above, the *vertexShader* and *fragmentShader* code is extracted from the DOM; it could be passed as a string directly or loaded via AJAX instead.

      [property:String fragmentShader]

      Fragment shader GLSL code. This is the actual code for the shader. In the example above, the *vertexShader* and *fragmentShader* code is extracted from the DOM; it could be passed as a string directly or loaded via AJAX instead.

      [property:Number shading]

      Define shading type, which determines whether normals are smoothed between vertices; possible values are [page:Materials THREE.SmoothShading] or [page:Materials THREE.FlatShading]. Default is THREE.SmoothShading.

      [property:Number linewidth]

      Controls line thickness; only effective if the material is attached to a [page:Line]. Default is 1.
      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:Boolean wireframe]

      Render geometry as wireframe (using GL_LINES instead of GL_TRIANGLES). Default is false (i.e. render as flat polygons).

      [property:Number wireframeLinewidth]

      Controls wireframe thickness; only effective if the material is attached to a [page:Mesh] and *wireframe* is true. Default is 1.
      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:Boolean fog]

      Define whether the material color is affected by global fog settings; true to pass fog uniforms to the shader. Default is false.

      [property:Boolean lights]

      Defines whether this material uses lighting; true to pass uniform data related to lighting to this shader

      [property:Number vertexColors]

      Define how the vertices are colored, by defining how the *colors* attribute gets populated. Possible values are [page:Materials THREE.NoColors], [page:Materials THREE.FaceColors] and [page:Materials THREE.VertexColors]. Default is THREE.NoColors.

      [property:Boolean skinning]

      Define whether the material uses skinning; true to pass skinning attributes to the shader. Default is false.

      [property:Boolean morphTargets]

      Defines whether the material uses morphTargets; true morphTarget attributes to this shader

      [property:boolean morphNormals]

      Defines whether the material uses morphNormals. Set as true to pass morphNormal attributes from the [page:Geometry] to the shader. Default is *false*.

      [property:WebGLProgram program]

      The compiled shader program associated with this material, generated by [page:WebGLRenderer]. You should not need to access this property.

      Methods

      [method:ShaderMaterial clone]()

      Generates a shallow copy of this material. Note that the vertexShader and fragmentShader are copied by reference, as are the definitions of the *attributes*; this means that clones of the material will share the same compiled [page:WebGLProgram]. However, the *uniforms* are copied by value, which allows you to have different sets of uniforms for different copies of the material.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/SpriteCanvasMaterial.html0000644000175500017550000000234512610076566023411 0ustar debacledebacle [page:Material] →

      [name]

      Create a material that can draw custom sprites using a 2d canvas.

      Constructor

      [name]( [page:Object parameters] )

      parameters is an object that can be used to set up the default properties
      color - the color of the sprite
      program - the program used to draw the sprite

      Properties

      [property:Color color]

      The color of the sprite. The material will set up the color for the context before calling the material's program.

      Methods

      [method:null program]([page:CanvasRenderingContext2D context], [page:Color color])

      context -- The canvas context
      color -- The color of the sprite
      Define a program that will use the context to draw the sprite.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/Material.html0000644000175500017550000001244212610076566021065 0ustar debacledebacle

      [name]

      Materials describe the appearance of [page:Object objects]. They are defined in a (mostly) renderer-independent way, so you don't have to rewrite materials if you decide to use a different renderer.

      Constructor

      [name]()

      This creates a generic material.

      Properties

      [property:Integer id]

      Unique number for this material instance.

      [property:String name]

      Material name. Default is an empty string.

      [property:Float opacity]

      Float in the range of 0.0 - 1.0 indicating how transparent the material is. A value of 0.0 indicates fully transparent, 1.0 is fully opaque. If *transparent* is not set to true for the material, the material will remain fully opaque and this value will only affect its color.
      Default is *1.0*.

      [property:Boolean transparent]

      Defines whether this material is transparent. This has an effect on rendering as transparent objects need special treatment and are rendered after non-transparent objects. For a working example of this behaviour, check the [page:WebGLRenderer WebGLRenderer] code.
      When set to true, the extent to which the material is transparent is controlled by setting *opacity*.
      Default is *false*.

      .[page:Blending blending]

      Which blending to use when displaying objects with this material. Default is [page:Materials NormalBlending]. See the blending mode [page:Materials constants] for all possible values.

      .[page:Integer blendSrc]

      Blending source. It's one of the blending mode constants defined in Three.js. Default is [page:CustomBlendingEquation SrcAlphaFactor]. See the destination factors [page:CustomBlendingEquation constants] for all possible values.

      [property:Integer blendDst]

      Blending destination. It's one of the blending mode constants defined in [page:Three Three.js]. Default is [page:CustomBlendingEquation OneMinusSrcAlphaFactor].

      [property:Integer blendEquation]

      Blending equation to use when applying blending. It's one of the constants defined in [page:Three Three.js]. Default is [page:CustomBlendingEquation AddEquation.]

      [property:Boolean depthTest]

      Whether to have depth test enabled when rendering this material. Default is *true*.

      [property:Boolean depthWrite]

      Whether rendering this material has any effect on the depth buffer. Default is *true*.
      When drawing 2D overlays it can be useful to disable the depth writing in order to layer several things together without creating z-index artifacts.

      [property:Boolean polygonOffset]

      Whether to use polygon offset. Default is *false*. This corresponds to the *POLYGON_OFFSET_FILL* WebGL feature.

      [property:Integer polygonOffsetFactor]

      Sets the polygon offset factor. Default is *0*.

      [property:Integer polygonOffsetUnits]

      Sets the polygon offset units. Default is *0*.

      [property:Number alphaTest]

      Sets the alpha value to be used when running an alpha test. Default is *0*.

      [property:Float overdraw]

      Amount of triangle expansion at draw time. This is a workaround for cases when gaps appear between triangles when using [page:CanvasRenderer]. *0.5* tends to give good results across browsers. Default is *0*.

      [property:Boolean visible]

      Defines whether this material is visible. Default is *true*.

      [property:Enum side]

      Defines which of the face sides will be rendered - front, back or both.
      Default is [page:Materials THREE.FrontSide]. Other options are [page:Materials THREE.BackSide] and [page:Materials THREE.DoubleSide].

      [property:Boolean needsUpdate]

      Specifies that the material needs to be updated at the WebGL level. Set it to true if you made changes that need to be reflected in WebGL.
      This property is automatically set to *true* when instancing a new material.

      Methods

      [page:EventDispatcher EventDispatcher] methods are available on this class.

      [method:Material clone]([page:material material])

      material -- this material gets the cloned information (optional).
      This clones the material in the optional parameter and returns it.

      [method:null dispose]()

      This disposes the material. Textures of a material don't get disposed. These needs to be disposed by [page:Texture Texture].

      [method:null setValues]([page:object values])

      values -- a container with parameters.
      Sets the properties based on the *values*.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/MeshNormalMaterial.html0000644000175500017550000000303712610076566023053 0ustar debacledebacle [page:Material] →

      [name]

      A material that maps the normal vectors to RGB colors.

      Constructor

      [name]([page:Object parameters])

      parameters is an object with one or more properties defining the material's appearance.
      wireframe -- Render geometry as wireframe. Default is false (i.e. render as smooth shaded).
      wireframeLinewidth -- Controls wireframe thickness. Default is 1.
      morphTargets -- Define whether the material uses morphTargets. Default is false.

      Properties

      [property:boolean wireframe]

      Render geometry as wireframe. Default is false (i.e. render as smooth shaded).

      [property:number wireframeLinewidth]

      Controls wireframe thickness. Default is 1.

      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:boolean morphTargets]

      Define whether the material uses morphTargets. Default is false.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/MeshPhongMaterial.html0000644000175500017550000002165312610076566022702 0ustar debacledebacle [page:Material] →

      [name]

      A material for shiny surfaces, evaluated per pixel.

      Constructor

      [name]([page:Object parameters])

      parameters -- an object with one or more of the material's properties defining the its appearance.
      color — geometry color in hexadecimal. Default is 0xffffff.
      map — Set texture map. Default is null
      lightMap — Set light map. Default is null.
      aoMap — Set ao map. Default is null.
      emissiveMap — Set emissive map. Default is null.
      specularMap — Set specular map. Default is null.
      alphaMap — Set alpha map. Default is null.
      envMap — Set env map. Default is null.
      fog — Define whether the material color is affected by global fog settings. Default is true.
      shading — Define shading type. Default is THREE.SmoothShading.
      wireframe — render geometry as wireframe. Default is false.
      wireframeLinewidth — Line thickness. Default is 1.
      wireframeLinecap — Define appearance of line ends. Default is 'round'.
      wireframeLinejoin — Define appearance of line joints. Default is 'round'.
      vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.
      skinning — Define whether the material uses skinning. Default is false.
      morphTargets — Define whether the material uses morphTargets. Default is false.
      Example:
      materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) );

      Properties

      See the base [page:Material] class for common parameters.

      [property:Color color]

      Diffuse color of the material. Default is white.

      [property:Color emissive]

      Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.

      [property:Color specular]

      Specular color of the material, i.e., how shiny the material is and the color of its shine. Setting this the same color as the diffuse value (times some intensity) makes the material more metallic-looking; setting this to some gray makes the material look more plastic. Default is dark gray.

      [property:Float shininess]

      How shiny the specular highlight is; a higher value gives a sharper highlight. Default is *30*.

      [property:boolean metal]

      If set to true the shader multiplies the specular highlight by the underlying color of the object, making it appear to be more metal-like and darker. If set to false the specular highlight is added ontop of the underlying colors.

      [property:Texture map]

      Set color texture map. Default is null. The texture map color is modulated by the diffuse color.

      [property:Texture lightMap]

      Set light map. Default is null. The lightMap requires a second set of UVs.

      [property:Texture aoMap]

      Set ambient occlusion map. Default is null. The aoMap requires a second set of UVs.

      [property:Texture emissiveMap]

      Set emisssive (glow) map. Default is null. The emissive map color is modulated by the emissive color. If you have an emissive map, be sure to set the emissive color to something other than black.

      [property:Texture bumpMap]

      The texture to create a bump map. The black and white values map to the perceived depth in relation to the lights. Bump doesn't actually affect the geometry of the object, only the lighting. If a normal map is defined this will be ignored.

      [property:Float bumpScale]

      How much the bump map affects the material. Typical ranges are 0-1. Default is 1.

      [property:Texture normalMap]

      The texture to create a normal map. The RGB values affect the surface normal for each pixel fragment and change the way the color is lit. Normal maps do not change the actual shape of the surface, only the lighting.

      [property:Vector2 normalScale]

      How much the normal map affects the material. Typical ranges are 0-1. Default is (1,1).

      [property:Texture specularMap]

      The specular map value affects both how much the specular surface highlight contributes and how much of the environment map affects the surface. Default is null.

      [property:Texture alphaMap]

      The alpha map is a grayscale texture that controls the opacity across the surface (black: fully transparent; white: fully opaque). Default is null.
      Only the color of the texture is used, ignoring the alpha channel if one exists. For RGB and RGBA textures, the [page:WebGLRenderer WebGL] renderer will use the green channel when sampling this texture due to the extra bit of precision provided for green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and luminance/alpha textures will also still work as expected.

      [property:TextureCube envMap]

      Set env map. Default is null.

      [property:Integer combine]

      How to combine the result of the surface's color with the environment map, if any.
      Options are [page:Textures THREE.MultiplyOperation] (default), [page:Textures THREE.MixOperation], [page:Textures THREE.AddOperation]. If mix is chosen, the reflectivity is used to blend between the two colors.

      [property:Float reflectivity]

      How much the environment map affects the surface; also see "combine".

      [property:Float refractionRatio]

      The index of refraction for an environment map using [page:Textures THREE.CubeRefractionMapping]. Default is *0.98*.

      [property:Boolean fog]

      Define whether the material color is affected by global fog settings. Default is *true*.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      [property:Integer shading]

      How the triangles of a curved surface are rendered: as a smooth surface, as flat separate facets, or no shading at all.
      Options are [page:Materials THREE.SmoothShading] (default), [page:Materials THREE.FlatShading].

      [property:Boolean wireframe]

      Whether the triangles' edges are displayed instead of surfaces. Default is *false*.

      [property:Float wireframeLinewidth]

      Line thickness for wireframe mode. Default is *1.0*.
      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:String wireframeLinecap]

      Define appearance of line ends. Possible values are "butt", "round" and "square". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:String wireframeLinejoin]

      Define appearance of line joints. Possible values are "round", "bevel" and "miter". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:Integer vertexColors]

      Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      [property:Boolean skinning]

      Define whether the material uses skinning. Default is *false*.

      [property:Boolean morphTargets]

      Define whether the material uses morphTargets. Default is *false*.

      [property:boolean morphNormals]

      Defines whether the material uses morphNormals. Set as true to pass morphNormal attributes from the [page:Geometry] to the shader. Default is *false*.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/RawShaderMaterial.html0000644000175500017550000000114012610076566022657 0ustar debacledebacle [page:ShaderMaterial] →

      [name]

      This class works just like [page:ShaderMaterial], except that definitions of built-in uniforms and attributes are not automatically prepended to the GLSL shader code.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/SpriteMaterial.html0000644000175500017550000000233112610076566022250 0ustar debacledebacle [page:Material] →

      [name]

      A material for a [page:Sprite].

      Constructor

      [name]( [page:Object parameters] )

      parameters -- an object defining the the default properties
      color - color of the sprite
      map - the texture map
      rotation - the rotation of the sprite
      fog - whether or not to use the scene fog

      Properties

      [property:Color color]

      The texture is multiplied by this color. The default is 0xffffff

      [property:Texture map]

      The texture map. Default is null.

      [property:Radians rotation]

      The rotation of the sprite in radians. Default is 0.

      [property:boolean fog]

      Whether or not this material affected by the scene's fog. Default is false

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/MeshBasicMaterial.html0000644000175500017550000001333412610076566022645 0ustar debacledebacle [page:Material] →

      [name]

      A material for drawing geometries in a simple shaded (flat or wireframe) way.
      The default will render as flat polygons. To draw the mesh as wireframe, simply set the 'wireframe' property to true.

      Constructor

      [name]( [page:Object parameters] )

      parameters is an object with one or more properties defining the material's appearance.
      color — geometry color in hexadecimal. Default is 0xffffff.
      map — Set texture map. Default is null
      aoMap — Set ambient occlusion map. Default is null
      specularMap — Set specular map. Default is null.
      alphaMap — Set alpha map. Default is null.
      envMap — Set env map. Default is null.
      fog — Define whether the material color is affected by global fog settings. Default is true.
      shading — Define shading type. Default is THREE.SmoothShading.
      wireframe — render geometry as wireframe. Default is false.
      wireframeLinewidth — Line thickness. Default is 1.
      wireframeLinecap — Define appearance of line ends. Default is 'round'.
      wireframeLinejoin — Define appearance of line joints. Default is 'round'.
      vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.
      skinning — Define whether the material uses skinning. Default is false.
      morphTargets — Define whether the material uses morphTargets. Default is false.

      Properties

      [property:Integer color]

      Sets the color of the geometry. Default is 0xffffff.

      [property:Texture map]

      Set texture map. Default is null.

      [property:Texture aoMap]

      Set ambient occlusion map. Default is null.

      [property:Texture specularMap]

      Set specular map. Default is null.

      [property:Texture alphaMap]

      The alpha map is a grayscale texture that controls the opacity across the surface (black: fully transparent; white: fully opaque). Default is null.
      Only the color of the texture is used, ignoring the alpha channel if one exists. For RGB and RGBA textures, the [page:WebGLRenderer WebGL] renderer will use the green channel when sampling this texture due to the extra bit of precision provided for green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and luminance/alpha textures will also still work as expected.

      [property:TextureCube envMap]

      Set env map. Default is null.

      [property:Boolean fog]

      Define whether the material color is affected by global fog settings.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      [property:String shading]

      Define shading type. Default is THREE.SmoothShading.

      [property:Boolean wireframe]

      Render geometry as wireframe. Default is false (i.e. render as flat polygons).

      [property:Float wireframeLinewidth]

      Controls wireframe thickness. Default is 1.
      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:String wireframeLinecap]

      Define appearance of line ends. Possible values are "butt", "round" and "square". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:String wireframeLinejoin]

      Define appearance of line joints. Possible values are "round", "bevel" and "miter". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:Integer vertexColors]

      Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      [property:Boolean skinning]

      Define whether the material uses skinning. Default is false.

      [property:Boolean morphTargets]

      Define whether the material uses morphTargets. Default is false.

      [property:number combine]

      How to combine the result of the surface's color with the environment map, if any.

      [property:number reflectivity]

      How much the environment map affects the surface; also see "combine".

      [property:number refractionRatio]

      The index of refraction for an environment map using [page:Textures THREE.CubeRefractionMapping]. Default is *0.98*.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/MeshFaceMaterial.html0000644000175500017550000000177512610076566022470 0ustar debacledebacle

      [name]

      A Material to define multiple materials for the same geometry. The geometry decides which material is used for which faces by the [page:Face3 faces materialindex]. The materialindex corresponds with the index of the material in the materials array.

      Constructor

      [name]([page:Array materials])

      materials -- The materials for the geometry.
      Creates a MeshFaceMaterial with the correct materials.

      Properties

      [property:Array materials]

      Get or set the materials for the geometry.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/LineBasicMaterial.html0000644000175500017550000000554512610076566022645 0ustar debacledebacle [page:Material] →

      [name]

      A material for drawing wireframe-style geometries.

      Constructor

      [name]( [page:Object parameters] )

      parameters is an object with one or more properties defining the material's appearance.
      color — Line color in hexadecimal. Default is 0xffffff.
      linewidth — Line thickness. Default is 1.
      linecap — Define appearance of line ends. Default is 'round'.
      linejoin — Define appearance of line joints. Default is 'round'.
      vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.
      fog — Define whether the material color is affected by global fog settings. Default is false.

      Properties

      [property:Integer color]

      Sets the color of the line. Default is 0xffffff.

      [property:Float linewidth]

      Controls line thickness. Default is 1.
      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:String linecap]

      Define appearance of line ends. Possible values are "butt", "round" and "square". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:String linejoin]

      Define appearance of line joints. Possible values are "round", "bevel" and "miter". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:Integer vertexColors]

      Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.
      This setting might not have any effect when used with certain renderers.

      [property:Boolean fog]

      Define whether the material color is affected by global fog settings.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/PointsMaterial.html0000644000175500017550000000465512610076566022271 0ustar debacledebacle [page:Material] →

      [name]

      The default material used by [page:Points particle] systems.

      Constructor

      [name]( [page:Object parameters] )

      parameters is an object with one or more properties defining the material's appearance.
      color — Particle color in hexadecimal. Default is 0xffffff.
      map — a [page:Texture texture].If defined, then a point has the data from texture as colors. Default is null.
      size — Define size of particles. Default is 1.0.
      sizeAttenuation — Enable/disable size attenuation with distance.
      vertexColors — Define whether the material uses vertex colors, or not. Default is false.
      fog — Define whether the material color is affected by global fog settings. Default is true.

      Properties

      [property:Number color]

      Sets the color of the particles. Default is 0xffffff.

      [property:Texture map]

      Sets the color of the particles using data from a texture.

      [property:Number size]

      Sets the size of the particles. Default is 1.0.

      [property:Boolean sizeAttenuation]

      Specify whether particles' size will get smaller with the distance. Default is true.

      [property:Boolean vertexColors]

      Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      [property:Boolean fog]

      Define whether the material color is affected by global fog settings.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/MeshDepthMaterial.html0000644000175500017550000000315512610076566022670 0ustar debacledebacle [page:Material] →

      [name]

      A material for drawing geometry by depth. Depth is based off of the camera near and far plane. White is nearest, black is farthest.

      Constructor

      [name]([page:Object parameters])

      parameters is an object with one or more properties defining the material's appearance.
      morphTargets -- Define whether the material uses morphTargets. Default is false.
      wireframe -- Render geometry as wireframe. Default is false (i.e. render as smooth shaded).
      wireframeLinewidth -- Controls wireframe thickness. Default is 1.

      Properties

      [property:boolean morphTargets]

      Define whether the material uses morphTargets. Default is false.

      [property:boolean wireframe]

      Render geometry as wireframe. Default is false (i.e. render as smooth shaded).

      [property:number wireframeLinewidth]

      Controls wireframe thickness. Default is 1.

      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/materials/MeshLambertMaterial.html0000644000175500017550000001417212610076566023213 0ustar debacledebacle [page:Material] →

      [name]

      A material for non-shiny (Lambertian) surfaces, evaluated per vertex.

      Constructor

      [name]([page:Object parameters])

      parameters -- parameters is an object with one or more properties defining the material's appearance.
      color — Line color in hexadecimal. Default is 0xffffff.
      map — Sets the texture map. Default is null
      specularMap — Set specular map. Default is null.
      alphaMap — Set alpha map. Default is null.
      envMap — Set env map. Default is null.
      fog — Define whether the material color is affected by global fog settings. Default is false.
      wireframe — Render geometry as wireframe. Default is false (i.e. render as smooth shaded).
      wireframeLinewidth — Controls wireframe thickness. Default is 1.
      wireframeLinecap — Define appearance of line ends. Default is 'round'.
      wireframeLinejoin — Define appearance of line joints. Default is 'round'.
      vertexColors — Define how the vertices gets colored. Default is THREE.NoColors.
      skinning — Define whether the material uses skinning. Default is false.
      morphTargets — Define whether the material uses morphTargets. Default is false.

      Properties

      See the base [page:Material] class for common parameters.

      [property:Color color]

      Diffuse color of the material. Default is white.

      [property:Color emissive]

      Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.

      [property:Texture map]

      Set color texture map. Default is null.

      [property:Texture specularMap]

      Since this material does not have a specular component, the specular value affects only how much of the environment map affects the surface. Default is null.

      [property:Texture alphaMap]

      The alpha map is a grayscale texture that controls the opacity across the surface (black: fully transparent; white: fully opaque). Default is null.
      Only the color of the texture is used, ignoring the alpha channel if one exists. For RGB and RGBA textures, the [page:WebGLRenderer WebGL] renderer will use the green channel when sampling this texture due to the extra bit of precision provided for green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and luminance/alpha textures will also still work as expected.

      [property:TextureCube envMap]

      Set env map. Default is null.

      [property:Integer combine]

      How to combine the result of the surface's color with the environment map, if any.
      Options are [page:Textures THREE.Multiply] (default), [page:Textures THREE.MixOperation], [page:Textures THREE.AddOperation]. If mix is chosen, the reflectivity is used to blend between the two colors.

      [property:Float reflectivity]

      How much the environment map affects the surface; also see "combine".

      [property:Float refractionRatio]

      The index of refraction for an environment map using [page:Textures THREE.CubeRefractionMapping]. Default is *0.98*.

      [property:Boolean fog]

      Define whether the material color is affected by global fog settings. Default is *true*.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      [property:Boolean wireframe]

      Whether the triangles' edges are displayed instead of surfaces. Default is *false*.

      [property:Float wireframeLinewidth]

      Line thickness for wireframe mode. Default is *1.0*.
      Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value.

      [property:String wireframeLinecap]

      Define appearance of line ends. Possible values are "butt", "round" and "square". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:String wireframeLinejoin]

      Define appearance of line joints. Possible values are "round", "bevel" and "miter". Default is 'round'.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:WebGLRenderer WebGL] renderer, but does work with the [page:CanvasRenderer Canvas] renderer.

      [property:Integer vertexColors]

      Define how the vertices gets colored. Possible values are THREE.NoColors, THREE.FaceColors and THREE.VertexColors. Default is THREE.NoColors.
      This setting might not have any effect when used with certain renderers. For example, it is ignored with the [page:CanvasRenderer Canvas] renderer, but does work with the [page:WebGLRenderer WebGL] renderer.

      [property:Boolean skinning]

      Define whether the material uses skinning. Default is *false*.

      [property:Boolean morphTargets]

      Define whether the material uses morphTargets. Default is *false*.

      [property:boolean morphNormals]

      Defines whether the material uses morphNormals. Set as true to pass morphNormal attributes from the [page:Geometry] to the shader. Default is *false*.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/0000755000175500017550000000000012610076566015406 5ustar debacledebaclethree.js-r73/docs/api/math/Matrix4.html0000644000175500017550000002022312610076566017623 0ustar debacledebacle

      [name]

      A 4x4 Matrix.

      Example

      // Simple rig for rotating around 3 axes var m = new THREE.Matrix4(); var m1 = new THREE.Matrix4(); var m2 = new THREE.Matrix4(); var m3 = new THREE.Matrix4(); var alpha = 0; var beta = Math.PI; var gamma = Math.PI/2; m1.makeRotationX( alpha ); m2.makeRotationY( beta ); m3.makeRotationZ( gamma ); m.multiplyMatrices( m1, m2 ); m.multiply( m3 );

      Constructor

      [name]()

      Creates and initializes the matrix to the identity matrix.

      Properties

      [property:Float32Array elements]

      A column-major list of matrix values.

      Methods

      [method:Matrix4 set]( [page:Float n11], [page:Float n12], [page:Float n13], [page:Float n14], [page:Float n21], [page:Float n22], [page:Float n23], [page:Float n24], [page:Float n31], [page:Float n32], [page:Float n33], [page:Float n34], [page:Float n41], [page:Float n42], [page:Float n43], [page:Float n44] ) [page:Matrix4 this]

      Sets all fields of this matrix to the supplied row-major values n11..n44.

      [method:Matrix4 identity]() [page:Matrix4 this]

      Resets this matrix to identity.

      [method:Matrix4 copy]( [page:Matrix4 m] ) [page:Matrix4 this]

      Copies the values of matrix *m* into this matrix.

      [method:Matrix4 copyPosition]( [page:Matrix4 m] ) [page:Matrix4 this]

      Copies the translation component of the supplied matrix *m* into this matrix translation component.

      [method:Matrix4 makeBasis]( [page:Vector3 xAxis], [page:Vector3 zAxis], [page:Vector3 zAxis] ) [page:Matrix4 this]

      Creates the basis matrix consisting of the three provided axis vectors. Returns the current matrix.

      [method:Matrix4 extractBasis]( [page:Vector3 xAxis], [page:Vector3 zAxis], [page:Vector3 zAxis] ) [page:Matrix4 this]

      Extracts basis of into the three axis vectors provided. Returns the current matrix.

      [method:Matrix4 extractRotation]( [page:Matrix4 m] ) [page:Matrix4 this]

      Extracts the rotation of the supplied matrix *m* into this matrix rotation component.

      [method:Matrix4 lookAt]( [page:Vector3 eye], [page:Vector3 center], [page:Vector3 up], ) [page:Matrix4 this]

      Constructs a rotation matrix, looking from *eye* towards *center* with defined *up* vector.

      [method:Matrix4 multiply]( [page:Matrix4 m] ) [page:Matrix4 this]

      Multiplies this matrix by *m*.

      [method:Matrix4 multiplyMatrices]( [page:Matrix4 a], [page:Matrix4 b] ) [page:Matrix4 this]

      Sets this matrix to *a x b*.

      [method:Matrix4 multiplyToArray]( [page:Matrix4 a], [page:Matrix4 b], [page:Array r] ) [page:Matrix4 this]

      Sets this matrix to *a x b* and stores the result into the flat array *r*.
      *r* can be either a regular Array or a TypedArray.

      [method:Matrix4 multiplyScalar]( [page:Float s] ) [page:Matrix4 this]

      Multiplies every component of the matrix by a scalar value *s*.

      [method:Float determinant]()

      Computes and returns the determinant of this matrix.
      Based on [link:http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm]

      [method:Matrix4 transpose]() [page:Matrix4 this]

      Transposes this matrix.

      [method:Array flattenToArrayOffset]( [page:Array flat], [page:Integer offset] )

      Flattens this matrix into supplied *flat* array starting from *offset* position in the array.

      [method:Matrix4 setPosition]( [page:Vector3 v] ) [page:Matrix4 this]

      Sets the position component for this matrix from vector *v*.

      [method:Matrix4 getInverse]( [page:Matrix4 m] ) [page:Matrix4 this]

      Sets this matrix to the inverse of matrix *m*.
      Based on [link:http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm].

      [method:Matrix4 makeRotationFromEuler]( [page:Euler euler] ) [page:Matrix4 this]

      euler — Rotation vector followed by order of rotations, e.g., "XYZ".
      Sets the rotation submatrix of this matrix to the rotation specified by Euler angles, the rest of the matrix is identity.
      Default order is *"XYZ"*.

      [method:Matrix4 makeRotationFromQuaternion]( [page:Quaternion q] ) [page:Matrix4 this]

      Sets the rotation submatrix of this matrix to the rotation specified by *q*. The rest of the matrix is identity.

      [method:Matrix4 scale]( [page:Vector3 v] ) [page:Matrix4 this]

      Multiplies the columns of this matrix by vector *v*.

      [method:Matrix4 compose]( [page:Vector3 translation], [page:Quaternion quaternion], [page:Vector3 scale] ) [page:Matrix4 this]

      Sets this matrix to the transformation composed of *translation*, *quaternion* and *scale*.

      [method:Array decompose]( [page:Vector3 translation], [page:Quaternion quaternion], [page:Vector3 scale] )

      Decomposes this matrix into the *translation*, *quaternion* and *scale* components.

      [method:Matrix4 makeTranslation]( [page:Float x], [page:Float y], [page:Float z] ) [page:Matrix4 this]

      Sets this matrix as translation transform.

      [method:Matrix4 makeRotationX]( [page:Float theta] ) [page:Matrix4 this]

      theta — Rotation angle in radians.
      Sets this matrix as rotation transform around x axis by *theta* radians.

      [method:Matrix4 makeRotationY]( [page:Float theta] ) [page:Matrix4 this]

      theta — Rotation angle in radians.
      Sets this matrix as rotation transform around y axis by *theta* radians.

      [method:Matrix4 makeRotationZ]( [page:Float theta] ) [page:Matrix4 this]

      theta — Rotation angle in radians.
      Sets this matrix as rotation transform around z axis by *theta* radians.

      [method:Matrix4 makeRotationAxis]( [page:Vector3 axis], [page:Float theta] ) [page:Matrix4 this]

      axis — Rotation axis, should be normalized. theta — Rotation angle in radians.
      Sets this matrix as rotation transform around *axis* by *angle* radians.
      Based on [link:http://www.gamedev.net/reference/articles/article1199.asp].

      [method:Matrix4 makeScale]( [page:Float x], [page:Float y], [page:Float z] ) [page:Matrix4 this]

      Sets this matrix as scale transform.

      [method:Matrix4 makeFrustum]( [page:Float left], [page:Float right], [page:Float bottom], [page:Float top], [page:Float near], [page:Float far] ) [page:Matrix4 this]

      Creates a [page:Frustum frustum] matrix.

      [method:Matrix4 makePerspective]( [page:Float fov], [page:Float aspect], [page:Float near], [page:Float far] ) [page:Matrix4 this]

      Creates a perspective projection matrix.

      [method:Matrix4 makeOrthographic]( [page:Float left], [page:Float right], [page:Float top], [page:Float bottom], [page:Float near], [page:Float far] ) [page:Matrix4 this]

      Creates an orthographic projection matrix.

      [method:Matrix4 clone]()

      Creates a copy of this matrix.

      [method:Array applyToVector3Array]([page:Array a])

      array -- An array in the form [vector1x, vector1y, vector1z, vector2x, vector2y, vector2z, ...]
      Multiplies (applies) this matrix to every vector3 in the array.

      [method:Float getMaxScaleOnAxis]()

      Gets the maximum scale value of the 3 axes.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Box3.html0000644000175500017550000001616012610076566017113 0ustar debacledebacle

      [name]

      Represents a boundary box in 3d space.

      Constructor

      [name]([page:Vector3 min], [page:Vector3 max])

      min -- Lower (x, y, z) boundary of the box.
      max -- Upper (x, y, z) boundary of the box.
      Creates a box bounded by min and max.

      Properties

      [property:Vector3 min]

      Lower (x, y, z) boundary of this box.

      [property:Vector3 max]

      Upper (x, y, z) boundary of this box.

      Methods

      [method:Box3 set]([page:Vector3 min], [page:Vector3 max]) [page:Box3 this]

      min -- Lower (x, y, z) boundary of the box.
      max -- Upper (x, y, z) boundary of the box.
      Sets the lower and upper (x, y, z) boundaries of this box.

      [method:Box3 applyMatrix4]([page:Matrix4 matrix]) [page:Box3 this]

      matrix -- The [page:Matrix4] to apply
      Transforms this Box3 with the supplied matrix.

      [method:Vector3 clampPoint]([page:Vector3 point], [page:Vector3 optionalTarget])

      point -- Position to clamp.
      optionalTarget -- If specified, the clamped result will be copied here.
      Clamps *point* within the bounds of this box.

      [method:Boolean isIntersectionBox]([page:Box3 box])

      box -- Box to check for intersection against.
      Determines whether or not this box intersects *box*.

      [method:Box3 setFromPoints]([page:Array points]) [page:Box3 this]

      points -- Set of points that the resulting box will envelop.
      Sets the upper and lower bounds of this box to include all of the points in *points*.

      [method:Box3 setFromObject]([page:Object3D object]) [page:Box3 this]

      object -- [page:Object3D] to compute the bounding box for.
      Computes the world-axis-aligned bounding box of an object (including its children), accounting for both the object's, and childrens', world transforms

      [method:Vector3 size]([page:Vector3 optionalTarget])

      optionalTarget -- If specified, the result will be copied here.
      Returns the width, height, and depth of this box.

      [method:Box3 union]([page:Box3 box])

      box -- Box that will be unioned with this box.
      Unions this box with *box* setting the upper bound of this box to the greater of the two boxes' upper bounds and the lower bound of this box to the lesser of the two boxes' lower bounds.

      [method:Vector3 getParameter]([page:Vector3 point], [page:Vector3 optionalTarget])

      point -- Point to parametrize. optionalTarget -- If specified, the result will be copied here.
      Returns point as a proportion of this box's width and height.

      [method:Box3 intersect]([page:Box3 box]) [page:Box3 this]

      box -- Box to intersect with.
      Returns the intersection of this and *box*, setting the upper bound of this box to the lesser
      of the two boxes' upper bounds and the lower bound of this box to the greater of the two boxes'
      lower bounds.

      [method:Boolean containsBox]([page:Box3 box])

      box -- Box to test for inclusion.
      Returns true if this box includes the entirety of *box*. If this and *box* overlap exactly,
      this function also returns true.

      [method:Boolean containsPoint]([page:Vector3 point])

      point -- [page:Vector3] to check for inclusion.
      Returns true if the specified point lies within the boundaries of this box.

      [method:Box3 translate]([page:Vector3 offset]) [page:Box3 this]

      offset -- Direction and distance of offset.
      Adds *offset* to both the upper and lower bounds of this box, effectively moving this box
      *offset* units in 3D space.

      [method:Boolean empty]()

      Returns true if this box includes zero points within its bounds.
      Note that a box with equal lower and upper bounds still includes one point, the one both bounds share.

      [method:Box3 clone]()

      Returns a copy of this box.

      [method:Boolean equals]([page:Box3 box])

      box -- Box to compare.
      Returns true if this box and *box* share the same lower and upper bounds.

      [method:Box3 expandByPoint]([page:Vector3 point]) [page:Box3 this]

      point -- Point that should be included in the box.
      Expands the boundaries of this box to include *point*.

      [method:Box3 expandByScalar]([page:float scalar]) [page:Box3 this]

      scalar -- Distance to expand.
      Expands each dimension of the box by *scalar*. If negative, the dimensions of the box
      will be contracted.

      [method:Box3 expandByVector]([page:Vector3 vector]) [page:Box3 this]

      vector -- Amount to expand this box in each dimension.
      Expands this box equilaterally by *vector*. The width of this box will be expanded by the x component of *vector* in both directions. The height of this box will be expanded by the y component of *vector* in both directions. The depth of this box will be expanded by the z component of *vector* in both directions.

      [method:Box3 copy]([page:Box3 box]) [page:Box3 this]

      box -- Box to copy.
      Copies the values of *box* to this box.

      [method:Box3 makeEmpty]() [page:Box3 this]

      Makes this box empty.

      [method:Vector3 center]([page:Vector3 optionalTarget])

      optionalTarget -- If specified, the result will be copied here.
      Returns the center point of this box.

      [method:Sphere getBoundingSphere]([page:Sphere optionalTarget])

      optionalTarget -- [page:Sphere] to optionally set the result to.
      Gets a sphere that bounds the box.

      [method:Float distanceToPoint]([page:Vector3 point])

      point -- Point to measure distance to.
      Returns the distance from any edge of this box to the specified point.
      If the point lies inside of this box, the distance will be 0.

      [method:Box3 setFromCenterAndSize]([page:Vector3 center], [page:Vector3 size]) [page:Box3 this]

      center -- Desired center position of the box.
      size -- Desired x and y dimensions of the box.
      Centers this box on *center* and sets this box's width and height to the values specified in *size*.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Vector2.html0000644000175500017550000001675712610076566017640 0ustar debacledebacle

      [name]

      2D vector.

      Example

      var a = new THREE.Vector2( 0, 1 ); var b = new THREE.Vector2( 1, 0 ); var d = a.distanceTo( b );

      Constructor

      [name]( [page:Float x], [page:Float y] )

      x -- [page:Float] representing the x value of the vector
      y -- [page:Float] representing the y value of the vector
      A vector in 2 dimensional space

      Properties

      [property:Float x]

      [property:Float y]

      Methods

      [method:Vector2 set]( [page:Float x], [page:Float y] ) [page:Vector2 this]

      Sets value of this vector.

      [method:Vector2 copy]( [page:Vector2 v] ) [page:Vector2 this]

      Copies value of *v* to this vector.

      [method:Vector2 add]( [page:Vector2 v] ) [page:Vector2 this]

      Adds *v* to this vector.

      [method:Vector2 addVectors]( [page:Vector2 a], [page:Vector2 b] ) [page:Vector2 this]

      Sets this vector to *a + b*.

      [method:Vector2 addScaledVector]( [page:Vector2 v], [page:Float s] ) [page:Vector2 this]

      Adds the multiple of v and s to this vector.

      [method:Vector2 sub]( [page:Vector2 v] ) [page:Vector2 this]

      Subtracts *v* from this vector.

      [method:Vector2 subVectors]( [page:Vector2 a], [page:Vector2 b] ) [page:Vector2 this]

      Sets this vector to *a - b*.

      [method:Vector2 multiplyScalar]( [page:Float s] ) [page:Vector2 this]

      Multiplies this vector by scalar *s*.

      [method:Vector2 divideScalar]( [page:Float s] ) [page:Vector2 this]

      Divides this vector by scalar *s*.
      Set vector to *( 0, 0 )* if *s == 0*.

      [method:Vector2 negate]() [page:Vector2 this]

      Inverts this vector.

      [method:Float dot]( [page:Vector2 v] )

      Computes dot product of this vector and *v*.

      [method:Float lengthSq]()

      Computes squared length of this vector.

      [method:Float length]()

      Computes length of this vector.

      [method:Float lengthManhattan]()

      Computes Manhattan length of this vector.
      [link:http://en.wikipedia.org/wiki/Taxicab_geometry]

      [method:Vector2 normalize]() [page:Vector2 this]

      Normalizes this vector.

      [method:Float distanceTo]( [page:Vector2 v] )

      Computes distance of this vector to *v*.

      [method:Float distanceToSquared]( [page:Vector2 v] )

      Computes squared distance of this vector to *v*.

      [method:Vector2 setLength]( [page:Float l] ) [page:Vector2 this]

      Normalizes this vector and multiplies it by *l*.

      [method:Boolean equals]( [page:Vector2 v] )

      Checks for strict equality of this vector and *v*.

      [method:Vector2 clone]()

      Clones this vector.

      [method:Vector2 clamp]([page:Vector2 min], [page:Vector2 max]) [page:Vector2 this]

      min -- [page:Vector2] containing the min x and y values in the desired range
      max -- [page:Vector2] containing the max x and y values in the desired range
      If this vector's x or y value is greater than the max vector's x or y value, it is replaced by the corresponding value.

      If this vector's x or y value is less than the min vector's x or y value, it is replaced by the corresponding value.

      [method:Vector2 clampScalar]([page:Float min], [page:Float max]) [page:Vector2 this]

      min -- [page:Float] the minimum value the components will be clamped to
      max -- [page:Float] the maximum value the components will be clamped to
      If this vector's x or y values are greater than the max value, they are replaced by the max value.

      If this vector's x or y values are less than the min value, they are replaced by the min value.

      [method:Vector2 floor]()

      The components of the vector are rounded downwards (towards negative infinity) to an integer value.

      [method:Vector2 ceil]()

      The components of the vector are rounded upwards (towards positive infinity) to an integer value.

      [method:Vector2 round]()

      The components of the vector are rounded towards the nearest integer value.

      [method:Vector2 roundToZero]()

      The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.

      [method:Vector2 lerp]([page:Vector2 v], [page:Float alpha]) [page:Vector2 this]

      v -- [page:Vector2]
      alpha -- [page:Float] between 0 and 1;
      Linear interpolation between this vector and v, where alpha is the percent along the line.

      [method:Vector2 lerpVectors]([page:Vector2 v1], [page:Vector2 v2], [page:Float alpha]) [page:Vector2 this]

      v1 -- [page:Vector2]
      v2 -- [page:Vector2]
      alpha -- [page:Float] between 0 and 1.
      Sets this vector to be the vector linearly interpolated between *v1* and *v2* with *alpha* factor.

      [method:undefined setComponent]([page:Integer index], [page:Float value])

      index -- 0 or 1
      value -- [page:Float]
      if index equals 0 method replaces this.x with value.
      if index equals 1 method replaces this.y with value.

      [method:Vector2 addScalar]([page:Float s]) [page:Vector2 this]

      s -- [page:Float]
      Add the scalar value s to this vector's x and y values.

      [method:Float getComponent]([page:Integer index])

      index -- 0 or 1
      if index equals 0 returns the x value.
      if index equals 1 returns the y value.

      [method:Vector2 fromArray]([page:Array array]) [page:Vector2 this]

      array -- [page:Array] of length 2
      Sets this vector's x value to be array[0] and y value to be array[1].

      [method:Array toArray]( [page:Array array] )

      array -- Optional array to store the vector.
      Returns an array [x, y].

      [method:Vector2 min]([page:Vector2 v]) [page:Vector2 this]

      v -- [page:Vector2]
      If this vector's x or y value is greater than v's x or y value, replace that value with the corresponding min value.

      [method:Vector2 max]([page:Vector2 v]) [page:Vector2 this]

      v -- [page:Vector2]
      If this vector's x or y value is less than v's x or y value, replace that value with the corresponding max value.

      [method:Vector2 setX]([page:Float x]) [page:Vector2 this]

      x -- [page:Float]
      replace this vector's x value with x.

      [method:Vector2 setY]([page:Float y]) [page:Vector2 this]

      y -- [page:Float]
      replace this vector's y value with y.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Spline.html0000644000175500017550000000503712610076566017533 0ustar debacledebacle

      [name]

      Represents a spline.

      Constructor

      [name]( [page:Array points] )

      Initialises the spline with *points*, which are the places through which the spline will go.

      Properties

      [property:Array points]

      Methods

      [method:null initFromArray]( [page:Array a] )

      a — array of triplets containing x, y, z coordinates
      Initialises using the data in the array as a series of points. Each value in *a* must be another array with three values, where a[n] is v, the value for the *nth* point, and v[0], v[1] and v[2] are the x, y and z coordinates of that point n, respectively.

      [method:Vector3 getPoint]( [page:Integer k] )

      k — point index
      Return the interpolated point at *k*.

      [method:Array getControlPointsArray]( )

      Returns an array with triplets of x, y, z coordinates that correspond to the current control points.

      [method:Object getLength]( [page:Integer nSubDivisions] )

      nSubDivisions — number of subdivisions between control points. Default is *100*.
      Returns an object with the two properties. The property .[page:Number total] contains the length of the spline when using nSubDivisions. The property .[page:Array chunkLength] contains an array with the total length from the beginning of the spline to the end of that chunk.

      [method:null reparametrizeByArcLength]( [page:Float samplingCoef] )

      samplingCoef — how many intermediate values to use between spline points
      Modifies the spline so that it looks similar to the original but has its points distributed in such way that moving along the spline it's done at a more or less constant speed. The points should also appear more uniformly spread along the curve.
      This is done by resampling the original spline, with the density of sampling controlled by *samplingCoef*. Here it's interesting to note that denser sampling is not necessarily better: if sampling is too high, you may get weird kinks in curvature.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Ray.html0000644000175500017550000001566712610076566017046 0ustar debacledebacle

      [name]

      A ray that emits from an origin in a certain direction.

      Constructor

      [name]([page:Vector3 origin], [page:Vector3 direction])

      origin -- [page:Vector3] The origin of the [page:Ray].
      direction -- [page:Vector3] The direction of the [page:Ray]. This must be normalized (with [page:Vector3].normalize) for the methods to operate properly.
      Initialises the origin and direction properties to the provided values.

      Properties

      [property:Vector3 origin]

      The origin of the [page:Ray].

      [property:Vector3 direction]

      The direction of the [page:Ray]. This must be normalized (with [page:Vector3].normalize) for the methods to operate properly.

      Methods

      [method:Ray applyMatrix4]([page:Matrix4 matrix4])

      matrix4 -- [page:Matrix4] The [page:Matrix4] to transform this [page:Ray] by.
      Transform this [page:Ray] by the [page:Matrix4].

      .at([page:Float t], [page:Vector3 optionalTarget] = null) [page:Vector3]

      t -- [page:Float] The distance along the [page:Ray] to retrieve a position for.
      optionalTarget -- [page:Vector3] Receives the position along the [page:Ray] if passed; otherwise a new [page:Vector3] is created.
      Get a [page:Vector3] that is a given distance along this [page:Ray].

      [method:Ray clone]()

      Create a clone of this [page:Ray].

      [method:Vector3 closestPointToPoint]([page:Vector3 point], [page:Vector3 optionalTarget])

      point -- [page:Vector3] The point to get the closest approach to.
      optionalTarget -- [page:Vector3] Receives the return value if passed; otherwise a new [page:Vector3] is created.
      Get the point along this [page:Ray] that is closest to the [page:Vector3] provided.

      [method:Ray copy]([page:Ray ray])

      ray -- [page:Ray] The [page:Ray] to copy values from.
      Copy the properties of the provided [page:Ray], then return this [page:Ray].

      .distanceSqToSegment([page:Vector3 v0], [page:Vector3 v1], [page:Vector3 optionalPointOnRay] = null, [page:Vector3 optionalPointOnSegment] = null) [page:Float]

      v0 -- [page:Vector3] The start of the line segment. v1 -- [page:Vector3] The end of the line segment. optionalPointOnRay -- [page:Vector3] If this is provided, it receives the point on this [page:Ray] that is closest to the segment. optionalPointOnSegment -- [page:Vector3] If this is provided, it receives the point on the line segment that is closest to this [page:Ray].
      Get the squared distance between this [page:Ray] and a line segment.

      [method:Float distanceToPlane]([page:Plane plane])

      plane -- [page:Plane] The [page:Plane] to get the distance to.
      Get the distance from the origin to the [page:Plane], or *null* if the [page:Ray] doesn't intersect the [page:Plane].

      [method:Float distanceToPoint]([page:Vector3 point])

      point -- [page:Vector3] The [page:Vector3] to compute a distance to.
      Get the distance of the closest approach between the [page:Ray] and the [page:Vector3].

      [method:Float distanceSqToPoint]([page:Vector3 point])

      point -- [page:Vector3] The [page:Vector3] to compute a distance to.
      Get the squared distance of the closest approach between the [page:Ray] and the [page:Vector3].

      [method:Boolean equals]([page:Ray ray])

      ray -- [page:Ray] The [page:Ray] to compare to.
      Return whether this and the other [page:Ray] have equal offsets and directions.

      .intersectBox([page:Box3 box], [page:Vector3 optionalTarget] = null) [page:Vector3]?

      box -- [page:Box3] The [page:Box3] to intersect with.
      optionalTarget -- [page:Vector3] The [page:Vector3] to store the result in, or *null* to create a new [page:Vector3].
      Intersect this [page:Ray] with a [page:Box3], returning the intersection point or *null* if there is no intersection.

      .intersectPlane([page:Plane plane], [page:Vector3 optionalTarget] = null) [page:Vector3]?

      plane -- [page:Plane] The [page:Plane] to intersect with.
      optionalTarget -- [page:Vector3] The [page:Vector3] to store the result in, or *null* to create a new [page:Vector3].
      Intersect this [page:Ray] with a [page:Plane], returning the intersection point or *null* if there is no intersection.
      function ( a, b, c, backfaceCulling, optionalTarget )

      .intersectTriangle([page:Vector3 a], [page:Vector3 b], [page:Vector3 c], [page:Boolean backfaceCulling], [page:Vector3 optionalTarget] = null) [page:Vector3]?

      a, b, c -- [page:Vector3] The [page:Vector3] points on the triangle.
      backfaceCulling -- [page:Boolean] Whether to use backface culling.
      optionalTarget -- [page:Vector3] The [page:Vector3] to store the result in, or *null* to create a new [page:Vector3].
      Intersect this [page:Ray] with a triangle, returning the intersection point or *null* if there is no intersection.

      [method:Boolean isIntersectionBox]([page:Box3 box])

      box -- [page:Box3] The [page:Box3] to intersect with.
      Return whether or not this [page:Ray] intersects with the [page:Box3].

      [method:Boolean isIntersectionPlane]([page:Plane plane])

      plane -- [page:Plane] The [page:Plane] to intersect with.
      Return whether or not this [page:Ray] intersects with the [page:Plane].

      [method:Boolean isIntersectionSphere]([page:Sphere sphere])

      sphere -- [page:Sphere] The [page:Sphere] to intersect with.
      Return whether or not this [page:Ray] intersects with the [page:Sphere].

      [method:Ray recast]([page:Float t])

      t -- The distance along the [page:Ray] to interpolate.
      Shift the origin of this [page:Ray] along its direction by the distance given.

      [method:Ray set]([page:Vector3 origin], [page:Vector3 direction])

      origin -- [page:Vector3] The origin of the [page:Ray].
      direction -- [page:Vector3] The direction of the [page:Ray]. This must be normalized (with [page:Vector3].normalize) for the methods to operate properly.
      Copy the parameters to the origin and direction properties.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Matrix3.html0000644000175500017550000000622012610076566017623 0ustar debacledebacle

      [name]

      A 3x3 matrix.

      Constructor

      [name]()

      Creates and initializes the 3x3 matrix to the identity matrix.

      Properties

      [property:Float32Array elements]

      A column-major list of matrix values.

      Methods

      [method:Matrix3 transpose]()

      Transposes this matrix in place.

      [method:Matrix3 transposeIntoArray]( [page:Array array] )

      array -- [page:Array]
      Transposes this matrix into the supplied array, and returns itself unchanged.

      [method:Float determinant]()

      Computes and returns the determinant of this matrix.

      [method:Matrix3 set]([page:Float n11], [page:Float n12], [page:Float n13], [page:Float n21], [page:Float n22], [page:Float n23], [page:Float n31], [page:Float n32], [page:Float n33]) [page:Matrix3 this]

      n11 -- [page:Float]
      n12 -- [page:Float]
      n13 -- [page:Float]
      n21 -- [page:Float]
      n22 -- [page:Float]
      n23 -- [page:Float]
      n31 -- [page:Float]
      n32 -- [page:Float]
      n33 -- [page:Float]
      Sets the 3x3 matrix values to the given row-major sequence of values.

      [method:Matrix3 multiplyScalar]([page:Float s]) [page:Matrix3 this]

      scalar -- [page:Float]
      Multiplies every component of the matrix by the scalar value *s*.

      [method:Array applyToVector3Array]([page:Array array])

      array -- An array in the form [vector1x, vector1y, vector1z, vector2x, vector2y, vector2z, ...]
      Multiplies (applies) this matrix to every vector3 in the array.

      [method:Matrix3 getNormalMatrix]([page:Matrix4 m]) [page:Matrix3 this]

      m -- [page:Matrix4]
      Sets this matrix as the normal matrix (upper left 3x3)of the passed [page:Matrix4 matrix4]. The normal matrix is the inverse transpose of the matrix *m*.

      [method:Matrix3 getInverse]([page:Matrix4 m], [page:Boolean throwOnInvertible]) [page:Matrix3 this]

      m -- [page:Matrix4]
      throwOnInvertible -- [Page:Boolean] If true, throw an error if the matrix is invertible.
      Set this matrix to the inverse of the passed matrix.

      [method:Matrix3 copy]([page:Matrix3 m]) [page:Matrix3 this]

      m -- [page:Matrix4]
      Copies the values of matrix *m* into this matrix.

      [method:Matrix3 clone]()

      Creates a copy of this matrix.

      [method:Matrix3 identity]() [page:Matrix3 this]

      Resets this matrix to identity.

      1, 0, 0
      0, 1, 0
      0, 0, 1

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Line3.html0000644000175500017550000000704712610076566017256 0ustar debacledebacle

      [name]

      A geometric line segment represented by a start and end point.

      Constructor

      [name]([page:Vector3 start], [page:Vector3 end])

      start -- [page:Vector3] Start of the line segment
      end -- [page:Vector3] End of the line segment
      The start and end vectors default to origin vectors if none are set.

      Properties

      [property:Vector3 start]

      [property:Vector3 end]

      Methods

      [method:Line3 set]([page:Vector3 start], [page:Vector3 end])

      start -- [page:Vector3]
      end -- [page:Vector3]
      Sets the start and end values by copying the provided vectors.

      [method:Line3 copy]([page:Line3 line])

      line -- [page:Line3]
      Copies the passed line's start and end vectors to this line.

      [method:Line3 clone]()

      Return a new copy of this [page:Line3].

      [method:Boolean equals]([page:Line3 line])

      line -- [page:Line3]

      [method:Float distance]()

      Returns the length of the line segment.
      Returns true if both line's start and end points are equal.

      [method:Float distanceSq]()

      Returns the line segment's length squared.

      [method:Line3 applyMatrix4]([page:Matrix4 matrix]) [page:Line3 this]

      matrix -- [page:Matrix4]
      Apply a matrix transform to the line segment.

      [method:Vector at]([page:Float t], [page:Vector3 optionalTarget])

      t -- [page:Float] Use values 0-1 to return a result on the line segment.
      optionalTarget -- [page:Vector] Optional target to set the result.
      Return a vector at a certain position along the line. When t = 0, it returns the start vector, and when t=1 it returns the end vector.

      [method:Vector3 center]([page:Vector3 optionalTarget])

      optionalTarget -- [page:Vector3] Optional target to set the result.
      Return the center of the line segment.

      [method:Vector3 delta]([page:Vector3 optionalTarget])

      optionalTarget -- [page:Vector3] Optional target to set the result.
      Returns the delta vector of the line segment, or the end vector minus the start vector.

      [method:Vector3 closestPointToPoint]([page:Vector3 point], [page:Boolean clampToLine], [page:Vector3 optionalTarget])

      point -- [page:Vector3]
      clampToLine -- [page:Boolean]
      optionalTarget -- [page:Vector3] Optional target to set the result.
      Returns the closets point on the line. If clamp to line is true, then the returned value will be clamped to the line segment.

      [method:Float closestPointToPointParameter]([page:Vector3 point], [page:Boolean clampToLine])

      point -- [page:Vector3]
      clampToLine -- [page:Boolean]
      Returns a point parameter based on the closest point as projected on the line segement. If clamp to line is true, then the returned value will be between 0 and 1.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Color.html0000644000175500017550000001360512610076566017357 0ustar debacledebacle

      [name]

      Represents a color.

      Example

      var color = new THREE.Color(); var color = new THREE.Color( 0xff0000 ); var color = new THREE.Color("rgb(255, 0, 0)"); var color = new THREE.Color("rgb(100%, 0%, 0%)"); var color = new THREE.Color("hsl(0, 100%, 50%)"); var color = new THREE.Color( 1, 0, 0 );

      Constructor

      [name]( value )

      value — optional argument that sets initial color. Can be a hexadecimal or a CSS-style string, for example, "rgb(250, 0,0)", "rgb(100%,0%,0%)", "hsl(0, 100%, 50%)", "#ff0000", "#f00", or "red", or three arguments that represent color channels.

      Properties

      [property:Float r]

      Red channel value between 0 and 1. Default is 1.

      [property:Float g]

      Green channel value between 0 and 1. Default is 1.

      [property:Float b]

      Blue channel value between 0 and 1. Default is 1.

      Methods

      [method:Color copy]( [page:Color color] ) [page:Color this]

      color — Color to copy.
      Copies given color.

      [method:Color copyGammaToLinear]( [page:Color color] ) [page:Color this]

      color — Color to copy.
      Copies given color making conversion from gamma to linear space.

      [method:Color copyLinearToGamma]( [page:Color color] ) [page:Color this]

      color — Color to copy.
      Copies given color making conversion from linear to gamma space.

      [method:Color convertGammaToLinear]() [page:Color this]

      Converts this color from gamma to linear space.

      [method:Color convertLinearToGamma]() [page:Color this]

      Converts this color from linear to gamma space.

      [method:Color setRGB]( [page:Float r], [page:Float g], [page:Float b] ) [page:Color this]

      r — Red channel value between 0 and 1.
      g — Green channel value between 0 and 1.
      b — Blue channel value between 0 and 1.
      Sets this color from RGB values.

      [method:Integer getHex]()

      Returns the hexadecimal value of this color.

      [method:String getHexString]()

      Returns the string formated hexadecimal value of this color.

      [method:Color setHex]( [page:Integer hex] ) [page:Color this]

      hex — Color in hexadecimal.
      Sets this color from a hexadecimal value.

      [method:Color setStyle]( [page:String style] ) [page:Color this]

      style — color as a CSS-style string.
      Sets this color from a CSS-style string. For example, "rgb(250, 0,0)", "rgb(100%, 0%, 0%)", "hsl(0, 100%, 50%)", "#ff0000", "#f00", or "red". Transluent colors such as "rgba(255, 0, 0, 0.5)" and "hsla(0, 100%, 50%, 0.5)" are also accepted, but the alpha-channel coordinate will be discarded.

      [method:String getStyle]()

      Returns the value of this color as a CSS-style string. Example: rgb(255,0,0)

      [method:Color setHSL]( [page:Float h], [page:Float s], [page:Float l] ) [page:Color this]

      h — hue value between 0.0 and 1.0
      s — saturation value between 0.0 and 1.0
      l — lightness value between 0.0 and 1.0
      Sets color from hsl

      .getHSL() [page:Object hsl]

      Returns an object with properties h, s, and l.

      [method:Color offsetHSL]( [page:Float h], [page:Float s], [page:Float l] ) [page:Color this]

      Adds given h, s, and l to this color's existing h, s, and l values.

      [method:Color add]( [page:Color color] ) [page:Color this]

      Adds rgb values of given color to rgb values of this color

      [method:Color addColors]( [page:Color color1], [page:Color color2] ) [page:Color this]

      Sets this color to the sum of color1 and color2

      [method:Color addScalar]( [page:Number s] ) [page:Color this]

      Adds s to the rgb values of this color

      [method:Color multiply]( [page:Color color] ) [page:Color this]

      Multiplies this color's rgb values by given color's rgb values

      [method:Color multiplyScalar]( [page:Number s] ) [page:Color this]

      Multiplies this color's rgb values by s

      [method:Color lerp]( [page:Color color], alpha ) [page:Color this]

      alpha -- a number between 0 and 1.
      Linear interpolation of this colors rgb values and the rgb values of the first argument. The alpha argument can be thought of as the percent between the two colors, where 0 is this color and 1 is the first argument.

      [method:Array toArray]( [page:Array array] )

      array -- Optional array to store the color.
      Returns an array [r,g,b]

      [method:Color equals]( [page:Color c] ) [page:Color this]

      Compares this color and c and returns true if they are the same, false otherwise.

      [method:Color clone]()

      Clones this color.

      [method:Color set]( value ) [page:Color this]

      value -- either an instance of [page:Color], a [page:Integer hexadecimal] value, or a css style [page:String string]
      Delegates to .copy, .setStyle, or .setHex depending on input type.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Math.html0000644000175500017550000000610712610076566017171 0ustar debacledebacle

      [name]

      Math utility functions

      Properties

      Methods

      [method:Float clamp]( [page:Float value], [page:Float min], [page:Float max] )

      value — Value to be clamped.
      min — Minimum value
      max — Maximum value.
      Clamps the *value* to be between *min* and *max*.

      [method:Float mapLinear]( [page:Float x], [page:Float a1], [page:Float a2], [page:Float b1], [page:Float b2] )

      x — Value to be mapped.
      a1 — Minimum value for range A.
      a2 — Maximum value for range A.
      b1 — Minimum value for range B.
      b2 — Maximum value for range B.
      Linear mapping of *x* from range [*a1*, *a2*] to range [*b1*, *b2*].

      [method:Float random16]()

      Random float from 0 to 1 with 16 bits of randomness.
      Standard Math.random() creates repetitive patterns when applied over larger space.

      [method:Integer randInt]( [page:Integer low], [page:Integer high] )

      Random integer from *low* to *high* interval.

      [method:Float randFloat]( [page:Float low], [page:Float high] )

      Random float from *low* to *high* interval.

      [method:Float randFloatSpread]( [page:Float range] )

      Random float from *- range / 2* to *range / 2* interval.

      [method:Float sign]( [page:Float x] )

      Returns -1 if *x* is less than 0, 1 if *x* is greater than 0, and 0 if *x* is zero.

      [method:Float degToRad]([page:Float degrees])

      degrees -- [page:Float]
      Converts degrees to radians.

      [method:Float radToDeg]([page:Float radians])

      radians -- [page:Float]
      Converts radians to degrees

      [method:Float smoothstep]([page:Float x], [page:Float min], [page:Float max])

      x -- The value to evaluate based on its position between min and max.
      min -- Any x value below min will be 0
      max -- Any x value above max will be 1
      Returns a value between 0-1 that represents the percentage that x has moved between min and max, but smoothed or slowed down the closer X is to the min and max.

      [link:http://en.wikipedia.org/wiki/Smoothstep Wikipedia]

      [method:Float smootherstep]([page:Float x], [page:Float min], [page:Float max])

      x -- The value to evaluate based on its position between min and max.
      min -- Any x value below min will be 0
      max -- Any x value above max will be 1
      Returns a value between 0-1. It works the same as smoothstep, but more smooth.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Euler.html0000644000175500017550000001055612610076566017357 0ustar debacledebacle

      [name]

      Euler Angles.

      Euler angles describe a rotation transformation by rotating an object on its various axes in specified amounts per axis, and a specified axis order. (More information on Wikipedia)

      Example

      var a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); var b = new THREE.Vector3( 1, 0, 1 ); b.applyEuler(a);

      Constructor

      [name]( [page:Float x], [page:Float y], [page:Float z], [page:String order] )

      x -- [page:Float] the angle of the x axis in radians
      y -- [page:Float] the angle of the y axis in radians
      z -- [page:Float] the angle of the z axis in radians
      order -- [page:String] A string representing the order that the rotations are applied, defaults to 'XYZ' (must be upper case).
      A euler angle for transforming

      Properties

      [property:Float x]

      [property:Float y]

      [property:Float z]

      [property:String order]

      Methods

      [method:Euler set]( [page:Float x], [page:Float y], [page:Float z], [page:String order] ) [page:Euler this]

      x -- [page:Float] Angle in x axis in radians
      y -- [page:Float] Angle in y axis in radians
      z -- [page:Float] Angle in z axis in radians
      order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
      Sets the angles of this euler transform.

      [method:Euler copy]( [page:Euler euler] ) [page:Euler this]

      Copies value of *euler* to this euler.

      [method:Euler setFromRotationMatrix]( [page:Matrix4 m], [page:String order] ) [page:Euler this]

      m -- [page:Matrix4] assumes upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled)
      order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
      Sets the angles of this euler transform from a pure rotation matrix based on the orientation specified by order.

      [method:Euler setFromQuaternion]( [page:Quaternion q], [page:String order] ) [page:Euler this]

      q -- [page:Quaternion] quaternion must be normalized
      order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
      Sets the angles of this euler transform from a normalized quaternion based on the orientation specified by order.

      [method:Euler reorder]( [page:String newOrder] ) [page:Euler this]

      Resets the euler angle with a new order by creating a quaternion from this euler angle and then setting this euler angle with the quaternion and the new order.
      WARNING: this discards revolution information.

      [method:Euler setFromVector3]([page:Vector3 vector], [page:String order]) [page:Euler this]

      vector -- [page:Vector3]. order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case)
      Optionally Vector3 to the XYZ parameters of Euler, and order to the Euler's order property.

      [method:Vector3 toVector3]()

      Returns the Euler's XYZ properties as a Vector3.

      [method:Euler fromArray]([page:Array array]) [page:Euler this]

      array -- [page:Array] of length 3 or 4. array[3] is an optional order argument.
      Assigns this euler's x angle to array[0].
      Assigns this euler's y angle to array[1].
      Assigns this euler's z angle to array[2].
      Optionally assigns this euler's order to array[3].

      [method:Array toArray]( [page:Array array] )

      array -- Optional array to store the euler.
      Returns an array [x, y, z, order]

      [method:Boolean equals]( [page:Euler euler] )

      Checks for strict equality of this euler and *euler*.

      [method:Euler clone]()

      Returns a new euler created from this euler.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Box2.html0000644000175500017550000001436612610076566017120 0ustar debacledebacle

      [name]

      Represents a boundary box in 2D space.

      Constructor

      [name]([page:Vector2 min], [page:Vector2 max])

      min -- Lower (x, y) boundary of the box.
      max -- Upper (x, y) boundary of the box.
      Creates a box bounded by min and max.

      Properties

      [property:Vector2 min]

      Lower (x, y) boundary of this box.

      [property:Vector2 max]

      Upper (x, y) boundary of this box.

      Methods

      [method:Box2 set]([page:Vector2 min], [page:Vector2 max]) [page:Box2 this]

      min -- Lower (x, y) boundary of the box.
      max -- Upper (x, y) boundary of the box.
      Sets the lower and upper (x, y) boundaries of this box.

      [method:Box2 expandByPoint]([page:Vector2 point]) [page:Box2 this]

      point -- Point that should be included in the box.
      Expands the boundaries of this box to include *point*.

      [method:Vector2 clampPoint]([page:Vector2 point], [page:Vector2 optionalTarget])

      point -- Position to clamp.
      optionalTarget -- If specified, the clamped result will be copied here.
      Clamps *point* within the bounds of this box.

      [method:Boolean isIntersectionBox]([page:Box2 box])

      box -- Box to check for intersection against.
      Determines whether or not this box intersects *box*.

      [method:Box2 setFromPoints]([page:Array points]) [page:Box2 this]

      points -- Set of points that the resulting box will envelop.
      Sets the upper and lower bounds of this box to include all of the points in *points*.

      [method:Vector2 size]([page:Vector2 optionalTarget])

      optionalTarget -- If specified, the result will be copied here.
      Returns the width and height of this box.

      [method:Box2 union]([page:Box2 box]) [page:Box2 this]

      box -- Box that will be unioned with this box.
      Unions this box with *box* setting the upper bound of this box to the greater of the two boxes' upper bounds and the lower bound of this box to the lesser of the two boxes' lower bounds.

      [method:Vector2 getParameter]([page:Vector2 point], [page:Vector2 optionalTarget])

      point -- [page:Vector2]
      optionalTarget -- [page:Vector2]
      Returns a point as a proportion of this box's width and height.

      [method:Box2 expandByScalar]([page:float scalar]) [page:Box2 this]

      scalar -- Distance to expand.
      Expands each dimension of the box by *scalar*. If negative, the dimensions of the box
      will be contracted.

      [method:Box2 intersect]([page:Box2 box]) [page:Box2 this]

      box -- Box to intersect with.
      Returns the intersection of this and *box*, setting the upper bound of this box to the lesser
      of the two boxes' upper bounds and the lower bound of this box to the greater of the two boxes'
      lower bounds.

      [method:Boolean containsBox]([page:Box2 box])

      box -- Box to test for inclusion.
      Returns true if this box includes the entirety of *box*. If this and *box* overlap exactly,
      this function also returns true.

      [method:Box2 translate]([page:Vector2 offset]) [page:Box2 this]

      offset -- Direction and distance of offset.
      Adds *offset* to both the upper and lower bounds of this box, effectively moving this box
      *offset* units in 2D space.

      [method:Boolean empty]()

      Returns true if this box includes zero points within its bounds.
      Note that a box with equal lower and upper bounds still includes one point, the one both bounds share.

      [method:Box2 clone]()

      Returns a copy of this box.

      [method:Boolean equals]([page:Box2 box])

      box -- Box to compare.
      Returns true if this box and *box* share the same lower and upper bounds.

      [method:Box2 expandByVector]([page:Vector2 vector]) [page:Box2 this]

      vector -- Amount to expand this box in each dimension.
      Expands this box equilaterally by *vector*. The width of this box will be expanded by the x component of *vector* in both directions. The height of this box will be expanded by the y component of *vector* in both directions.

      [method:Box2 copy]([page:Box2 box]) [page:Box2 this]

      box -- Box to copy.
      Copies the values of *box* to this box.

      [method:Box2 makeEmpty]() [page:Box2 this]

      Makes this box empty.

      [method:Vector2 center]([page:Vector2 optionalTarget])

      optionalTarget -- If specified, the result will be copied here.
      Returns the center point of this box.

      [method:Float distanceToPoint]([page:Vector2 point])

      point -- Point to measure distance to.
      Returns the distance from any edge of this box to the specified point.
      If the point lies inside of this box, the distance will be 0.

      [method:Boolean containsPoint]([page:Vector2 point])

      point -- [page:Vector2] to check for inclusion.
      Returns true if the specified point lies within the boundaries of this box.

      [method:Box2 setFromCenterAndSize]([page:Vector2 center], [page:Vector2 size]) [page:Box2 this]

      center -- Desired center position of the box.
      size -- Desired x and y dimensions of the box.
      Centers this box on *center* and sets this box's width and height to the values specified in *size*.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Vector4.html0000644000175500017550000002111412610076566017621 0ustar debacledebacle

      [name]

      4D vector.

      Constructor

      [name]( [page:Float x], [page:Float y], [page:Float z], [page:Float w] )

      x -- [page:Float]
      y -- [page:Float]
      z -- [page:Float]
      w -- [page:Float]

      Properties

      [property:Float x]

      [property:Float y]

      [property:Float z]

      [property:Float w]

      Methods

      [method:Vector4 set]( [page:Float x], [page:Float y], [page:Float z], [page:Float w] ) [page:Vector4 this]

      Sets value of this vector.

      [method:Vector4 copy]( [page:Vector4 v] ) [page:Vector4 this]

      Copies value of *v* to this vector.

      [method:Vector4 add]( [page:Vector4 v] ) [page:Vector4 this]

      Adds *v* to this vector.

      [method:Vector4 addVectors]( [page:Vector4 a], [page:Vector4 b] ) [page:Vector4 this]

      Sets this vector to *a + b*.

      [method:Vector4 addScaledVector]( [page:Vector4 v], [page:Float s] ) [page:Vector4 this]

      Adds the multiple of v and s to this vector.

      [method:Vector4 sub]( [page:Vector4 v] )

      Subtracts *v* from this vector.

      [method:Vector4 subVectors]( [page:Vector4 a], [page:Vector4 b] ) [page:Vector4 this]

      Sets this vector to *a - b*.

      [method:Vector4 multiplyScalar]( [page:Float s] ) [page:Vector4 this]

      Multiplies this vector by scalar *s*.

      [method:Vector4 divideScalar]( [page:Float s] ) [page:Vector4 this]

      Divides this vector by scalar *s*.
      Set vector to *( 0, 0, 0 )* if *s == 0*.

      [method:Vector4 negate]() [page:Vector4 this]

      Inverts this vector.

      [method:Float dot]( [page:Vector4 v] )

      Computes dot product of this vector and *v*.

      [method:Float lengthSq]()

      Computes squared length of this vector.

      [method:Float length]()

      Computes length of this vector.

      [method:Vector4 normalize]() [page:Vector4 this]

      Normalizes this vector.

      [method:Vector4 setLength]( [page:Float l] ) [page:Vector4 this]

      Normalizes this vector and multiplies it by *l*.

      [method:Vector4 lerp]( [page:Vector4 v], [page:Float alpha] ) [page:Vector4 this]

      Linearly interpolate between this vector and *v* with *alpha* factor.

      [method:Vector4 lerpVectors]( [page:Vector4 v1], [page:Vector4 v2], [page:Float alpha] ) [page:Vector4 this]

      Sets this vector to be the vector linearly interpolated between *v1* and *v2* with *alpha* factor.

      [method:Vector4 clone]()

      Clones this vector.

      [method:Vector4 clamp]([page:Vector4 min], [page:Vector4 max]) [page:Vector4 this]

      min -- [page:Vector4]
      max -- [page:Vector4]
      If this vector's x, y, z, or w value is greater than the max vector's x, y, z, or w value, it is replaced by the corresponding value.

      If this vector's x, y, z, or w value is less than the min vector's x, y, z, or w value, it is replaced by the corresponding value.

      [method:Vector4 clampScalar]([page:Float min], [page:Float max]) [page:Vector4 this]

      min -- [page:Float] the minimum value the components will be clamped to
      max -- [page:Float] the maximum value the components will be clamped to
      If this vector's x, y, z or w values are greater than the max value, they are replaced by the max value.

      If this vector's x, y, z or w values are less than the min value, they are replaced by the min value.

      [method:Vector4 floor]()

      The components of the vector are rounded downwards (towards negative infinity) to an integer value.

      [method:Vector4 ceil]()

      The components of the vector are rounded upwards (towards positive infinity) to an integer value.

      [method:Vector4 round]()

      The components of the vector are rounded towards the nearest integer value.

      [method:Vector4 roundToZero]()

      The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.

      [method:Vector4 applyMatrix4]([page:Matrix4 m]) [page:Vector4 this]

      m -- [page:Matrix4]
      Transforms the vector by the matrix.

      [method:Vector4 min]([page:Vector4 v]) [page:Vector4 this]

      v -- [page:Vector4]
      If this vector's x, y, z, or w value is greater than vector v's x, y, z, or w value, that value is replaced by the corresponding vector v value.

      [method:Vector4 max]([page:Vector4 v]) [page:Vector4 this]

      v -- [page:Vector4]
      If this vector's x, y, z, or w value is less than vector v's x, y, z, or w value, that value is replaced by the corresponding vector v value.

      [method:Vector4 addScalar]([page:Float s]) [page:Vector4 this]

      s -- [page:Float]
      Adds a scalar value to all of the vector's components.

      [method:Boolean equals]([page:Vector4 v])

      v -- [page:Vector4]
      Checks to see if this vector matches vector v.

      [method:Vector4 setAxisAngleFromRotationMatrix]([page:Matrix4 m]) [page:Vector4 this]

      m -- [page:Matrix4]
      Sets this Vector4 to the computed axis-angle representation of the rotation defined by Matrix4 m. Assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled).

      The axis is stored in components (x, y, z) of the vector, and the rotation in radians is stored in component w

      [method:Vector4 setAxisAngleFromQuaternion]([page:Quaternion q]) [page:Vector4 this]

      q -- [page:Quaternion]
      Sets this Vector4 to the computed axis-angle representation of the rotation defined by Quaternion q.

      The axis is stored in components (x, y, z) of the vector, and the rotation in radians is stored in component w

      [method:Float getComponent]([page:Integer index])

      index -- [page:Integer] 0, 1, 2, or 3
      Returns the value of the vector component x, y, or z by an index.

      Index 0: x
      Index 1: y
      Index 2: z
      Index 3: w

      [method:null setComponent]([page:Integer index], [page:Float value])

      index -- [page:Integer] 0 - 3
      value -- [page:Float]
      Sets the value of the vector component x, y, or z by an index.

      Index 0: x
      Index 1: y
      Index 2: z
      Index 3: w

      [method:Vector4 fromArray]([page:Array array]) [page:Vector4 this]

      array -- [page:Array] An array formatted [x, y, z, w]
      Sets the vector's components based on an array formatted like [x, y, z, w]

      [method:Array toArray]( [page:Array array] )

      array -- Optional array to store the vector.
      Returns an array in the format [x, y, z, w]

      [method:Float lengthManhattan]()

      Computes Manhattan length of this vector.
      [link:http://en.wikipedia.org/wiki/Taxicab_geometry]

      [method:Vector4 setX]([page:Float x]) [page:Vector4 this]

      x -- [page:Float]
      Sets the x component of the vector.

      [method:Vector4 setY]([page:Float y]) [page:Vector4 this]

      y -- [page:Float]
      Sets the y component of the vector.

      [method:Vector4 setZ]([page:Float z]) [page:Vector4 this]

      z -- [page:Float]
      Sets the z component of the vector.

      [method:Vector4 setW]([page:Float w]) [page:Vector4 this]

      w -- [page:Float]
      Sets the w component of the vector.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Sphere.html0000644000175500017550000000717012610076566017527 0ustar debacledebacle

      [name]

      A geometric sphere defined by a center position and radius.

      Constructor

      [name]([page:Vector3 center], [page:Float radius])

      center -- [page:Vector3]
      radius -- [page:Float]

      Properties

      [property:Vector3 center]

      [property:Float radius]

      Methods

      .set([page:Vector3 center], [page:Float radius]) [page:this:Sphere]

      center -- [page:Vector3]
      radius -- [page:Float]
      Sets the center and radius.

      [method:Sphere applyMatrix4]([page:Matrix4 matrix]) [page:Sphere this]

      matrix -- [page:Matrix4]
      Transforms this sphere with the provided [page:Matrix4].

      [method:Vector3 clampPoint]([page:Vector3 point], [page:Vector3 optionalTarget])

      point -- [page:Vector3] The point to clamp
      optionalTarget -- [page:Vector3] The optional target point to return
      Clamps a point within the sphere. If the point is is outside the sphere, it will clamp it to the closets point on the edge of the sphere.

      [method:Sphere translate]([page:Vector3 offset]) [page:Sphere this]

      offset -- [page:Vector3]
      Translate the sphere's center by the provided offset vector.

      [method:Sphere clone]()

      Provides a new copy of the sphere.

      [method:Boolean equals]([page:Sphere sphere])

      sphere -- [page:Sphere]
      Checks to see if the two spheres' centers and radii are equal.

      [method:Sphere setFromPoints]([page:Array points], [page:Vector3 optionalCenter]) [page:Sphere this]

      points -- [page:Array] of [page:Vector3] positions.
      optionalCenter -- Optional [page:Vector3] position for the sphere's center.
      Computes the minimum bounding sphere for *points*. If *optionalCenter* is given, it is used as the sphere's center. Otherwise, the center of the axis-aligned bounding box encompassing *points* is calculated.

      [method:Float distanceToPoint]([page:Vector3 point])

      point -- [page:Vector3]
      Returns the closest distance from the boundary of the sphere to the point. If the sphere contains the point, the distance will be negative.

      [method:Box getBoundingBox]([page:Box optionalTarget])

      optionalTarget -- [page:Box]
      Returns a bounding box for the sphere, optionally setting a provided box target.

      [method:Boolean containsPoint]([page:Vector3 point])

      point -- [page:Vector3]
      Checks to see if the sphere contains the provided point inclusive of the edge of the sphere.

      [method:Sphere copy]([page:Sphere sphere])

      sphere -- [page:Sphere] to copy
      Copies the values of the passed sphere to this sphere.

      [method:Boolean intersectsSphere]([page:Sphere sphere])

      sphere -- [page:Sphere]
      Checks to see if two spheres intersect.

      [method:Boolean empty]()

      Checks to see if the sphere is empty (the radius set to 0).

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Plane.html0000644000175500017550000001321012610076566017330 0ustar debacledebacle

      [name]

      A two dimensional surface that extends infinitely in 3d space.

      Constructor

      [name]([page:Vector3 normal], [page:Float constant])

      normal -- ([Page:Vector3]) normal vector defining the plane pointing towards the origin
      constant -- ([Page:Float]) the negative distance from the origin to the plane along the normal vector

      Properties

      [property:Vector3 normal]

      [property:Float constant]

      Methods

      [method:Plane normalize]() [page:Plane this]

      Normalizes the normal vector, and adjusts the constant value accordingly.

      [method:Plane set]([page:Vector3 normal], [page:Float constant]) [page:Plane this]

      normal -- [Page:Vector3]
      constant -- [Page:Float]
      Sets the plane's values.

      [method:Plane copy]([page:Plane plane]) [page:Plane this]

      plane -- [page:Plane] to copy
      Copies the values of the passed plane to this plane.

      [method:Plane applyMatrix4]([page:Matrix4 matrix], [page:Matrix3 optionalNormalMatrix]) [page:Plane this]

      matrix -- [Page:Matrix4] to apply
      optionalNormalMatrix -- (optional) pre-computed normal [Page:Matrix3] of the Matrix4 to apply
      Apply a Matrix4 to the plane. The second parameter is optional. var optionalNormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix )

      [method:Vector3 orthoPoint]([page:Vector3 point], [page:Vector3 optionalTarget])

      point -- [page:Vector3]
      optionalTarget -- [page:Vector3]
      Returns a vector in the same direction as the Plane's normal, but the magnitude is passed point's original distance to the plane.

      [method:Boolean isIntersectionLine]([page:Line3 line])

      line -- [page:Line3]
      Tests whether a line segment intersects with the plane. (Do not mistake this for a collinear check.)

      [method:Vector3 intersectLine]([page:Line3 line], [page:Vector3 optionalTarget]) or [page:undefined]

      line -- [page:Line3]
      optionalTarget -- [page:Vector3]
      Returns the intersection point of the passed line and the plane. Returns undefined if the line does not intersect. Returns the line's starting point if the line is coplanar with the plane.

      [method:Vector3 setFromNormalAndCoplanarPoint]([page:Vector3 normal], [page:Vector3 point]) [page:Vector3 this]

      normal -- [page:Vector3]
      point -- [page:Vector3]
      Sets the plane's values as defined by a normal and arbitrary coplanar point.

      [method:Plane clone]()

      Returns a new copy of this plane.

      [method:Float distanceToPoint]([page:Vector3 point])

      point -- [page:Vector3]
      Returns the smallest distance from the point to the plane.

      [method:Boolean equals]([page:Plane plane])

      plane -- [page:Planen]
      Checks to see if two planes are equal (their normals and constants match)

      [method:Plane setComponents]([page:Float x], [page:Float y], [page:Float z], [page:Float w]) [page:Plane this]

      x -- [page:Float] x of the normal vector
      y -- [page:Float] y of the normal vector
      z -- [page:Float] z of the normal vector
      w -- [page:Float] distance of the plane from the origin along the normal vector
      Set the individual components that make up the plane.

      [method:Float distanceToSphere]([page:Sphere sphere])

      sphere -- [Page:Sphere]
      Returns the smallest distance from an edge of the sphere to the plane.

      [method:Plane setFromCoplanarPoints]([page:Vector3 a], [page:Vector3 b], [page:Vector3 c]) [page:Plane this]

      a -- [page:Vector3]
      b -- [page:Vector3]
      c -- [page:Vector3]
      Defines the plane based on the 3 provided points. The winding order is counter clockwise, and determines which direction the normal will point.

      [method:Vector3 projectPoint]([page:Vector3 point], [page:Vector3 optionalTarget])

      point -- [page:Vector3]
      optionalTarget -- [page:Vector3]
      Projects a point onto the plane. The projected point is the closest point on the plane to the passed point, so a line drawn from the projected point and the passed point would be orthogonal to the plane.

      [method:Plane negate]() [page:Plane this]

      Negates both the normal vector and constant, effectively mirroring the plane across the origin.

      [method:Plane translate]([page:Vector3 offset]) [page:Plane this]

      offset -- [page:Vector3]
      Translates the plane the distance defined by the vector. Note that this only affects the constant (distance from origin) and will not affect the normal vector.

      [method:Vector3 coplanarPoint]([page:Vector3 optionalTarget])

      optionalTarget -- [page:Vector3]
      Returns a coplanar point. (The projection of the normal vector at the origin onto the plane.)

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Quaternion.html0000644000175500017550000001441312610076566020424 0ustar debacledebacle

      [name]

      Implementation of a quaternion. This is used for rotating things without encountering the dreaded gimbal lock issue, amongst other advantages.

      Example

      var quaternion = new THREE.Quaternion(); quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 ); var vector = new THREE.Vector3( 1, 0, 0 ); vector.applyQuaternion( quaternion );

      Constructor

      [name]( [page:Float x], [page:Float y], [page:Float z], [page:Float w] )

      x - x coordinate
      y - y coordinate
      z - z coordinate
      w - w coordinate

      Properties

      [property:Float x]

      [property:Float y]

      [property:Float z]

      [property:Float w]

      Methods

      [method:Quaternion set]( [page:Float x], [page:Float y], [page:Float z], [page:Float w] )

      Sets values of this quaternion.

      [method:Quaternion copy]( [page:Quaternion q] )

      Copies values of *q* to this quaternion.

      [method:Quaternion setFromEuler]( [page:Euler euler] )

      Sets this quaternion from rotation specified by Euler angle.

      [method:Quaternion setFromAxisAngle]( [page:Vector3 axis], [page:Float angle] )

      Sets this quaternion from rotation specified by axis and angle.
      Adapted from [link:http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm].
      *Axis* is asumed to be normalized, *angle* is in radians.

      [method:Quaternion setFromRotationMatrix]( [page:Matrix4 m] )

      Sets this quaternion from rotation component of *m*.
      Adapted from [link:http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm].

      [method:Quaternion setFromUnitVectors]( [page:Vector3 vFrom], [page:Vector3 vTo] )

      Sets this quaternion to the rotation required to rotate direction vector *vFrom* to direction vector *vTo*.
      Adapted from [link:http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors].
      *vFrom* and *vTo* are assumed to be normalized.

      [method:Quaternion inverse]()

      Inverts this quaternion.

      [method:Float length]()

      Computes length of this quaternion.

      [method:Quaternion normalize]()

      Normalizes this quaternion.

      [method:Quaternion multiply]( [page:Quaternion b] )

      Multiplies this quaternion by *b*.

      [method:Quaternion multiplyQuaternions]( [page:Quaternion a], [page:Quaternion b] )

      Sets this quaternion to *a x b*
      Adapted from [link:http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm].

      [method:Quaternion multiplyVector3]( [page:Vector3 vector], [page:Vector3 dest] )

      Rotates *vector* by this quaternion into *dest*.
      If *dest* is not specified, result goes to *vec*.

      [method:Quaternion clone]()

      Clones this quaternion.

      [method:Array toArray]( [page:Array array] )

      array -- Array to store the quaternion.
      Returns the numerical elements of this quaternion in an array of format (x, y, z, w).

      [method:Boolean equals]([page:Quaternion v])

      v -- Quaternion that this quaternion will be compared to.
      Compares each component of *v* to each component of this quaternion to determine if they represent the same rotation.

      [method:Float lengthSq]()

      Calculates the squared length of the quaternion.

      [method:Quaternion fromArray]([page:Array array])

      array -- Array of format (x, y, z, w) used to construct the quaternion.
      Sets this quaternion's component values from an array.

      [method:Quaternion conjugate]()

      Returns the rotational conjugate of this quaternion. The conjugate of a quaternion represents the same rotation in the opposite direction about the rotational axis.

      [method:Quaternion slerp]([page:Quaternion quaternionB], [page:float t])

      quaternionB -- The other quaternion rotation
      t -- Normalized 0 to 1 interpolation factor
      Handles the spherical linear interpolation between quaternions. *t* represents the amount of rotation between this quaternion (where *t* is 0) and quaternionB (where *t* is 1). This quaternion is set to the result. Also see the static version of the *slerp* below.
      // rotate a mesh towards a target quaternion mesh.quaternion.slerp( endQuaternion, 0.01 );

      Static Methods

      [method:Quaternion slerp]( [page:Quaternion qStart], [page:Quaternion qEnd], [page:Quaternion qTarget], [page:Float t] )

      qStart -- The starting quaternion (where *t* is 0)
      qEnd -- The ending quaternion (where *t* is 1)
      qTarget -- The target quaternion that gets set with the result
      t -- Normalized 0 to 1 interpolation factor
      Unlike the normal method, the static version of slerp sets a target quaternion to the result of the slerp operation.
      // Code setup var startQuaternion = new THREE.Quaternion().set( 0, 0, 0, 1 ).normalize(); var endQuaternion = new THREE.Quaternion().set( 1, 1, 1, 1 ).normalize(); var t = 0; // Update a mesh's rotation in the loop t = ( t + 0.01 ) % 1; // constant angular momentum THREE.Quaternion.slerp( startQuaternion, endQuaternion, mesh.quaternion, t );

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Frustum.html0000644000175500017550000000452612610076566017750 0ustar debacledebacle

      [name]

      Frustums are used to determine what is inside the camera's field of view. They help speed up the rendering process.

      Constructor

      [name]([page:Plane p0], [page:Plane p1], [page:Plane p2], [page:Plane p3], [page:Plane p4], [page:Plane p5])

      p0 -- [page:Plane]
      p1 -- [page:Plane]
      p2 -- [page:Plane]
      p3 -- [page:Plane]
      p4 -- [page:Plane]
      p5 -- [page:Plane]
      Creates a frustum from the designated planes.

      Properties

      [property:Array planes]

      Array of 6 [page:Plane planes].

      Methods

      [method:Frustum setFromMatrix]( [page:Matrix4 matrix] )

      [method:Boolean intersectsObject]( [page:Object3D object] )

      Checks whether the object's bounding sphere is intersecting the Frustum.

      [method:Frustum clone]()

      Return a copy of this Frustum

      [method:Boolean set]([page:Plane p0], [page:Plane p1], [page:Plane p2], [page:Plane p3], [page:Plane p4], [page:Plane p5])

      p0 -- [page:Plane]
      p1 -- [page:Plane]
      p2 -- [page:Plane]
      p3 -- [page:Plane]
      p4 -- [page:Plane]
      p5 -- [page:Plane]
      Sets the current frustum from the passed planes. No plane order is implicitely implied.

      [method:Frustum copy]([page:Frustum frustum]) [page:Frustum this]

      frustum -- The frustum to copy
      Copies the values of the passed frustum.

      [method:Boolean containsPoint]([page:Vector3 point])

      point -- [page:Vector3] to test
      Checks to see if the frustum contains the point.

      [method:Boolean intersectsSphere]([page:Sphere sphere])

      sphere -- [page:Sphere]
      Check to see if the sphere intersects with the frustum.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Vector3.html0000644000175500017550000003060712610076566017627 0ustar debacledebacle

      [name]

      3D vector.

      Example

      var a = new THREE.Vector3( 1, 0, 0 ); var b = new THREE.Vector3( 0, 1, 0 ); var c = new THREE.Vector3(); c.crossVectors( a, b );

      Constructor

      [name]( [page:Float x], [page:Float y], [page:Float z] )

      x -- [page:Float] the vector's x value
      y -- [page:Float] the vector's y value
      z -- [page:Float] the vector's z value
      A 3 dimensional vector

      Properties

      [property:Float x]

      [property:Float y]

      [property:Float z]

      Methods

      [method:Vector3 set]( [page:Float x], [page:Float y], [page:Float z] ) [page:Vector3 this]

      Sets value of this vector.

      [method:Vector3 setX]( [page:Float x] ) [page:Vector3 this]

      Sets x value of this vector.

      [method:Vector3 setY]( [page:Float y] ) [page:Vector3 this]

      Sets y value of this vector.

      [method:Vector3 setZ]( [page:Float z] ) [page:Vector3 this]

      Sets z value of this vector.

      [method:Vector3 copy]( [page:Vector3 v] ) [page:Vector3 this]

      Copies value of *v* to this vector.

      [method:Vector3 add]( [page:Vector3 v] ) [page:Vector3 this]

      Adds *v* to this vector.

      [method:Vector3 addVectors]( [page:Vector3 a], [page:Vector3 b] ) [page:Vector3 this]

      Sets this vector to *a + b*.

      [method:Vector3 addScaledVector]( [page:Vector3 v], [page:Float s] ) [page:Vector3 this]

      Adds the multiple of v and s to this vector.

      [method:Vector3 sub]( [page:Vector3 v] ) [page:Vector3 this]

      Subtracts *v* from this vector.

      [method:Vector3 subVectors]( [page:Vector3 a], [page:Vector3 b] ) [page:Vector3 this]

      Sets this vector to *a - b*.

      [method:Vector3 multiplyScalar]( [page:Float s] ) [page:Vector3 this]

      Multiplies this vector by scalar *s*.

      [method:Vector3 divideScalar]( [page:Float s] ) [page:Vector3 this]

      Divides this vector by scalar *s*.
      Set vector to *( 0, 0, 0 )* if *s == 0*.

      [method:Vector3 negate]() [page:Vector3 this]

      Inverts this vector.

      [method:Float dot]( [page:Vector3 v] )

      Computes dot product of this vector and *v*.

      [method:Float lengthSq]()

      Computes squared length of this vector.

      [method:Float length]()

      Computes length of this vector.

      [method:Float lengthManhattan]()

      Computes Manhattan length of this vector.
      [link:http://en.wikipedia.org/wiki/Taxicab_geometry]

      [method:Vector3 normalize]() [page:Vector3 this]

      Normalizes this vector. Transforms this Vector into a Unit vector by dividing the vector by it's length.

      [method:Float distanceTo]( [page:Vector3 v] )

      Computes distance of this vector to *v*.

      [method:Float distanceToSquared]( [page:Vector3 v] )

      Computes squared distance of this vector to *v*.

      [method:Vector3 setLength]( [page:Float l] ) [page:Vector3 this]

      Normalizes this vector and multiplies it by *l*.

      [method:Vector3 cross]( [page:Vector3 v] ) [page:Vector3 this]

      Sets this vector to cross product of itself and *v*.

      [method:Vector3 crossVectors]( [page:Vector3 a], [page:Vector3 b] ) [page:Vector3 this]

      Sets this vector to cross product of *a* and *b*.

      [method:Vector3 setFromMatrixPosition]( [page:Matrix4 m] ) [page:Vector3 this]

      Sets this vector extracting position from matrix transform.

      [method:Vector3 setFromMatrixScale]( [page:Matrix4 m] ) [page:Vector3 this]

      Sets this vector extracting scale from matrix transform.

      [method:Boolean equals]( [page:Vector3 v] )

      Checks for strict equality of this vector and *v*.

      [method:Vector3 clone]()

      Clones this vector.

      [method:Vector3 clamp]([page:Vector3 min], [page:Vector3 max]) [page:Vector3 this]

      min -- [page:Vector3]
      max -- [page:Vector3]
      If this vector's x, y or z value is greater than the max vector's x, y or z value, it is replaced by the corresponding value.

      If this vector's x, y or z value is less than the min vector's x, y or z value, it is replaced by the corresponding value.

      [method:Vector3 clampScalar]([page:Float min], [page:Float max]) [page:Vector3 this]

      min -- [page:Float] the minimum value the components will be clamped to
      max -- [page:Float] the maximum value the components will be clamped to
      If this vector's x, y or z values are greater than the max value, they are replaced by the max value.

      If this vector's x, y or z values are less than the min value, they are replaced by the min value.

      [method:Vector3 floor]()

      The components of the vector are rounded downwards (towards negative infinity) to an integer value.

      [method:Vector3 ceil]()

      The components of the vector are rounded upwards (towards positive infinity) to an integer value.

      [method:Vector3 round]()

      The components of the vector are rounded towards the nearest integer value.

      [method:Vector3 roundToZero]()

      The components of the vector are rounded towards zero (up if negative, down if positive) to an integer value.

      [method:Vector3 applyMatrix3]([page:Matrix3 m]) [page:Vector3 this]

      m -- [page:Matrix3]
      Multiplies this vector times a 3 x 3 matrix.

      [method:Vector3 applyMatrix4]([page:Matrix3 m]) [page:Vector3 this]

      m -- [page:Matrix4]
      Multiplies this vector by 4 x 3 subset of a Matrix4.

      [method:Vector3 projectOnPlane]([page:Vector3 planeNormal]) [page:Vector3 this]

      planeNormal -- [page:Vector3 planeNormal] A vector representing a plane normal.
      Projects this vector onto a plane by subtracting this vector projected onto the plane's normal from this vector.

      [method:Vector3 projectOnVector]([page:Vector3]) [page:Vector3 this]

      vector -- [page:Vector3]
      Projects this vector onto another vector.

      [method:Vector3 addScalar]([page:Float]) [page:Vector3 this]

      s -- [page:Float]
      Adds a s to this vector.

      [method:Vector3 divide]([page:Vector3 v]) [page:Vector3 this]

      v -- [page:Vector3]
      Divides this vector by vector v.

      [method:Vector3 min]([page:Vector3 v]) [page:Vector3 this]

      v -- [page:Vector3]
      If this vector's x, y, or z value is greater than vector v's x, y, or z value, that value is replaced by the corresponding vector v value.

      [method:Vector3 max]([page:Vector3 v]) [page:Vector3 this]

      v -- [page:Vector3]
      If this vector's x, y, or z value is less than vector v's x, y, or z value, that value is replaced by the corresponding vector v value.

      [method:Vector3 setComponent]([page:Integer index], [page:Float value]) [page:Vector3 this]

      index -- 0, 1, or 2
      value -- [page:Float]
      If index equals 0 the method sets this vector's x value to value
      If index equals 1 the method sets this vector's y value to value
      If index equals 2 the method sets this vector's z value to value

      [method:Vector3 transformDirection]([page:Matrix4 m]) [page:Vector3 this]

      m -- [page:Matrix4]
      Transforms the direction of this vector by a matrix (a 3 x 3 subset of a Matrix4) and then normalizes the result.

      [method:Vector3 multiplyVectors]([page:Vector3 a], [page:Vector3 b]) [page:Vector3 this]

      a -- [page:Vector3]
      b -- [page:Vector3]
      Sets this vector equal to the result of multiplying vector a by vector b.

      [method:Float getComponent]([page:Integer index])

      index -- [page:Integer] 0, 1, or 2
      Returns the value of the vector component x, y, or z by an index.

      Index 0: x
      Index 1: y
      Index 2: z

      [method:Vector3 applyAxisAngle]([page:Vector3 axis], [page:Float angle]) [page:Vector3 this]

      axis -- A normalized [page:Vector3]
      angle -- An angle in radians
      Applies a rotation specified by an axis and an angle to this vector.

      [method:Vector3 lerp]([page:Vector3 v], [page:Float alpha]) [page:Vector3 this]

      v -- [page:Vector3]
      alpha -- [page:Float] between 0 and 1.
      Linear Interpolation between this vector and vector v, where alpha is the percent along the line.

      [method:Vector3 lerpVectors]([page:Vector3 v1], [page:Vector3 v2], [page:Float alpha]) [page:Vector3 this]

      v1 -- [page:Vector3]
      v2 -- [page:Vector3]
      alpha -- [page:Float] between 0 and 1.
      Sets this vector to be the vector linearly interpolated between *v1* and *v2* with *alpha* factor.

      [method:Float angleTo]([page:Vector3 v])

      v -- [page:Vector3]
      Returns the angle between this vector and vector v in radians.

      [method:Vector3 setFromMatrixColumn]([page:Integer index], [page:Matrix4 matrix]) [page:Vector3 this]

      index -- 0, 1, 2, or 3
      matrix -- [page:Matrix4]
      Sets this vector's x, y, and z equal to the column of the matrix specified by the index.

      [method:Vector3 reflect]([page:Vector3 normal]) [page:Vector3 this]

      normal -- [page:Vector3] the normal to the reflecting plane
      Reflect incident vector off of plane orthogonal to normal. normal is assumed to have unit length.

      [method:Vector3 fromArray]([page:Array array]) [page:Vector3 this]

      array -- [page:Array] [x, y, z]
      Sets the vector's components based on an array formatted like [x, y, z]

      [method:Vector3 multiply]([page:Vector3 v]) [page:Vector3 this]

      v -- [page:Vector3]
      Multipies this vector by vector v.

      [method:Vector3 applyProjection]([page:Matrix4 m]) [page:Vector3 this]

      m -- [page:Matrix4] projection matrix.
      Multiplies this vector and m, and divides by perspective.

      [method:Array toArray]( [page:Array array] )

      array -- Optional array to store the vector.
      Assigns this vector's x value to array[0].
      Assigns this vector's y value to array[1].
      Assigns this vector's z value to array[2].
      Returns the created array.

      [method:Vector3 applyEuler]([page:Euler euler]) [page:Vector3 this]

      euler -- [page:Euler]
      Applies euler transform to this vector by converting the [page:Euler] obect to a [page:Quaternion] and applying.

      [method:Vector3 applyQuaternion]([page:Quaternion quaternion]) [page:Vector3 this]

      quaternion -- [page:Quaternion]
      Applies a [page:Quaternion] transform to this vector.

      [method:Vector3 project]( [page:Camera camera] )

      [page:Camera camera] — camera to use in the projection.
      Projects the vector with the camera.

      [method:Vector3 unproject]( [page:Camera camera] )

      [page:Camera camera] — camera to use in the projection.
      Unprojects the vector with the camera.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/math/Triangle.html0000644000175500017550000000705012610076566020043 0ustar debacledebacle

      [name]

      A geometric triangle as defined by three vectors.

      Constructor

      [name]([page:Vector3 a], [page:Vector3 b], [page:Vector3 c])

      a -- [page:Vector3]
      b -- [page:Vector3]
      c -- [page:Vector3]
      Sets the triangle's vectors to the passed vectors.

      Properties

      [property:Vector3 a]

      The first [page:Vector3] of the triangle.

      [property:Vector3 b]

      The second [page:Vector3] of the triangle.

      [property:Vector3 c]

      The third [page:Vector3] of the triangle.

      Methods

      [method:Triangle setFromPointsAndIndices]([page:Array points], [page:Integer i0], [page:Integer i1], [page:Integer i2]) [page:Triangle this]

      points -- [page:Array] of [page:Vector3]s
      i0 -- [page:Integer] index
      i1 -- [page:Integer] index
      i2 -- [page:Integer] index
      Sets the triangle's vectors to the vectors in the array.

      [method:Triangle set]([page:Vector3 a], [page:Vector3 b], [page:Vector3 c]) [page:Triangle this]

      a -- [page:Vector3]
      b -- [page:Vector3]
      c -- [page:Vector3]
      Sets the triangle's vectors to the passed vectors.

      [method:Vector3 normal]([page:Vector3 optionalTarget])

      optionalTarget -- Optional [page:Vector3] target to set the result.
      Return the calculated normal of the triangle.

      [method:Vector3 barycoordFromPoint]([page:Vector3 point], [page:Vector3 optionalTarget])

      point -- [page:Vector3]
      optionalTarget -- Optional [page:Vector3] target to set the result.
      Return a barycentric coordinate from the given vector.

      [link:http://commons.wikimedia.org/wiki/File:Barycentric_coordinates_1.png](Picture of barycentric coordinates)

      [method:Triangle clone]()

      Return a new copy of this triangle.

      [method:Float area]()

      Return the area of the triangle.

      [method:Vector3 midpoint]([page:Vector3 optionalTarget])

      optionalTarget -- Optional [page:Vector3] target to set the result.
      Return the midpoint of the triangle. Optionally sets a target vector.

      [method:Boolean equals]([page:Triangle triangle])

      triangle -- [page:Triangle]
      Checks to see if two triangles are equal (share the same vectors).

      [method:Plane plane]([page:Plane optionalTarget])

      optionalTarget -- Optional [page:Plane] target to set the result.
      Return a [page:Plane plane] based on the triangle. Optionally sets a target plane.

      [method:Boolean containsPoint]([page:Vector3 point])

      point -- [page:Vector3]
      Checks to see if the passed vector is within the triangle.

      [method:Triangle copy]([page:Triangle triangle])

      triangle -- [page:Triangle]
      Copies the values of the vertices of the passed triangle to this triangle.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/textures/0000755000175500017550000000000012610076566016340 5ustar debacledebaclethree.js-r73/docs/api/textures/CubeTexture.html0000644000175500017550000000303412610076566021465 0ustar debacledebacle [page:Texture] →

      [name]

      Creates a cube texture made up of six images.

      Example

      var path = "textures/cube/pisa/"; var format = '.png'; var urls = [ path + 'px' + format, path + 'nx' + format, path + 'py' + format, path + 'ny' + format, path + 'pz' + format, path + 'nz' + format ]; var textureCube = THREE.ImageUtils.loadTextureCube( urls ); var material = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap: textureCube } );

      Constructor

      [name]( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy )

      CubeTexture is almost equivalent in functionality and usage to [page:Texture]. The only differences are that the images are an array of 6 images as opposed to a single image, and the mapping options are [page:Textures THREE.CubeReflectionMapping] (default) or [page:Textures THREE.CubeRefractionMapping]

      Generally [page:ImageUtils.loadTextureCube] is used instead of using CubeTexture directly.

      Properties

      See [page:Texture]

      Methods

      See [page:Texture]

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/textures/Texture.html0000644000175500017550000001540112610076566020667 0ustar debacledebacle

      [name]

      Create a texture to apply to a surface or as a reflection or refraction map.

      Constructor

      [name]( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy )

      Example

      // load a texture, set wrap mode to repeat var texture = THREE.ImageUtils.loadTexture( "textures/water.jpg" ); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 4, 4 );

      Properties

      [property:Integer id]

      Unique number for this texture instance.

      [property:Image image]

      An Image object, typically created using the ImageUtils or [page:ImageLoader ImageLoader] classes. The Image object can include an image (e.g., PNG, JPG, GIF, DDS), video (e.g., MP4, OGG/OGV), or set of six images for a cube map. To use video as a texture you need to have a playing HTML5 video element as a source for your texture image and continuously update this texture as long as video is playing.

      [property:object mapping]

      How the image is applied to the object. An object type of THREE.UVMapping is the default, where the U,V coordinates are used to apply the map, and a single texture is expected. The other types are THREE.CubeReflectionMapping, for cube maps used as a reflection map; THREE.CubeRefractionMapping, refraction mapping; and THREE.SphericalReflectionMapping, a spherical reflection map projection.

      [property:number wrapS]

      The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. The other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.

      [property:number wrapT]

      The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. The other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.
      NOTE: tiling of images in textures only functions if image dimensions are powers of two (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, ...) in terms of pixels. Individual dimensions need not be equal, but each must be a power of two. This is a limitation of WebGL, not Three.js.

      [property:number magFilter]

      How the texture is sampled when a texel covers more than one pixel. The default is THREE.LinearFilter, which takes the four closest texels and bilinearly interpolates among them. The other option is THREE.NearestFilter, which uses the value of the closest texel.

      [property:number minFilter]

      How the texture is sampled when a texel covers less than one pixel. The default is THREE.LinearMipMapLinearFilter, which uses mipmapping and a trilinear filter. Other choices are THREE.NearestFilter, THREE.NearestMipMapNearestFilter, THREE.NearestMipMapLinearFilter, THREE.LinearFilter, and THREE.LinearMipMapNearestFilter. These vary whether the nearest texel or nearest four texels are retrieved on the nearest mipmap or nearest two mipmaps. Interpolation occurs among the samples retrieved.

      [property:number format]

      The default is THREE.RGBAFormat for the texture. Other formats are: THREE.AlphaFormat, THREE.RGBFormat, THREE.LuminanceFormat, and THREE.LuminanceAlphaFormat. There are also compressed texture formats, if the S3TC extension is supported: THREE.RGB_S3TC_DXT1_Format, THREE.RGBA_S3TC_DXT1_Format, THREE.RGBA_S3TC_DXT3_Format, and THREE.RGBA_S3TC_DXT5_Format.

      [property:number type]

      The default is THREE.UnsignedByteType. Other valid types (as WebGL allows) are THREE.ByteType, THREE.ShortType, THREE.UnsignedShortType, THREE.IntType, THREE.UnsignedIntType, THREE.FloatType, THREE.UnsignedShort4444Type, THREE.UnsignedShort5551Type, and THREE.UnsignedShort565Type.

      [property:number anisotropy]

      The number of samples taken along the axis through the pixel that has the highest density of texels. By default, this value is 1. A higher value gives a less blurry result than a basic mipmap, at the cost of more texture samples being used. Use renderer.getMaxAnisotropy() to find the maximum valid anisotropy value for the GPU; this value is usually a power of 2.

      [property:boolean needsUpdate]

      If a texture is changed after creation, set this flag to true so that the texture is properly set up. Particularly important for setting the wrap mode.

      [property:Vector2 repeat]

      How many times the texture is repeated across the surface, in each direction U and V.

      [property:Vector2 offset]

      How much a single repetition of the texture is offset from the beginning, in each direction U and V. Typical range is 0.0 to 1.0.

      [property:string name]

      Given name of the texture, empty string by default.

      [property:boolean generateMipmaps]

      Whether to generate mipmaps (if possible) for a texture. True by default.

      [property:boolean flipY]

      True by default. Flips the image's Y axis to match the WebGL texture coordinate space.

      [property:array mipmaps]

      Array of mipmaps generated.

      [property:number unpackAlignment]

      4 by default. Specifies the alignment requirements for the start of each pixel row in memory. The allowable values are 1 (byte-alignment), 2 (rows aligned to even-numbered bytes), 4 (word-alignment), and 8 (rows start on double-word boundaries). See glPixelStorei for more information.

      [property:boolean premultiplyAlpha]

      False by default, which is the norm for PNG images. Set to true if the RGB values have been stored premultiplied by alpha.

      [property:object onUpdate]

      A callback function, called when the texture is updated (e.g., when needsUpdate has been set to true and then the texture is used).

      Methods

      [page:EventDispatcher EventDispatcher] methods are available on this class.

      .clone([page:Texture texture])

      Make copy of texture. Note this is not a "deep copy", the image is shared.

      .dispose()

      Call [page:EventDispatcher EventDispatcher].dispatchEvent with a 'dispose' event type.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/textures/CompressedTexture.html0000644000175500017550000000675212610076566022725 0ustar debacledebacle [page:Texture] →

      [name]

      Creates a texture based on data in compressed form.

      Constructor

      [name]([page:Array mipmaps], [page:Number width], [page:Number height], [page:Number format], [page:Number type], [page:Number mapping], [page:Number wrapS], [page:Number wrapT], [page:Number magFilter], [page:Number minFilter], [page:Number anisotropy])

      mipmaps -- The mipmaps array should contains objects with data, width and height. The mipmaps should be from of the correct format and type.
      width -- The width of the biggest mipmap
      height -- The height of the biggest mipmap
      format -- The format used in the mipmaps
      type -- The type used in the mipmaps
      mapping -- How the image is applied to the object. An object type of THREE.UVMapping is the default, where the U,V coordinates are used to apply the map, and a single texture is expected. The other types are THREE.CubeReflectionMapping, for cube maps used as a reflection map; THREE.CubeRefractionMapping, refraction mapping; and THREE.SphericalReflectionMapping, a spherical reflection map projection.
      wrapS -- The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. The other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.
      wrapT -- The default is THREE.ClampToEdgeWrapping, where the edge is clamped to the outer edge texels. The other two choices are THREE.RepeatWrapping and THREE.MirroredRepeatWrapping.
      magFilter -- How the texture is sampled when a texel covers more than one pixel. The default is THREE.LinearFilter, which takes the four closest texels and bilinearly interpolates among them. The other option is THREE.NearestFilter, which uses the value of the closest texels.
      minFilter -- How the texture is sampled when a texel covers less than one pixel. The default is THREE.LinearMipMapLinearFilter, which uses mipmapping and a trilinear filter. Other choices are THREE.NearestFilter, THREE.NearestMipMapNearestFilter, THREE.NearestMipMapLinearFilter, THREE.LinearFilter, and THREE.LinearMipMapNearestFilter. These vary whether the nearest texel or nearest four texels are retrieved on the nearest mipmap or nearest two mipmaps. Interpolation occurs among the samples retrieved.
      anisotropy -- The number of samples taken along the axis through the pixel that has the highest density of texels. By default, this value is 1. A higher value gives a less blurry result than a basic mipmap, at the cost of more texture samples being used. Use renderer.getMaxAnisotropy() to find the maximum valid anisotropy value for the GPU; this value is usually a power of 2.
      This creates a texture from compressed data. This is mostly used in ImageUtils.loadCompressedTexture.

      Properties

      [property:boolean flipY]

      False by default. Flipping textures does not work for compressed textures.

      [property:boolean generateMipmaps]

      False by default. Mipmaps can't be generated for compressed textures

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/textures/DataTexture.html0000644000175500017550000000411212610076566021456 0ustar debacledebacle [page:Texture] →

      [name]

      Creates a texture directly from raw data, width and height.

      Constructor

      [name]( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy )

      The data argument must be an ArrayBuffer or a typed array view. Further parameters correspond to the properties inherited from [page:Texture], where both magFilter and minFilter default to THREE.NearestFilter. The properties flipY and generateMipmaps are intially set to false.
      The interpretation of the data depends on type and format: If the type is THREE.UnsignedByteType, a Uint8Array will be useful for addressing the texel data. If the format is THREE.RGBAFormat, data needs four values for one texel; Red, Green, Blue and Alpha (typically the opacity). Similarly, THREE.RGBFormat specifies a format where only three values are used for each texel.
      For the packed types, THREE.UnsignedShort4444Type, THREE.UnsignedShort5551Type or THREE.UnsignedShort565Type, all color components of one texel can be addressed as bitfields within an integer element of a Uint16Array.
      In order to use the types THREE.FloatType and THREE.HalfFloatType, the WebGL implementation must support the respective extensions OES_texture_float and OES_texture_half_float. In order to use THREE.LinearFilter for component-wise, bilinear interpolation of the texels based on these types, the WebGL extensions OES_texture_float_linear or OES_texture_half_float_linear must also be present.

      Properties

      [property:Image image]

      Overridden with a record type holding data, width and height.

      Methods

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/0000755000175500017550000000000012610076566016106 5ustar debacledebaclethree.js-r73/docs/api/objects/Points.html0000644000175500017550000000334712610076566020257 0ustar debacledebacle [page:Object3D] →

      [name]

      A class for displaying particles in the form of variable size points. For example, if using the [page:WebGLRenderer], the particles are displayed using GL_POINTS.

      Constructor

      [name]( [page:Geometry geometry], [page:Material material] )

      geometry — An instance of [page:Geometry].
      material — An instance of [page:Material] (optional).

      Properties

      [property:Geometry geometry]

      An instance of [page:Geometry], where each vertex designates the position of a particle in the system.

      [property:Material material]

      An instance of [page:Material], defining the object's appearance. Default is a [page:PointsMaterial] with randomised colour.

      Methods

      [method:Points clone]()

      This creates a clone of the particle system.

      [method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])

      Get intersections between a casted ray and this Points. [page:Raycaster.intersectObject] will call this method.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned Points Object.
      Clone a Points Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/Sprite.html0000644000175500017550000000330312610076566020241 0ustar debacledebacle [page:Object3D] →

      [name]

      A sprite is a plane in an 3d scene which faces always towards the camera.

      Example

      var map = THREE.ImageUtils.loadTexture( "sprite.png" ); var material = new THREE.SpriteMaterial( { map: map, color: 0xffffff, fog: true } ); var sprite = new THREE.Sprite( material ); scene.add( sprite );

      Constructor

      [name]([page:Material material])

      material — An instance of [page:Material] (optional).
      This creates a new sprite with an specific material.

      Properties

      [property:SpriteMaterial material]

      An instance of [page:Material], defining the object's appearance. Default is a [page:SpriteMaterial] which is a white plane.
      -

      Methods

      [method:Sprite clone]()

      This creates a new clone of the sprite.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned Sprite Object.
      Clone a Sprite Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/LOD.html0000644000175500017550000000376112610076566017421 0ustar debacledebacle [page:Object3D] →

      [name]

      Level of Detail - Show meshes with more or less geometry based on distance.

      Example

      [example:webgl_lod LOD]
      var lod = new THREE.LOD(); //Create 5 levels of spheres for( var i = 0; i < 5; i++ ) { var geometry = new THREE.IcosahedronGeometry( 10, 5 - i ) new THREE.Mesh( geometry, material ); lod.addLevel( mesh, i * 50 ); }

      Constructor

      [name]()

      Properties

      [property:array objects]

      An array of [page:Object3D Object3Ds]

      Methods

      [method:null addLevel]([page:Object3D mesh], [page:Float distance])

      mesh -- The Object3D to display
      distance -- The distance at which to display this level of detail
      Adds a mesh that will display at a certain distance and greater. Typically the further away the distance, the lower the detail on the mesh.

      [method:Object3D getObjectForDistance]([page:Float distance])

      Get a reference to the first [page:Object3D] (mesh) that is greater than supplied distance.

      [method:null update]([page:Camera camera])

      camera -- The current camera
      Update the visiblility of the level of detail based on the distance from the camera.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned LOD Object.
      Clone a LOD Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/LensFlare.html0000644000175500017550000000412212610076566020646 0ustar debacledebacle [page:Object3D] →

      [name]

      Creates a simulated lens flare that tracks a light

      Example

      [example:webgl_lensflares lensflares]

      Constructor

      [name]([page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color])

      texture -- THREE.Texture (optional)
      size -- size in pixels (-1 = use texture.width)
      distance -- (0-1) from light source (0 = at light source)
      blending -- [page:Materials Blending Mode] - Defaults to THREE.NormalBlending
      color -- The color of the lens flare
      Automatically adds a lens flare to the lensFlares array if a texture is set.

      Properties

      [property:array lensFlares]

      The array of flares as set by [page:LensFlare.add]

      [property:Vector3 positionScreen]

      The position of the lens flare on the screen.

      [property:Function customUpdateCallback]

      A custom update callback

      Methods

      [method:null add]([page:Texture texture], [page:Float size], [page:Float distance], [page:Materials blending], [page:Color color])

      Adds a lens flare. See the constructor for details on the parameters.

      [method:null updateLensFlares]()

      Updates the lens flare based on the [page:LensFlare.positionScreen positionScreen] property.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned LensFlare Object.
      Clone a LensFlare Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/Bone.html0000644000175500017550000000242112610076566017656 0ustar debacledebacle [page:Object3D] →

      [name]

      A bone which is part of a [page:Skeleton]. The skeleton in turn is used by the [page:SkinnedMesh]. Bones are almost identical to a blank [page:Object3D].

      Example

      var root = new THREE.Bone(); var child = new THREE.Bone(); root.add( child ); child.position.y = 5;

      Constructor

      [name]([page:SkinnedMesh skin])

      skin — (optional) The [page:SkinnedMesh] to which the bone belongs.

      Properties

      [property:SkinnedMesh skin]

      An optional reference to the [page:SkinnedMesh].

      Methods

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned Bone Object.
      Clone a Bone Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/SkinnedMesh.html0000644000175500017550000001041112610076566021201 0ustar debacledebacle [page:Object3D] →

      [name]

      A mesh that has a [page:Skeleton] with [page:Bone bones] that can then be used to animate the vertices of the geometry.

      Example

      var geometry = new THREE.CylinderGeometry( 5, 5, 5, 5, 15, 5, 30 ); //Create the skin indices and skin weights for ( var i = 0; i < geometry.vertices.length; i ++ ) { // Imaginary functions to calculate the indices and weights var skinIndex = calculateSkinIndex( geometry.vertices, i ); var skinWeight = calculateSkinWeight( geometry.vertices, i ); // Ease between each bone geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) ); geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) ); } var mesh = THREE.SkinnedMesh( geometry, material ); // See example from THREE.Skeleton for the armSkeleton var rootBone = armSkeleton.bones[ 0 ]; mesh.add( rootBone ); // Bind the skeleton to the mesh mesh.bind( armSkeleton ); // Move the bones and manipulate the model armSkeleton.bones[ 0 ].rotation.x = -0.1; armSkeleton.bones[ 1 ].rotation.x = 0.2;

      Constructor

      [name]([page:Geometry geometry], [page:Material material], [page:boolean useVertexTexture])

      geometry — An instance of [page:Geometry]. [page:Geometry.skinIndices] and [page:Geometry.skinWeights] should be set.
      material — An instance of [page:Material] (optional).
      useVertexTexture -- Defines whether a vertex texture can be used (optional).

      Properties

      [property:array bones]

      This contains the array of bones for this mesh. These should be set in the constructor.

      [property:Matrix4 identityMatrix]

      This is an identityMatrix to calculate the bones matrices from.

      [property:boolean useVertexTexture]

      The boolean defines whether a vertex texture is used to calculate the bones. This boolean shouldn't be changed after constructor.

      [property:array boneMatrices]

      This array of matrices contains the matrices of the bones. These get calculated in the constructor.

      [property:string bindMode]

      Either "attached" or "detached". "attached" uses the [page:SkinnedMesh.matrixWorld] property for the base transform matrix of the bones. "detached" uses the [page:SkinnedMesh.bindMatrix].

      [property:Matrix4 bindMatrix]

      The base matrix that is used for the bound bone transforms.

      [property:Matrix4 inverseBindMatrix]

      The inverse of the bindMatrix.

      Methods

      [method:null bind]([page:Skeleton skeleton], [page:Matrix4 bindMatrix])

      skeleton — [page:Skeleton]
      bindMatrix — [page:Matrix4] that represents the base transform of the skeleton
      Bind a skeleton to the skinned mesh. The bindMatrix gets saved to .bindMatrix property and the .bindMatrixInverse gets calculated.

      [method:null normalizeSkinWeights]()

      Normalizes the [page:Geometry.skinWeights] vectors. Does not affect [page:BufferGeometry].

      [method:null pose]()

      This method sets the skinned mesh in the rest pose.

      [method:Bone addBone]([page:Bone bone])

      bone — This is the bone that needs to be added. (optional)
      This method adds the bone to the skinned mesh when it is provided. It creates a new bone and adds that when no bone is given.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned SkinnedMesh Object.
      Clone a SkinnedMesh Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/MorphAnimMesh.html0000644000175500017550000001105712610076566021507 0ustar debacledebacle [page:Object3D] →

      [name]

      Play a sequence of morphs in a smooth animation sequence.

      Examples

      [example:webgl_lights_hemisphere lights / hemisphere ]
      [example:webgl_morphtargets_md2 morphtargets / md2 ]
      [example:webgl_loader_json_blender loader / json / blender ]
      var meshAnim; loader.load( "models/animated/flamingo.js", function( geometry ) { meshAnim = new THREE.MorphAnimMesh( geometry, material ); meshAnim.duration = 1000; scene.add( meshAnim ); } function update() { var delta = clock.getDelta(); meshAnim.updateAnimation( 1000 * delta ); }

      Constructor

      [name]([page:Geometry geometry], [page:Material material])

      geometry — An instance of [page:Geometry].
      material — An instance of [page:Material] (optional).

      Properties

      [property:Boolean directionBackwards]

      Animation is playing backwards

      [property:Float direction]

      1 if playing forward, -1 if playing backwards

      [property:Integer startKeyframe]

      The first keyframe (morph) of the sequence

      [property:Integer endKeyframe]

      The last keyframe (morph) of the sequence

      [property:Boolean mirroredLoop]

      Loop animation back and forth

      [property:Integer lastKeyframe]

      The index of the last keyframe played.

      [property:Integer currentKeyframe]

      The index of the current frame being played.

      [property:Integer length]

      The number of frames (morphs)

      [property:Float time]

      The current playback position of the animation in milliseconds.

      [property:Float duration]

      The length of the animation in milliseconds.

      Methods

      [method:null setDirectionForward]()

      Sets the animation to play forwards

      [method:null setDirectionBackward]()

      Set the animation to play backwards.

      [method:null playAnimation]([page:String label], [page:Float fps])

      label -- The label of the animation
      fps -- The frames per second (in seconds)
      Starts playing a labeled animation. Animations are defined by calling [page:MorphAnimMesh.parseAnimations parseAnimations].

      [method:null setFrameRange]([page:Integer start], [page:Integer end])

      start -- The starting frame (morph) index
      end -- The ending frame (morph) index
      Sets the range of morphs to be played

      [method:null parseAnimations]()

      Goes through the geometry's morphTargets and generates animations based on the morphTargets' names (morph.name). Names are of the form "walk_01", "walk_02", "walk_03", etc or "run001", "run002", "run003". The animation label is then the part before the underscore and number, so "walk" or "run" in the examples.

      This function changes the underlying geometry object by adding the animations property to it. This property is set to an object of key/pair values, with the key being the label and the value being an object with a start and end property that represents the frame index.

      [method:null updateAnimation]([page:Float delta])

      delta -- The change in time in milliseconds
      Update the morphTargetInfluences array on the MorphAnimMesh.

      [method:null setAnimationLabel]([page:String label], [page:Integer start], [page:Integer end])

      label -- The name of the animation
      start -- The starting frame index
      end -- The ending frame index
      Defines an animation. Sets the geometry.animations[label] to be an object with the start and end properties.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned MorphAnimMesh Object.
      Clone a MorphAnimMesh Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/Line.html0000644000175500017550000000354012610076566017665 0ustar debacledebacle [page:Object3D] →

      [name]

      A continuous line.

      Example

      var material = new THREE.LineBasicMaterial({ color: 0x0000ff }); var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( 0, 10, 0 ), new THREE.Vector3( 10, 0, 0 ) ); var line = new THREE.Line( geometry, material ); scene.add( line );

      Constructor

      [name]( [page:Geometry geometry], [page:Material material] )

      geometry — Vertices representing the line segment(s).
      material — Material for the line. Default is [page:LineBasicMaterial LineBasicMaterial].
      If no material is supplied, a randomized line material will be created and assigned to the object.

      Properties

      [property:Geometry geometry]

      Vertices representing the line segment(s).

      [property:Material material]

      Material for the line.

      Methods

      [method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])

      Get intersections between a casted ray and this Line. [page:Raycaster.intersectObject] will call this method.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned Line Object.
      Clone a Line Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/LineSegments.html0000644000175500017550000000300312610076566021365 0ustar debacledebacle [page:Line] →

      [name]

      A series of lines.

      Constructor

      [name]( [page:Geometry geometry], [page:Material material] )

      geometry — Vertices representing the line segment(s).
      material — Material for the line. Default is [page:LineBasicMaterial LineBasicMaterial].
      If no material is supplied, a randomized line material will be created and assigned to the object.

      Properties

      [property:Geometry geometry]

      Vertices representing the line segment(s).

      [property:Material material]

      Material for the line.

      Methods

      [method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])

      Get intersections between a casted ray and this Line. [page:Raycaster.intersectObject] will call this method.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned LineSegments Object.
      Clone a LineSegments Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/Mesh.html0000644000175500017550000000610612610076566017673 0ustar debacledebacle [page:Object3D] →

      [name]

      Base class for Mesh objects, such as [page:MorphAnimMesh] and [page:SkinnedMesh].

      Example

      var geometry = new THREE.BoxGeometry( 1, 1, 1 ); var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); var mesh = new THREE.Mesh( geometry, material ); scene.add( mesh );

      Constructor

      [name]( [page:Geometry geometry], [page:Material material] )

      geometry — An instance of [page:Geometry].
      material — An instance of [page:Material] (optional).

      Properties

      [property:Geometry geometry]

      An instance of [page:Geometry], defining the object's structure.

      [property:Material material]

      An instance of [page:Material], defining the object's appearance. Default is a [page:MeshBasicMaterial] with wireframe mode enabled and randomised colour.

      [property:Array morphTargetInfluences]

      An array of weights typically from 0-1 that specify how much of the morph is applied. Undefined by default, but reset to a blank array by [page:Mesh.updateMorphTargets updateMorphTargets].

      [property:Array morphTargetDictionary]

      A dictionary of morphTargets based on the morphTarget.name property. Undefined by default, but rebuilt [page:Mesh.updateMorphTargets updateMorphTargets].

      [property:Integer morphTargetBase]

      Specify the index of the morph that should be used as the base morph. Replaces the positions. Undefined by default, but reset to -1 (non set) by [page:Mesh.updateMorphTargets updateMorphTargets].

      Methods

      [method:Integer getMorphTargetIndexByName]( [page:String name] )

      name — a morph target name
      Returns the index of a morph target defined by name.

      [method:null updateMorphTargets]()

      Updates the morphtargets to have no influence on the object. Resets the [page:Mesh.morphTargetForcedOrder morphTargetForcedOrder], [page:Mesh.morphTargetInfluences morphTargetInfluences], [page:Mesh.morphTargetDictionary morphTargetDictionary], and [page:Mesh.morphTargetBase morphTargetBase] properties.

      [method:Array raycast]([page:Raycaster raycaster], [page:Array intersects])

      Get intersections between a casted ray and this mesh. [page:Raycaster.intersectObject] will call this method.

      [method:Object3D clone]([page:Object3D object])

      object -- (optional) Object3D which needs to be cloned. If undefined, clone method will create a new cloned Mesh Object.
      Clone a Mesh Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/objects/Skeleton.html0000644000175500017550000000637312610076566020571 0ustar debacledebacle

      [name]

      Use an array of [page:Bone bones] to create a skeleton that can be used by a [page:SkinnedMesh]. WebGL only.

      Example

      // Create a simple "arm" var bones = []; var shoulder = new THREE.Bone(); var elbow = new THREE.Bone(); var hand = new THREE.Bone(); shoulder.add( elbow ); elbow.add( hand ); bones.push( shoulder ); bones.push( elbow ); bones.push( hand ); shoulder.position.y = -5; elbow.position.y = 0; hand.position.y = 5; var armSkeleton = THREE.Skeleton( bones ); // See THREE.SkinnedMesh for an example of usage with a mesh

      Constructor

      [name]( [page:Array bones], [page:Array boneInverses], [page:Boolean useVertexTexture] )

      bones — The array of [page:bone bones]
      boneInverses — (optional) An array of [page:Matrix4 Matrix4s]
      useVertexTexture — (optional) Whether or not to use a vertex texture in the shader.
      The constructor automatically sets up all of the properties below.

      Properties

      [property:Array bones]

      The array of [page:bone bones]

      [property:Boolean useVertexTexture]

      Whether or not to use a vertex texture in the shader, set in the constructor. Not all devices support floating point pixel textures. If this option is set then the bone matrices will be packed into a texture and sent to the shader. This method allows a much larger set of bones to be used. Otherwise the vertex shader will use uniforms, which do not allow for as many bones to be used. The exact numbers vary between devices.

      [property:Array boneInverses]

      An array of [page:Matrix4 Matrix4s] that represent the inverse of the matrixWorld of the individual bones.

      [property:Integer boneTextureWidth]

      The width of the vertex data texture.

      [property:Integer boneTextureHeight]

      The height of the vertex data texture.

      [property:Float32Array boneMatrices]

      The array buffer holding the bone data when using a vertex texture.

      [property:DataTexture boneTexture]

      The [page:DataTexture] holding the bone data when using a vertex texture.

      Methods

      [method:null calculateInverses]()

      Generates the boneInverses.

      [method:null pose]()

      Returns the skeleton to the base pose.

      [method:null update]()

      Updates the [page:Float32Array boneMatrices] and [page:DataTexture boneTexture] after changing the bones. This is called automatically by the [page:WebGLRenderer] if the skeleton is used with a [page:SkinnedMesh].

      [method:Skeleton clone]()

      Clone a Skeleton Object.

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/Template.html0000644000175500017550000000132612610076566017120 0ustar debacledebacle [page:Geometry] →

      [name]

      todo

      Example

      todo

      Constructor

      [name]([page:Number todo])

      Properties

      [property:Number todo]

      todo

      Methods

      [method:null todo]()

      todo
      todo

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] three.js-r73/docs/api/CONTRIBUTING.md0000644000175500017550000000125712610076566016713 0ustar debacledebacleContributing to the documentation ================================= - To link to the page for `ClassName`, use `[page:ClassName link title]` (or just `[page:ClassName]`). Use `[page:ClassName.memberName]` to link to a class member (a property or method) called `memberName` on the page for `ClassName`. You can write `[page:.memberName]` to link to a property or method called `memberName` on the same page. - Use `[example:exampleName title]` (not just `[example:exampleName]`) to link to the example `threejs.org/examples/#exampleName`. - Document a property by writing `

      [property:TypeName propertyName]

      `. - Document a method using `

      [method:ReturnType methodName]

      `. three.js-r73/docs/api/constants/0000755000175500017550000000000012610076566016471 5ustar debacledebaclethree.js-r73/docs/api/constants/Textures.html0000644000175500017550000000416512610076566021210 0ustar debacledebacle

      Texture Constants

      Operations

      THREE.MultiplyOperation
      THREE.MixOperation
      THREE.AddOperation

      Mapping Modes

      THREE.UVMapping
      THREE.CubeReflectionMapping
      THREE.CubeRefractionMapping
      THREE.EquirectangularReflectionMapping
      THREE.EquirectangularRefractionMapping
      THREE.SphericalReflectionMapping

      Wrapping Modes

      THREE.RepeatWrapping
      THREE.ClampToEdgeWrapping
      THREE.MirroredRepeatWrapping

      Filters

      THREE.NearestFilter
      THREE.NearestMipMapNearestFilter
      THREE.NearestMipMapLinearFilter
      THREE.LinearFilter
      THREE.LinearMipMapNearestFilter
      THREE.LinearMipMapLinearFilter

      Data Types

      THREE.UnsignedByteType
      THREE.ByteType
      THREE.ShortType
      THREE.UnsignedShortType
      THREE.IntType
      THREE.UnsignedIntType
      THREE.FloatType
      THREE.HalfFloatType

      Pixel Types

      THREE.UnsignedShort4444Type
      THREE.UnsignedShort5551Type
      THREE.UnsignedShort565Type

      Pixel Formats

      THREE.AlphaFormat
      THREE.RGBFormat
      THREE.RGBAFormat
      THREE.LuminanceFormat
      THREE.LuminanceAlphaFormat
      THREE.RGBEFormat

      DDS / ST3C Compressed Texture Formats

      THREE.RGB_S3TC_DXT1_Format
      THREE.RGBA_S3TC_DXT1_Format
      THREE.RGBA_S3TC_DXT3_Format
      THREE.RGBA_S3TC_DXT5_Format

      PVRTC Compressed Texture Formats

      THREE.RGB_PVRTC_4BPPV1_Format
      THREE.RGB_PVRTC_2BPPV1_Format
      THREE.RGBA_PVRTC_4BPPV1_Format
      THREE.RGBA_PVRTC_2BPPV1_Format

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js] three.js-r73/docs/api/constants/ShadowingTypes.html0000644000175500017550000000100412610076566022322 0ustar debacledebacle

      Shadowing Type Constants

      Shadow Map

      THREE.BasicShadowMap
      THREE.PCFShadowMap
      THREE.PCFSoftShadowMap

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js] three.js-r73/docs/api/constants/CustomBlendingEquations.html0000644000175500017550000000176712610076566024200 0ustar debacledebacle

      Custom Blending Equation Constants

      Equations

      THREE.AddEquation
      THREE.SubtractEquation
      THREE.ReverseSubtractEquation
      THREE.MinEquation
      THREE.MaxEquation

      Destination Factors

      THREE.ZeroFactor
      THREE.OneFactor
      THREE.SrcColorFactor
      THREE.OneMinusSrcColorFactor
      THREE.SrcAlphaFactor
      THREE.OneMinusSrcAlphaFactor
      THREE.DstAlphaFactor
      THREE.OneMinusDstAlphaFactor

      Source Factors

      THREE.DstColorFactor
      THREE.OneMinusDstColorFactor
      THREE.SrcAlphaSaturateFactor

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js] three.js-r73/docs/api/constants/Materials.html0000644000175500017550000000157612610076566021311 0ustar debacledebacle

      Material Constants

      Side

      THREE.FrontSide
      THREE.BackSide
      THREE.DoubleSide

      Shading

      THREE.FlatShading
      THREE.SmoothShading

      Colors

      THREE.NoColors
      THREE.FaceColors
      THREE.VertexColors

      Blending Mode

      THREE.NoBlending
      THREE.NormalBlending
      THREE.AdditiveBlending
      THREE.SubtractiveBlending
      THREE.MultiplyBlending
      THREE.CustomBlending

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js] three.js-r73/docs/api/constants/GLState.html0000644000175500017550000000122112610076566020656 0ustar debacledebacle

      GL State Constants

      Cull Face

      THREE.CullFaceNone
      THREE.CullFaceBack
      THREE.CullFaceFront
      THREE.CullFaceFrontBack

      Front Face Direction

      THREE.FrontFaceDirectionCW
      THREE.FrontFaceDirectionCCW

      Source

      [link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js] three.js-r73/docs/index.html0000644000175500017550000002204312610076566015702 0ustar debacledebacle three.js / documentation three.js-r73/docs/scenes/0000755000175500017550000000000012610076566015164 5ustar debacledebaclethree.js-r73/docs/scenes/bones-browser.html0000644000175500017550000001507512610076566020651 0ustar debacledebacle Three.js Bones Browser Open in New Window three.js-r73/docs/scenes/js/0000755000175500017550000000000012610076566015600 5ustar debacledebaclethree.js-r73/docs/scenes/js/material.js0000644000175500017550000003307112610076566017740 0ustar debacledebacle/** * @author TatumCreative (Greg Tatum) / http://gregtatum.com/ */ var constants = { combine: { "THREE.MultiplyOperation" : THREE.MultiplyOperation, "THREE.MixOperation" : THREE.MixOperation, "THREE.AddOperation" : THREE.AddOperation }, side : { "THREE.FrontSide" : THREE.FrontSide, "THREE.BackSide" : THREE.BackSide, "THREE.DoubleSide" : THREE.DoubleSide }, shading : { "THREE.FlatShading" : THREE.FlatShading, "THREE.SmoothShading" : THREE.SmoothShading }, colors : { "THREE.NoColors" : THREE.NoColors, "THREE.FaceColors" : THREE.FaceColors, "THREE.VertexColors" : THREE.VertexColors }, blendingMode : { "THREE.NoBlending" : THREE.NoBlending, "THREE.NormalBlending" : THREE.NormalBlending, "THREE.AdditiveBlending" : THREE.AdditiveBlending, "THREE.SubtractiveBlending" : THREE.SubtractiveBlending, "THREE.MultiplyBlending" : THREE.MultiplyBlending, "THREE.CustomBlending" : THREE.CustomBlending }, equations : { "THREE.AddEquation" : THREE.AddEquation, "THREE.SubtractEquation" : THREE.SubtractEquation, "THREE.ReverseSubtractEquation" : THREE.ReverseSubtractEquation }, destinationFactors : { "THREE.ZeroFactor" : THREE.ZeroFactor, "THREE.OneFactor" : THREE.OneFactor, "THREE.SrcColorFactor" : THREE.SrcColorFactor, "THREE.OneMinusSrcColorFactor" : THREE.OneMinusSrcColorFactor, "THREE.SrcAlphaFactor" : THREE.SrcAlphaFactor, "THREE.OneMinusSrcAlphaFactor" : THREE.OneMinusSrcAlphaFactor, "THREE.DstAlphaFactor" : THREE.DstAlphaFactor, "THREE.OneMinusDstAlphaFactor" : THREE.OneMinusDstAlphaFactor }, sourceFactors : { "THREE.DstColorFactor" : THREE.DstColorFactor, "THREE.OneMinusDstColorFactor" : THREE.OneMinusDstColorFactor, "THREE.SrcAlphaSaturateFactor" : THREE.SrcAlphaSaturateFactor } } function getObjectsKeys( obj ) { var keys = []; for ( var key in obj ) { if ( obj.hasOwnProperty( key ) ) { keys.push( key ); } } return keys; } var envMaps = (function () { var path = "../../examples/textures/cube/SwedishRoyalCastle/"; var format = '.jpg'; var urls = [ path + 'px' + format, path + 'nx' + format, path + 'py' + format, path + 'ny' + format, path + 'pz' + format, path + 'nz' + format ]; var reflectionCube = THREE.ImageUtils.loadTextureCube( urls ); reflectionCube.format = THREE.RGBFormat; var refractionCube = THREE.ImageUtils.loadTextureCube( urls ); refractionCube.mapping = THREE.CubeRefractionMapping; refractionCube.format = THREE.RGBFormat; return { none : null, reflection : reflectionCube, refraction : refractionCube }; })(); var envMapKeys = getObjectsKeys( envMaps ); var textureMaps = (function () { return { none : null, grass : THREE.ImageUtils.loadTexture( "../../examples/textures/terrain/grasslight-thin.jpg" ) }; })(); var textureMapKeys = getObjectsKeys( textureMaps ); function generateVertexColors ( geometry ) { for ( var i=0, il = geometry.faces.length; i < il; i++ ) { geometry.faces[i].vertexColors.push( new THREE.Color().setHSL( i / il * Math.random(), 0.5, 0.5 ) ); geometry.faces[i].vertexColors.push( new THREE.Color().setHSL( i / il * Math.random(), 0.5, 0.5 ) ); geometry.faces[i].vertexColors.push( new THREE.Color().setHSL( i / il * Math.random(), 0.5, 0.5 ) ); geometry.faces[i].color = new THREE.Color().setHSL( i / il * Math.random(), 0.5, 0.5 ); } } function generateMorphTargets ( mesh, geometry ) { var vertices = [], scale; for ( var i = 0; i < geometry.vertices.length; i++ ) { vertices.push( geometry.vertices[ i ].clone() ); scale = 1 + Math.random() * 0.3; vertices[ vertices.length - 1 ].x *= scale; vertices[ vertices.length - 1 ].y *= scale; vertices[ vertices.length - 1 ].z *= scale; } geometry.morphTargets.push( { name: "target1", vertices: vertices } ); geometry.update } function handleColorChange ( color ) { return function ( value ){ if (typeof value === "string") { value = value.replace('#', '0x'); } color.setHex( value ); }; } function needsUpdate ( material, geometry ) { return function () { material.shading = +material.shading; //Ensure number material.vertexColors = +material.vertexColors; //Ensure number material.side = +material.side; //Ensure number material.needsUpdate = true; geometry.verticesNeedUpdate = true; geometry.normalsNeedUpdate = true; geometry.colorsNeedUpdate = true; }; }; function updateMorphs ( torus, material ) { return function () { torus.updateMorphTargets(); material.needsUpdate = true; }; } function updateTexture ( material, materialKey, textures ) { return function ( key ) { material[materialKey] = textures[key]; material.needsUpdate = true; }; } function guiScene ( gui, scene ) { var folder = gui.addFolder('Scene'); var data = { background : "#000000", "ambient light" : ambientLight.color.getHex() } var color = new THREE.Color(); var colorConvert = handleColorChange( color ); folder.addColor( data, "background" ).onChange( function ( value ) { colorConvert( value ); renderer.setClearColor( color.getHex() ); } ); folder.addColor( data, "ambient light" ).onChange( handleColorChange( ambientLight.color ) ) guiSceneFog( folder, scene ); } function guiSceneFog ( folder, scene ) { var fogFolder = folder.addFolder('scene.fog'); var fog = new THREE.Fog( 0x3f7b9d, 0, 60 ); var data = { fog : { "THREE.Fog()" : false, "scene.fog.color" : fog.color.getHex() } }; fogFolder.add( data.fog, 'THREE.Fog()' ).onChange( function ( useFog ) { if ( useFog ) { scene.fog = fog; } else { scene.fog = null; } } ); fogFolder.addColor( data.fog, 'scene.fog.color').onChange( handleColorChange( fog.color ) ); } function guiMaterial ( gui, mesh, material, geometry ) { var folder = gui.addFolder('THREE.Material'); folder.add( material, 'transparent' ); folder.add( material, 'opacity', 0, 1 ); // folder.add( material, 'blending', constants.blendingMode ); // folder.add( material, 'blendSrc', constants.destinationFactors ); // folder.add( material, 'blendDst', constants.destinationFactors ); // folder.add( material, 'blendEquation', constants.equations ); folder.add( material, 'depthTest' ); folder.add( material, 'depthWrite' ); // folder.add( material, 'polygonOffset' ); // folder.add( material, 'polygonOffsetFactor' ); // folder.add( material, 'polygonOffsetUnits' ); folder.add( material, 'alphaTest', 0, 1 ); // folder.add( material, 'overdraw', 0, 5 ); folder.add( material, 'visible' ); folder.add( material, 'side', constants.side ).onChange( needsUpdate( material, geometry ) ); } function guiMeshBasicMaterial ( gui, mesh, material, geometry ) { var data = { color : material.color.getHex(), envMaps : envMapKeys, map : textureMapKeys, specularMap : textureMapKeys, alphaMap : textureMapKeys }; var folder = gui.addFolder('THREE.MeshBasicMaterial'); folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) ); folder.add( material, 'wireframe' ); folder.add( material, 'wireframeLinewidth', 0, 10 ); folder.add( material, 'shading', constants.shading); folder.add( material, 'vertexColors', constants.colors).onChange( needsUpdate( material, geometry ) ); folder.add( material, 'fog' ); folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) ); folder.add( data, 'map', textureMapKeys ).onChange( updateTexture( material, 'map', textureMaps ) ); folder.add( data, 'specularMap', textureMapKeys ).onChange( updateTexture( material, 'specularMap', textureMaps ) ); folder.add( data, 'alphaMap', textureMapKeys ).onChange( updateTexture( material, 'alphaMap', textureMaps ) ); folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) ); folder.add( material, 'combine', constants.combine ).onChange( updateMorphs( mesh, material ) ); folder.add( material, 'reflectivity', 0, 1 ); folder.add( material, 'refractionRatio', 0, 1 ); //folder.add( material, 'skinning' ); } function guiMeshDepthMaterial ( gui, mesh, material, geometry ) { var folder = gui.addFolder('THREE.MeshDepthMaterial'); folder.add( material, 'wireframe' ); folder.add( material, 'wireframeLinewidth', 0, 10 ); folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) ); } function guiMeshNormalMaterial ( gui, mesh, material, geometry ) { var folder = gui.addFolder('THREE.MeshNormalMaterial'); folder.add( material, 'wireframe' ); folder.add( material, 'wireframeLinewidth', 0, 10 ); folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) ); } function guiLineBasicMaterial ( gui, mesh, material, geometry ) { var data = { color : material.color.getHex() }; var folder = gui.addFolder('THREE.LineBasicMaterial'); folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) ); folder.add( material, 'linewidth', 0, 10 ); folder.add( material, 'linecap', ["butt", "round", "square"] ); folder.add( material, 'linejoin', ["round", "bevel", "miter"] ); folder.add( material, 'vertexColors', constants.colors).onChange( needsUpdate( material, geometry ) ); folder.add( material, 'fog' ); } function guiMeshLambertMaterial ( gui, mesh, material, geometry ) { var data = { color : material.color.getHex(), emissive : material.emissive.getHex(), envMaps : envMapKeys, map : textureMapKeys, specularMap : textureMapKeys, alphaMap : textureMapKeys }; var envObj = {}; var folder = gui.addFolder('THREE.MeshLambertMaterial'); folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) ); folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) ); folder.add( material, 'wireframe' ); folder.add( material, 'wireframeLinewidth', 0, 10 ); folder.add( material, 'vertexColors', constants.colors ).onChange( needsUpdate( material, geometry ) ); folder.add( material, 'fog' ); folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) ); folder.add( data, 'map', textureMapKeys ).onChange( updateTexture( material, 'map', textureMaps ) ); folder.add( data, 'specularMap', textureMapKeys ).onChange( updateTexture( material, 'specularMap', textureMaps ) ); folder.add( data, 'alphaMap', textureMapKeys ).onChange( updateTexture( material, 'alphaMap', textureMaps ) ); folder.add( material, 'morphTargets' ).onChange( updateMorphs( mesh, material ) ); folder.add( material, 'combine', constants.combine ).onChange( updateMorphs( mesh, material ) ); folder.add( material, 'reflectivity', 0, 1 ); folder.add( material, 'refractionRatio', 0, 1 ); //folder.add( material, 'skinning' ); } function guiMeshPhongMaterial ( gui, mesh, material, geometry ) { var data = { color : material.color.getHex(), emissive : material.emissive.getHex(), specular : material.specular.getHex(), envMaps : envMapKeys, map : textureMapKeys, lightMap : textureMapKeys, specularMap : textureMapKeys, alphaMap : textureMapKeys }; var folder = gui.addFolder('THREE.MeshPhongMaterial'); folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) ); folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) ); folder.addColor( data, 'specular' ).onChange( handleColorChange( material.specular ) ); folder.add( material, 'shininess', 0, 100); folder.add( material, 'shading', constants.shading).onChange( needsUpdate( material, geometry ) ); folder.add( material, 'wireframe' ); folder.add( material, 'wireframeLinewidth', 0, 10 ); folder.add( material, 'vertexColors', constants.colors); folder.add( material, 'fog' ); folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) ); folder.add( data, 'map', textureMapKeys ).onChange( updateTexture( material, 'map', textureMaps ) ); folder.add( data, 'lightMap', textureMapKeys ).onChange( updateTexture( material, 'lightMap', textureMaps ) ); folder.add( data, 'specularMap', textureMapKeys ).onChange( updateTexture( material, 'specularMap', textureMaps ) ); folder.add( data, 'alphaMap', textureMapKeys ).onChange( updateTexture( material, 'alphaMap', textureMaps ) ); } function chooseFromHash ( gui, mesh, geometry ) { var selectedMaterial = window.location.hash.substring(1) || "MeshBasicMaterial"; var material; switch (selectedMaterial) { case "MeshBasicMaterial" : material = new THREE.MeshBasicMaterial({color: 0x2194CE}); guiMaterial( gui, mesh, material, geometry ); guiMeshBasicMaterial( gui, mesh, material, geometry ); return material; break; case "MeshLambertMaterial" : material = new THREE.MeshLambertMaterial({color: 0x2194CE}); guiMaterial( gui, mesh, material, geometry ); guiMeshLambertMaterial( gui, mesh, material, geometry ); return material; break; case "MeshPhongMaterial" : material = new THREE.MeshPhongMaterial({color: 0x2194CE}); guiMaterial( gui, mesh, material, geometry ); guiMeshPhongMaterial( gui, mesh, material, geometry ); return material; break; case "MeshDepthMaterial" : material = new THREE.MeshDepthMaterial({color: 0x2194CE}); guiMaterial( gui, mesh, material, geometry ); guiMeshDepthMaterial( gui, mesh, material, geometry ); return material; break; case "MeshNormalMaterial" : material = new THREE.MeshNormalMaterial(); guiMaterial( gui, mesh, material, geometry ); guiMeshNormalMaterial( gui, mesh, material, geometry ); return material; break; case "LineBasicMaterial" : material = new THREE.LineBasicMaterial({color: 0x2194CE}); guiMaterial( gui, mesh, material, geometry ); guiLineBasicMaterial( gui, mesh, material, geometry ); return material; break; } } three.js-r73/docs/scenes/js/geometry.js0000644000175500017550000003133712610076566020000 0ustar debacledebacle/** * @author TatumCreative (Greg Tatum) / http://gregtatum.com/ */ var twoPi = Math.PI * 2; var constants = { combine: { "THREE.MultiplyOperation" : THREE.MultiplyOperation, "THREE.MixOperation" : THREE.MixOperation, "THREE.AddOperation" : THREE.AddOperation }, side : { "THREE.FrontSide" : THREE.FrontSide, "THREE.BackSide" : THREE.BackSide, "THREE.DoubleSide" : THREE.DoubleSide }, shading : { "THREE.FlatShading" : THREE.FlatShading, "THREE.SmoothShading" : THREE.SmoothShading }, colors : { "THREE.NoColors" : THREE.NoColors, "THREE.FaceColors" : THREE.FaceColors, "THREE.VertexColors" : THREE.VertexColors }, blendingMode : { "THREE.NoBlending" : THREE.NoBlending, "THREE.NormalBlending" : THREE.NormalBlending, "THREE.AdditiveBlending" : THREE.AdditiveBlending, "THREE.SubtractiveBlending" : THREE.SubtractiveBlending, "THREE.MultiplyBlending" : THREE.MultiplyBlending, "THREE.CustomBlending" : THREE.CustomBlending }, equations : { "THREE.AddEquation" : THREE.AddEquation, "THREE.SubtractEquation" : THREE.SubtractEquation, "THREE.ReverseSubtractEquation" : THREE.ReverseSubtractEquation }, destinationFactors : { "THREE.ZeroFactor" : THREE.ZeroFactor, "THREE.OneFactor" : THREE.OneFactor, "THREE.SrcColorFactor" : THREE.SrcColorFactor, "THREE.OneMinusSrcColorFactor" : THREE.OneMinusSrcColorFactor, "THREE.SrcAlphaFactor" : THREE.SrcAlphaFactor, "THREE.OneMinusSrcAlphaFactor" : THREE.OneMinusSrcAlphaFactor, "THREE.DstAlphaFactor" : THREE.DstAlphaFactor, "THREE.OneMinusDstAlphaFactor" : THREE.OneMinusDstAlphaFactor }, sourceFactors : { "THREE.DstColorFactor" : THREE.DstColorFactor, "THREE.OneMinusDstColorFactor" : THREE.OneMinusDstColorFactor, "THREE.SrcAlphaSaturateFactor" : THREE.SrcAlphaSaturateFactor } } function updateGroupGeometry( mesh, geometry ) { mesh.children[0].geometry.dispose(); mesh.children[1].geometry.dispose(); mesh.children[0].geometry = new THREE.WireframeGeometry( geometry ); mesh.children[1].geometry = geometry; //these do not update nicely together if shared } var guis = { BoxGeometry : function( mesh ) { var data = { width : 15, height : 15, depth : 15, widthSegments : 1, heightSegments : 1, depthSegments : 1 }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ) ); } var folder = gui.addFolder('THREE.BoxGeometry'); folder.add( data, 'width', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'height', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'depth', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'widthSegments', 1, 10 ).step(1).onChange( generateGeometry ); folder.add( data, 'heightSegments', 1, 10 ).step(1).onChange( generateGeometry ); folder.add( data, 'depthSegments', 1, 10 ).step(1).onChange( generateGeometry ); generateGeometry(); }, CylinderGeometry : function( mesh ) { var data = { radiusTop : 5, radiusBottom : 5, height : 10, radiusSegments : 8, heightSegments : 1, openEnded : false, thetaStart : 0, thetaLength : twoPi, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radiusSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ) ) } var folder = gui.addFolder('THREE.CylinderGeometry'); folder.add( data, 'radiusTop', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'radiusBottom', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'height', 1, 50 ).onChange( generateGeometry ); folder.add( data, 'radiusSegments', 3, 64 ).step(1).onChange( generateGeometry ); folder.add( data, 'heightSegments', 1, 64 ).step(1).onChange( generateGeometry ); folder.add( data, 'openEnded' ).onChange( generateGeometry ); folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry ); folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry ); generateGeometry(); }, CircleGeometry : function( mesh ) { var data = { radius : 10, segments : 32, thetaStart : 0, thetaLength : twoPi, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ) ); } var folder = gui.addFolder('THREE.CircleGeometry'); folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry ); folder.add( data, 'segments', 0, 128 ).step(1).onChange( generateGeometry ); folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry ); folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry ); generateGeometry(); }, DodecahedronGeometry : function() { var data = { radius : 10, detail : 0, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.DodecahedronGeometry( data.radius, data.detail ) ) } var folder = gui.addFolder('THREE.DodecahedronGeometry'); folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry ) folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry ) generateGeometry() }, IcosahedronGeometry : function() { var data = { radius : 10, detail : 0, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.IcosahedronGeometry( data.radius, data.detail ) ) } var folder = gui.addFolder('THREE.IcosahedronGeometry'); folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry ) folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry ) generateGeometry() }, OctahedronGeometry : function() { var data = { radius : 10, detail : 0, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.OctahedronGeometry( data.radius, data.detail ) ) } var folder = gui.addFolder('THREE.OctahedronGeometry'); folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry ) folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry ) generateGeometry() }, PlaneGeometry : function( mesh ) { var data = { width : 10, height : 10, widthSegments : 1, heightSegments : 1 }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ) ); } var folder = gui.addFolder('THREE.PlaneGeometry'); folder.add( data, 'width', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'height', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'widthSegments', 1, 30 ).step(1).onChange( generateGeometry ); folder.add( data, 'heightSegments', 1, 30 ).step(1).onChange( generateGeometry ); generateGeometry(); }, RingGeometry : function( mesh ) { var data = { innerRadius : 5, outerRadius : 10, thetaSegments : 8, phiSegments : 8, thetaStart : 0, thetaLength : twoPi, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ) ); } var folder = gui.addFolder('THREE.RingGeometry'); folder.add( data, 'innerRadius', 0, 30 ).onChange( generateGeometry ); folder.add( data, 'outerRadius', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'thetaSegments', 1, 30 ).step(1).onChange( generateGeometry ); folder.add( data, 'phiSegments', 1, 30 ).step(1).onChange( generateGeometry ); folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry ); folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry ); generateGeometry(); }, SphereGeometry : function( mesh ) { var data = { radius : 15, widthSegments : 8, heightSegments : 6, phiStart : 0, phiLength : twoPi, thetaStart : 0, thetaLength : Math.PI, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ) ); } var folder = gui.addFolder('THREE.SphereGeometry'); folder.add( data, 'radius', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'widthSegments', 3, 32 ).step(1).onChange( generateGeometry ); folder.add( data, 'heightSegments', 2, 32 ).step(1).onChange( generateGeometry ); folder.add( data, 'phiStart', 0, twoPi ).onChange( generateGeometry ); folder.add( data, 'phiLength', 0, twoPi ).onChange( generateGeometry ); folder.add( data, 'thetaStart', 0, twoPi ).onChange( generateGeometry ); folder.add( data, 'thetaLength', 0, twoPi ).onChange( generateGeometry ); generateGeometry(); }, TetrahedronGeometry : function() { var data = { radius : 10, detail : 0, }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.TetrahedronGeometry( data.radius, data.detail ) ) } var folder = gui.addFolder('THREE.TetrahedronGeometry'); folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry ) folder.add( data, 'detail', 0, 5 ).step(1).onChange( generateGeometry ) generateGeometry() }, TextGeometry : function( mesh ) { var data = { text : "TextGeometry", size : 5, height : 2, curveSegments : 12, font : "helvetiker", weight : "normal", style : "normal", bevelEnabled : false, bevelThickness : 1, bevelSize : 0.5 }; var fonts = [ "helvetiker", "optimer", "gentilis", "droid serif" ] var weights = [ "normal", "bold" ] function generateGeometry() { var geometry = new THREE.TextGeometry( data.text, data ) geometry.center() updateGroupGeometry( mesh, geometry ); } //Hide the wireframe mesh.children[0].visible = false; var folder = gui.addFolder('THREE.TextGeometry'); folder.add( data, 'text' ).onChange( generateGeometry ); folder.add( data, 'size', 1, 30 ).onChange( generateGeometry ); folder.add( data, 'height', 1, 20 ).onChange( generateGeometry ); folder.add( data, 'curveSegments', 1, 20 ).step(1).onChange( generateGeometry ); folder.add( data, 'font', fonts ).onChange( generateGeometry ); folder.add( data, 'weight', weights ).onChange( generateGeometry ); // folder.add( data, 'style', 1, 1 ).onChange( generateGeometry ); folder.add( data, 'bevelEnabled' ).onChange( generateGeometry ); folder.add( data, 'bevelThickness', 0.1, 3 ).onChange( generateGeometry ); folder.add( data, 'bevelSize', 0.1, 3 ).onChange( generateGeometry ); generateGeometry(); }, TorusGeometry : function( mesh ) { var data = { radius : 10, tube : 3, radialSegments : 16, tubularSegments : 100, arc : twoPi }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ) ) } var folder = gui.addFolder('THREE.TorusGeometry'); folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry ); folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry ); folder.add( data, 'radialSegments', 2, 30 ).step(1).onChange( generateGeometry ); folder.add( data, 'tubularSegments', 3, 200 ).step(1).onChange( generateGeometry ); folder.add( data, 'arc', 0.1, twoPi ).onChange( generateGeometry ); generateGeometry(); }, TorusKnotGeometry : function( mesh ) { var data = { radius : 10, tube : 3, radialSegments : 64, tubularSegments : 8, p : 2, q : 3, heightScale : 1 }; function generateGeometry() { updateGroupGeometry( mesh, new THREE.TorusKnotGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.p, data.q, data.heightScale ) ) } var folder = gui.addFolder('THREE.TorusGeometry'); folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry ) folder.add( data, 'tube', 0.1, 10 ).onChange( generateGeometry ) folder.add( data, 'radialSegments', 3, 300 ).step(1).onChange( generateGeometry ) folder.add( data, 'tubularSegments', 3, 20 ).step(1).onChange( generateGeometry ) folder.add( data, 'p', 1, 20 ).step(1).onChange( generateGeometry ) folder.add( data, 'q', 1, 20 ).step(1).onChange( generateGeometry ) folder.add( data, 'heightScale', 1, 20 ).onChange( generateGeometry ) generateGeometry() } } function chooseFromHash ( mesh ) { var selectedGeometry = window.location.hash.substring(1) || "TorusGeometry"; if ( guis[ selectedGeometry ] !== undefined ) { guis[ selectedGeometry ]( mesh ); } if ( selectedGeometry === 'TextGeometry' ) { return { fixed : true }; } //No configuration options return {}; } three.js-r73/docs/scenes/material-browser.html0000644000175500017550000000553012610076566021334 0ustar debacledebacle Three.js Material Browser Open in New Window three.js-r73/docs/scenes/geometry-browser.html0000644000175500017550000000717312610076566021376 0ustar debacledebacle Three.js Geometry Browser Open in New Window three.js-r73/docs/page.css0000644000175500017550000000253012610076566015332 0ustar debacledebacle@font-face { font-family: 'inconsolata'; src: url('files/inconsolata.woff') format('woff'); font-weight: normal; font-style: normal; } body { margin: 30px 20px; color: #555; font-family: 'inconsolata'; font-size: 15px; line-height: 18px; overflow: auto; } a { color: #1184CE; } h1 { color: #333; font-size: 25px; font-weight: normal; margin-top: 10px; } h2 { color: #4B0; font-size: 18px; font-weight: normal; margin-top: 40px; } h3 { color: #000; font-size: 16px; font-weight: normal; margin-top: 30px; } div { /* padding-left: 30px; */ margin-bottom: 20px; } div.desc { padding-left: 0px; } pre, code { margin-top: 20px; margin-bottom: 20px; } code { display: block; width: -webkit-calc( 100% - 40px ); width: -moz-calc( 100% - 40px ); width: calc( 100% - 40px ); padding: 20px; white-space: pre-wrap; background-color: #f9f9f9; overflow: auto; } iframe { width: 100%; height: 420px; border:0; } th { padding: 10px; text-decoration: underline; } td { text-align: center; } table code { padding: 2px; margin: 0px; width: auto; } strong { color: #000; font-weight: normal; } #button { position: fixed; top: 20px; right: 20px; padding: 8px; color: #fff; background-color: #555; opacity: 0.5; } #button:hover { cursor: pointer; opacity: 1; } a.permalink { float: right; margin-left: 5px; } three.js-r73/docs/list.js0000644000175500017550000002344412610076566015224 0ustar debacledebaclevar list = { "Manual": { "Introduction": [ [ "Creating a scene", "manual/introduction/Creating-a-scene" ], [ "Matrix transformations", "manual/introduction/Matrix-transformations" ] ] }, "Reference": { "Constants": [ [ "CustomBlendingEquation", "api/constants/CustomBlendingEquations"], [ "GLState", "api/constants/GLState"], [ "Materials", "api/constants/Materials"], [ "ShadowingTypes", "api/constants/ShadowingTypes"], [ "Textures", "api/constants/Textures"] ], "Cameras": [ [ "Camera", "api/cameras/Camera" ], [ "CubeCamera", "api/cameras/CubeCamera" ], [ "OrthographicCamera", "api/cameras/OrthographicCamera" ], [ "PerspectiveCamera", "api/cameras/PerspectiveCamera" ] ], "Core": [ [ "BufferAttribute", "api/core/BufferAttribute" ], [ "BufferGeometry", "api/core/BufferGeometry" ], [ "Clock", "api/core/Clock" ], [ "EventDispatcher", "api/core/EventDispatcher" ], [ "Face3", "api/core/Face3" ], [ "Geometry", "api/core/Geometry" ], [ "Object3D", "api/core/Object3D" ], [ "Raycaster", "api/core/Raycaster" ] ], "Lights": [ [ "AmbientLight", "api/lights/AmbientLight" ], [ "DirectionalLight", "api/lights/DirectionalLight" ], [ "HemisphereLight", "api/lights/HemisphereLight" ], [ "Light", "api/lights/Light" ], [ "PointLight", "api/lights/PointLight" ], [ "SpotLight", "api/lights/SpotLight" ] ], "Loaders": [ [ "BabylonLoader", "api/loaders/BabylonLoader" ], [ "BufferGeometryLoader", "api/loaders/BufferGeometryLoader" ], [ "Cache", "api/loaders/Cache" ], [ "ColladaLoader", "api/loaders/ColladaLoader" ], [ "glTFLoader", "api/loaders/glTFLoader" ], [ "ImageLoader", "api/loaders/ImageLoader" ], [ "JSONLoader", "api/loaders/JSONLoader" ], [ "Loader", "api/loaders/Loader" ], [ "LoadingManager", "api/loaders/LoadingManager" ], [ "MaterialLoader", "api/loaders/MaterialLoader" ], [ "MTLLoader", "api/loaders/MTLLoader" ], [ "OBJLoader", "api/loaders/OBJLoader" ], [ "OBJMTLLoader", "api/loaders/OBJMTLLoader" ], [ "ObjectLoader", "api/loaders/ObjectLoader" ], [ "PDBLoader", "api/loaders/PDBLoader" ], [ "SVGLoader", "api/loaders/SVGLoader" ], [ "TextureLoader", "api/loaders/TextureLoader" ], [ "TGALoader", "api/loaders/TGALoader" ], [ "XHRLoader", "api/loaders/XHRLoader" ] ], "Materials": [ [ "LineBasicMaterial", "api/materials/LineBasicMaterial" ], [ "LineDashedMaterial", "api/materials/LineDashedMaterial" ], [ "Material", "api/materials/Material" ], [ "MeshBasicMaterial", "api/materials/MeshBasicMaterial" ], [ "MeshDepthMaterial", "api/materials/MeshDepthMaterial" ], [ "MeshFaceMaterial", "api/materials/MeshFaceMaterial" ], [ "MeshLambertMaterial", "api/materials/MeshLambertMaterial" ], [ "MeshNormalMaterial", "api/materials/MeshNormalMaterial" ], [ "MeshPhongMaterial", "api/materials/MeshPhongMaterial" ], [ "PointsMaterial", "api/materials/PointsMaterial" ], [ "RawShaderMaterial", "api/materials/RawShaderMaterial" ], [ "ShaderMaterial", "api/materials/ShaderMaterial" ], [ "SpriteCanvasMaterial", "api/materials/SpriteCanvasMaterial" ], [ "SpriteMaterial", "api/materials/SpriteMaterial" ] ], "Math": [ [ "Box2", "api/math/Box2" ], [ "Box3", "api/math/Box3" ], [ "Color", "api/math/Color" ], [ "Euler", "api/math/Euler" ], [ "Frustum", "api/math/Frustum" ], [ "Line3", "api/math/Line3" ], [ "Math", "api/math/Math" ], [ "Matrix3", "api/math/Matrix3" ], [ "Matrix4", "api/math/Matrix4" ], [ "Plane", "api/math/Plane" ], [ "Quaternion", "api/math/Quaternion" ], [ "Ray", "api/math/Ray" ], [ "Sphere", "api/math/Sphere" ], [ "Spline", "api/math/Spline" ], [ "Triangle", "api/math/Triangle" ], [ "Vector2", "api/math/Vector2" ], [ "Vector3", "api/math/Vector3" ], [ "Vector4", "api/math/Vector4" ] ], "Objects": [ [ "Bone", "api/objects/Bone" ], [ "LensFlare", "api/objects/LensFlare" ], [ "Line", "api/objects/Line" ], [ "LineSegments", "api/objects/LineSegments" ], [ "LOD", "api/objects/LOD" ], [ "Mesh", "api/objects/Mesh" ], [ "MorphAnimMesh", "api/objects/MorphAnimMesh" ], [ "Points", "api/objects/Points" ], [ "SkinnedMesh", "api/objects/SkinnedMesh" ], [ "Skeleton", "api/objects/Skeleton" ], [ "Sprite", "api/objects/Sprite" ] ], "Renderers": [ [ "CanvasRenderer", "api/renderers/CanvasRenderer" ], [ "WebGLRenderer", "api/renderers/WebGLRenderer" ], [ "WebGLRenderTarget", "api/renderers/WebGLRenderTarget" ], [ "WebGLRenderTargetCube", "api/renderers/WebGLRenderTargetCube" ] ], "Renderers / Shaders": [ [ "ShaderChunk", "api/renderers/shaders/ShaderChunk" ], [ "ShaderLib", "api/renderers/shaders/ShaderLib" ], [ "UniformsLib", "api/renderers/shaders/UniformsLib" ], [ "UniformsUtils", "api/renderers/shaders/UniformsUtils" ] ], "Renderers / WebGL": [ [ "WebGLProgram", "api/renderers/webgl/WebGLProgram" ], [ "WebGLShader", "api/renderers/webgl/WebGLShader" ], [ "WebGLState", "api/renderers/webgl/WebGLState" ] ], "Renderers / WebGL / Plugins": [ [ "LensFlarePlugin", "api/renderers/webgl/plugins/LensFlarePlugin" ], [ "ShadowMapPlugin", "api/renderers/webgl/plugins/ShadowMapPlugin" ], [ "SpritePlugin", "api/renderers/webgl/plugins/SpritePlugin" ] ], "Scenes": [ [ "Fog", "api/scenes/Fog" ], [ "FogExp2", "api/scenes/FogExp2" ], [ "Scene", "api/scenes/Scene" ] ], "Textures": [ [ "CubeTexture", "api/textures/CubeTexture" ], [ "CompressedTexture", "api/textures/CompressedTexture" ], [ "DataTexture", "api/textures/DataTexture" ], [ "Texture", "api/textures/Texture" ] ], "Extras": [ [ "FontUtils", "api/extras/FontUtils" ], [ "GeometryUtils", "api/extras/GeometryUtils" ], [ "ImageUtils", "api/extras/ImageUtils" ], [ "SceneUtils", "api/extras/SceneUtils" ] ], "Extras / Animation": [ [ "Animation", "api/extras/animation/Animation" ], [ "AnimationHandler", "api/extras/animation/AnimationHandler" ], [ "KeyFrameAnimation", "api/extras/animation/KeyFrameAnimation" ] ], "Extras / Core": [ [ "Curve", "api/extras/core/Curve" ], [ "CurvePath", "api/extras/core/CurvePath" ], [ "Gyroscope", "api/extras/core/Gyroscope" ], [ "Path", "api/extras/core/Path" ], [ "Shape", "api/extras/core/Shape" ] ], "Extras / Curves": [ [ "ArcCurve", "api/extras/curves/ArcCurve" ], [ "ClosedSplineCurve3", "api/extras/curves/ClosedSplineCurve3" ], [ "CubicBezierCurve", "api/extras/curves/CubicBezierCurve" ], [ "CubicBezierCurve3", "api/extras/curves/CubicBezierCurve3" ], [ "EllipseCurve", "api/extras/curves/EllipseCurve" ], [ "LineCurve", "api/extras/curves/LineCurve" ], [ "LineCurve3", "api/extras/curves/LineCurve3" ], [ "QuadraticBezierCurve", "api/extras/curves/QuadraticBezierCurve" ], [ "QuadraticBezierCurve3", "api/extras/curves/QuadraticBezierCurve3" ], [ "SplineCurve", "api/extras/curves/SplineCurve" ], [ "SplineCurve3", "api/extras/curves/SplineCurve3" ] ], "Extras / Geometries": [ [ "BoxGeometry", "api/extras/geometries/BoxGeometry" ], [ "CircleGeometry", "api/extras/geometries/CircleGeometry" ], [ "CubeGeometry", "api/extras/geometries/CubeGeometry" ], [ "CylinderGeometry", "api/extras/geometries/CylinderGeometry" ], [ "DodecahedronGeometry", "api/extras/geometries/DodecahedronGeometry" ], [ "ExtrudeGeometry", "api/extras/geometries/ExtrudeGeometry" ], [ "IcosahedronGeometry", "api/extras/geometries/IcosahedronGeometry" ], [ "LatheGeometry", "api/extras/geometries/LatheGeometry" ], [ "OctahedronGeometry", "api/extras/geometries/OctahedronGeometry" ], [ "ParametricGeometry", "api/extras/geometries/ParametricGeometry" ], [ "PlaneGeometry", "api/extras/geometries/PlaneGeometry" ], [ "PolyhedronGeometry", "api/extras/geometries/PolyhedronGeometry" ], [ "RingGeometry", "api/extras/geometries/RingGeometry" ], [ "ShapeGeometry", "api/extras/geometries/ShapeGeometry" ], [ "SphereGeometry", "api/extras/geometries/SphereGeometry" ], [ "TetrahedronGeometry", "api/extras/geometries/TetrahedronGeometry" ], [ "TextGeometry", "api/extras/geometries/TextGeometry" ], [ "TorusGeometry", "api/extras/geometries/TorusGeometry" ], [ "TorusKnotGeometry", "api/extras/geometries/TorusKnotGeometry" ], [ "TubeGeometry", "api/extras/geometries/TubeGeometry" ] ], "Extras / Helpers": [ [ "ArrowHelper", "api/extras/helpers/ArrowHelper" ], [ "AxisHelper", "api/extras/helpers/AxisHelper" ], [ "BoundingBoxHelper", "api/extras/helpers/BoundingBoxHelper" ], [ "BoxHelper", "api/extras/helpers/BoxHelper" ], [ "CameraHelper", "api/extras/helpers/CameraHelper" ], [ "DirectionalLightHelper", "api/extras/helpers/DirectionalLightHelper" ], [ "EdgesHelper", "api/extras/helpers/EdgesHelper" ], [ "FaceNormalsHelper", "api/extras/helpers/FaceNormalsHelper" ], [ "GridHelper", "api/extras/helpers/GridHelper" ], [ "HemisphereLightHelper", "api/extras/helpers/HemisphereLightHelper" ], [ "PointLightHelper", "api/extras/helpers/PointLightHelper" ], [ "SpotLightHelper", "api/extras/helpers/SpotLightHelper" ], [ "VertexNormalsHelper", "api/extras/helpers/VertexNormalsHelper" ], [ "WireframeHelper", "api/extras/helpers/WireframeHelper" ] ], "Extras / Objects": [ [ "ImmediateRenderObject", "api/extras/objects/ImmediateRenderObject" ], [ "MorphBlendMesh", "api/extras/objects/MorphBlendMesh" ] ], "Examples" : [ [ "CombinedCamera", "api/examples/cameras/CombinedCamera" ], [ "LookupTable", "api/examples/Lut" ] ] } }; var pages = {}; for ( var section in list ) { pages[ section ] = {}; for ( var category in list[ section ] ) { pages[ section ][ category ] = {}; for ( var i = 0; i < list[ section ][ category ].length; i ++ ) { var page = list[ section ][ category ][ i ]; pages[ section ][ category ][ page[ 0 ] ] = page[ 1 ]; } } } three.js-r73/docs/page.js0000644000175500017550000000752612610076566015170 0ustar debacledebaclevar onDocumentLoad = function ( event ) { var path; var pathname = window.location.pathname; var section = /\/(manual|api)\//.exec( pathname )[ 1 ].toString().split( '.html' )[ 0 ]; var name = /[\-A-z0-9]+\.html/.exec( pathname ).toString().split( '.html' )[ 0 ]; if ( section == 'manual' ) { name = name.replace(/\-/g, ' '); path = pathname.replace( /\ /g, '-' ); path = /\/manual\/[-A-z0-9\/]+/.exec( path ).toString().substr( 8 ); } else { path = /\/api\/[A-z0-9\/]+/.exec( pathname ).toString().substr( 5 ); } var text = document.body.innerHTML; text = text.replace(/\[name\]/gi, name); text = text.replace(/\[path\]/gi, path); text = text.replace(/\[page:([\w\.]+)\]/gi, "[page:$1 $1]" ); // [page:name] to [page:name title] text = text.replace(/\[page:\.([\w\.]+) ([\w\.\s]+)\]/gi, "[page:"+name+".$1 $2]" ); // [page:.member title] to [page:name.member title] text = text.replace(/\[page:([\w\.]+) ([\w\.\s]+)\]/gi, "$2" ); // [page:name title] // text = text.replace(/\[member:.([\w]+) ([\w\.\s]+)\]/gi, "$2" ); text = text.replace(/\[(?:member|property|method):([\w]+)\]/gi, "[member:$1 $1]" ); // [member:name] to [member:name title] text = text.replace(/\[(?:member|property|method):([\w]+) ([\w\.\s]+)\]/gi, "# .$2 " ); text = text.replace(/\[link:([\w|\:|\/|\.|\-|\_]+)\]/gi, "[link:$1 $1]" ); // [link:url] to [link:url title] text = text.replace(/\[link:([\w|\:|\/|\.|\-|\_|\(|\)|\#]+) ([\w|\:|\/|\.|\-|\_|\s]+)\]/gi, "$2" ); // [link:url title] text = text.replace(/\*([\w|\d|\"|\-|\(][\w|\d|\ |\-|\/|\+|\-|\(|\)|\=|\,|\.\"]*[\w|\d|\"|\)]|\w)\*/gi, "$1" ); // * text = text.replace(/\[example:([\w\_]+)\]/gi, "[example:$1 $1]" ); // [example:name] to [example:name title] text = text.replace(/\[example:([\w\_]+) ([\w\:\/\.\-\_ \s]+)\]/gi, "$2" ); // [example:name title] document.body.innerHTML = text; // handle code snippets formatting var elements = document.getElementsByTagName( 'code' ); for ( var i = 0; i < elements.length; i ++ ) { var element = elements[ i ]; text = element.textContent.trim(); text = text.replace( /^\t\t/gm, '' ); element.textContent = text; } // Edit button var button = document.createElement( 'div' ); button.id = 'button'; button.textContent = 'Edit'; button.addEventListener( 'click', function ( event ) { window.open( 'https://github.com/mrdoob/three.js/blob/dev/docs/' + section + '/' + path + '.html' ); }, false ); document.body.appendChild( button ); // Syntax highlighting var styleBase = document.createElement( 'link' ); styleBase.href = pathname.substring( 0, pathname.indexOf( 'docs' ) + 4 ) + '/prettify/prettify.css'; styleBase.rel = 'stylesheet'; var styleCustom = document.createElement( 'link' ); styleCustom.href = pathname.substring( 0, pathname.indexOf( 'docs' ) + 4 ) + '/prettify/threejs.css'; styleCustom.rel = 'stylesheet'; document.head.appendChild( styleBase ); document.head.appendChild( styleCustom ); var prettify = document.createElement( 'script' ); prettify.src = pathname.substring( 0, pathname.indexOf( 'docs' ) + 4 ) + '/prettify/prettify.js'; prettify.onload = function () { var elements = document.getElementsByTagName( 'code' ); for ( var i = 0; i < elements.length; i ++ ) { var e = elements[ i ]; e.className += ' prettyprint'; } prettyPrint(); } document.head.appendChild( prettify ); }; document.addEventListener( 'DOMContentLoaded', onDocumentLoad, false ); three.js-r73/docs/files/0000755000175500017550000000000012610076566015006 5ustar debacledebaclethree.js-r73/docs/files/inconsolata.woff0000644000175500017550000006661012610076566020214 0ustar debacledebaclewOFFmˆÄÐFFTMlXêø_GDEFˆ OS/2¨Y`mŒ-cmapzÊ÷A±cvt €88 ‰ Cfpgm¸±e´/§gaspl glyfxa'³li¸Âéheadf 16øÅVhheafÔ$ ßzhmtxfôwŽu5mPlocahl¿Ê6" ºmaxpj, ÚnamejLF”>¢Rÿpostk”±—"úY±prepmH@@^Ë»yxÚc```d‚cWôf‚è“Ü) ôcG}˜xÚc`d``àb `b`ÂÇ@Ìæ1 xÚc`f~Íø…•ƒÕ˜u£<„f¾ÎÂ$ÀÀÀÄÍÆÉÌÀÌÀÀÐÀÀ ”Ïf€‚€4×E%¶þý lYŒY@aaó –?@J|µ -xÚc```f€`F8ä1‚ù, +€´ƒÅÆPÇðŸ1˜±‚éÓ.A)9%5}+…x…5ŠJÿÿÕ+0,` ‚ªcPPVPª³„©ûÿøÿ¡ÿÿ}þþÿûêÁñ‡|°ïÁÞ»l°þÁ²MÌ‡ÀÈÆWÌÈ$˜Ð½ÈÂÊÆÎÁÉÅÍÃËÇ/ ($,"*&.!)%-#+'¯ ¨¤¬¢ª¦®¡©¥­£«§o`hdlbjfnaiemckgïàèäìâêæîáéåíãëçŸÈÐÖÞÙ=yƼŋ–,[º|åêUkÖ®_·aãæ­[¶íؾg÷Þ} E)©™w*d?.Ëbè˜ÅPÌÀ^v]N Ê]Éy vníݤ¦Öé‡_¹zóÖµë;axtÿP¦òÆm†–žæÞ®þ û¦Nc˜2gîl†£Ç RU@ U¥¡þª¨üRurw{‰k„†}fc’nyS]XJiNxÚ]Q»N[AÝ ÄØ 9Ú³™ï…6H ®.ÂÈvc9BÚ\äb\ÀP Qƒökh(S¤Mƒ $>Oˆ”™5‰¢4;;³sΙ3KÊ‘ªwi½ç©sHánƒf›~'¤ÚE€ÒõFFÚÁ#-63zåº}¿Áf4åN@yÏ[ÊCFÓN í¹2?ƒá>ÿË<ƒ–fšžZg!=„À|3nið5£YwýA_±:\ †ÓTÜõÇTÊÿ–æ\m¶63šwp!"?˜hj­@ÓŸ:¤z>Žb rùl¬ &¦¬?ÉDpa2]ÕT-3¾vpŸì,:ؤJsà°Už‚‡ã£ …ô-‰2KC„ƒØ*1BÄ$‡BN9w²?)P>’„1o’Òθa­qä50¨ÍÓ¾ÌfSÛ[‡0~GðÝ/Æ’>²¡6F„ØŽX `‘QU¾¡Æs/‹¹Ôþ3%`yúí_'­;6/emcŒ‚žß6ßùeÅݪ\çE¡»wU5T锿C/gßãO…á ±àÍç}£@í ‹ šÁÞÞÿÑZuÄUÞ Ùo5³±ÿÿxÚܽ |ç•/<ÏÌh4ú¾m˲, [a KÈBc0ŽqÇu]×뺮c‡>BˆãR—úR¯/¥„BI¡4eÙ\^^6/;’ÚKÓÔm’¥i–ͦ4ds³Ù.IÓ”M7M{³iHlqÏyfä>zßû»÷÷¾$fÆÒóœsžsþçã9bX²åòEv@×Åè™|æV&­'L8Ãé&JAD!ç3:_i¿Æm:"†3¢À8ù°"F26z–ò’pÊ&Úì㬠çæy’Ì¢ªy‹«£n§PÂ-NT{¢nÛå„{A®’-«ïX½úŽ˜ä]áO˜™-½³ˆ·EššùWâóêIEدx"oêgluãà ðÌ[\ W¡ë`¬ŒŸ9Ϥ <Vòc«Ža þ(QŠ# s>Å‘°"D3f‰Âu³œ’ad¸èŽf ¦ Æ€WÕJYIY™Ê˜c­|®œ^öÞo×3®°QRY!ŠUV,ô9¿ŒÏÉþ+Ÿ“eÅ6¡øe¥Ÿ—¬G8 Çâû‹ï ’ÍždƉd+ª„dúLYoiælvÅL:àw>Ì‘¨N,.‹/®ŽEVVRGªã³_¿Uá$R<L6T½_a7ãYc·öÚ˜§Ó™\R»¢éés^ÝbŒ“{IÇ3^ÆOƘ´ÈÝô1…‰¤yÞX,–!:¦œ§Y[a4M3Ä_Á çä"ÿÒ(å–ÓDÊe¼¤˜'tðØ8[ w„Ç9zð¨äËã†|NÜò¸Ñm‚—<øèÁ{}tK{[K{Wk Êvóåw¸×t"é^ÂüIî¾X*¤»H5]ªZw‘(Ijæ Çuó1LåxžœŠM@–¥*Yþþÿyí9UU…eeÁD*bº¤NœžwôÅo¨—9YY4‘ .)ü’D% ?RÚåïß{ínÔ.ãV|9îÅcŠ[$Ž/³4\¥Z¼Iæ{œdõ./Êi rÕj"b•6{Z „’ɤb²)EÀ‹êpˆ1å‡(e¡'ôŽê„j1Aïч$ÔxPGˆD`©à"A5ïÚGžØ:ô¯Üñë:¬ o©;uÇ®SßÞжí>Cö“öžÛGš>בL¶“ðÖ×Wž|hð±o ü ž}¦¹G4ð’`6|iäžÓ_|ª­ïÔ£]÷ŽI컹ÿphGcÓ>ÇrŒka÷P›½QµØš¹&Š|µ­NÙþ ³,M€b•€pô8Ûž‚%‰¹v“«pR»¹*v…µ„1ú²skaŒ&Is0F¢8öÐ ŒÌA”Á½ÀºœvPDôÑûµ¢È[yÁœ~ñ½XùÁGlyvÝÏ ë³{_ÿC¶gxãv€. aög³uíŒ?CO?CŠ(Üù”>ÃJ?ÃSm/fC 7c“Ýþ—?xïg¡ÉüìË—™‹›Éƒ¿y‹ìÜ´}0˾Ÿým¶ì+êûv0¯q'øccGBÇÅ$¢çJ=:¢7‘鈓–À1Vdý¤1ž=JØ-o¼½™Ùs;“ f¿9û÷lȾØE:²'ºI ߯‡y…;ÆG@—µ3€'¤Ý4,0ÂiÂà)áÐ.˜#Šñ¼ÂFSXR|4m0â=ƒ3ðÔÈÂ) ¡#°ÅlWÀ´õ £¤7{t”íÁß#ÙQ¢ÒŠ´g³ƒÌ9Ff0i™™1i2c‹(öM¶îþûa\›'÷3¯NŽÏ d;èõYçñUˆ9eP…HCÃd3žýý 0ޱË'¸í SϤ ¢Z.‚ƒÀõÁ‚†Òͬ N]\å ö,ž³„®–P¨RDõ¡œÅ-"ˆ€ÊölE£±¬?¾yÿñ¢í7×Ý<²f´»m$sàÅ»:û‡_SÎnCF³?ü؆-_ç¾»kÛ‡ú»v=óžGÁÌà¡× CýÜ~¹ÇA~`-†Áj¢³0à c2°ðÊb)t²¥6Är^1DQª}4ÍYpvœÚ×Âá©dP!Q41(†ñ¿øç£(†¼B*u ;‘2™/ñàá²)bASÊš4Ÿu‰Ùb® ,Ò€­Ÿõ?ñÄìäˤÿ..6ya{öéa—©ëd ø²—ŸdÌV&íÏñÅ|q_ò%¿ÃBYD”Ê”BX†AÍüçOž§¤¼Gû„.å¶\’Øw»µ‹ÝáöLËi¡ äÔéB9EÖ3ÄVHмô!Xn¢ŽmG? zïŠMÚX¿=ÒfwNýÁ5°éØëo?9øÂÉ^¡”—"K>¸ïÈŠd)»k4»¯ê­3/\¸y² 0þ˜Îó«`™´gX 3Ôá Á]Êä…}:˜aΰ’*S°Ä%§æƒ®ñÂd#ðÛ…++˜TæÛž2êò|%¥²½ö”¨Çù„z3^âpk<*&MÑS˜—ÀµæÑW’P%èO‰ÓÓµ'ãÌBe Á==ñ]K¯m;úå£U«Kƒ Ý+clx_ûÞ—^y´óÈ’¾æG†ºGwv5ídß{ìÈwîÛ$yÑ•'¯xz¤é³oeÇÞíüìÃï(Üsp/ðö(ÈãðÖÌô1i1')3NÕQÄó½À¬@;(¢Èé¤$•µ5'~óš*oðV¼5 À[ã-•RZg4WꀋåX.h {”=7¶eSïÑÁ±®5üÐζìkÙ—³¯fÏ‘.ÒþίPîзý-·Sg¦–­ŠYǤ]šmS"‘”G¥ÌÈfäÉJÕõ›"© ½”*¾Øát!Þ2£Ð)X´ÙŸ2p.o±#Y©²§Ál/.ŸFÝ•$¾x®Èy;‹ËBµ‹wåÐö¶=ƒ]ÎìÛ󣻿´yç…cÇ~¹ÿ¡u<<Ò³mqde½;¿¥¨³ãR¿é'ñŠ£=cßW¶÷«Šýèîý/žù«¾£§…±U‘®dØd,ßÙÔv÷zUWì†ùoÿÇñ^&m!ªAW-;˜ªŒ/há@.}HŠ…”Å0Ùb9U yЂ©bË”UN¢?þ”ÅÎùÊpšŠhWBhÅ- ŠÖ¤â³)r2UD„Q-‚ê¢+®GO#”€5ˆHT'f<x…$ØýêÁMÏDÂñÄy¥S¬¹­e÷¼ˆ¾â¶½/=°£§ñëayß½=c\ÿ©÷wïýÕo÷îd³Tˆtvoú‡ºæ ßßùHÇêÓ¿9 óV±×XÌÊ$ç 1ÅA¼h×| r^£S̹3ô4f!2v.2[= Ÿ±çÖÜtÓš›ð3).…Ï”Ã÷¨ÈTÉ‹dœÚ‡åçÀ©"ÉÔÞdìê§ÚaÄ2nõƒ‘ì¼H(;òÐæ¸mi“Ó“ÄõŸ'MÉk`ÙéñÍ´åtW"[Þ© ÖmÓÇ)ü.ÀA]ŒB"VÇÌç1¨‡Á¼Õ²a_v •ÏÒÃãFa¥ê™‚ʦRŒhÐ×=Ÿ®yò×LzFFÈñ‘Õ¶´ÃIßtçM7ÝÉ l9w ÑÝZº’}ieGGû½ åÒU¥=#}í“r_cc_£ªkêÀÆ_'3•ÌrfŸ†¾Àâ‚‹ê˜/Àœj"\)^*d„ÕÑV1¢â-U‘Sf8ÍKF£X¥VÀksÄfÏè¬ÞÒH“-š‹£tˆÜü¤bµNR¢ö”É„©±¥íÅš{±ØN ÊÈŒ£2ÆÈaµ'†ôÀgGl@øJ–ªzi9[KУ¯ûâ¾ã]ƒOWUlkûÚæÃwö´?^ôÝÁ†Ñõ+ZGܺõŽÄØá|g 9vÛªH»G’Ø’ÇÛÙ±c„?xËW6¬ýq¶¯µ÷ðÝ—úÉàÑúíçvì}cûІ;:Z㞆/F*|‘šPd ÐÐ9˽¡³Ãj02£y' §Åb`’],#Rª¤#Љªk=";9Å£ËêÚ¬Êù²mïÚfDô2ÕÓÏÍ»HCñ)½QDGÃ8AcV êŠ< #>†^ôFð(D<âu^çÀõd©E>E`5ˆãÌ" neŒ¹çp~òywÿƒÙ Û’®§Xóã÷ÈPvy›ü†ÚdįÇ/Ø©Uº]ó›`•ÐK…Á*ûV©xÆ*9Ð*E‡œÊ‡™bȲ ²^³P¥˜"1‚øñÄ ^*a;EG1[ ê¡6XµÄz!ŠiX=T&qð0sçýdÃãŸíZsgçúolè>ùúß”¬kº¥¡ák/ÿthëÊUË“[~ÆOCtõ –žÚ¼öD84âõÝ×Ôøµ€8Ö—HÞž—¯Å^ÀöþX‡^fŒIÕI œ:Y¢”щ¹a!ô4ù ØÆXèÓ ÄrÅU_VË.QWØå´£TzÐtVru·ïY¹ý\õý¢P>Ö¼çÌÙý-†××¼0Xÿ—£·×°[÷ÿÛÞÞÒ]ƒ«I¯7Z>“ýÕe_ïhjì¿»l;_Ó5»äí$ðÂÚ·FåDF¢‹UeFÔKªZ®”SÃ…8扢Pà?P––ÝådUâÂÒrÈ0ì0ÙLÊûw®¾oßýÊ®±–ñï“#ñÍ-±|Ö[Þš}å™sÙc[ÜÁÒDZþ²Â‹´Ù >މY­É‡!'<È ”j$Ìtt¹ð =LàÕ°Q5Τ—ÔÀ’ú3ÌISìgê";Êg·g{Ʋ!-w>w;|®Y¡~îµ?ÓxÏX«} éŠ<ÂþrJ!odƒ|v$»ydjúYÍ 'á]˘{Ô¸4zª| ÇPè ðy…øy!úyNø<§ŠÌüpjˆ¦ üøÑ…ð¡èG88XtN¿Ú„Bôüà/øÐ6ŒÎ+„‹J,—ŒÀ,ª1`CÈ5¯Þ°{krëó‰³Õ?ÖÞùX¤~[ß·†7¾C6fžmÜ9ÖWËn>òÇÝ_,¼÷öµ¢¿ás½]Ã/e_ݽ¹•DF²–ó×ìyæˆòuäËÅ4«ôTl1JRźÌiCŠŠ8CwÎ'J³¼>¢k–}W›p1c˜•`<ei¾Çe À‰O‚pºù»¬™|ðm–X÷e%~’—9+±AžÆO"lÿÔ•îÇ`LI•-“&[à«Î°ô76Qõ‰^Ó'¹Å sJëéJÖ€·ŒœaÕZXÍ)Æ¡ð8 6Š€kçqÖhdׂ“vÇ'Ϩ:õi|á1~BŒºÃ £Þ0PÏÔ3Ñ$iJŠTs…ÿîµ·¢™²•¬ù”IG=áÓKÞ{óY• ˜=7 ,5_¢ˆ¿3¦›Õø]°©f–sÁ^[Ì@0xI‚ÄÖ±…Ôú;³ï&²YõÔ^vð†{~*K>™¬‡±®…±…±[ÐS¤c7ÅÒ<ŽUÓxL¼`,›à`˜žÐ©) œÄOCÿú#: S%¯˜'Rœt ÃH¸ æYñ£”ÎhCË ž£à.¡¤ÕÛ`¬k`ó²¢Hî™:ËON¶r³U’>IpïM:©ÝªÝù¼ÎÈ8™ùÌÍàk¡Ý*Ð1]`·¨‡:¥œŽV‹³øµ\ÞÔž.+Y@Ü8¯T&aL#ÚeU-ºmª¿ZÉ:(,Tý-Ô”[³¬wd¸vÓß-km©9³¹vÛ¶Þöš¾ ɦ±òdUùž–Ä}5ä}Rü›=}¥Ûî;”ý8{hÛ׿߾ìÞ÷úÖDG×ðÏ^ݶööªM/ª˜íÜ1Íþ6̶8`x3f‰ZóŒ FÜ#E‹j†õ³ÍpJÐ'g bœ0±qY(g˜ì8ÜÑÕ×ÛÙ~p’%l_u¼¦.™¸ãüd¸âÉ3Ç+ʧβé|ߺÚú»}^¤qöUJã ³„éfTº.e•Aü¢¸£³ò¦˜-ÌdKS‘yfG‘ì×P::**ÆQ¼Ie±mœ1ùËçØ"•èz ÷WÇôa8×Ù»wˆ„¾›}û£úb‰¥µËâkL ëß~Æ?u†Ía,µGëaý,X%±¦mwϦUž¯,xddz-Ûx¯l¼»e°Å>VÛsýW·¬"ê|ë@·e@·é™¥ ÉÓ« ãä\”&å„ó¨ÈÒ:M€À\ZÐá©€Yš™(æ&븡ìÎ}üÈèè'£üvúþ˜C;JãÛ+4û.iöEqÆhL[Å‹^­:3Èh/)øbõT• ©sPtƒ6F#([ÌæTËT[{”•Ä¢ÀŽÖ–À.GqüÙÁ¡ŸÄýò}®D—Ñ69¹meS[kSÃ×¹“?éüÚ²¾;ïìK«´ˆ?Gó_C*-À¯'“Ò„¡•×Óáà>QÕ<¯&ÅPxŸíyw^p,^‚þãéeß{—):Ñ\Jp0u úÁ -€¢úŠ4J$;@V“ê=ÙŽz>;æÎ}< c ÂØÞ¡±ä³êŠK‹Xr¹ñ z:>¬VQG3qö?.ª£ÁxެƒQ¥ˆåœ¦Ì–K§kÿåwßÑìÚR]Š•iäêôOäßýJø*S&pˆÁNé —~ât]òCI½'`Ñ–Ñèm—ŠX¶¦³]bÐØêŒZâ̢ŅÔÚ¯«+¼pÎ^‚ÿsA wì:[ñÒÐW~¶äõ_Ö€y;Ê1““\ÿÇ“ÝÊåíîêÿü^³ K¤9@é@]L®#¤à¢ˆ*tZáÕŽ¨,*­–¬¾°'uú§}žhWL@µqÂè¸ D Ý8a ŽðœÛüôm^pX1·äëÞ§·Mò¸Þ$8PûÓÛú«n§oÛñÍ™qÂëZÑ£v¦Ñ Ńþ4Ò“=qˆ˜‰øPöi²þ¯²ogßcw³ƒY/y{jïÔ ù8+ ½’@¯€^"3ªF{ç ´Æ˜ˆºöÈ4öRt3âmÔ`Øßü£Š¶@¾ÅiùN¾û«çæÊ7¯Ê7 ¢-â,@̧yò z"ùYJ fù6 ­ýì†ÉɬH>Òôê#”ó®<ª˜4„US'9!¯Þ÷/NCC2üT¥GTEhð•°‚>ŠQ¡ª]ò8 ÄzˆV{\kÙ±©œ“ºŸí–‚;Àç|ò¶ÄîVk*Ì—›¹.]èÇÂêÔ(,Q£°¨ ¨rdrÊžê¥ ï•+–V4è±5!ûR¹ªÉ%‰ÄT|†>õ6îið©ã˜sÍÇU¦7S¢°ì¬Zy‘ч í–pFO/¥šJ FPüj4Q,F1˜J o€C““J¾-cµ–TÐü^¸Ýî‚d2eÑk©°EU‰Å!®Q‹JµŒÿLt91;„*+ÑS×|`ÓúÄáÛúýþÄýÇšF^Þ|’ÐkßW)³Å )=ƒ×dõ€Ç‘LôåtÉœƒ®·a˜½ˆ¥€àŠÞ0†S|%GcMÛžä%3©8Ôݸc㊆{ã[‘XB/Æ[j}•­µåášÖ:Ó½Þ|]»Ñ"JS´|¡fðôÖmÏm]ÑÚ°üaϺÎ,W4noïÝÛV%ß¼¢f;ˆóçN3^f1“.˜Ît²j<(…T'Øar>tš¬. U½'BU»Ì¨!±Å•<Å¥nšЗ ñ¥Í§’w{yõg+ÇÒÿu×þ;:wÿãÂcÄÙÓ>,-î?ï™ÃOüã½û æµ_^/îbÒväE©†Dëu ó ¹p¢Ê ð§Ú&{$R¸h¤Žƒb‹R†ˆ>>]í…%X—â‘ @Ô•bq¶âG |°¬–¨Žl"çÈ&rnTOÓÖ±Õ}·ˆ¬q¿Xq¸«it㊇bíá–¯{íÄêÝ}K¸£­Š¼>úìÆê/ÜÌÆÌ³ôIm,è ·µöÔ ýäÀ¦£íe}íµ›öÔô~!䇮ÉßrrÏ0ùL)Fö=8e»ŽÖƒG«"˜…¥iŸ²i‡¶€:´>-š‚ß> L޳ÓÜ–Ñ–6c=ÌÙb×j;”[Š1jY6ša ˜©e˜Žu7pšªÙ²¡E6pSwò+oïï¿­}øÕ3?̲líê{ÊÛÛjÈ RÒ¼£{ÉÒ@Iÿ¾¦À]m{'ÉÍ6¹÷æÏûj‡P·Ž¾xteóEµº‹ ÔâǼ¨âˆ¨õ,´ÀÁaÂÂGDñQlV(ÐbùBÞ+,ÇÂWˆ§>&ÔsÍd;â±x®–ŽÊ)½à#ªß1úb¬êÄ@fÃ*ÞÄò+Æ’AËžÝÃNõþl[ÇèNQ´ë#5kk\=4ų“j Dköw–;ÃT3MLó“^Œ5“5j"©!’*ƒ9FR-ð«-¢8bp'–(Ÿ(†ó©f?ƒ¹–œ4ËJ1"K^-9ç#˜¸Ã³f9ÕŠ*C¸8^—ß*Ò^ª®4'`r,MÈI¥Õ¾ÂXXd^°¸¦aõ-mè:ÖÙR0:Éǘ -Üi¨öG˜²¿Ì–bWÃí–B qÁ•6[ʾ¦b¶+œʼn²Äâ\µ…~ü °Ôªžî'.äjw Ã¥DSK íªæF—…;V§/.+i}¬…¬¯¿ùå=cÝkÿR’Þ®æÈ™ÝµKëI"Üm_V´Pòu•45GÖœ¼ç™=­C;Zºª“[¾Ø_3T1|bxøÄØæ¾òŽž®ðΖ]Ïvž óMc?ò$b6#jl³Õw÷ŠX_g|l¤µÔ_^ÕRºBx¡Ž}ÿzåm/0n+è?F^¦ãæ¨7Lù4(dB½Qû»·ÈÖ׳Cµ]Ë—wmeOo|i+¢«¶¶«V­¡Ëæœ0Æ<¦˜¹IËš‘PÉ>AþޤÖ=EWàx/l¼‚9XQ›ˆ¯áŒÃ“‡µw÷ Rn*4¶ý÷ ÈŠ9©QÛb©Ò’Y Û:¨œØ¨œ(65 ãœv¢ IT]8òÔÕOœ NÙ&NÿÃÖW‡UDkDžÐ27Ú<n¶o9n¶™p™q½Y¶©®Ùb•gêBD†*:…  ˜‰¥«ý †ôwgÍ"y%¼2žÝJ^””ìè6V×avÍ“o´1»gê%¼1˜=¬Õõ¼gbú9)ãU)£¡ý?%[¹L]\ó\G‰3ûyœØ·ò[?)Us7­à«= 6mîQ Ÿãô#}´ãùDŠ9†Õ¨N @m†)µµÙ¨²@-—ÖÐ&nËqÂÊ\ˆEU (ÆD!©¸ÔŽR¬´â Imuª “„"Ö‡>%µjzšòš>mÝX›¨ý’Ù;¸ª?j·±˜=±šªò]ÏÊúJw¼'Vwë²Ú–[¼-±*yj-{h½/ÖQß>u€ÝÝãoêJ´NíÅyîÆ:>˜g樨Î1ÏžeÊ9‡.P'W clVÅbV¾@Eõ)'ò™›3‡«”ËîƒqªZ‚ßâó~ßæ£Ç7þ59û )È~üÎ/³$®7Žýá±ÌO~¢ú Û²'¸ ŒËÉ,d>¯æ!02œ†›aJ»´€#œ#¬È¥#R¬CMp–hóJ ¬bNBq˜óÁÖ¥MN­[ÑH8ƒ¨mœ“š²¹˜ú‘ÈãÝM;6­ºiË®æÎý‹XÖböÞ×è_Ù¾<\±¼½Ößôeo~öŸÝÛòÉ-Ooynxykc6Âut6uÖÞd©híèÛבn^‘TçÖ sÛÅý´x€édÒÖ¢61šbÏ9I «N,”´«úE_Ö¨Å7MˆÜ8+»¸êÍÉiø²úÛ†:‘ÍUj0Uèüñ“ÒîýáÃ]G.øî¦–Ñ<'ñøv¬^˜¼qp÷;ù]Ÿ°ä·­=Äù‡Ó/"=R×Öö$Èï‹°nO€<»˜e¹ÌÊŒ0Ks’ΈÓ<´Ü›AäiÀÑ¡–RKbúéÚÚ2=8r¬Ëöâc|øëö7Ýl⎣~?Ïr'2}ë×îƒ|#ùN¤³ª4› úc0ñÇ"æ"“Žh±v X&_ƒÂÿÝçS¥XÓ¢Òn¡ê€¡6~·öÙ/«n¶“©ý’R>/Æ%»4®•ez´áQ ÉãóCåà‚ÃqÆOÛÐ>%ѳ•’Š5ɬ0Xä b~ù¬-׸HöR7¦É0‹ÿq1¿$‚àm¡=å-B®–¨q··pa.î/䪭CêçUx6;ì^?iCFVt®ØÙ<ðÀm¡gœ¾@[¤ü…#¯îè4¾tgWû½=¥Õìz9óîöý|‘Þ»hIÇŠ– {Ò`”**Ú+6=¶”õ ‘¶¦DcØÞhÝ9ø·”î{/¿Çí០¿‡Q/¬1bAC bÅ¥ö½HÝ3$Ñ\; w\˜´òü¤‘šÂbš“Õ¥ÌhôÄ R,³Åœ·Ì"ÖG¥8(øˉsñLmTÊnÀ)WúD ȃ"Ö«„Ðü–P% ø/û¯òQ–5²ùˆî킱«¦w°bÏã{šò x'þ¸Àlöˆo ŸúþÎÊÖÕCë‚ýõ‰÷sÞ>ðî8ãì¨e>?—ÜAáW¤QŠÔu2¦I±D±üfH]E ‰Hǽ¨ÊKb3©ˆ¦"À¯Œ«¼¡²íìþ ·/Q?(%Œ‡y¶âÛ]=——’ÇYãÔ‡»êãËÛ–5ÜÇò“OƾðêÖ®;º;´ºÍ˃¿~œ±2ÛUí£K3,­ ¡µ¹Fš+×vý~î¾ß<0ê×ËéW¡rÊ*\:½ôܯFoKpŠ Sze3/,•j'žJÖ+£ónäqT'bØ€ ]aE–Hûü;Bku/w\ôò‚0ÕAz.=ñþÔoÕñ@¿¼ãw3/3i7ÒÚîpÑ\ÎA†9xry”Tž:‡×ý÷êjèt:˜€ §ÜºK§—/ù=K'à‚ 8'R:AL n˜€~âôONýû~~9*S.§÷¥”A¼“;]÷ùŸSïÙ+%ZX`Q ª®#ÖÏôò!X^YRÑ*ˆ,ïŠû›“b_vÇ)ÖÈG:æx,P“}½4ܽo8ûÛ1Á+z¼Ëƒ77rO}fÓTùpß›þjrr`ÑÚé<É! ÅÕyöêË1¥„cÔ*:8©ù1Z=Œ¤¸™"p-<€Ã ÍÄe@¿À¤¼j\¦î/?²©vÞ++ü6Ò¡PÔ+s^;ØÜ÷Çÿ‹Šs`Ò°Yãv<êÆôE~ms£¾‹ ÿ¬ÿl¼ºñ þJÃ¥Y¢_’LÃ[à™!ÉdDƒ½°DƒFއ—ŽüÂ’à•Ýl‚›=cbÌ.7zœMaUG¯“|VÚ£%„31o˜èC‰2ôú<‰ôOžõíbíœóH{·HÄdïm‡·Ü¼ãœì¿¯ðЩoÝs[×è16ò‘MoKf¿õ¸ÿ? R¾ØX8µøÞ}¿¶¾&̳c?,eŸŸYm»|{–ŸdâŒÂ¤ã]¿ø"‰n0HËZ]*—‹'"è gLb\¶„±¿ „ý¢ªiYÐ<ð æÑ,ò¼€!<î›'ˆá\ÓÌÙ”EÓÜ·@õ`Q° Š6ôÏòkÉü Æâ **±o ZÒù´ÃˆqñTIm$«-€ËY »‚ñ˜Z05½±µGÌtëzÌ7æ°ŒÚjJCr“牜;pðÞn£E7‡ºG峊—Üì-lüùÒŽUÕë7Ô½Ù²þ[^g óî–ÿ4ÔœýóýüGôŠ ë—º©EÔ;áÖì‡Íø0®«W¿:£Ý‚‡ø0þ¹ÿütÅJí áá|8 4k˜“i¸ŒgÖd>hÖ-G2 CÀ3w’ùщf«Ã]0ÓÕåÊ+ÓåhùC ÌgxÌf`»A_Òç2»“5C̓kÚ›kk¶4oi_»®cK/MBƒ÷µß±¶}hõ½5É{VoéX·öó÷4m©!ËÉ xÿ+êÀæ§AOå1¯ú`³ëf26»•±ÐR}›Êks4ãrÓkB cAŠ¥Õâš•jqM¦`™±0Ø`ˬˣu#¢!ŒÐ-ÖÕå¹ ˜×œ]‚S oú×ú霼éœ%¾i¼n NÞµJp\í¿`< ý×ü]RNlf{ö=üÙ½@üøÃg§.²®©¾ðÐè½/¼pïèPíÍ †ÑƒO­ÕÂ`á?Gç´×0e8Ï܈†ý»©¥Ü>öõ©Rº†v\ÞÇuéú˜¦™x%Á$¼ЍÛ;n³ FŒ˜h[' hhUYMUcå%ü´¨ÔyçÛϽ2ÝYÎ:‘ZÀ~åÄéßl|n”B&Y¹i"µPº¤D&Æ+F@ÃWânŒ76Ý/Wã1 ·f‰ie2 7ñlu’Ya¶.Œ,_yS“\QÙ¸ºrNˆëÞ¢a¢e˜Äã àž6¬°Ø3F[a(‰– Ú–..]Œ¤*ܑ¤BF3Ê÷Wçvè³´T@‹Ñ zÚ&WÐlüŠÀ‘>×[Š^©¦éÒDvl0ÃòÞxO¼gsoùËñ±ž–]{þ¦j°ª|{sëúM¾ýåOw¬{þàÚnì6“/û¶ç—ÇêFX³5£%½«º–zêü­_i¸ÇÛ±ë“ýkÉ® ßÚ³²o©wtï­Ýäí~xDéfŸïKÈó¥PÇÚeR¹Qj¤ü~›ãºvºÿ¸^Ý÷‰ËHO“JŠ-Îé}ÈTð&,ƒº«Â9½9·[3·!ùíå55¤ª¦sÙ²Nþ™Îåô5AR}Lˆ›äk#ã`ª˜Œbˆàž®rxïHDë5†áGm+¦æäËqt/<:àn¸n¢EæØ:,¦¶“Õí¨pî/uÒnJ`²¾'Z8»§`a„¹’ù6û £`²ÊÎÆ^¨y3±(ãr‚S ¶¾¸Z.+<Ó•ÀqͲ¹§a™”œ=K‚Ù׳ë²ÿÒó;Òòþ{Ùôï•‘Þ=® V]«*Z·li«jww‡wÞ9°7P·Œ$6o&'ãwD³I`9Âæ5k»;VÆÖdëWumï ¯\éMV” ÆÚÓ‚áöq1F`,Ì¿3¸ÿÔS؈bˆÑ ºó Ú å7sMD¨¹fÕ27V5Ñ ïyù÷ªÎbénT¬Z7§ÃçtZÝÜË7ÿbåLxlÞ:÷œÁˆÏ Úûÿù|õ9b`ň#és3>g¶hïçúŰúœ…æ2Íø:‡×‹&M£Íy5ÓÛÄ£'zí×.²ä3GªŠÄÛ>‚ßäÕ©èø}öB;éΡ-=Mê¹6ö £cåv²çºbñX"äú ;€Wy è§;_m§ÙclãhváÿüþSüœud*™ßÍ^ùÅ,¾)Õ1ùà%JñóN°À•‘ŒK}b–ˆ\CU 7/ªéfÅÍ”«×Ê#è¼ÌR‹f¡Ø ñkõŽú7ÿIõaŠe%¦öEe”¢J’* hF$ˆ£ÁnASQnS¸¤â·§%›Hk€Åj³‰R[š1 øH¥=%{“×Ñ1[,·y¡ç‚.›VÁškk˜ç~܉-©õmß¹¾9ª ÜJ-Ú&<’‚ó(œ@­tuå ì°øTïãthûÙ'T5áBÀ™2ÊX7EµÁ¬Û•°ÉƒÇ4œÏ‚Mž$Ì d攘g0ºÔFD4Ñ0÷5lóã0Ó¡š·'%Ÿ=ÍÁ™øˆÚ-E듈/çhÓ_­¥Ö[‘#½Ã‡ú<¯7!³I2O=Zß°‘_GÚ›}>ÁÈó›Ûº¿Ñ·¶Ëy¤E”øÑîĦd;ßÙk®*½"ÊæÛ,ËÕé¼L˜ég”ÐÁAŸcOQTù‘LÑL{,ÃyìGBF;–TÃ÷7Ìa¶YPº8B縲E–ƒ¶|I ¤Ñ`O|:Õ~e‹¬’·×ˆFcÃÚæ ÖÀ­KüENWOkgýà­Í›þzËáúXýçOoSØŒ!CiMÈÁ›¿‹­ Gš{[¶}1Ñ%ïXÙ}øŽòì«:ìlWŒuÐh×Í8ÄRWiz凇#G3£/ñëIegö]ºv«²'¸¸ã€ Ö0éy˜—*Šå– 'ª¦öy––dÑî-4WkäÊÕž«´£4@Ú¶C „BÒpÇ£‰– B*.ª¶ÓÍ=svúÐ9uÄ#„JÊÔ!§¾Š íôùº«wxÇäürB2/i¹«þKbéζ–‘›=±…LîdS¯ Õ&–5ÕÖnfýSþòX~þ][HÏÊæÎÖ†wþ-×kˆ|jÅZZ/þHÚ¨›^‘¸ZÆž¾hbÔ d xZù¨n_žN±iŒŠ=ªc¸pñ¿J2¶¹àyÂl=ü•Ãç¸úž‡?êÖ}|+2þ#Ýs°™­bû9/è¹JªåÔþ<7Ð(‘™Ûއêohèo ïYŸ=À¡vc¾÷vcl"íš±nl0†-EÝjûofbWg‚®«ÙD;Hzq©£-Eì˜÷VCó$¡Š3˜DLïQ Rë¾'¾ bq­§ÛŒùjî»ë٠ͤÈåôìcy‹oUMÚÌ ì€Njz™Oë:¨ÿ˜ÈÝcÇ?:ù!{çbf.vÅ~Âm³±«EÝš™Á4 -Öái{àzµ¡ŒfjT—0Öë¸e@¥z ­ ͽ¼qî‹6«C/"ÎÛNïVNoÛžùêæ–æ»7ÜŒ°’]þäk?:ùýÎ<9<6ºmd÷î+ñãû9üÈEhvWÂÂ,uÉOAÚfƒÇ¹›)*¿—…j+“™½svŠœ>÷ 2Á¾ŠWáL‹Õk¸°ò§¿èPßROñ# C³ú"L†¢Mú–ÿéçœÚ/EgCMæ)ÂëÄÜN/2çU®) %ˆ‹”ª¿váŸ!K²O“ á?j#‰ì_"þßwdÏE²ÇÚ§ÏpmòŒñòîeÝz ›‘q1yÌ«LZ¤þc[¾Øb7EqŠ5š6¹qÁšÈ¥Ý&Ú¸ÐbP[MéÏcKĈÐ8•QœÑŒ¤Š½=š–hPF²ÁßæÑ†yØáÀÅ&Ö¢1*UTê1ø&ªÒŠ£[þé°º•µR‡ÙGwþ%L(›2çᆋ[3}9¹N‰n,Áâ´:”pñ„ÖLÐŒ‡bqãëëßÊŽöO¼Cšêî¼³÷™ þƒ/O=LÞÿI‘n0ññÞµËÈÙ-ßýnËtM/¯ç>ÐhVAŒÓÏ7ú¤0R m›7ªÌÏ!bÚ†ï**áÄKM4P WÒ¥6$L©°BäFȺpVstß–L¤\îKŠcbÜér8°·Ñx ¸0gæÀMO9œ®â@IN¤f¿šMA¾&ÉMÛQÒ/H¹qÿE6 7Ù ÐßL‰Ò5ˆl ת5†‹³èNü¥£7÷m»ÅžŠ“°c6èŒwò ‰ž¸ ç¯`9Y×¼±¥½Q­Œì]M‘z¶±¦¼æ&Á# L{¨Læˆ0K™ZâfÒõ1qáŠæ¶hTžIchk2y꫼^—öÙ°SØg8*_gŸæ€k ñˆ×möìÓ˜£ÞgÉcNY;fNg‘3XÛ±|yÒ®sYGmmÇ Õ”Ëd?ù ù}.ï¢Ò®Ö¨“)bÞaÒ¥œÅ†”_ÚËØUÊ9P,1ûCq¨zwŽÒmf©j3ƒc¯T òIjçCÜPBi6ü®y6Íl2þ=W~ñVJ3›SÄN³Î IõotŠS·:¥Üòubñº¯#ÍÌN•ff+–†Î’Ú—ÖcˆIù°?-oð$Uù¤[ïTl¢õ€4‘\lQð“ï7õmþö¦¾fraº'ägb7E£7ÅXþCqmcóúõÍë„O̹&‘äP<^?€3DP€¿ä³ æ;¹<ÖXl¦ ƒ¶pÉH2mÅ#ÑF}æéF}Nl®ŠikQÛ°M‹Ó‹,¶ë±]ŸK%g­å·¯Õ+ŽJ¬Îµ/aÃI¿è7w9PÊðÈ=ÅÉ*;fKT «¹Ú ¨¸[$ßboÊ>Î’pöUžtf˳n~àßÝÓ=Iwöy™=©õüÈ ý"—âÓ\›Hì[© JM®a¤â–±O¦LZ,¹¨|¹Â 8ò‹åáx5-•å€9Ã3±¯dÙÂOï+i%¹xFIhV˜ãºÍ&ãÇûMj¬cçÆ\øÃÙþÈ®¶?Ñ}²s£¹U‹†Ü¢…G‰·|+;Ýk'Ø:Œ5jçGùÓ:?Ú®êüHÌêþ8uÑÇ4?tÏðøß3À³Çq,iÏþ—™<`î8ìÌg>mŽO6 £­ÌÉ«ÆCíòì!õk8ÛðÊ[3ƒÚE-2Å$ê¸Ú`\Æ‹ßBð§F†+  •?ö +¼þH-fºN•¬ÎL¾úJˆÒ]â66Kr$¯œsE’|ödz–uÖÖv’X *ô™==;sŽô¦½!gø~Ýîò u‡´]Õå/×!rêßPø¦ûDRÔû¿e {¹1dË©àÍ ¡çœ1Ø™Ïý‰18nh TîXìM*Ù’*œ3*{Ód9 ÁÁ™AíÖÓÆ•“»¯]wd×¹Oé¸ÍÀŠ3 %rM9¤í#æNáJÑ›žËáZ¬Ð Ñ”²™ =s¥ÜÕ¼N󓀂ÌÚ^;{®O¿Va¬…¶4åV¥€V¦É5Ütç¦í2NÄ^b§eºSYÆ9ÙÕz,£ vÕïLóÔ@olN×ހ͡¶–“C•l˜``¡öRØûÚÍ¿óPÇþì䨶­ÝýC›nªÞ÷ê«ìº­¬Ï_Ñž}åä¹ì©U!v}Ö¯ýÃ!ÂîO,³=[a^´§$àv BÏ%×UÒÏ«•ÃsÚKÂŒ0qG”ù×ë2Yþçu™4šo=.;ü4?°Ú[˜Ô¾6cºýdÊéá”JhPfžM)L*²=e÷&¯jLÉi(¼ºŽTÏÁá³;VVonë¨-—òÍN½-¯¥ö ñPk¬¡°4^ye/KÝ÷)·¸ô3PœêWÚßÖö·\È´\¯Ãeŵ:\Vj.Çe¡å-ƒsWy%.ΰ ¿ÇcOå—\‡.×[ Ü tr]uÝ…{Ëôxå•«WóTá5ú¾ò-Û¨¬,b–à·®]KZPX±ÌBÕŒÅÔŽ«3Ò³lR¥j¡*eÜ1œ©V_UÏHV¥E+Q² „yÿs’ueõá ˆ˜s6Þº19;:×&æ$)ç¶ðØú°’ ìfu³û `Ĩ¶#FêMjîЄ‘zZ3®›©"ŸÉš³ahþ†–Š=tîCKÎmL±qz#áé—G~a˜ >‹øå¢8½‘pÎmýôíÜFÂ9onœ~óÜFÂ?±wÐa šºÑÈIÂf³}YÂÞžýÂ÷f'/3d7±¹7û1wgßËþ{/‘³iºh;÷¼n½ú}³DÇÐF`™Ð,é*¦ÝN¨:Ê;?îÎc$õ{¨ª À°ž¯j†¬ž<$Vž‡N«Å‹PÂ-» Î-Oó`nŠG7yð$ÜxÄëùx}ÜGE¹gJé3<¦á9_­Œù,1™†7À×¥I%š!É|O4¹ó}E¥‘™úù+¯ÐèýB/Æ*œ«(ÆÊKÆšœö|i5ý´¸‡pû ~× íå@Å‚!ªŒnèÝ<è±S9Ýxçúáo>x9ÚÒ"þHK/•xÝ‹ÒÝž®9ç/Ñ$ü³Ï$ÞTÈ-vqr3÷ÔѢʺEÍŸÐ~±`+L)³êZcËþDÇØÖ1v\*,™§î^úô¦±hÒ¯×8ö‡ÔŽZ÷Xþv´áÿGÆfûzcŸTmõ§~™f§g>ú6W¿üOŒAÎ….IÒy<%ç•ÍGÓ嶤Þà|¨©¾Þ”FsöùS'ÊÙfuNm4W…¶ùÊYá¤Ñ65hFs_|63Ëñ õ¼CÓ6åñˆÛ×Ãêõp$Q½ ¬a¹ó¼rj˜S…¦4í©ŠE7ØÇøJ»r=z|³V­v_ÞQSÓñéDéžcHXµ7,ð[dÌÌ#×êkùôî°Òÿšî°ðÖ@0l/’ât舩ّ鎱øÝ¼3]c×hA¡™Þ±Ü±Yq¡cô{5J˜ŽY}ã3N7º€o•1”ÐSÃÌ÷·bïÑ"ǵ¬l¡Öïq:‡%Xœ!Y5·‡rÏG{Ñ~òÁ@>™ÓOþk>̵”kÄçZÊÈOâ·nˆÒ÷‘w¼¢<û4ùqwýòú» ½Ô¶oüsJ× ²ú môØ"cZ@$¹Æ(¶ã f¾¥¯ ˜R¥~ ŒyÜ`-Ãôë;CêÙ‡¨/*6hÒY…Mèíf“â.['mÄaÅ&‚ŒƒáF¯ÚxovŠ=”ÐÒïÚwM¹'v€Ù+aý¡×:[w½öøP_SmkÿC-5õ÷._– Ö4õ 6ú ®ÿû·¯zu_×áà϶ÿeÝ`Õ£›[w––ßgËÿJóÀ®µ¡õÍË&©þígª;È1Q¦{sÿ‰Ž¦¹Ž¦´P3qÝŽ¦Kæt4=E;šÆâêž„ÿ—=MËhCSG¡¿‘¦¦#ÕØÑtx4sç§w5eYìiÊ[;³?¯ýÿ*]¼ÄÃÝ8]NdF_ºQºp‰\©ê4m¶QÚ$™ÿ¸aÚ i’ ú–Φ®™j¸­:O¢­±P,Å(ÉjfÐ`2†0–ÔJ`¢ÿÔ¢æ¡b²²xBIÊʵš.QÏU'ÔçÎ~ýŸhÃŽTr‰¨$ð! %>Á¤Ç—Ð/ûTSMyÍ>¼ÿ«xs€ù½qö”¿Uq¡ïñÿrÃ*'þì/›Î½<ãQÝ:àQ‚¹¿Õm†G5Wò¨q6"úýy‹#ªl¡¼ZlY¢Is½*Í`ÎS·Âë%Û“ýI$Ú P-0/’¨iDl’‡‰ &ÕXsýR¥pýQÚms1ýJç€= :e¯“‘æ®&øu)}×–/·uÔ…¤|¯Ùîi©é^\~ëâ•þÒx¸êJ\ö|Õt.»½yµšËÞy?ÀßV×I;]'K™zæ¹k¬”j,¬e–ªé4wö±m]×_’øñÞ“DŠ¢(Šß¢iꙤ$úY–,Ë2­Éª¦¨ªjšæ²êºN4Aõ W0Œ¬ /qÝÀΊ ²Ì32Ôà£o1º Kº Æõ AÀÈÒ®ŠnXP2ÌÜî9÷>’¢HY^‹¬@,RÏÏy÷ûqÎ=÷œß9œn¸®©ž5ýdÛ½ŸGû·®2PQv‚ÐÒ¿>¨G©í4^Y~´ýàêp»@þ%- ¡ÆY#Ÿ£’6rXýµ üZƒk÷3ÀZíÇÞõ$B±Hè—Èö~ÑrU«?òN5?$ƒÓwTºL ªäF«vd„ì]2Ùýýx˜úîXù€|÷}°pîåÕ՗飙ÌÑô®û`áÆÙ³7ÎÞ‰e³1òÖ£6ÒŸßã2\Ž›åÞå ðʧ2Φ EAPä|O§‹Çz’̈Œv ó}òÇÄü l?Cª»¡ŸtC¿¨ðp°‘—pâ~,ˆÚ¬T8­ž#Âï瘡™‘4[ 1­­|NH›îhbÖ¬nãpZ4A:*f[ë' f›€ÝF+²;Y7 â™ÃŠtƒ›Q3]ˆÍ4U3ÖXFE¥o ìHøˆþ¯Íî¶/-N]TœòLjqtbáÆäÅžÐùCC«O§PšwyÎŒ,e'¾5}%úúäê«O-JLÊF‹!y¶_Éðo3k,>™‰ñ¥¹ç!£ap<œ9±°Æ984>4”XÍž¿4ŸRsSóOM½¶1¾˜N:ü1[,6-;<ó¼ÕŸMÆSÓêi°^zÙæin+ìƒþêÌlÁ›Ce/›™jc‚HžW…ù¡%dˆœíÞPDÙ‡ã¼7D$Qóû$­'Jä dô¢™ÓÁè˜W·ŒÞ V j¨ÏK¿XØ)pçü{ïm'¨?)NÕˆ¼Èté¿ Ï[ÐÍõpa¨µƒõ¼!Ý«ÃNó]•¹ŠJ£t¤kÏi-ð ·ªzKëëøðx8õiËèáë6z¸íêÀÃW‰I[ˆŸø >|ý ßðyûhÄ~æmGóó¡m•˜ÛÎÿB74õ¶o`Ûñ$¯aÛÉ^ OðÊ͇d! QÇ+öc,va ÆìGßSÔ~ @Ð|>&æ£Ô~Œ„r_8¢lµcQk>79òaËã ÁPíGúI94*0j>Tfâ?'?Zzõæb»_¶þŒLn³Dn~ôôߨH®à{#‘E¬%]léi÷R¶wQÃ×òxH•Ú“Þô´€£ÆGŠ–êc¬àkt?B6ÅvÜlù>¹ ‚˜B[LÏ‚Ñ5•À¤q7’ÐÓ#!§”åÄÏSßÿv9 ï£Aðà6!‡¨y sÃ_âš8»N ®å†³Ä¡ˆÎNF×lvu+œ'Ó™bÁܲ¸Â à¦16AÝÏoÙöüV·À°äËo>ùCJ®'êÏß ÏXT—›.*˜ûÛL+è4nFUÙ‘ºëÅÚÉF“æ"‚÷9ì0Ù쎚É&:1ŒÐ©‡rZ “gŸ:å°ê=q&1QNýmËsC`ï;‹œxwaëÛè¶FŒV÷A'$ðå¹4#ÂCµ½íÒØlµ@(‡»ür¼0‰‚sƒ9׿Që³ãÃ[òn¢ý ÞG2¾õ÷x»ÆÇˆ|jÓI²jFmZÛ ê9 û‹Y»(+§‹&EH°å–ÚÈ– )*HOVáÙË)F¤3%ø.±Î”¾ùÎ×ðìÅ*nZ¬˜Ý$n67‰§ ?áº × äbÕ‹S-Û᛬r›–f§LOŸôo¸wÍdóÐ?ˆŒ£!˦2º93ŲQ¢ÿáXEÖÁöh\h‹y¶tû¹Ó‡ÖJŸ†tríæÉÙû¡Ûÿ:­¾r§ô߯ÜúZra.=8?Ÿ\ÿSþï~ȇϾòõß:¥Îd“úKÿUºôÁ7Oó­½ñ÷±™—V–oLï“ XådOÝÉõëÄí´r"mØ9“ÅSóÁ¸hÀ.„l7°H½ýäýìRÑìëÙ›‚UÓ&k½qµB4×{ÉfÍ«PŒf©OÖü½êάó†Q#u èç×.NaxÃmo³ÈLJOà´/’M4£ïTŽõ=0Ì/:&_Bfº"ÉêPÓ»êQÓ}Œš¾)4utbïïœÖR=xú7À>ªP7ü5óï}¶í˨^;‹` Õk'ÿïUþ6ÚÖ lk7w§N[óÝŠÒÍš ñWz“{*Óº›©v×®ËbÞóý|·˜÷Ñu¹Ë ë²·«f]îöYÉBnr°“¬ËžN®Ëôçð£±ï™ TO:afõÔЇú¢®Ëç ‘O„K×å×å£ —+Ê`§žý(pôD<|1'2JUó{¥7‡ä‹4Á„4Ëš§^G‰³×Ñd™’¶žLÉ ”ïTóY=µ/ºC`H]úÿ™†± Ѻu„»ÛgáƒåJ±#“Í,Æ.ú‰}•I=œ î‚HfMSyùX8-þ¾io«Še•à‰¸6#æNr=@¯æ…*½8(—6,›Hdž¸} ÅNY E1’ß]wP”m¿*ÑèÚ±JD×Q”ű‚8ª­Ry‡Úzóú¤?¬;ƒî9îçºÑC¾D²ÙJ€¯Çˆ´Zˆàtƒ܆À![Ò!‚˜ê™ ž¢·ÍÀ>Ÿ3ü¤4”`ÿ §ôOÇ÷ï?>hø.~й|I¸mŒa$iˆ·s;ôF·>V=hnåÍ †ZJï 1 œ- ±-Íä·€ŠZéá•e“«¬¥yDrˆ/Äh‰¡ÖPccf•¹Òò7­¢46ü„ë2\'OƒŸnýž.¼'? ä†*eî QÉò?€ß»T‘²ªÜŸ›¬NÙåî U¢%j¯à"€!"P @7"ØhÀP Œ “ÈB˜„…¬ôtPÄ`$ÌMMûí—øÿ¼½¼0ûÕ…_>ÊÌì_ÿãï¨ã«¯MáH^záJ‰ †ä‹Ù›ßúë§ ã^þ’-ô—7o® ÝÌz²þû¸DÍ5 ÖPëCŒZ¿iõtÓÒ;»׃Âj¯ÿ%(­öÆê®ÿ·¶Ã^¢!x?šl‡Æ Oè Moÿi˜{«AûÉðG‡D76@ÚVÕKD+ã>Ü c½;\«Òˆ2óŸîÕñ¾`TZ X£ÒÂ!k>Hóìb¾‡¨4&ѱO­^¡€©µFòºÎTÛN;Y9ИÌf‰Ì"\’»V+µ,å½U¡•qЧƒM¿+yˆ®Ø[ÅfBl¯„aÄxÕÕCðî éò1IóXU(¤Å÷>‚,jO e¥0¸£hÞ©ññ(¿žÌ ðrÕ!ØGÊûèo4ÁæØ.(ö8Ý‚²7ý#q¬^úƒî‹täà>‘Ö ‚Š]M {,P˜£‚2¹ÒiHš$**•`´pRF M­èÒI`üºË¬W jcEÝV4èu箪™o9"R©eW•ƒÖÿ³¤ÿÁãõ!W3GW¯îèÚ6&RJ>ø>¤³¡ñSíÑÚt÷í±&P éÏr¸hÑ $­NÑ5æ4÷2óö* ëGFµ3nCjËä{ÈÐ2·Í?ù~)|hr½ñbcÑ1þF—>جÿ Œk,çQÓÏ‹6§ËjO@áG½|™—(+/­Pe–/Y™€Ý+1³DjJä›Òä‹£)F{Ћ59ÍߊA6š ·^,DìÍ%×- /‘¸¨$ntm‘}‘•ôj1Ë9åê䩯t“”>€ʱ•¹Wz÷=¥ª_˜u¸IÍy{ —ùÀw?u|ˆeušæ/?ý"ßRúøÙ«óG ÷rk³3ɸ´ûûá.•£Ü$d“ö€× œ°õ|u0Ae ƒä×céâaW‰Èä0ôrïî@JqQ£È(ò[a smƈ ¦ˆ Æâp¾bjòö„])u¬mYÒœ>9Þ"“î Ô4_†|– \|€ü:áÓĤÄÊ€âb·à3\Ue‚(—>Ë–y2ù~›DÄf 0|¨Ùv ùÌÔÆÑ™ËÓ°6›M¥¤¡Ë³2²~tâì·Ÿ>½¸š{*q`ÃïYˆ;lÍV5žœ÷Føü‰@rq5ÞÁÿô¯ÎÍÍ/-8!Ç•P÷%á*Œª¦O¬ÎÍÎÌŸÿä•¥é‰DÄ<óGŸ_?be†Õ™ÑÖË™©ÕQÔ“4în†³r"×{åÚÈ;0¯é9c&EW¡¤Y$^sKˆEÈÌ-ÇåmÊ&+Ñ®2.·†ý+é¹ 4¯µckhž¡fWÂôþeknaU´Þjæ&ÏËFY0{ËÌ}“ 9S4 ž.ÏWWoÚ©º¸nW=´ºxÙ°ÚEuqæµåej Uµ>£t˰νGž±‡+ˆPSøW}Jég•§,MÁS@Ÿ½føX8ƒïà¦Ajy† `Ù~BâÑn(t@Â?×ÑEÚ. œÿPÉ™…eÙRØ]¤VدÝËY§Õ\JãoÝ;J›Ryø­VðSÛûÁÀ]"mÏUÚN¼@†‰)ßEÛ¾MR°ÔµÓš¡…v?\m÷°¶·ØK ж×J2R{áÒPÒG$›Q¿p?Yù^ۗõ] í.ÝrØ·n†öîo@ËkÇÇpÍpáù%¾h¸+4W3%m”)iÛ”´Q¦¤m;SréË×VV®X£\ôOGn%—[á½”åXÎå–“§r9@CU~’÷Ž“‘ö6²ŸEÒ¢AAmÂã1iFKESZRºÿ€Ò)<ÑñPJ7…tc¥ n8†1¢5ê§‚<%hóq> èìÇ*èì:m]VlàwP„Œ#*Bcc4¤Îq¬ACrdË*× á¬Í ÙHÚl®%5R4NÆÃÒÄ~ˆÅéÓýÛvºr‹ßg§™ÚQ”átÑbÆ Ý¬]sgé—ýi-5?Óx4`*2§ÅûÈ—½PA*Ÿ G•¦f§‘N­Y¨Êf³åš¤T›š-KJÅ[ˆ©èrƒ¥h ö ±ñÎYãïu~ųoâÞÚ­s«Ñh¬Ÿy+n6òŸ&K#S)=ï^þ³Ë‹Cÿ$ûÕSÓNþí Üð…ós—ŸxâY³ÏÜH]¹ÖÖ~!;–¸péóWø¹•3¼{|ùs°VD ׄû¦62?\©Ç‘žÌÔ3Ê0:´™,Vg:V3ö²‹Ð&ä1›„¦DÁŒüY3ä­³9ÓNi}ÍX.¦ åWêõÿæöO¯Tfµvï§P<ñîþ¿ýÉïSP"»ÄV¨Wíù”˜“Vr—þ—XÊÏÖE`ZÅM¹ÎIɯUè8r ÙÎ-6 ê$êÆ7[lö2§ŒŒ@Hâ¥Lë!˜‹N^á¥ÿƒ¿Xäg&®OM™?t°gÍøîc=øC?ùótéÇן°Á¿µö¸ðA‰8ÿ ýÊxÚc`d```dêgqe:Ïoó•AžƒNr§<…Óÿ¦±³e¹ L QD :xÚc`d``Ëú7ƒØ‹PÁcGxlxÚu“1KA…çb AD+ *)D,‚ˆ ‚’"H  WDBH‚ ""‡ b‘"…•Uþͯþ ßì¼À±èÁÇÛ›}³{—{‘¤(A:Ë r xÌ`|vÁæEh=…^€¼‚{pŽ¿Ϭwmùní¶Õ‘"óÖA†ët­[OæÁÍáCJ`´˜§û®2Wµ ʬ²—yææ,¤¹g¼™×_‰>«ô¦ósP· O-öT°ž\ úz5æ7ùn,=`¿´G_ó×Ú;¬™gÎ%øêï‘çÙµ³w±ðE¿Ë ÔÛ’õèÎ{ãïØú12ÍyæRôW÷h{¬ÅîÁç…zäX«Âsþ‹)Þ…ï{c÷àQ›YÞ™ê$H›§@ÇÝ‘‘ѲÈPs"Á˜0äºÝwÿN4$eÿD;q÷ë]œÁ!t\×a¼¨hMÄ6eá ~` xÚc`€ƒ†Œ˜0DZè±4°lb¹ÇÊÆêÁZÃ:…õë¶ ¶>ö0öJ“88ã8ïqEqMázíÇÀ=G„g¯ïÞw|V|e|køåø3øñH˜&ðEÐKpà¡¡WÂI“„_ˆ˜‰ì ]%úILFÌG¬LìŠØqñ+!³$Å$›$Hí’–Î’¾ ã#Ó óEÖI¶Oö\ŒÜùùk : =Š Š;”ì”Z”e”ÍTØTÜ€p–jŒƒÚ;õ:õE³4nhfiþÑš¢µGëŠö,í: :~:/t#t+t_ééè…é­Ð;¡/£¿Ã ÈPɈË耱ƒñ'“o¦SÌì̶˜›™W™ï³à²(³ØañËÒÍr“•œÕ.k5ë)6,6«lmloÙ­²ç°Ï°¿äàpÊQËq‹“ƒÓ9ç.I®j®/ܹ»¹/ñ`ò˜çiâYâ¹ÅKÇk’·—÷Ÿ6_1ß%~:~9þþ}þï:%—IÝN ‘ YÊê†Æ…–…ö…. ½Ææ6/ìWxXxCø¥ðK:‘‘Ûg”œäSƒxÚuQÁJ1}±UÄ£ç<ʶzèÁk¡"T+âuÕlw¡f×ÍÖâ/ø)~…G?Ë7³ÙJ¥˜¼L2oÞ¼ØG†Lÿ0# bƒcžZ¼ƒC3¸‡#óq'¦«Ý…5ï±ö3âoxó…1j8¤hŸañˆwÆ[f*äDSæßP0zž–Äsâœ(p/±Ò»†¨ÄBs)3Â6aÆóFöšU ³cž*ö©É0'OÃÜ9†\£{'zãÈ/jCT»Ô>ŽLÒ?'²˜áŠ•7diUw*„±À“f…áT§h¸*\`Àx+ª*æ{Ê´ î­ú9'äHØÁóe©<2³ø—âZUTõBO½ÌbçíïíFŽÎ!KU-~œ±—Ä!ÏÛ9îÖÿ­§\©CVýöÊú÷;¯~™á•* ¾­Õe‹Ëjq ùÐþiÊxÚmÐ5l•a†áë+…-ÅÝ]OO)nEŠ»»»Kq ®°A°®Ü‚˜ð0+ÖŸ'ysm÷ðJðw?™è{ûû‚¹$Ê-$ÉòÊ'¿ *$Ea©Š(ª˜âJ(©”ÒÊ(«œò*¨¨’ʪ¨ªšêj¨©–Úꨫžúh(&M\ºF24ÖDSÍ4×BK­´ÖF[™Úi¯ƒŽ²tÒY]uÓ]=õÒ[}õÓß 2ØC 3Ü#2ژ࠵ֹb·wÖÛn‹=;rÙìµ5v…ÄÛ¶ÇF×½ Iö:â»o~8à˜;n9n¬qvïž n»ë‘ûxèýïï=õØ'LòÕN/<óÜd}¶ÉTSL3Ãt3í3˳Í5O¶ùXèƒE–Xl©å–¹h¿•VXeµO¾¸ä¤S.{éUHyC¾?C¡ ‡ÔP$ ÅœvÆyÜpÖ97mp4wÕµP"”´5){æ”X,3Ù!ÇvñÈôÈŒÈfŒÇb±È´Èxdzd£ÈŒÈÆ‘M"›Fþëeæ˜uÓ¢n<+ÇŒ¬ÄŽÙsgý‡‰®¸ÿ…°K°PX±ŽY±F+X!°YK°RX!°€Y°+\X° E°+D° E°+DY°+three.js-r73/docs/prettify/0000755000175500017550000000000012640541423015542 5ustar debacledebaclethree.js-r73/docs/prettify/threejs.css0000644000175500017550000000102412610076566017725 0ustar debacledebaclepre .str, code .str { color: #8000ff; } /* string */ pre .kwd, code .kwd { color: #30b030; } /* keyword */ pre .com, code .com { color: #999999; } /* comment */ pre .typ, code .typ { color: #2194ce; } /* type */ pre .lit, code .lit { color: #ff0080; } /* literal */ pre .pun, code .pun { color: #888888; } /* punctuation */ pre .pln, code .pln { color: #444444; } /* plaintext */ pre .dec, code .dec { color: #22c0c4; } /* decimal */ pre.prettyprint, code.prettyprint { background-color: #f9f9f9; font-family: 'inconsolata'; } three.js-r73/docs/prettify/prettify.css0000644000175500017550000000124312610076566020132 0ustar debacledebacle.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}three.js-r73/docs/prettify/readme.txt0000644000175500017550000000023112610076566017544 0ustar debacledebaclePrettify syntax highlighter: http://code.google.com/p/google-code-prettify/ Code license - Apache License 2.0 http://www.apache.org/licenses/LICENSE-2.0three.js-r73/LICENSE0000644000175500017550000000207112610076566013761 0ustar debacledebacleThe MIT License Copyright © 2010-2015 three.js authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. three.js-r73/package.json0000644000175500017550000000124112610076566015240 0ustar debacledebacle{ "name": "three.js", "version": "0.73.0", "description": "JavaScript 3D library", "main": "build/three.js", "directories": { "doc": "docs", "example": "examples", "test": "test" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "https://github.com/mrdoob/three.js" }, "keywords": [ "three", "three.js", "3d", "webgl" ], "author": "mrdoob", "license": "MIT", "bugs": { "url": "https://github.com/mrdoob/three.js/issues" }, "homepage": "http://threejs.org/", "devDependencies": { "jscs": "^1.13.1", "lodash": "^3.10.0" } } three.js-r73/bower.json0000644000175500017550000000054612610076566014772 0ustar debacledebacle{ "name": "three.js", "homepage": "http://threejs.org/", "description": "JavaScript 3D library", "main": "build/three.js", "keywords": [ "three", "threejs", "three.js", "3D", "webgl" ], "license": "MIT", "ignore": [ "**/.*", "*.md", "docs", "editor", "examples/*", "!examples/js", "src", "test", "utils", "LICENSE" ] } three.js-r73/src/0000755000175500017550000000000012610076566013543 5ustar debacledebaclethree.js-r73/src/extras/0000755000175500017550000000000012610076566015051 5ustar debacledebaclethree.js-r73/src/extras/audio/0000755000175500017550000000000012610076566016152 5ustar debacledebaclethree.js-r73/src/extras/audio/Audio.js0000644000175500017550000000747312610076566017564 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Audio = function ( listener ) { THREE.Object3D.call( this ); this.type = 'Audio'; this.context = listener.context; this.source = this.context.createBufferSource(); this.source.onended = this.onEnded.bind( this ); this.gain = this.context.createGain(); this.gain.connect( this.context.destination ); this.panner = this.context.createPanner(); this.panner.connect( this.gain ); this.autoplay = false; this.startTime = 0; this.playbackRate = 1; this.isPlaying = false; }; THREE.Audio.prototype = Object.create( THREE.Object3D.prototype ); THREE.Audio.prototype.constructor = THREE.Audio; THREE.Audio.prototype.load = function ( file ) { var scope = this; var request = new XMLHttpRequest(); request.open( 'GET', file, true ); request.responseType = 'arraybuffer'; request.onload = function ( e ) { scope.context.decodeAudioData( this.response, function ( buffer ) { scope.source.buffer = buffer; if ( scope.autoplay ) scope.play(); } ); }; request.send(); return this; }; THREE.Audio.prototype.play = function () { if ( this.isPlaying === true ) { console.warn( 'THREE.Audio: Audio is already playing.' ); return; } var source = this.context.createBufferSource(); source.buffer = this.source.buffer; source.loop = this.source.loop; source.onended = this.source.onended; source.start( 0, this.startTime ); source.playbackRate.value = this.playbackRate; this.isPlaying = true; this.source = source; this.connect(); }; THREE.Audio.prototype.pause = function () { this.source.stop(); this.startTime = this.context.currentTime; }; THREE.Audio.prototype.stop = function () { this.source.stop(); this.startTime = 0; }; THREE.Audio.prototype.connect = function () { if ( this.filter !== undefined ) { this.source.connect( this.filter ); this.filter.connect( this.panner ); } else { this.source.connect( this.panner ); } }; THREE.Audio.prototype.disconnect = function () { if ( this.filter !== undefined ) { this.source.disconnect( this.filter ); this.filter.disconnect( this.panner ); } else { this.source.disconnect( this.panner ); } }; THREE.Audio.prototype.setFilter = function ( value ) { if ( this.isPlaying === true ) { this.disconnect(); this.filter = value; this.connect(); } else { this.filter = value; } }; THREE.Audio.prototype.getFilter = function () { return this.filter; }; THREE.Audio.prototype.setPlaybackRate = function ( value ) { this.playbackRate = value; if ( this.isPlaying === true ) { this.source.playbackRate.value = this.playbackRate; } }; THREE.Audio.prototype.getPlaybackRate = function () { return this.playbackRate; }; THREE.Audio.prototype.onEnded = function() { this.isPlaying = false; }; THREE.Audio.prototype.setLoop = function ( value ) { this.source.loop = value; }; THREE.Audio.prototype.getLoop = function () { return this.source.loop; }; THREE.Audio.prototype.setRefDistance = function ( value ) { this.panner.refDistance = value; }; THREE.Audio.prototype.getRefDistance = function () { return this.panner.refDistance; }; THREE.Audio.prototype.setRolloffFactor = function ( value ) { this.panner.rolloffFactor = value; }; THREE.Audio.prototype.getRolloffFactor = function () { return this.panner.rolloffFactor; }; THREE.Audio.prototype.setVolume = function ( value ) { this.gain.gain.value = value; }; THREE.Audio.prototype.getVolume = function () { return this.gain.gain.value; }; THREE.Audio.prototype.updateMatrixWorld = ( function () { var position = new THREE.Vector3(); return function updateMatrixWorld( force ) { THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); position.setFromMatrixPosition( this.matrixWorld ); this.panner.setPosition( position.x, position.y, position.z ); }; } )(); three.js-r73/src/extras/audio/AudioListener.js0000644000175500017550000000204212610076566021255 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.AudioListener = function () { THREE.Object3D.call( this ); this.type = 'AudioListener'; this.context = new ( window.AudioContext || window.webkitAudioContext )(); }; THREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype ); THREE.AudioListener.prototype.constructor = THREE.AudioListener; THREE.AudioListener.prototype.updateMatrixWorld = ( function () { var position = new THREE.Vector3(); var quaternion = new THREE.Quaternion(); var scale = new THREE.Vector3(); var orientation = new THREE.Vector3(); return function updateMatrixWorld( force ) { THREE.Object3D.prototype.updateMatrixWorld.call( this, force ); var listener = this.context.listener; var up = this.up; this.matrixWorld.decompose( position, quaternion, scale ); orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); listener.setPosition( position.x, position.y, position.z ); listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); }; } )(); three.js-r73/src/extras/core/0000755000175500017550000000000012610076566016001 5ustar debacledebaclethree.js-r73/src/extras/core/CurvePath.js0000644000175500017550000000746512610076566020254 0ustar debacledebacle/** * @author zz85 / http://www.lab4games.net/zz85/blog * **/ /************************************************************** * Curved Path - a curve path is simply a array of connected * curves, but retains the api of a curve **************************************************************/ THREE.CurvePath = function () { this.curves = []; this.autoClose = false; // Automatically closes the path }; THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); THREE.CurvePath.prototype.constructor = THREE.CurvePath; THREE.CurvePath.prototype.add = function ( curve ) { this.curves.push( curve ); }; /* THREE.CurvePath.prototype.checkConnection = function() { // TODO // If the ending of curve is not connected to the starting // or the next curve, then, this is not a real path }; */ THREE.CurvePath.prototype.closePath = function() { // TODO Test // and verify for vector3 (needs to implement equals) // Add a line curve if start and end of lines are not connected var startPoint = this.curves[ 0 ].getPoint( 0 ); var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); if ( ! startPoint.equals( endPoint ) ) { this.curves.push( new THREE.LineCurve( endPoint, startPoint ) ); } }; // To get accurate point with reference to // entire path distance at time t, // following has to be done: // 1. Length of each sub path have to be known // 2. Locate and identify type of curve // 3. Get t for the curve // 4. Return curve.getPointAt(t') THREE.CurvePath.prototype.getPoint = function( t ) { var d = t * this.getLength(); var curveLengths = this.getCurveLengths(); var i = 0; // To think about boundaries points. while ( i < curveLengths.length ) { if ( curveLengths[ i ] >= d ) { var diff = curveLengths[ i ] - d; var curve = this.curves[ i ]; var u = 1 - diff / curve.getLength(); return curve.getPointAt( u ); } i ++; } return null; // loop where sum != 0, sum > d , sum+1 0 ) { high = i - 1; } else { high = i; break; // DONE } } i = high; //console.log('b' , i, low, high, Date.now()- time); if ( arcLengths[ i ] === targetArcLength ) { var t = i / ( il - 1 ); return t; } // we could get finer grain at lengths, or use simple interpolation between two points var lengthBefore = arcLengths[ i ]; var lengthAfter = arcLengths[ i + 1 ]; var segmentLength = lengthAfter - lengthBefore; // determine where we are between the 'before' and 'after' points var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; // add that fractional amount to t var t = ( i + segmentFraction ) / ( il - 1 ); return t; }, // Returns a unit vector tangent at t // In case any sub curve does not implement its tangent derivation, // 2 points a small delta apart will be used to find its gradient // which seems to give a reasonable approximation getTangent: function( t ) { var delta = 0.0001; var t1 = t - delta; var t2 = t + delta; // Capping in case of danger if ( t1 < 0 ) t1 = 0; if ( t2 > 1 ) t2 = 1; var pt1 = this.getPoint( t1 ); var pt2 = this.getPoint( t2 ); var vec = pt2.clone().sub( pt1 ); return vec.normalize(); }, getTangentAt: function ( u ) { var t = this.getUtoTmapping( u ); return this.getTangent( t ); } } THREE.Curve.Utils = THREE.CurveUtils; // backwards compatibility // TODO: Transformation for Curves? /************************************************************** * 3D Curves **************************************************************/ // A Factory method for creating new curve subclasses THREE.Curve.create = function ( constructor, getPointFunc ) { constructor.prototype = Object.create( THREE.Curve.prototype ); constructor.prototype.constructor = constructor; constructor.prototype.getPoint = getPointFunc; return constructor; }; three.js-r73/src/extras/core/Shape.js0000644000175500017550000000276412610076566017410 0ustar debacledebacle/** * @author zz85 / http://www.lab4games.net/zz85/blog * Defines a 2d shape plane using paths. **/ // STEP 1 Create a path. // STEP 2 Turn path into shape. // STEP 3 ExtrudeGeometry takes in Shape/Shapes // STEP 3a - Extract points from each shape, turn to vertices // STEP 3b - Triangulate each shape, add faces. THREE.Shape = function () { THREE.Path.apply( this, arguments ); this.holes = []; }; THREE.Shape.prototype = Object.create( THREE.Path.prototype ); THREE.Shape.prototype.constructor = THREE.Shape; // Convenience method to return ExtrudeGeometry THREE.Shape.prototype.extrude = function ( options ) { return new THREE.ExtrudeGeometry( this, options ); }; // Convenience method to return ShapeGeometry THREE.Shape.prototype.makeGeometry = function ( options ) { return new THREE.ShapeGeometry( this, options ); }; // Get points of holes THREE.Shape.prototype.getPointsHoles = function ( divisions ) { var holesPts = []; for ( var i = 0, l = this.holes.length; i < l; i ++ ) { holesPts[ i ] = this.holes[ i ].getPoints( divisions ); } return holesPts; }; // Get points of shape and holes (keypoints based on segments parameter) THREE.Shape.prototype.extractAllPoints = function ( divisions ) { return { shape: this.getPoints( divisions ), holes: this.getPointsHoles( divisions ) }; }; THREE.Shape.prototype.extractPoints = function ( divisions ) { return this.extractAllPoints( divisions ); }; THREE.Shape.Utils = THREE.ShapeUtils; // backwards compatibility three.js-r73/src/extras/core/Path.js0000644000175500017550000003544512610076566017246 0ustar debacledebacle/** * @author zz85 / http://www.lab4games.net/zz85/blog * Creates free form 2d path using series of points, lines or curves. * **/ THREE.Path = function ( points ) { THREE.CurvePath.call( this ); this.actions = []; if ( points ) { this.fromPoints( points ); } }; THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); THREE.Path.prototype.constructor = THREE.Path; // TODO Clean up PATH API // Create path using straight lines to connect all points // - vectors: array of Vector2 THREE.Path.prototype.fromPoints = function ( vectors ) { this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); for ( var i = 1, l = vectors.length; i < l; i ++ ) { this.lineTo( vectors[ i ].x, vectors[ i ].y ); } }; // startPath() endPath()? THREE.Path.prototype.moveTo = function ( x, y ) { this.actions.push( { action: 'moveTo', args: [ x, y ] } ); }; THREE.Path.prototype.lineTo = function ( x, y ) { var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); this.curves.push( curve ); this.actions.push( { action: 'lineTo', args: [ x, y ] } ); }; THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( aCPx, aCPy ), new THREE.Vector2( aX, aY ) ); this.curves.push( curve ); this.actions.push( { action: 'quadraticCurveTo', args: [ aCPx, aCPy, aX, aY ] } ); }; THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( aCP1x, aCP1y ), new THREE.Vector2( aCP2x, aCP2y ), new THREE.Vector2( aX, aY ) ); this.curves.push( curve ); this.actions.push( { action: 'bezierCurveTo', args: [ aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ] } ); }; THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { var args = Array.prototype.slice.call( arguments ); var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var npts = [ new THREE.Vector2( x0, y0 ) ]; Array.prototype.push.apply( npts, pts ); var curve = new THREE.SplineCurve( npts ); this.curves.push( curve ); this.actions.push( { action: 'splineThru', args: args } ); }; // FUTURE: Change the API or follow canvas API? THREE.Path.prototype.arc = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; this.absarc( aX + x0, aY + y0, aRadius, aStartAngle, aEndAngle, aClockwise ); }; THREE.Path.prototype.absarc = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); }; THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); }; THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { var args = [ aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation || 0 // aRotation is optional. ]; var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); this.curves.push( curve ); var lastPoint = curve.getPoint( 1 ); args.push( lastPoint.x ); args.push( lastPoint.y ); this.actions.push( { action: 'ellipse', args: args } ); }; THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { if ( ! divisions ) divisions = 40; var points = []; for ( var i = 0; i < divisions; i ++ ) { points.push( this.getPoint( i / divisions ) ); //if ( !this.getPoint( i / divisions ) ) throw "DIE"; } // if ( closedPath ) { // // points.push( points[ 0 ] ); // // } return points; }; /* Return an array of vectors based on contour of the path */ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { divisions = divisions || 12; var b2 = THREE.ShapeUtils.b2; var b3 = THREE.ShapeUtils.b3; var points = []; var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, laste, tx, ty; for ( var i = 0, l = this.actions.length; i < l; i ++ ) { var item = this.actions[ i ]; var action = item.action; var args = item.args; switch ( action ) { case 'moveTo': points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); break; case 'lineTo': points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); break; case 'quadraticCurveTo': cpx = args[ 2 ]; cpy = args[ 3 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = this.actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( var j = 1; j <= divisions; j ++ ) { var t = j / divisions; tx = b2( t, cpx0, cpx1, cpx ); ty = b2( t, cpy0, cpy1, cpy ); points.push( new THREE.Vector2( tx, ty ) ); } break; case 'bezierCurveTo': cpx = args[ 4 ]; cpy = args[ 5 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; cpx2 = args[ 2 ]; cpy2 = args[ 3 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = this.actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( var j = 1; j <= divisions; j ++ ) { var t = j / divisions; tx = b3( t, cpx0, cpx1, cpx2, cpx ); ty = b3( t, cpy0, cpy1, cpy2, cpy ); points.push( new THREE.Vector2( tx, ty ) ); } break; case 'splineThru': laste = this.actions[ i - 1 ].args; var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); var spts = [ last ]; var n = divisions * args[ 0 ].length; spts = spts.concat( args[ 0 ] ); var spline = new THREE.SplineCurve( spts ); for ( var j = 1; j <= n; j ++ ) { points.push( spline.getPointAt( j / n ) ); } break; case 'arc': var aX = args[ 0 ], aY = args[ 1 ], aRadius = args[ 2 ], aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], aClockwise = !! args[ 5 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; for ( var j = 1; j <= tdivisions; j ++ ) { var t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + aRadius * Math.cos( angle ); ty = aY + aRadius * Math.sin( angle ); //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.push( new THREE.Vector2( tx, ty ) ); } //console.log(points); break; case 'ellipse': var aX = args[ 0 ], aY = args[ 1 ], xRadius = args[ 2 ], yRadius = args[ 3 ], aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], aClockwise = !! args[ 6 ], aRotation = args[ 7 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; var cos, sin; if ( aRotation !== 0 ) { cos = Math.cos( aRotation ); sin = Math.sin( aRotation ); } for ( var j = 1; j <= tdivisions; j ++ ) { var t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + xRadius * Math.cos( angle ); ty = aY + yRadius * Math.sin( angle ); if ( aRotation !== 0 ) { var x = tx, y = ty; // Rotate the point about the center of the ellipse. tx = ( x - aX ) * cos - ( y - aY ) * sin + aX; ty = ( x - aX ) * sin + ( y - aY ) * cos + aY; } //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.push( new THREE.Vector2( tx, ty ) ); } //console.log(points); break; } // end switch } // Normalize to remove the closing point by default. var lastPoint = points[ points.length - 1 ]; if ( Math.abs( lastPoint.x - points[ 0 ].x ) < Number.EPSILON && Math.abs( lastPoint.y - points[ 0 ].y ) < Number.EPSILON ) points.splice( points.length - 1, 1 ); if ( closedPath ) { points.push( points[ 0 ] ); } return points; }; // // Breaks path into shapes // // Assumptions (if parameter isCCW==true the opposite holds): // - solid shapes are defined clockwise (CW) // - holes are defined counterclockwise (CCW) // // If parameter noHoles==true: // - all subPaths are regarded as solid shapes // - definition order CW/CCW has no relevance // THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { function extractSubpaths( inActions ) { var subPaths = [], lastPath = new THREE.Path(); for ( var i = 0, l = inActions.length; i < l; i ++ ) { var item = inActions[ i ]; var args = item.args; var action = item.action; if ( action === 'moveTo' ) { if ( lastPath.actions.length !== 0 ) { subPaths.push( lastPath ); lastPath = new THREE.Path(); } } lastPath[ action ].apply( lastPath, args ); } if ( lastPath.actions.length !== 0 ) { subPaths.push( lastPath ); } // console.log(subPaths); return subPaths; } function toShapesNoHoles( inSubpaths ) { var shapes = []; for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { var tmpPath = inSubpaths[ i ]; var tmpShape = new THREE.Shape(); tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; shapes.push( tmpShape ); } //console.log("shape", shapes); return shapes; } function isPointInsidePolygon( inPt, inPolygon ) { var polyLen = inPolygon.length; // inPt on polygon contour => immediate success or // toggling of inside/outside at every single! intersection point of an edge // with the horizontal line through inPt, left of inPt // not counting lowerY endpoints of edges and whole edges on that line var inside = false; for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { var edgeLowPt = inPolygon[ p ]; var edgeHighPt = inPolygon[ q ]; var edgeDx = edgeHighPt.x - edgeLowPt.x; var edgeDy = edgeHighPt.y - edgeLowPt.y; if ( Math.abs( edgeDy ) > Number.EPSILON ) { // not parallel if ( edgeDy < 0 ) { edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; } if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; if ( inPt.y === edgeLowPt.y ) { if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? // continue; // no intersection or edgeLowPt => doesn't count !!! } else { var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); if ( perpEdge === 0 ) return true; // inPt is on contour ? if ( perpEdge < 0 ) continue; inside = ! inside; // true intersection left of inPt } } else { // parallel or collinear if ( inPt.y !== edgeLowPt.y ) continue; // parallel // edge lies on the same horizontal line as inPt if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! // continue; } } return inside; } var isClockWise = THREE.ShapeUtils.isClockWise; var subPaths = extractSubpaths( this.actions ); if ( subPaths.length === 0 ) return []; if ( noHoles === true ) return toShapesNoHoles( subPaths ); var solid, tmpPath, tmpShape, shapes = []; if ( subPaths.length === 1 ) { tmpPath = subPaths[ 0 ]; tmpShape = new THREE.Shape(); tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; shapes.push( tmpShape ); return shapes; } var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); holesFirst = isCCW ? ! holesFirst : holesFirst; // console.log("Holes first", holesFirst); var betterShapeHoles = []; var newShapes = []; var newShapeHoles = []; var mainIdx = 0; var tmpPoints; newShapes[ mainIdx ] = undefined; newShapeHoles[ mainIdx ] = []; for ( var i = 0, l = subPaths.length; i < l; i ++ ) { tmpPath = subPaths[ i ]; tmpPoints = tmpPath.getPoints(); solid = isClockWise( tmpPoints ); solid = isCCW ? ! solid : solid; if ( solid ) { if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; newShapes[ mainIdx ] = { s: new THREE.Shape(), p: tmpPoints }; newShapes[ mainIdx ].s.actions = tmpPath.actions; newShapes[ mainIdx ].s.curves = tmpPath.curves; if ( holesFirst ) mainIdx ++; newShapeHoles[ mainIdx ] = []; //console.log('cw', i); } else { newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); //console.log('ccw', i); } } // only Holes? -> probably all Shapes with wrong orientation if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); if ( newShapes.length > 1 ) { var ambiguous = false; var toChange = []; for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { betterShapeHoles[ sIdx ] = []; } for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { var sho = newShapeHoles[ sIdx ]; for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { var ho = sho[ hIdx ]; var hole_unassigned = true; for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); if ( hole_unassigned ) { hole_unassigned = false; betterShapeHoles[ s2Idx ].push( ho ); } else { ambiguous = true; } } } if ( hole_unassigned ) { betterShapeHoles[ sIdx ].push( ho ); } } } // console.log("ambiguous: ", ambiguous); if ( toChange.length > 0 ) { // console.log("to change: ", toChange); if ( ! ambiguous ) newShapeHoles = betterShapeHoles; } } var tmpHoles; for ( var i = 0, il = newShapes.length; i < il; i ++ ) { tmpShape = newShapes[ i ].s; shapes.push( tmpShape ); tmpHoles = newShapeHoles[ i ]; for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { tmpShape.holes.push( tmpHoles[ j ].h ); } } //console.log("shape", shapes); return shapes; }; three.js-r73/src/extras/geometries/0000755000175500017550000000000012610076566017214 5ustar debacledebaclethree.js-r73/src/extras/geometries/RingGeometry.js0000644000175500017550000000532312610076566022170 0ustar debacledebacle/** * @author Kaleb Murphy */ THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { THREE.Geometry.call( this ); this.type = 'RingGeometry'; this.parameters = { innerRadius: innerRadius, outerRadius: outerRadius, thetaSegments: thetaSegments, phiSegments: phiSegments, thetaStart: thetaStart, thetaLength: thetaLength }; innerRadius = innerRadius || 0; outerRadius = outerRadius || 50; thetaStart = thetaStart !== undefined ? thetaStart : 0; thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 8; var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); for ( i = 0; i < phiSegments + 1; i ++ ) { // concentric circles inside ring for ( o = 0; o < thetaSegments + 1; o ++ ) { // number of segments per circle var vertex = new THREE.Vector3(); var segment = thetaStart + o / thetaSegments * thetaLength; vertex.x = radius * Math.cos( segment ); vertex.y = radius * Math.sin( segment ); this.vertices.push( vertex ); uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); } radius += radiusStep; } var n = new THREE.Vector3( 0, 0, 1 ); for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring var thetaSegment = i * ( thetaSegments + 1 ); for ( o = 0; o < thetaSegments ; o ++ ) { // number of segments per circle var segment = o + thetaSegment; var v1 = segment; var v2 = segment + thetaSegments + 1; var v3 = segment + thetaSegments + 2; this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ] ); v1 = segment; v2 = segment + thetaSegments + 2; v3 = segment + 1; this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ] ); } } this.computeFaceNormals(); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); }; THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.RingGeometry.prototype.constructor = THREE.RingGeometry; THREE.RingGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.RingGeometry( parameters.innerRadius, parameters.outerRadius, parameters.thetaSegments, parameters.phiSegments, parameters.thetaStart, parameters.thetaLength ); }; three.js-r73/src/extras/geometries/ExtrudeGeometry.js0000644000175500017550000003637112610076566022720 0ustar debacledebacle/** * @author zz85 / http://www.lab4games.net/zz85/blog * * Creates extruded geometry from a path shape. * * parameters = { * * curveSegments: , // number of points on the curves * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too * amount: , // Depth to extrude the shape * * bevelEnabled: , // turn on bevel * bevelThickness: , // how deep into the original shape bevel goes * bevelSize: , // how far from shape outline is bevel * bevelSegments: , // number of bevel layers * * extrudePath: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) * frames: // containing arrays of tangents, normals, binormals * * uvGenerator: // object that provides UV generator functions * * } **/ THREE.ExtrudeGeometry = function ( shapes, options ) { if ( typeof( shapes ) === "undefined" ) { shapes = []; return; } THREE.Geometry.call( this ); this.type = 'ExtrudeGeometry'; shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; this.addShapeList( shapes, options ); this.computeFaceNormals(); // can't really use automatic vertex normals // as then front and back sides get smoothed too // should do separate smoothing just for sides //this.computeVertexNormals(); //console.log( "took", ( Date.now() - startTime ) ); }; THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ExtrudeGeometry.prototype.constructor = THREE.ExtrudeGeometry; THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { var sl = shapes.length; for ( var s = 0; s < sl; s ++ ) { var shape = shapes[ s ]; this.addShape( shape, options ); } }; THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var amount = options.amount !== undefined ? options.amount : 100; var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; var steps = options.steps !== undefined ? options.steps : 1; var extrudePath = options.extrudePath; var extrudePts, extrudeByPath = false; // Use default WorldUVGenerator if no UV generators are specified. var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; var splineTube, binormal, normal, position2; if ( extrudePath ) { extrudePts = extrudePath.getSpacedPoints( steps ); extrudeByPath = true; bevelEnabled = false; // bevels not supported for path extrusion // SETUP TNB variables // Reuse TNB from TubeGeomtry for now. // TODO1 - have a .isClosed in spline? splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames( extrudePath, steps, false ); // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); binormal = new THREE.Vector3(); normal = new THREE.Vector3(); position2 = new THREE.Vector3(); } // Safeguards if bevels are not enabled if ( ! bevelEnabled ) { bevelSegments = 0; bevelThickness = 0; bevelSize = 0; } // Variables initialization var ahole, h, hl; // looping of holes var scope = this; var shapesOffset = this.vertices.length; var shapePoints = shape.extractPoints( curveSegments ); var vertices = shapePoints.shape; var holes = shapePoints.holes; var reverse = ! THREE.ShapeUtils.isClockWise( vertices ); if ( reverse ) { vertices = vertices.reverse(); // Maybe we should also check if holes are in the opposite direction, just to be safe ... for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; if ( THREE.ShapeUtils.isClockWise( ahole ) ) { holes[ h ] = ahole.reverse(); } } reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! } var faces = THREE.ShapeUtils.triangulateShape( vertices, holes ); /* Vertices */ var contour = vertices; // vertices has all points but contour has only points of circumference for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; vertices = vertices.concat( ahole ); } function scalePt2 ( pt, vec, size ) { if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); return vec.clone().multiplyScalar( size ).add( pt ); } var b, bs, t, z, vert, vlen = vertices.length, face, flen = faces.length; // Find directions for point movement function getBevelVec( inPt, inPrev, inNext ) { // computes for inPt the corresponding point inPt' on a new contour // shifted by 1 unit (length of normalized vector) to the left // if we walk along contour clockwise, this new contour is outside the old one // // inPt' is the intersection of the two lines parallel to the two // adjacent edges of inPt at a distance of 1 unit on the left side. var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt // good reading for geometry algorithms (here: line-line intersection) // http://geomalgorithms.com/a05-_intersect-1.html var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); // check for collinear edges var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); if ( Math.abs( collinear0 ) > Number.EPSILON ) { // not collinear // length of vectors for normalizing var v_prev_len = Math.sqrt( v_prev_lensq ); var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); // shift adjacent points by unit vectors to the left var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); // scaling factor for v_prev to intersection point var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / ( v_prev_x * v_next_y - v_prev_y * v_next_x ); // vector from inPt to intersection point v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); // Don't normalize!, otherwise sharp corners become ugly // but prevent crazy spikes var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); if ( v_trans_lensq <= 2 ) { return new THREE.Vector2( v_trans_x, v_trans_y ); } else { shrink_by = Math.sqrt( v_trans_lensq / 2 ); } } else { // handle special case of collinear edges var direction_eq = false; // assumes: opposite if ( v_prev_x > Number.EPSILON ) { if ( v_next_x > Number.EPSILON ) { direction_eq = true; } } else { if ( v_prev_x < - Number.EPSILON ) { if ( v_next_x < - Number.EPSILON ) { direction_eq = true; } } else { if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { direction_eq = true; } } } if ( direction_eq ) { // console.log("Warning: lines are a straight sequence"); v_trans_x = - v_prev_y; v_trans_y = v_prev_x; shrink_by = Math.sqrt( v_prev_lensq ); } else { // console.log("Warning: lines are a straight spike"); v_trans_x = v_prev_x; v_trans_y = v_prev_y; shrink_by = Math.sqrt( v_prev_lensq / 2 ); } } return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); } var contourMovements = []; for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { if ( j === il ) j = 0; if ( k === il ) k = 0; // (j)---(i)---(k) // console.log('i,j,k', i, j , k) contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); } var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; oneHoleMovements = []; for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { if ( j === il ) j = 0; if ( k === il ) k = 0; // (j)---(i)---(k) oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); } holesMovements.push( oneHoleMovements ); verticesMovements = verticesMovements.concat( oneHoleMovements ); } // Loop bevelSegments, 1 for the front, 1 for the back for ( b = 0; b < bevelSegments; b ++ ) { //for ( b = bevelSegments; b > 0; b -- ) { t = b / bevelSegments; z = bevelThickness * ( 1 - t ); //z = bevelThickness * t; bs = bevelSize * ( Math.sin ( t * Math.PI / 2 ) ); // curved //bs = bevelSize * t; // linear // contract shape for ( i = 0, il = contour.length; i < il; i ++ ) { vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); v( vert.x, vert.y, - z ); } // expand holes for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; oneHoleMovements = holesMovements[ h ]; for ( i = 0, il = ahole.length; i < il; i ++ ) { vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); v( vert.x, vert.y, - z ); } } } bs = bevelSize; // Back facing vertices for ( i = 0; i < vlen; i ++ ) { vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; if ( ! extrudeByPath ) { v( vert.x, vert.y, 0 ); } else { // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); v( position2.x, position2.y, position2.z ); } } // Add stepped vertices... // Including front facing vertices var s; for ( s = 1; s <= steps; s ++ ) { for ( i = 0; i < vlen; i ++ ) { vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; if ( ! extrudeByPath ) { v( vert.x, vert.y, amount / steps * s ); } else { // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); v( position2.x, position2.y, position2.z ); } } } // Add bevel segments planes //for ( b = 1; b <= bevelSegments; b ++ ) { for ( b = bevelSegments - 1; b >= 0; b -- ) { t = b / bevelSegments; z = bevelThickness * ( 1 - t ); //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); bs = bevelSize * Math.sin ( t * Math.PI / 2 ); // contract shape for ( i = 0, il = contour.length; i < il; i ++ ) { vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); v( vert.x, vert.y, amount + z ); } // expand holes for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; oneHoleMovements = holesMovements[ h ]; for ( i = 0, il = ahole.length; i < il; i ++ ) { vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); if ( ! extrudeByPath ) { v( vert.x, vert.y, amount + z ); } else { v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); } } } } /* Faces */ // Top and bottom faces buildLidFaces(); // Sides faces buildSideFaces(); ///// Internal functions function buildLidFaces() { if ( bevelEnabled ) { var layer = 0; // steps + 1 var offset = vlen * layer; // Bottom faces for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); } layer = steps + bevelSegments * 2; offset = vlen * layer; // Top faces for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); } } else { // Bottom faces for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; f3( face[ 2 ], face[ 1 ], face[ 0 ] ); } // Top faces for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); } } } // Create faces for the z-sides of the shape function buildSideFaces() { var layeroffset = 0; sidewalls( contour, layeroffset ); layeroffset += contour.length; for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; sidewalls( ahole, layeroffset ); //, true layeroffset += ahole.length; } } function sidewalls( contour, layeroffset ) { var j, k; i = contour.length; while ( -- i >= 0 ) { j = i; k = i - 1; if ( k < 0 ) k = contour.length - 1; //console.log('b', i,j, i-1, k,vertices.length); var s = 0, sl = steps + bevelSegments * 2; for ( s = 0; s < sl; s ++ ) { var slen1 = vlen * s; var slen2 = vlen * ( s + 1 ); var a = layeroffset + j + slen1, b = layeroffset + k + slen1, c = layeroffset + k + slen2, d = layeroffset + j + slen2; f4( a, b, c, d, contour, s, sl, j, k ); } } } function v( x, y, z ) { scope.vertices.push( new THREE.Vector3( x, y, z ) ); } function f3( a, b, c ) { a += shapesOffset; b += shapesOffset; c += shapesOffset; scope.faces.push( new THREE.Face3( a, b, c, null, null, 0 ) ); var uvs = uvgen.generateTopUV( scope, a, b, c ); scope.faceVertexUvs[ 0 ].push( uvs ); } function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { a += shapesOffset; b += shapesOffset; c += shapesOffset; d += shapesOffset; scope.faces.push( new THREE.Face3( a, b, d, null, null, 1 ) ); scope.faces.push( new THREE.Face3( b, c, d, null, null, 1 ) ); var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); } }; THREE.ExtrudeGeometry.WorldUVGenerator = { generateTopUV: function ( geometry, indexA, indexB, indexC ) { var vertices = geometry.vertices; var a = vertices[ indexA ]; var b = vertices[ indexB ]; var c = vertices[ indexC ]; return [ new THREE.Vector2( a.x, a.y ), new THREE.Vector2( b.x, b.y ), new THREE.Vector2( c.x, c.y ) ]; }, generateSideWallUV: function ( geometry, indexA, indexB, indexC, indexD ) { var vertices = geometry.vertices; var a = vertices[ indexA ]; var b = vertices[ indexB ]; var c = vertices[ indexC ]; var d = vertices[ indexD ]; if ( Math.abs( a.y - b.y ) < 0.01 ) { return [ new THREE.Vector2( a.x, 1 - a.z ), new THREE.Vector2( b.x, 1 - b.z ), new THREE.Vector2( c.x, 1 - c.z ), new THREE.Vector2( d.x, 1 - d.z ) ]; } else { return [ new THREE.Vector2( a.y, 1 - a.z ), new THREE.Vector2( b.y, 1 - b.z ), new THREE.Vector2( c.y, 1 - c.z ), new THREE.Vector2( d.y, 1 - d.z ) ]; } } }; three.js-r73/src/extras/geometries/CircleBufferGeometry.js0000644000175500017550000000411412610076566023621 0ustar debacledebacle/** * @author benaadams / https://twitter.com/ben_a_adams */ THREE.CircleBufferGeometry = function ( radius, segments, thetaStart, thetaLength ) { THREE.BufferGeometry.call( this ); this.type = 'CircleBufferGeometry'; this.parameters = { radius: radius, segments: segments, thetaStart: thetaStart, thetaLength: thetaLength }; radius = radius || 50; segments = segments !== undefined ? Math.max( 3, segments ) : 8; thetaStart = thetaStart !== undefined ? thetaStart : 0; thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; var vertices = segments + 2; var positions = new Float32Array( vertices * 3 ); var normals = new Float32Array( vertices * 3 ); var uvs = new Float32Array( vertices * 2 ); // center data is already zero, but need to set a few extras normals[ 2 ] = 1.0; uvs[ 0 ] = 0.5; uvs[ 1 ] = 0.5; for ( var s = 0, i = 3, ii = 2 ; s <= segments; s ++, i += 3, ii += 2 ) { var segment = thetaStart + s / segments * thetaLength; positions[ i ] = radius * Math.cos( segment ); positions[ i + 1 ] = radius * Math.sin( segment ); normals[ i + 2 ] = 1; // normal z uvs[ ii ] = ( positions[ i ] / radius + 1 ) / 2; uvs[ ii + 1 ] = ( positions[ i + 1 ] / radius + 1 ) / 2; } var indices = []; for ( var i = 1; i <= segments; i ++ ) { indices.push( i, i + 1, 0 ); } this.setIndex( new THREE.BufferAttribute( new Uint16Array( indices ), 1 ) ); this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); }; THREE.CircleBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.CircleBufferGeometry.prototype.constructor = THREE.CircleBufferGeometry; THREE.CircleBufferGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.CircleBufferGeometry( parameters.radius, parameters.segments, parameters.thetaStart, parameters.thetaLength ); }; three.js-r73/src/extras/geometries/CylinderGeometry.js0000644000175500017550000001140112610076566023034 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { THREE.Geometry.call( this ); this.type = 'CylinderGeometry'; this.parameters = { radiusTop: radiusTop, radiusBottom: radiusBottom, height: height, radialSegments: radialSegments, heightSegments: heightSegments, openEnded: openEnded, thetaStart: thetaStart, thetaLength: thetaLength }; radiusTop = radiusTop !== undefined ? radiusTop : 20; radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; height = height !== undefined ? height : 100; radialSegments = radialSegments || 8; heightSegments = heightSegments || 1; openEnded = openEnded !== undefined ? openEnded : false; thetaStart = thetaStart !== undefined ? thetaStart : 0; thetaLength = thetaLength !== undefined ? thetaLength : 2 * Math.PI; var heightHalf = height / 2; var x, y, vertices = [], uvs = []; for ( y = 0; y <= heightSegments; y ++ ) { var verticesRow = []; var uvsRow = []; var v = y / heightSegments; var radius = v * ( radiusBottom - radiusTop ) + radiusTop; for ( x = 0; x <= radialSegments; x ++ ) { var u = x / radialSegments; var vertex = new THREE.Vector3(); vertex.x = radius * Math.sin( u * thetaLength + thetaStart ); vertex.y = - v * height + heightHalf; vertex.z = radius * Math.cos( u * thetaLength + thetaStart ); this.vertices.push( vertex ); verticesRow.push( this.vertices.length - 1 ); uvsRow.push( new THREE.Vector2( u, 1 - v ) ); } vertices.push( verticesRow ); uvs.push( uvsRow ); } var tanTheta = ( radiusBottom - radiusTop ) / height; var na, nb; for ( x = 0; x < radialSegments; x ++ ) { if ( radiusTop !== 0 ) { na = this.vertices[ vertices[ 0 ][ x ] ].clone(); nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); } else { na = this.vertices[ vertices[ 1 ][ x ] ].clone(); nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); } na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); for ( y = 0; y < heightSegments; y ++ ) { var v1 = vertices[ y ][ x ]; var v2 = vertices[ y + 1 ][ x ]; var v3 = vertices[ y + 1 ][ x + 1 ]; var v4 = vertices[ y ][ x + 1 ]; var n1 = na.clone(); var n2 = na.clone(); var n3 = nb.clone(); var n4 = nb.clone(); var uv1 = uvs[ y ][ x ].clone(); var uv2 = uvs[ y + 1 ][ x ].clone(); var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); var uv4 = uvs[ y ][ x + 1 ].clone(); this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); } } // top cap if ( openEnded === false && radiusTop > 0 ) { this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); for ( x = 0; x < radialSegments; x ++ ) { var v1 = vertices[ 0 ][ x ]; var v2 = vertices[ 0 ][ x + 1 ]; var v3 = this.vertices.length - 1; var n1 = new THREE.Vector3( 0, 1, 0 ); var n2 = new THREE.Vector3( 0, 1, 0 ); var n3 = new THREE.Vector3( 0, 1, 0 ); var uv1 = uvs[ 0 ][ x ].clone(); var uv2 = uvs[ 0 ][ x + 1 ].clone(); var uv3 = new THREE.Vector2( uv2.x, 0 ); this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ], undefined, 1 ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); } } // bottom cap if ( openEnded === false && radiusBottom > 0 ) { this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); for ( x = 0; x < radialSegments; x ++ ) { var v1 = vertices[ heightSegments ][ x + 1 ]; var v2 = vertices[ heightSegments ][ x ]; var v3 = this.vertices.length - 1; var n1 = new THREE.Vector3( 0, - 1, 0 ); var n2 = new THREE.Vector3( 0, - 1, 0 ); var n3 = new THREE.Vector3( 0, - 1, 0 ); var uv1 = uvs[ heightSegments ][ x + 1 ].clone(); var uv2 = uvs[ heightSegments ][ x ].clone(); var uv3 = new THREE.Vector2( uv2.x, 1 ); this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ], undefined, 2 ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); } } this.computeFaceNormals(); }; THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.CylinderGeometry.prototype.constructor = THREE.CylinderGeometry; THREE.CylinderGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.CylinderGeometry( parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments, parameters.heightSegments, parameters.openEnded, parameters.thetaStart, parameters.thetaLength ); }; three.js-r73/src/extras/geometries/TubeGeometry.js0000644000175500017550000001601412610076566022167 0ustar debacledebacle/** * @author WestLangley / https://github.com/WestLangley * @author zz85 / https://github.com/zz85 * @author miningold / https://github.com/miningold * @author jonobr1 / https://github.com/jonobr1 * * Modified from the TorusKnotGeometry by @oosmoxiecode * * Creates a tube which extrudes along a 3d spline * * Uses parallel transport frames as described in * http://www.cs.indiana.edu/pub/techreports/TR425.pdf */ THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed, taper ) { THREE.Geometry.call( this ); this.type = 'TubeGeometry'; this.parameters = { path: path, segments: segments, radius: radius, radialSegments: radialSegments, closed: closed, taper: taper }; segments = segments || 64; radius = radius || 1; radialSegments = radialSegments || 8; closed = closed || false; taper = taper || THREE.TubeGeometry.NoTaper; var grid = []; var scope = this, tangent, normal, binormal, numpoints = segments + 1, u, v, r, cx, cy, pos, pos2 = new THREE.Vector3(), i, j, ip, jp, a, b, c, d, uva, uvb, uvc, uvd; var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ), tangents = frames.tangents, normals = frames.normals, binormals = frames.binormals; // proxy internals this.tangents = tangents; this.normals = normals; this.binormals = binormals; function vert( x, y, z ) { return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; } // construct the grid for ( i = 0; i < numpoints; i ++ ) { grid[ i ] = []; u = i / ( numpoints - 1 ); pos = path.getPointAt( u ); tangent = tangents[ i ]; normal = normals[ i ]; binormal = binormals[ i ]; r = radius * taper( u ); for ( j = 0; j < radialSegments; j ++ ) { v = j / radialSegments * 2 * Math.PI; cx = - r * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. cy = r * Math.sin( v ); pos2.copy( pos ); pos2.x += cx * normal.x + cy * binormal.x; pos2.y += cx * normal.y + cy * binormal.y; pos2.z += cx * normal.z + cy * binormal.z; grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); } } // construct the mesh for ( i = 0; i < segments; i ++ ) { for ( j = 0; j < radialSegments; j ++ ) { ip = ( closed ) ? ( i + 1 ) % segments : i + 1; jp = ( j + 1 ) % radialSegments; a = grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** b = grid[ ip ][ j ]; c = grid[ ip ][ jp ]; d = grid[ i ][ jp ]; uva = new THREE.Vector2( i / segments, j / radialSegments ); uvb = new THREE.Vector2( ( i + 1 ) / segments, j / radialSegments ); uvc = new THREE.Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments ); uvd = new THREE.Vector2( i / segments, ( j + 1 ) / radialSegments ); this.faces.push( new THREE.Face3( a, b, d ) ); this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); this.faces.push( new THREE.Face3( b, c, d ) ); this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); } } this.computeFaceNormals(); this.computeVertexNormals(); }; THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TubeGeometry.prototype.constructor = THREE.TubeGeometry; THREE.TubeGeometry.prototype.clone = function() { return new this.constructor( this.parameters.path, this.parameters.segments, this.parameters.radius, this.parameters.radialSegments, this.parameters.closed, this.parameters.taper ); }; THREE.TubeGeometry.NoTaper = function ( u ) { return 1; }; THREE.TubeGeometry.SinusoidalTaper = function ( u ) { return Math.sin( Math.PI * u ); }; // For computing of Frenet frames, exposing the tangents, normals and binormals the spline THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { var normal = new THREE.Vector3(), tangents = [], normals = [], binormals = [], vec = new THREE.Vector3(), mat = new THREE.Matrix4(), numpoints = segments + 1, theta, smallest, tx, ty, tz, i, u; // expose internals this.tangents = tangents; this.normals = normals; this.binormals = binormals; // compute the tangent vectors for each segment on the path for ( i = 0; i < numpoints; i ++ ) { u = i / ( numpoints - 1 ); tangents[ i ] = path.getTangentAt( u ); tangents[ i ].normalize(); } initialNormal3(); /* function initialNormal1(lastBinormal) { // fixed start binormal. Has dangers of 0 vectors normals[ 0 ] = new THREE.Vector3(); binormals[ 0 ] = new THREE.Vector3(); if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); } function initialNormal2() { // This uses the Frenet-Serret formula for deriving binormal var t2 = path.getTangentAt( epsilon ); normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); } */ function initialNormal3() { // select an initial normal vector perpendicular to the first tangent vector, // and in the direction of the smallest tangent xyz component normals[ 0 ] = new THREE.Vector3(); binormals[ 0 ] = new THREE.Vector3(); smallest = Number.MAX_VALUE; tx = Math.abs( tangents[ 0 ].x ); ty = Math.abs( tangents[ 0 ].y ); tz = Math.abs( tangents[ 0 ].z ); if ( tx <= smallest ) { smallest = tx; normal.set( 1, 0, 0 ); } if ( ty <= smallest ) { smallest = ty; normal.set( 0, 1, 0 ); } if ( tz <= smallest ) { normal.set( 0, 0, 1 ); } vec.crossVectors( tangents[ 0 ], normal ).normalize(); normals[ 0 ].crossVectors( tangents[ 0 ], vec ); binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); } // compute the slowly-varying normal and binormal vectors for each segment on the path for ( i = 1; i < numpoints; i ++ ) { normals[ i ] = normals[ i - 1 ].clone(); binormals[ i ] = binormals[ i - 1 ].clone(); vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); if ( vec.length() > Number.EPSILON ) { vec.normalize(); theta = Math.acos( THREE.Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); } binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); } // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same if ( closed ) { theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints - 1 ] ), - 1, 1 ) ); theta /= ( numpoints - 1 ); if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) { theta = - theta; } for ( i = 1; i < numpoints; i ++ ) { // twist a little... normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); } } }; three.js-r73/src/extras/geometries/OctahedronGeometry.js0000644000175500017550000000154312610076566023357 0ustar debacledebacle/** * @author timothypratley / https://github.com/timothypratley */ THREE.OctahedronGeometry = function ( radius, detail ) { var vertices = [ 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 1, 0, 0, - 1 ]; var indices = [ 0, 2, 4, 0, 4, 3, 0, 3, 5, 0, 5, 2, 1, 2, 5, 1, 5, 3, 1, 3, 4, 1, 4, 2 ]; THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); this.type = 'OctahedronGeometry'; this.parameters = { radius: radius, detail: detail }; }; THREE.OctahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.OctahedronGeometry.prototype.constructor = THREE.OctahedronGeometry; THREE.OctahedronGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.OctahedronGeometry( parameters.radius, parameters.detail ); }; three.js-r73/src/extras/geometries/PlaneGeometry.js0000644000175500017550000000162412610076566022330 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as */ THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { THREE.Geometry.call( this ); this.type = 'PlaneGeometry'; this.parameters = { width: width, height: height, widthSegments: widthSegments, heightSegments: heightSegments }; this.fromBufferGeometry( new THREE.PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); }; THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.PlaneGeometry.prototype.constructor = THREE.PlaneGeometry; THREE.PlaneGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.PlaneGeometry( parameters.width, parameters.height, parameters.widthSegments, parameters.heightSegments ); }; three.js-r73/src/extras/geometries/TetrahedronGeometry.js0000644000175500017550000000146512610076566023553 0ustar debacledebacle/** * @author timothypratley / https://github.com/timothypratley */ THREE.TetrahedronGeometry = function ( radius, detail ) { var vertices = [ 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 ]; var indices = [ 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 ]; THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); this.type = 'TetrahedronGeometry'; this.parameters = { radius: radius, detail: detail }; }; THREE.TetrahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.TetrahedronGeometry.prototype.constructor = THREE.TetrahedronGeometry; THREE.TetrahedronGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.TetrahedronGeometry( parameters.radius, parameters.detail ); }; three.js-r73/src/extras/geometries/WireframeGeometry.js0000644000175500017550000000742412610076566023216 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WireframeGeometry = function ( geometry ) { THREE.BufferGeometry.call( this ); var edge = [ 0, 0 ], hash = {}; function sortFunction( a, b ) { return a - b; } var keys = [ 'a', 'b', 'c' ]; if ( geometry instanceof THREE.Geometry ) { var vertices = geometry.vertices; var faces = geometry.faces; var numEdges = 0; // allocate maximal size var edges = new Uint32Array( 6 * faces.length ); for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0; j < 3; j ++ ) { edge[ 0 ] = face[ keys[ j ] ]; edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; edge.sort( sortFunction ); var key = edge.toString(); if ( hash[ key ] === undefined ) { edges[ 2 * numEdges ] = edge[ 0 ]; edges[ 2 * numEdges + 1 ] = edge[ 1 ]; hash[ key ] = true; numEdges ++; } } } var coords = new Float32Array( numEdges * 2 * 3 ); for ( var i = 0, l = numEdges; i < l; i ++ ) { for ( var j = 0; j < 2; j ++ ) { var vertex = vertices[ edges [ 2 * i + j ] ]; var index = 6 * i + 3 * j; coords[ index + 0 ] = vertex.x; coords[ index + 1 ] = vertex.y; coords[ index + 2 ] = vertex.z; } } this.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); } else if ( geometry instanceof THREE.BufferGeometry ) { if ( geometry.index !== null ) { // Indexed BufferGeometry var indices = geometry.index.array; var vertices = geometry.attributes.position; var drawcalls = geometry.drawcalls; var numEdges = 0; if ( drawcalls.length === 0 ) { geometry.addGroup( 0, indices.length ); } // allocate maximal size var edges = new Uint32Array( 2 * indices.length ); for ( var o = 0, ol = drawcalls.length; o < ol; ++ o ) { var drawcall = drawcalls[ o ]; var start = drawcall.start; var count = drawcall.count; for ( var i = start, il = start + count; i < il; i += 3 ) { for ( var j = 0; j < 3; j ++ ) { edge[ 0 ] = indices[ i + j ]; edge[ 1 ] = indices[ i + ( j + 1 ) % 3 ]; edge.sort( sortFunction ); var key = edge.toString(); if ( hash[ key ] === undefined ) { edges[ 2 * numEdges ] = edge[ 0 ]; edges[ 2 * numEdges + 1 ] = edge[ 1 ]; hash[ key ] = true; numEdges ++; } } } } var coords = new Float32Array( numEdges * 2 * 3 ); for ( var i = 0, l = numEdges; i < l; i ++ ) { for ( var j = 0; j < 2; j ++ ) { var index = 6 * i + 3 * j; var index2 = edges[ 2 * i + j ]; coords[ index + 0 ] = vertices.getX( index2 ); coords[ index + 1 ] = vertices.getY( index2 ); coords[ index + 2 ] = vertices.getZ( index2 ); } } this.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); } else { // non-indexed BufferGeometry var vertices = geometry.attributes.position.array; var numEdges = vertices.length / 3; var numTris = numEdges / 3; var coords = new Float32Array( numEdges * 2 * 3 ); for ( var i = 0, l = numTris; i < l; i ++ ) { for ( var j = 0; j < 3; j ++ ) { var index = 18 * i + 6 * j; var index1 = 9 * i + 3 * j; coords[ index + 0 ] = vertices[ index1 ]; coords[ index + 1 ] = vertices[ index1 + 1 ]; coords[ index + 2 ] = vertices[ index1 + 2 ]; var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); coords[ index + 3 ] = vertices[ index2 ]; coords[ index + 4 ] = vertices[ index2 + 1 ]; coords[ index + 5 ] = vertices[ index2 + 2 ]; } } this.addAttribute( 'position', new THREE.BufferAttribute( coords, 3 ) ); } } }; THREE.WireframeGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.WireframeGeometry.prototype.constructor = THREE.WireframeGeometry; three.js-r73/src/extras/geometries/ParametricGeometry.js0000644000175500017550000000341212610076566023355 0ustar debacledebacle/** * @author zz85 / https://github.com/zz85 * Parametric Surfaces Geometry * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 * * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); * */ THREE.ParametricGeometry = function ( func, slices, stacks ) { THREE.Geometry.call( this ); this.type = 'ParametricGeometry'; this.parameters = { func: func, slices: slices, stacks: stacks }; var verts = this.vertices; var faces = this.faces; var uvs = this.faceVertexUvs[ 0 ]; var i, j, p; var u, v; var sliceCount = slices + 1; for ( i = 0; i <= stacks; i ++ ) { v = i / stacks; for ( j = 0; j <= slices; j ++ ) { u = j / slices; p = func( u, v ); verts.push( p ); } } var a, b, c, d; var uva, uvb, uvc, uvd; for ( i = 0; i < stacks; i ++ ) { for ( j = 0; j < slices; j ++ ) { a = i * sliceCount + j; b = i * sliceCount + j + 1; c = ( i + 1 ) * sliceCount + j + 1; d = ( i + 1 ) * sliceCount + j; uva = new THREE.Vector2( j / slices, i / stacks ); uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); faces.push( new THREE.Face3( a, b, d ) ); uvs.push( [ uva, uvb, uvd ] ); faces.push( new THREE.Face3( b, c, d ) ); uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); } } // console.log(this); // magic bullet // var diff = this.mergeVertices(); // console.log('removed ', diff, ' vertices by merging'); this.computeFaceNormals(); this.computeVertexNormals(); }; THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ParametricGeometry.prototype.constructor = THREE.ParametricGeometry; three.js-r73/src/extras/geometries/BoxGeometry.js0000644000175500017550000000752112610076566022023 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as */ THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { THREE.Geometry.call( this ); this.type = 'BoxGeometry'; this.parameters = { width: width, height: height, depth: depth, widthSegments: widthSegments, heightSegments: heightSegments, depthSegments: depthSegments }; this.widthSegments = widthSegments || 1; this.heightSegments = heightSegments || 1; this.depthSegments = depthSegments || 1; var scope = this; var width_half = width / 2; var height_half = height / 2; var depth_half = depth / 2; buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { var w, ix, iy, gridX = scope.widthSegments, gridY = scope.heightSegments, width_half = width / 2, height_half = height / 2, offset = scope.vertices.length; if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { w = 'z'; } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { w = 'y'; gridY = scope.depthSegments; } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { w = 'x'; gridX = scope.depthSegments; } var gridX1 = gridX + 1, gridY1 = gridY + 1, segment_width = width / gridX, segment_height = height / gridY, normal = new THREE.Vector3(); normal[ w ] = depth > 0 ? 1 : - 1; for ( iy = 0; iy < gridY1; iy ++ ) { for ( ix = 0; ix < gridX1; ix ++ ) { var vector = new THREE.Vector3(); vector[ u ] = ( ix * segment_width - width_half ) * udir; vector[ v ] = ( iy * segment_height - height_half ) * vdir; vector[ w ] = depth; scope.vertices.push( vector ); } } for ( iy = 0; iy < gridY; iy ++ ) { for ( ix = 0; ix < gridX; ix ++ ) { var a = ix + gridX1 * iy; var b = ix + gridX1 * ( iy + 1 ); var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); var d = ( ix + 1 ) + gridX1 * iy; var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); var face = new THREE.Face3( a + offset, b + offset, d + offset ); face.normal.copy( normal ); face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); face.materialIndex = materialIndex; scope.faces.push( face ); scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); face = new THREE.Face3( b + offset, c + offset, d + offset ); face.normal.copy( normal ); face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); face.materialIndex = materialIndex; scope.faces.push( face ); scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); } } } this.mergeVertices(); }; THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.BoxGeometry.prototype.constructor = THREE.BoxGeometry; THREE.BoxGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.BoxGeometry( parameters.width, parameters.height, parameters.depth, parameters.widthSegments, parameters.heightSegments, parameters.depthSegments ); }; THREE.CubeGeometry = THREE.BoxGeometry; // backwards compatibility three.js-r73/src/extras/geometries/LatheGeometry.js0000644000175500017550000000447612610076566022336 0ustar debacledebacle/** * @author astrodud / http://astrodud.isgreat.org/ * @author zz85 / https://github.com/zz85 * @author bhouston / http://clara.io */ // points - to create a closed torus, one must use a set of points // like so: [ a, b, c, d, a ], see first is the same as last. // segments - the number of circumference segments to create // phiStart - the starting radian // phiLength - the radian (0 to 2*PI) range of the lathed section // 2*pi is a closed lathe, less than 2PI is a portion. THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { THREE.Geometry.call( this ); this.type = 'LatheGeometry'; this.parameters = { points: points, segments: segments, phiStart: phiStart, phiLength: phiLength }; segments = segments || 12; phiStart = phiStart || 0; phiLength = phiLength || 2 * Math.PI; var inversePointLength = 1.0 / ( points.length - 1 ); var inverseSegments = 1.0 / segments; for ( var i = 0, il = segments; i <= il; i ++ ) { var phi = phiStart + i * inverseSegments * phiLength; var c = Math.cos( phi ), s = Math.sin( phi ); for ( var j = 0, jl = points.length; j < jl; j ++ ) { var pt = points[ j ]; var vertex = new THREE.Vector3(); vertex.x = c * pt.x - s * pt.y; vertex.y = s * pt.x + c * pt.y; vertex.z = pt.z; this.vertices.push( vertex ); } } var np = points.length; for ( var i = 0, il = segments; i < il; i ++ ) { for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { var base = j + np * i; var a = base; var b = base + np; var c = base + 1 + np; var d = base + 1; var u0 = i * inverseSegments; var v0 = j * inversePointLength; var u1 = u0 + inverseSegments; var v1 = v0 + inversePointLength; this.faces.push( new THREE.Face3( a, b, d ) ); this.faceVertexUvs[ 0 ].push( [ new THREE.Vector2( u0, v0 ), new THREE.Vector2( u1, v0 ), new THREE.Vector2( u0, v1 ) ] ); this.faces.push( new THREE.Face3( b, c, d ) ); this.faceVertexUvs[ 0 ].push( [ new THREE.Vector2( u1, v0 ), new THREE.Vector2( u1, v1 ), new THREE.Vector2( u0, v1 ) ] ); } } this.mergeVertices(); this.computeFaceNormals(); this.computeVertexNormals(); }; THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.LatheGeometry.prototype.constructor = THREE.LatheGeometry; three.js-r73/src/extras/geometries/TorusGeometry.js0000644000175500017550000000475212610076566022412 0ustar debacledebacle/** * @author oosmoxiecode * @author mrdoob / http://mrdoob.com/ * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 */ THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { THREE.Geometry.call( this ); this.type = 'TorusGeometry'; this.parameters = { radius: radius, tube: tube, radialSegments: radialSegments, tubularSegments: tubularSegments, arc: arc }; radius = radius || 100; tube = tube || 40; radialSegments = radialSegments || 8; tubularSegments = tubularSegments || 6; arc = arc || Math.PI * 2; var center = new THREE.Vector3(), uvs = [], normals = []; for ( var j = 0; j <= radialSegments; j ++ ) { for ( var i = 0; i <= tubularSegments; i ++ ) { var u = i / tubularSegments * arc; var v = j / radialSegments * Math.PI * 2; center.x = radius * Math.cos( u ); center.y = radius * Math.sin( u ); var vertex = new THREE.Vector3(); vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); vertex.z = tube * Math.sin( v ); this.vertices.push( vertex ); uvs.push( new THREE.Vector2( i / tubularSegments, j / radialSegments ) ); normals.push( vertex.clone().sub( center ).normalize() ); } } for ( var j = 1; j <= radialSegments; j ++ ) { for ( var i = 1; i <= tubularSegments; i ++ ) { var a = ( tubularSegments + 1 ) * j + i - 1; var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; var c = ( tubularSegments + 1 ) * ( j - 1 ) + i; var d = ( tubularSegments + 1 ) * j + i; var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); this.faces.push( face ); this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); this.faces.push( face ); this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); } } this.computeFaceNormals(); }; THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TorusGeometry.prototype.constructor = THREE.TorusGeometry; THREE.TorusGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.TorusGeometry( parameters.radius, parameters.tube, parameters.radialSegments, parameters.tubularSegments, parameters.arc ); }; three.js-r73/src/extras/geometries/SphereGeometry.js0000644000175500017550000000202612610076566022514 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { THREE.Geometry.call( this ); this.type = 'SphereGeometry'; this.parameters = { radius: radius, widthSegments: widthSegments, heightSegments: heightSegments, phiStart: phiStart, phiLength: phiLength, thetaStart: thetaStart, thetaLength: thetaLength }; this.fromBufferGeometry( new THREE.SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); }; THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.SphereGeometry.prototype.constructor = THREE.SphereGeometry; THREE.SphereGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.SphereGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength, parameters.thetaStart, parameters.thetaLength ); }; three.js-r73/src/extras/geometries/EdgesGeometry.js0000644000175500017550000000351612610076566022322 0ustar debacledebacle/** * @author WestLangley / http://github.com/WestLangley */ THREE.EdgesGeometry = function ( geometry, thresholdAngle ) { THREE.BufferGeometry.call( this ); thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) ); var edge = [ 0, 0 ], hash = {}; function sortFunction( a, b ) { return a - b; } var keys = [ 'a', 'b', 'c' ]; var geometry2; if ( geometry instanceof THREE.BufferGeometry ) { geometry2 = new THREE.Geometry(); geometry2.fromBufferGeometry( geometry ); } else { geometry2 = geometry.clone(); } geometry2.mergeVertices(); geometry2.computeFaceNormals(); var vertices = geometry2.vertices; var faces = geometry2.faces; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0; j < 3; j ++ ) { edge[ 0 ] = face[ keys[ j ] ]; edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; edge.sort( sortFunction ); var key = edge.toString(); if ( hash[ key ] === undefined ) { hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; } else { hash[ key ].face2 = i; } } } var coords = []; for ( var key in hash ) { var h = hash[ key ]; if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) { var vertex = vertices[ h.vert1 ]; coords.push( vertex.x ); coords.push( vertex.y ); coords.push( vertex.z ); vertex = vertices[ h.vert2 ]; coords.push( vertex.x ); coords.push( vertex.y ); coords.push( vertex.z ); } } this.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( coords ), 3 ) ); }; THREE.EdgesGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.EdgesGeometry.prototype.constructor = THREE.EdgesGeometry; three.js-r73/src/extras/geometries/IcosahedronGeometry.js0000644000175500017550000000226112610076566023525 0ustar debacledebacle/** * @author timothypratley / https://github.com/timothypratley */ THREE.IcosahedronGeometry = function ( radius, detail ) { var t = ( 1 + Math.sqrt( 5 ) ) / 2; var vertices = [ - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 ]; var indices = [ 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 ]; THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); this.type = 'IcosahedronGeometry'; this.parameters = { radius: radius, detail: detail }; }; THREE.IcosahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.IcosahedronGeometry.prototype.constructor = THREE.IcosahedronGeometry; THREE.IcosahedronGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.IcosahedronGeometry( parameters.radius, parameters.detail ); }; three.js-r73/src/extras/geometries/TorusKnotGeometry.js0000644000175500017550000000654112610076566023244 0ustar debacledebacle/** * @author oosmoxiecode * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 */ THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { THREE.Geometry.call( this ); this.type = 'TorusKnotGeometry'; this.parameters = { radius: radius, tube: tube, radialSegments: radialSegments, tubularSegments: tubularSegments, p: p, q: q, heightScale: heightScale }; radius = radius || 100; tube = tube || 40; radialSegments = radialSegments || 64; tubularSegments = tubularSegments || 8; p = p || 2; q = q || 3; heightScale = heightScale || 1; var grid = new Array( radialSegments ); var tang = new THREE.Vector3(); var n = new THREE.Vector3(); var bitan = new THREE.Vector3(); for ( var i = 0; i < radialSegments; ++ i ) { grid[ i ] = new Array( tubularSegments ); var u = i / radialSegments * 2 * p * Math.PI; var p1 = getPos( u, q, p, radius, heightScale ); var p2 = getPos( u + 0.01, q, p, radius, heightScale ); tang.subVectors( p2, p1 ); n.addVectors( p2, p1 ); bitan.crossVectors( tang, n ); n.crossVectors( bitan, tang ); bitan.normalize(); n.normalize(); for ( var j = 0; j < tubularSegments; ++ j ) { var v = j / tubularSegments * 2 * Math.PI; var cx = - tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. var cy = tube * Math.sin( v ); var pos = new THREE.Vector3(); pos.x = p1.x + cx * n.x + cy * bitan.x; pos.y = p1.y + cx * n.y + cy * bitan.y; pos.z = p1.z + cx * n.z + cy * bitan.z; grid[ i ][ j ] = this.vertices.push( pos ) - 1; } } for ( var i = 0; i < radialSegments; ++ i ) { for ( var j = 0; j < tubularSegments; ++ j ) { var ip = ( i + 1 ) % radialSegments; var jp = ( j + 1 ) % tubularSegments; var a = grid[ i ][ j ]; var b = grid[ ip ][ j ]; var c = grid[ ip ][ jp ]; var d = grid[ i ][ jp ]; var uva = new THREE.Vector2( i / radialSegments, j / tubularSegments ); var uvb = new THREE.Vector2( ( i + 1 ) / radialSegments, j / tubularSegments ); var uvc = new THREE.Vector2( ( i + 1 ) / radialSegments, ( j + 1 ) / tubularSegments ); var uvd = new THREE.Vector2( i / radialSegments, ( j + 1 ) / tubularSegments ); this.faces.push( new THREE.Face3( a, b, d ) ); this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); this.faces.push( new THREE.Face3( b, c, d ) ); this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); } } this.computeFaceNormals(); this.computeVertexNormals(); function getPos( u, in_q, in_p, radius, heightScale ) { var cu = Math.cos( u ); var su = Math.sin( u ); var quOverP = in_q / in_p * u; var cs = Math.cos( quOverP ); var tx = radius * ( 2 + cs ) * 0.5 * cu; var ty = radius * ( 2 + cs ) * su * 0.5; var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; return new THREE.Vector3( tx, ty, tz ); } }; THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.TorusKnotGeometry.prototype.constructor = THREE.TorusKnotGeometry; THREE.TorusKnotGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.TorusKnotGeometry( parameters.radius, parameters.tube, parameters.radialSegments, parameters.tubularSegments, parameters.p, parameters.q, parameters.heightScale ); }; three.js-r73/src/extras/geometries/PolyhedronGeometry.js0000644000175500017550000001176112610076566023417 0ustar debacledebacle/** * @author clockworkgeek / https://github.com/clockworkgeek * @author timothypratley / https://github.com/timothypratley * @author WestLangley / http://github.com/WestLangley */ THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { THREE.Geometry.call( this ); this.type = 'PolyhedronGeometry'; this.parameters = { vertices: vertices, indices: indices, radius: radius, detail: detail }; radius = radius || 1; detail = detail || 0; var that = this; for ( var i = 0, l = vertices.length; i < l; i += 3 ) { prepare( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); } var p = this.vertices; var faces = []; for ( var i = 0, j = 0, l = indices.length; i < l; i += 3, j ++ ) { var v1 = p[ indices[ i ] ]; var v2 = p[ indices[ i + 1 ] ]; var v3 = p[ indices[ i + 2 ] ]; faces[ j ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ], undefined, j ); } var centroid = new THREE.Vector3(); for ( var i = 0, l = faces.length; i < l; i ++ ) { subdivide( faces[ i ], detail ); } // Handle case when face straddles the seam for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { var uvs = this.faceVertexUvs[ 0 ][ i ]; var x0 = uvs[ 0 ].x; var x1 = uvs[ 1 ].x; var x2 = uvs[ 2 ].x; var max = Math.max( x0, x1, x2 ); var min = Math.min( x0, x1, x2 ); if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary if ( x0 < 0.2 ) uvs[ 0 ].x += 1; if ( x1 < 0.2 ) uvs[ 1 ].x += 1; if ( x2 < 0.2 ) uvs[ 2 ].x += 1; } } // Apply radius for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { this.vertices[ i ].multiplyScalar( radius ); } // Merge vertices this.mergeVertices(); this.computeFaceNormals(); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); // Project vector onto sphere's surface function prepare( vector ) { var vertex = vector.normalize().clone(); vertex.index = that.vertices.push( vertex ) - 1; // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. var u = azimuth( vector ) / 2 / Math.PI + 0.5; var v = inclination( vector ) / Math.PI + 0.5; vertex.uv = new THREE.Vector2( u, 1 - v ); return vertex; } // Approximate a curved face with recursively sub-divided triangles. function make( v1, v2, v3, materialIndex ) { var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ], undefined, materialIndex ); that.faces.push( face ); centroid.copy( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); var azi = azimuth( centroid ); that.faceVertexUvs[ 0 ].push( [ correctUV( v1.uv, v1, azi ), correctUV( v2.uv, v2, azi ), correctUV( v3.uv, v3, azi ) ] ); } // Analytically subdivide a face to the required detail level. function subdivide( face, detail ) { var cols = Math.pow( 2, detail ); var a = prepare( that.vertices[ face.a ] ); var b = prepare( that.vertices[ face.b ] ); var c = prepare( that.vertices[ face.c ] ); var v = []; var materialIndex = face.materialIndex; // Construct all of the vertices for this subdivision. for ( var i = 0 ; i <= cols; i ++ ) { v[ i ] = []; var aj = prepare( a.clone().lerp( c, i / cols ) ); var bj = prepare( b.clone().lerp( c, i / cols ) ); var rows = cols - i; for ( var j = 0; j <= rows; j ++ ) { if ( j === 0 && i === cols ) { v[ i ][ j ] = aj; } else { v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); } } } // Construct all of the faces. for ( var i = 0; i < cols ; i ++ ) { for ( var j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { var k = Math.floor( j / 2 ); if ( j % 2 === 0 ) { make( v[ i ][ k + 1 ], v[ i + 1 ][ k ], v[ i ][ k ], materialIndex ); } else { make( v[ i ][ k + 1 ], v[ i + 1 ][ k + 1 ], v[ i + 1 ][ k ], materialIndex ); } } } } // Angle around the Y axis, counter-clockwise when looking from above. function azimuth( vector ) { return Math.atan2( vector.z, - vector.x ); } // Angle above the XZ plane. function inclination( vector ) { return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); } // Texture fixing helper. Spheres have some odd behaviours. function correctUV( uv, vector, azimuth ) { if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); return uv.clone(); } }; THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.PolyhedronGeometry.prototype.constructor = THREE.PolyhedronGeometry; THREE.PolyhedronGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.PolyhedronGeometry( parameters.vertices, parameters.indices, parameters.radius, parameters.detail ); }; three.js-r73/src/extras/geometries/ShapeGeometry.js0000644000175500017550000000533012610076566022327 0ustar debacledebacle/** * @author jonobr1 / http://jonobr1.com * * Creates a one-sided polygonal geometry from a path shape. Similar to * ExtrudeGeometry. * * parameters = { * * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. * * material: // material index for front and back faces * uvGenerator: // object that provides UV generator functions * * } **/ THREE.ShapeGeometry = function ( shapes, options ) { THREE.Geometry.call( this ); this.type = 'ShapeGeometry'; if ( Array.isArray( shapes ) === false ) shapes = [ shapes ]; this.addShapeList( shapes, options ); this.computeFaceNormals(); }; THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ShapeGeometry.prototype.constructor = THREE.ShapeGeometry; /** * Add an array of shapes to THREE.ShapeGeometry. */ THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { for ( var i = 0, l = shapes.length; i < l; i ++ ) { this.addShape( shapes[ i ], options ); } return this; }; /** * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. */ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { if ( options === undefined ) options = {}; var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; var material = options.material; var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; // var i, l, hole; var shapesOffset = this.vertices.length; var shapePoints = shape.extractPoints( curveSegments ); var vertices = shapePoints.shape; var holes = shapePoints.holes; var reverse = ! THREE.ShapeUtils.isClockWise( vertices ); if ( reverse ) { vertices = vertices.reverse(); // Maybe we should also check if holes are in the opposite direction, just to be safe... for ( i = 0, l = holes.length; i < l; i ++ ) { hole = holes[ i ]; if ( THREE.ShapeUtils.isClockWise( hole ) ) { holes[ i ] = hole.reverse(); } } reverse = false; } var faces = THREE.ShapeUtils.triangulateShape( vertices, holes ); // Vertices for ( i = 0, l = holes.length; i < l; i ++ ) { hole = holes[ i ]; vertices = vertices.concat( hole ); } // var vert, vlen = vertices.length; var face, flen = faces.length; for ( i = 0; i < vlen; i ++ ) { vert = vertices[ i ]; this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); } for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; var a = face[ 0 ] + shapesOffset; var b = face[ 1 ] + shapesOffset; var c = face[ 2 ] + shapesOffset; this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); this.faceVertexUvs[ 0 ].push( uvgen.generateTopUV( this, a, b, c ) ); } }; three.js-r73/src/extras/geometries/CircleGeometry.js0000644000175500017550000000140212610076566022464 0ustar debacledebacle/** * @author hughes */ THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { THREE.Geometry.call( this ); this.type = 'CircleGeometry'; this.parameters = { radius: radius, segments: segments, thetaStart: thetaStart, thetaLength: thetaLength }; this.fromBufferGeometry( new THREE.CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); }; THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; THREE.CircleGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.CircleGeometry( parameters.radius, parameters.segments, parameters.thetaStart, parameters.thetaLength ); }; three.js-r73/src/extras/geometries/SphereBufferGeometry.js0000644000175500017550000000631112610076566023647 0ustar debacledebacle/** * @author benaadams / https://twitter.com/ben_a_adams * based on THREE.SphereGeometry */ THREE.SphereBufferGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { THREE.BufferGeometry.call( this ); this.type = 'SphereBufferGeometry'; this.parameters = { radius: radius, widthSegments: widthSegments, heightSegments: heightSegments, phiStart: phiStart, phiLength: phiLength, thetaStart: thetaStart, thetaLength: thetaLength }; radius = radius || 50; widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); phiStart = phiStart !== undefined ? phiStart : 0; phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; thetaStart = thetaStart !== undefined ? thetaStart : 0; thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; var thetaEnd = thetaStart + thetaLength; var vertexCount = ( ( widthSegments + 1 ) * ( heightSegments + 1 ) ); var positions = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 ); var normals = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 ); var uvs = new THREE.BufferAttribute( new Float32Array( vertexCount * 2 ), 2 ); var index = 0, vertices = [], normal = new THREE.Vector3(); for ( var y = 0; y <= heightSegments; y ++ ) { var verticesRow = []; var v = y / heightSegments; for ( var x = 0; x <= widthSegments; x ++ ) { var u = x / widthSegments; var px = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); var py = radius * Math.cos( thetaStart + v * thetaLength ); var pz = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); normal.set( px, py, pz ).normalize(); positions.setXYZ( index, px, py, pz ); normals.setXYZ( index, normal.x, normal.y, normal.z ); uvs.setXY( index, u, 1 - v ); verticesRow.push( index ); index ++; } vertices.push( verticesRow ); } var indices = []; for ( var y = 0; y < heightSegments; y ++ ) { for ( var x = 0; x < widthSegments; x ++ ) { var v1 = vertices[ y ][ x + 1 ]; var v2 = vertices[ y ][ x ]; var v3 = vertices[ y + 1 ][ x ]; var v4 = vertices[ y + 1 ][ x + 1 ]; if ( y !== 0 || thetaStart > 0 ) indices.push( v1, v2, v4 ); if ( y !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( v2, v3, v4 ); } } this.setIndex( new ( positions.count > 65535 ? THREE.Uint32Attribute : THREE.Uint16Attribute )( indices, 1 ) ); this.addAttribute( 'position', positions ); this.addAttribute( 'normal', normals ); this.addAttribute( 'uv', uvs ); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); }; THREE.SphereBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.SphereBufferGeometry.prototype.constructor = THREE.SphereBufferGeometry; THREE.SphereBufferGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.SphereBufferGeometry( parameters.radius, parameters.widthSegments, parameters.heightSegments, parameters.phiStart, parameters.phiLength, parameters.thetaStart, parameters.thetaLength ); }; three.js-r73/src/extras/geometries/DodecahedronGeometry.js0000644000175500017550000000325012610076566023645 0ustar debacledebacle/** * @author Abe Pazos / https://hamoid.com */ THREE.DodecahedronGeometry = function ( radius, detail ) { var t = ( 1 + Math.sqrt( 5 ) ) / 2; var r = 1 / t; var vertices = [ // (±1, ±1, ±1) - 1, - 1, - 1, - 1, - 1, 1, - 1, 1, - 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1, // (0, ±1/φ, ±φ) 0, - r, - t, 0, - r, t, 0, r, - t, 0, r, t, // (±1/φ, ±φ, 0) - r, - t, 0, - r, t, 0, r, - t, 0, r, t, 0, // (±φ, 0, ±1/φ) - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, r ]; var indices = [ 3, 11, 7, 3, 7, 15, 3, 15, 13, 7, 19, 17, 7, 17, 6, 7, 6, 15, 17, 4, 8, 17, 8, 10, 17, 10, 6, 8, 0, 16, 8, 16, 2, 8, 2, 10, 0, 12, 1, 0, 1, 18, 0, 18, 16, 6, 10, 2, 6, 2, 13, 6, 13, 15, 2, 16, 18, 2, 18, 3, 2, 3, 13, 18, 1, 9, 18, 9, 11, 18, 11, 3, 4, 14, 12, 4, 12, 0, 4, 0, 8, 11, 9, 5, 11, 5, 19, 11, 19, 7, 19, 5, 14, 19, 14, 4, 19, 4, 17, 1, 12, 14, 1, 14, 5, 1, 5, 9 ]; THREE.PolyhedronGeometry.call( this, vertices, indices, radius, detail ); this.type = 'DodecahedronGeometry'; this.parameters = { radius: radius, detail: detail }; }; THREE.DodecahedronGeometry.prototype = Object.create( THREE.PolyhedronGeometry.prototype ); THREE.DodecahedronGeometry.prototype.constructor = THREE.DodecahedronGeometry; THREE.DodecahedronGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.DodecahedronGeometry( parameters.radius, parameters.detail ); }; three.js-r73/src/extras/geometries/PlaneBufferGeometry.js0000644000175500017550000000501112610076566023454 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as */ THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) { THREE.BufferGeometry.call( this ); this.type = 'PlaneBufferGeometry'; this.parameters = { width: width, height: height, widthSegments: widthSegments, heightSegments: heightSegments }; var width_half = width / 2; var height_half = height / 2; var gridX = Math.floor( widthSegments ) || 1; var gridY = Math.floor( heightSegments ) || 1; var gridX1 = gridX + 1; var gridY1 = gridY + 1; var segment_width = width / gridX; var segment_height = height / gridY; var vertices = new Float32Array( gridX1 * gridY1 * 3 ); var normals = new Float32Array( gridX1 * gridY1 * 3 ); var uvs = new Float32Array( gridX1 * gridY1 * 2 ); var offset = 0; var offset2 = 0; for ( var iy = 0; iy < gridY1; iy ++ ) { var y = iy * segment_height - height_half; for ( var ix = 0; ix < gridX1; ix ++ ) { var x = ix * segment_width - width_half; vertices[ offset ] = x; vertices[ offset + 1 ] = - y; normals[ offset + 2 ] = 1; uvs[ offset2 ] = ix / gridX; uvs[ offset2 + 1 ] = 1 - ( iy / gridY ); offset += 3; offset2 += 2; } } offset = 0; var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 ); for ( var iy = 0; iy < gridY; iy ++ ) { for ( var ix = 0; ix < gridX; ix ++ ) { var a = ix + gridX1 * iy; var b = ix + gridX1 * ( iy + 1 ); var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); var d = ( ix + 1 ) + gridX1 * iy; indices[ offset ] = a; indices[ offset + 1 ] = b; indices[ offset + 2 ] = d; indices[ offset + 3 ] = b; indices[ offset + 4 ] = c; indices[ offset + 5 ] = d; offset += 6; } } this.setIndex( new THREE.BufferAttribute( indices, 1 ) ); this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); }; THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry; THREE.PlaneBufferGeometry.prototype.clone = function () { var parameters = this.parameters; return new THREE.PlaneBufferGeometry( parameters.width, parameters.height, parameters.widthSegments, parameters.heightSegments ); }; three.js-r73/src/extras/ShapeUtils.js0000644000175500017550000004263712610076566017504 0ustar debacledebacle/** * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.ShapeUtils = { // calculate area of the contour polygon area: function ( contour ) { var n = contour.length; var a = 0.0; for ( var p = n - 1, q = 0; q < n; p = q ++ ) { a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; } return a * 0.5; }, triangulate: ( function () { /** * This code is a quick port of code written in C++ which was submitted to * flipcode.com by John W. Ratcliff // July 22, 2000 * See original code and more information here: * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml * * ported to actionscript by Zevan Rosser * www.actionsnippet.com * * ported to javascript by Joshua Koo * http://www.lab4games.net/zz85/blog * */ function snip( contour, u, v, w, n, verts ) { var p; var ax, ay, bx, by; var cx, cy, px, py; ax = contour[ verts[ u ] ].x; ay = contour[ verts[ u ] ].y; bx = contour[ verts[ v ] ].x; by = contour[ verts[ v ] ].y; cx = contour[ verts[ w ] ].x; cy = contour[ verts[ w ] ].y; if ( Number.EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) return false; var aX, aY, bX, bY, cX, cY; var apx, apy, bpx, bpy, cpx, cpy; var cCROSSap, bCROSScp, aCROSSbp; aX = cx - bx; aY = cy - by; bX = ax - cx; bY = ay - cy; cX = bx - ax; cY = by - ay; for ( p = 0; p < n; p ++ ) { px = contour[ verts[ p ] ].x; py = contour[ verts[ p ] ].y; if ( ( ( px === ax ) && ( py === ay ) ) || ( ( px === bx ) && ( py === by ) ) || ( ( px === cx ) && ( py === cy ) ) ) continue; apx = px - ax; apy = py - ay; bpx = px - bx; bpy = py - by; cpx = px - cx; cpy = py - cy; // see if p is inside triangle abc aCROSSbp = aX * bpy - aY * bpx; cCROSSap = cX * apy - cY * apx; bCROSScp = bX * cpy - bY * cpx; if ( ( aCROSSbp >= - Number.EPSILON ) && ( bCROSScp >= - Number.EPSILON ) && ( cCROSSap >= - Number.EPSILON ) ) return false; } return true; } // takes in an contour array and returns return function ( contour, indices ) { var n = contour.length; if ( n < 3 ) return null; var result = [], verts = [], vertIndices = []; /* we want a counter-clockwise polygon in verts */ var u, v, w; if ( THREE.ShapeUtils.area( contour ) > 0.0 ) { for ( v = 0; v < n; v ++ ) verts[ v ] = v; } else { for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v; } var nv = n; /* remove nv - 2 vertices, creating 1 triangle every time */ var count = 2 * nv; /* error detection */ for ( v = nv - 1; nv > 2; ) { /* if we loop, it is probably a non-simple polygon */ if ( ( count -- ) <= 0 ) { //** Triangulate: ERROR - probable bad polygon! //throw ( "Warning, unable to triangulate polygon!" ); //return null; // Sometimes warning is fine, especially polygons are triangulated in reverse. console.warn( 'THREE.ShapeUtils: Unable to triangulate polygon! in triangulate()' ); if ( indices ) return vertIndices; return result; } /* three consecutive vertices in current polygon, */ u = v; if ( nv <= u ) u = 0; /* previous */ v = u + 1; if ( nv <= v ) v = 0; /* new v */ w = v + 1; if ( nv <= w ) w = 0; /* next */ if ( snip( contour, u, v, w, nv, verts ) ) { var a, b, c, s, t; /* true names of the vertices */ a = verts[ u ]; b = verts[ v ]; c = verts[ w ]; /* output Triangle */ result.push( [ contour[ a ], contour[ b ], contour[ c ] ] ); vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); /* remove v from the remaining polygon */ for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { verts[ s ] = verts[ t ]; } nv --; /* reset error detection counter */ count = 2 * nv; } } if ( indices ) return vertIndices; return result; } } )(), triangulateShape: function ( contour, holes ) { function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { // inOtherPt needs to be collinear to the inSegment if ( inSegPt1.x !== inSegPt2.x ) { if ( inSegPt1.x < inSegPt2.x ) { return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); } else { return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); } } else { if ( inSegPt1.y < inSegPt2.y ) { return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); } else { return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); } } } function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; var limit = seg1dy * seg2dx - seg1dx * seg2dy; var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; if ( Math.abs( limit ) > Number.EPSILON ) { // not parallel var perpSeg2; if ( limit > 0 ) { if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; } else { if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; } // i.e. to reduce rounding errors // intersection at endpoint of segment#1? if ( perpSeg2 === 0 ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; return [ inSeg1Pt1 ]; } if ( perpSeg2 === limit ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 === 0 ) || ( perpSeg1 === limit ) ) ) return []; return [ inSeg1Pt2 ]; } // intersection at endpoint of segment#2? if ( perpSeg1 === 0 ) return [ inSeg2Pt1 ]; if ( perpSeg1 === limit ) return [ inSeg2Pt2 ]; // return real intersection point var factorSeg1 = perpSeg2 / limit; return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; } else { // parallel or collinear if ( ( perpSeg1 !== 0 ) || ( seg2dy * seg1seg2dx !== seg2dx * seg1seg2dy ) ) return []; // they are collinear or degenerate var seg1Pt = ( ( seg1dx === 0 ) && ( seg1dy === 0 ) ); // segment1 is just a point? var seg2Pt = ( ( seg2dx === 0 ) && ( seg2dy === 0 ) ); // segment2 is just a point? // both segments are points if ( seg1Pt && seg2Pt ) { if ( ( inSeg1Pt1.x !== inSeg2Pt1.x ) || ( inSeg1Pt1.y !== inSeg2Pt1.y ) ) return []; // they are distinct points return [ inSeg1Pt1 ]; // they are the same point } // segment#1 is a single point if ( seg1Pt ) { if ( ! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 return [ inSeg1Pt1 ]; } // segment#2 is a single point if ( seg2Pt ) { if ( ! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 return [ inSeg2Pt1 ]; } // they are collinear segments, which might overlap var seg1min, seg1max, seg1minVal, seg1maxVal; var seg2min, seg2max, seg2minVal, seg2maxVal; if ( seg1dx !== 0 ) { // the segments are NOT on a vertical line if ( inSeg1Pt1.x < inSeg1Pt2.x ) { seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; } else { seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; } if ( inSeg2Pt1.x < inSeg2Pt2.x ) { seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; } else { seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; } } else { // the segments are on a vertical line if ( inSeg1Pt1.y < inSeg1Pt2.y ) { seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; } else { seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; } if ( inSeg2Pt1.y < inSeg2Pt2.y ) { seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; } else { seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; } } if ( seg1minVal <= seg2minVal ) { if ( seg1maxVal < seg2minVal ) return []; if ( seg1maxVal === seg2minVal ) { if ( inExcludeAdjacentSegs ) return []; return [ seg2min ]; } if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; return [ seg2min, seg2max ]; } else { if ( seg1minVal > seg2maxVal ) return []; if ( seg1minVal === seg2maxVal ) { if ( inExcludeAdjacentSegs ) return []; return [ seg1min ]; } if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; return [ seg1min, seg2max ]; } } } function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { // The order of legs is important // translation of all points, so that Vertex is at (0,0) var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; if ( Math.abs( from2toAngle ) > Number.EPSILON ) { // angle != 180 deg. var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); if ( from2toAngle > 0 ) { // main angle < 180 deg. return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); } else { // main angle > 180 deg. return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); } } else { // angle == 180 deg. // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); return ( from2otherAngle > 0 ); } } function removeHoles( contour, holes ) { var shape = contour.concat(); // work on this shape var hole; function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { // Check if hole point lies within angle around shape point var lastShapeIdx = shape.length - 1; var prevShapeIdx = inShapeIdx - 1; if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; var nextShapeIdx = inShapeIdx + 1; if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; var insideAngle = isPointInsideAngle( shape[ inShapeIdx ], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[ inHoleIdx ] ); if ( ! insideAngle ) { // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); return false; } // Check if shape point lies within angle around hole point var lastHoleIdx = hole.length - 1; var prevHoleIdx = inHoleIdx - 1; if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; var nextHoleIdx = inHoleIdx + 1; if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; insideAngle = isPointInsideAngle( hole[ inHoleIdx ], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[ inShapeIdx ] ); if ( ! insideAngle ) { // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); return false; } return true; } function intersectsShapeEdge( inShapePt, inHolePt ) { // checks for intersections with shape edges var sIdx, nextIdx, intersection; for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { nextIdx = sIdx + 1; nextIdx %= shape.length; intersection = intersect_segments_2D( inShapePt, inHolePt, shape[ sIdx ], shape[ nextIdx ], true ); if ( intersection.length > 0 ) return true; } return false; } var indepHoles = []; function intersectsHoleEdge( inShapePt, inHolePt ) { // checks for intersections with hole edges var ihIdx, chkHole, hIdx, nextIdx, intersection; for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) { chkHole = holes[ indepHoles[ ihIdx ]]; for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { nextIdx = hIdx + 1; nextIdx %= chkHole.length; intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[ hIdx ], chkHole[ nextIdx ], true ); if ( intersection.length > 0 ) return true; } } return false; } var holeIndex, shapeIndex, shapePt, holePt, holeIdx, cutKey, failedCuts = [], tmpShape1, tmpShape2, tmpHole1, tmpHole2; for ( var h = 0, hl = holes.length; h < hl; h ++ ) { indepHoles.push( h ); } var minShapeIndex = 0; var counter = indepHoles.length * 2; while ( indepHoles.length > 0 ) { counter --; if ( counter < 0 ) { console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); break; } // search for shape-vertex and hole-vertex, // which can be connected without intersections for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) { shapePt = shape[ shapeIndex ]; holeIndex = - 1; // search for hole which can be reached without intersections for ( var h = 0; h < indepHoles.length; h ++ ) { holeIdx = indepHoles[ h ]; // prevent multiple checks cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; if ( failedCuts[ cutKey ] !== undefined ) continue; hole = holes[ holeIdx ]; for ( var h2 = 0; h2 < hole.length; h2 ++ ) { holePt = hole[ h2 ]; if ( ! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; if ( intersectsShapeEdge( shapePt, holePt ) ) continue; if ( intersectsHoleEdge( shapePt, holePt ) ) continue; holeIndex = h2; indepHoles.splice( h, 1 ); tmpShape1 = shape.slice( 0, shapeIndex + 1 ); tmpShape2 = shape.slice( shapeIndex ); tmpHole1 = hole.slice( holeIndex ); tmpHole2 = hole.slice( 0, holeIndex + 1 ); shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); minShapeIndex = shapeIndex; // Debug only, to show the selected cuts // glob_CutLines.push( [ shapePt, holePt ] ); break; } if ( holeIndex >= 0 ) break; // hole-vertex found failedCuts[ cutKey ] = true; // remember failure } if ( holeIndex >= 0 ) break; // hole-vertex found } } return shape; /* shape with no holes */ } var i, il, f, face, key, index, allPointsMap = {}; // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first. var allpoints = contour.concat(); for ( var h = 0, hl = holes.length; h < hl; h ++ ) { Array.prototype.push.apply( allpoints, holes[ h ] ); } //console.log( "allpoints",allpoints, allpoints.length ); // prepare all points map for ( i = 0, il = allpoints.length; i < il; i ++ ) { key = allpoints[ i ].x + ":" + allpoints[ i ].y; if ( allPointsMap[ key ] !== undefined ) { console.warn( "THREE.Shape: Duplicate point", key ); } allPointsMap[ key ] = i; } // remove holes by cutting paths to holes and adding them to the shape var shapeWithoutHoles = removeHoles( contour, holes ); var triangles = THREE.ShapeUtils.triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape //console.log( "triangles",triangles, triangles.length ); // check all face vertices against all points map for ( i = 0, il = triangles.length; i < il; i ++ ) { face = triangles[ i ]; for ( f = 0; f < 3; f ++ ) { key = face[ f ].x + ":" + face[ f ].y; index = allPointsMap[ key ]; if ( index !== undefined ) { face[ f ] = index; } } } return triangles.concat(); }, isClockWise: function ( pts ) { return THREE.ShapeUtils.area( pts ) < 0; }, // Bezier Curves formulas obtained from // http://en.wikipedia.org/wiki/B%C3%A9zier_curve // Quad Bezier Functions b2: ( function () { function b2p0( t, p ) { var k = 1 - t; return k * k * p; } function b2p1( t, p ) { return 2 * ( 1 - t ) * t * p; } function b2p2( t, p ) { return t * t * p; } return function ( t, p0, p1, p2 ) { return b2p0( t, p0 ) + b2p1( t, p1 ) + b2p2( t, p2 ); }; } )(), // Cubic Bezier Functions b3: ( function () { function b3p0( t, p ) { var k = 1 - t; return k * k * k * p; } function b3p1( t, p ) { var k = 1 - t; return 3 * k * k * t * p; } function b3p2( t, p ) { var k = 1 - t; return 3 * k * t * t * p; } function b3p3( t, p ) { return t * t * t * p; } return function ( t, p0, p1, p2, p3 ) { return b3p0( t, p0 ) + b3p1( t, p1 ) + b3p2( t, p2 ) + b3p3( t, p3 ); }; } )() }; three.js-r73/src/extras/SceneUtils.js0000644000175500017550000000131312610076566017463 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.SceneUtils = { createMultiMaterialObject: function ( geometry, materials ) { var group = new THREE.Group(); for ( var i = 0, l = materials.length; i < l; i ++ ) { group.add( new THREE.Mesh( geometry, materials[ i ] ) ); } return group; }, detach: function ( child, parent, scene ) { child.applyMatrix( parent.matrixWorld ); parent.remove( child ); scene.add( child ); }, attach: function ( child, scene, parent ) { var matrixWorldInverse = new THREE.Matrix4(); matrixWorldInverse.getInverse( parent.matrixWorld ); child.applyMatrix( matrixWorldInverse ); scene.remove( child ); parent.add( child ); } }; three.js-r73/src/extras/CurveUtils.js0000644000175500017550000000213012610076566017510 0ustar debacledebacle/** * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.CurveUtils = { tangentQuadraticBezier: function ( t, p0, p1, p2 ) { return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); }, // Puay Bing, thanks for helping with this derivative! tangentCubicBezier: function ( t, p0, p1, p2, p3 ) { return - 3 * p0 * ( 1 - t ) * ( 1 - t ) + 3 * p1 * ( 1 - t ) * ( 1 - t ) - 6 * t * p1 * ( 1 - t ) + 6 * t * p2 * ( 1 - t ) - 3 * t * t * p2 + 3 * t * t * p3; }, tangentSpline: function ( t, p0, p1, p2, p3 ) { // To check if my formulas are correct var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t var h01 = - 6 * t * t + 6 * t; // − 2t3 + 3t2 var h11 = 3 * t * t - 2 * t; // t3 − t2 return h00 + h10 + h01 + h11; }, // Catmull-Rom interpolate: function( p0, p1, p2, p3, t ) { var v0 = ( p2 - p0 ) * 0.5; var v1 = ( p3 - p1 ) * 0.5; var t2 = t * t; var t3 = t * t2; return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; } }; three.js-r73/src/extras/ImageUtils.js0000644000175500017550000000243612610076566017457 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author Daosheng Mu / https://github.com/DaoshengMu/ */ THREE.ImageUtils = { crossOrigin: undefined, loadTexture: function ( url, mapping, onLoad, onError ) { console.warn( 'THREE.ImageUtils.loadTexture is being deprecated. Use THREE.TextureLoader() instead.' ); var loader = new THREE.TextureLoader(); loader.setCrossOrigin( this.crossOrigin ); var texture = loader.load( url, onLoad, undefined, onError ); if ( mapping ) texture.mapping = mapping; return texture; }, loadTextureCube: function ( urls, mapping, onLoad, onError ) { console.warn( 'THREE.ImageUtils.loadTextureCube is being deprecated. Use THREE.CubeTextureLoader() instead.' ); var loader = new THREE.CubeTextureLoader(); loader.setCrossOrigin( this.crossOrigin ); var texture = loader.load( urls, onLoad, undefined, onError ); if ( mapping ) texture.mapping = mapping; return texture; }, loadCompressedTexture: function () { console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) }, loadCompressedTextureCube: function () { console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) } }; three.js-r73/src/extras/curves/0000755000175500017550000000000012610076566016360 5ustar debacledebaclethree.js-r73/src/extras/curves/CubicBezierCurve.js0000644000175500017550000000172012610076566022111 0ustar debacledebacle/************************************************************** * Cubic Bezier curve **************************************************************/ THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; this.v3 = v3; }; THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.CubicBezierCurve.prototype.constructor = THREE.CubicBezierCurve; THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { var b3 = THREE.ShapeUtils.b3; return new THREE.Vector2( b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ), b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ) ); }; THREE.CubicBezierCurve.prototype.getTangent = function( t ) { var tangentCubicBezier = THREE.CurveUtils.tangentCubicBezier; return new THREE.Vector2( tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ), tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ) ).normalize(); }; three.js-r73/src/extras/curves/SplineCurve.js0000644000175500017550000000210312610076566021151 0ustar debacledebacle/************************************************************** * Spline curve **************************************************************/ THREE.SplineCurve = function ( points /* array of Vector2 */ ) { this.points = ( points == undefined ) ? [] : points; }; THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.SplineCurve.prototype.constructor = THREE.SplineCurve; THREE.SplineCurve.prototype.getPoint = function ( t ) { var points = this.points; var point = ( points.length - 1 ) * t; var intPoint = Math.floor( point ); var weight = point - intPoint; var point0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; var point1 = points[ intPoint ]; var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; var interpolate = THREE.CurveUtils.interpolate; return new THREE.Vector2( interpolate( point0.x, point1.x, point2.x, point3.x, weight ), interpolate( point0.y, point1.y, point2.y, point3.y, weight ) ); }; three.js-r73/src/extras/curves/QuadraticBezierCurve3.js0000644000175500017550000000101112610076566023055 0ustar debacledebacle/************************************************************** * Quadratic Bezier 3D curve **************************************************************/ THREE.QuadraticBezierCurve3 = THREE.Curve.create( function ( v0, v1, v2 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; }, function ( t ) { var b2 = THREE.ShapeUtils.b2; return new THREE.Vector3( b2( t, this.v0.x, this.v1.x, this.v2.x ), b2( t, this.v0.y, this.v1.y, this.v2.y ), b2( t, this.v0.z, this.v1.z, this.v2.z ) ); } ); three.js-r73/src/extras/curves/LineCurve.js0000644000175500017550000000143412610076566020614 0ustar debacledebacle/************************************************************** * Line **************************************************************/ THREE.LineCurve = function ( v1, v2 ) { this.v1 = v1; this.v2 = v2; }; THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.LineCurve.prototype.constructor = THREE.LineCurve; THREE.LineCurve.prototype.getPoint = function ( t ) { var point = this.v2.clone().sub( this.v1 ); point.multiplyScalar( t ).add( this.v1 ); return point; }; // Line curve is linear, so we can overwrite default getPointAt THREE.LineCurve.prototype.getPointAt = function ( u ) { return this.getPoint( u ); }; THREE.LineCurve.prototype.getTangent = function( t ) { var tangent = this.v2.clone().sub( this.v1 ); return tangent.normalize(); }; three.js-r73/src/extras/curves/ArcCurve.js0000644000175500017550000000071212610076566020430 0ustar debacledebacle/************************************************************** * Arc curve **************************************************************/ THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); }; THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype ); THREE.ArcCurve.prototype.constructor = THREE.ArcCurve; three.js-r73/src/extras/curves/CatmullRomCurve3.js0000644000175500017550000001031312610076566022063 0ustar debacledebacle/** * @author zz85 https://github.com/zz85 * * Centripetal CatmullRom Curve - which is useful for avoiding * cusps and self-intersections in non-uniform catmull rom curves. * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf * * curve.type accepts centripetal(default), chordal and catmullrom * curve.tension is used for catmullrom which defaults to 0.5 */ THREE.CatmullRomCurve3 = ( function() { var tmp = new THREE.Vector3(), px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly(); /* Based on an optimized c++ solution in - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ - http://ideone.com/NoEbVM This CubicPoly class could be used for reusing some variables and calculations, but for three.js curve use, it could be possible inlined and flatten into a single function call which can be placed in CurveUtils. */ function CubicPoly() { } /* * Compute coefficients for a cubic polynomial * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 * such that * p(0) = x0, p(1) = x1 * and * p'(0) = t0, p'(1) = t1. */ CubicPoly.prototype.init = function( x0, x1, t0, t1 ) { this.c0 = x0; this.c1 = t0; this.c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; this.c3 = 2 * x0 - 2 * x1 + t0 + t1; }; CubicPoly.prototype.initNonuniformCatmullRom = function( x0, x1, x2, x3, dt0, dt1, dt2 ) { // compute tangents when parameterized in [t1,t2] var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; // rescale tangents for parametrization in [0,1] t1 *= dt1; t2 *= dt1; // initCubicPoly this.init( x1, x2, t1, t2 ); }; // standard Catmull-Rom spline: interpolate between x1 and x2 with previous/following points x1/x4 CubicPoly.prototype.initCatmullRom = function( x0, x1, x2, x3, tension ) { this.init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); }; CubicPoly.prototype.calc = function( t ) { var t2 = t * t; var t3 = t2 * t; return this.c0 + this.c1 * t + this.c2 * t2 + this.c3 * t3; }; // Subclass Three.js curve return THREE.Curve.create( function ( p /* array of Vector3 */ ) { this.points = p || []; }, function ( t ) { var points = this.points, point, intPoint, weight, l; l = points.length; if ( l < 2 ) console.log( 'duh, you need at least 2 points' ); point = ( l - 1 ) * t; intPoint = Math.floor( point ); weight = point - intPoint; if ( weight === 0 && intPoint === l - 1 ) { intPoint = l - 2; weight = 1; } var p0, p1, p2, p3; if ( intPoint === 0 ) { // extrapolate first point tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); p0 = tmp; } else { p0 = points[ intPoint - 1 ]; } p1 = points[ intPoint ]; p2 = points[ intPoint + 1 ]; if ( intPoint + 2 < l ) { p3 = points[ intPoint + 2 ] } else { // extrapolate last point tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 2 ] ); p3 = tmp; } if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) { // init Centripetal / Chordal Catmull-Rom var pow = this.type === 'chordal' ? 0.5 : 0.25; var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); // safety check for repeated points if ( dt1 < 1e-4 ) dt1 = 1.0; if ( dt0 < 1e-4 ) dt0 = dt1; if ( dt2 < 1e-4 ) dt2 = dt1; px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); } else if ( this.type === 'catmullrom' ) { var tension = this.tension !== undefined ? this.tension : 0.5; px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension ); py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension ); pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension ); } var v = new THREE.Vector3( px.calc( weight ), py.calc( weight ), pz.calc( weight ) ); return v; } ); } )(); three.js-r73/src/extras/curves/QuadraticBezierCurve.js0000644000175500017550000000167612610076566023013 0ustar debacledebacle/************************************************************** * Quadratic Bezier curve **************************************************************/ THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; }; THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.QuadraticBezierCurve.prototype.constructor = THREE.QuadraticBezierCurve; THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { var b2 = THREE.ShapeUtils.b2; return new THREE.Vector2( b2( t, this.v0.x, this.v1.x, this.v2.x ), b2( t, this.v0.y, this.v1.y, this.v2.y ) ); }; THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { var tangentQuadraticBezier = THREE.CurveUtils.tangentQuadraticBezier; return new THREE.Vector2( tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ), tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ) ).normalize(); }; three.js-r73/src/extras/curves/SplineCurve3.js0000644000175500017550000000214612610076566021243 0ustar debacledebacle/************************************************************** * Spline 3D curve **************************************************************/ THREE.SplineCurve3 = THREE.Curve.create( function ( points /* array of Vector3 */ ) { console.warn( 'THREE.SplineCurve3 will be deprecated. Please use THREE.CatmullRomCurve3' ); this.points = ( points == undefined ) ? [] : points; }, function ( t ) { var points = this.points; var point = ( points.length - 1 ) * t; var intPoint = Math.floor( point ); var weight = point - intPoint; var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ]; var point1 = points[ intPoint ]; var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; var interpolate = THREE.CurveUtils.interpolate; return new THREE.Vector3( interpolate( point0.x, point1.x, point2.x, point3.x, weight ), interpolate( point0.y, point1.y, point2.y, point3.y, weight ), interpolate( point0.z, point1.z, point2.z, point3.z, weight ) ); } ); three.js-r73/src/extras/curves/CubicBezierCurve3.js0000644000175500017550000000106412610076566022175 0ustar debacledebacle/************************************************************** * Cubic Bezier 3D curve **************************************************************/ THREE.CubicBezierCurve3 = THREE.Curve.create( function ( v0, v1, v2, v3 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; this.v3 = v3; }, function ( t ) { var b3 = THREE.ShapeUtils.b3; return new THREE.Vector3( b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ), b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ), b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ) ); } ); three.js-r73/src/extras/curves/ClosedSplineCurve3.js0000644000175500017550000000217312610076566022375 0ustar debacledebacle/************************************************************** * Closed Spline 3D curve **************************************************************/ THREE.ClosedSplineCurve3 = THREE.Curve.create( function ( points /* array of Vector3 */ ) { this.points = ( points == undefined ) ? [] : points; }, function ( t ) { var points = this.points; var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1 var intPoint = Math.floor( point ); var weight = point - intPoint; intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; var point0 = points[ ( intPoint - 1 ) % points.length ]; var point1 = points[ ( intPoint ) % points.length ]; var point2 = points[ ( intPoint + 1 ) % points.length ]; var point3 = points[ ( intPoint + 2 ) % points.length ]; var interpolate = THREE.CurveUtils.interpolate; return new THREE.Vector3( interpolate( point0.x, point1.x, point2.x, point3.x, weight ), interpolate( point0.y, point1.y, point2.y, point3.y, weight ), interpolate( point0.z, point1.z, point2.z, point3.z, weight ) ); } ); three.js-r73/src/extras/curves/LineCurve3.js0000644000175500017550000000065412610076566020702 0ustar debacledebacle/************************************************************** * Line3D **************************************************************/ THREE.LineCurve3 = THREE.Curve.create( function ( v1, v2 ) { this.v1 = v1; this.v2 = v2; }, function ( t ) { var vector = new THREE.Vector3(); vector.subVectors( this.v2, this.v1 ); // diff vector.multiplyScalar( t ); vector.add( this.v1 ); return vector; } ); three.js-r73/src/extras/curves/EllipseCurve.js0000644000175500017550000000271412610076566021324 0ustar debacledebacle/************************************************************** * Ellipse curve **************************************************************/ THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { this.aX = aX; this.aY = aY; this.xRadius = xRadius; this.yRadius = yRadius; this.aStartAngle = aStartAngle; this.aEndAngle = aEndAngle; this.aClockwise = aClockwise; this.aRotation = aRotation || 0; }; THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.EllipseCurve.prototype.constructor = THREE.EllipseCurve; THREE.EllipseCurve.prototype.getPoint = function ( t ) { var deltaAngle = this.aEndAngle - this.aStartAngle; if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; var angle; if ( this.aClockwise === true ) { angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); } else { angle = this.aStartAngle + t * deltaAngle; } var x = this.aX + this.xRadius * Math.cos( angle ); var y = this.aY + this.yRadius * Math.sin( angle ); if ( this.aRotation !== 0 ) { var cos = Math.cos( this.aRotation ); var sin = Math.sin( this.aRotation ); var tx = x, ty = y; // Rotate the point about the center of the ellipse. x = ( tx - this.aX ) * cos - ( ty - this.aY ) * sin + this.aX; y = ( tx - this.aX ) * sin + ( ty - this.aY ) * cos + this.aY; } return new THREE.Vector2( x, y ); }; three.js-r73/src/extras/GeometryUtils.js0000644000175500017550000000132712610076566020226 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.GeometryUtils = { merge: function ( geometry1, geometry2, materialIndexOffset ) { console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); var matrix; if ( geometry2 instanceof THREE.Mesh ) { geometry2.matrixAutoUpdate && geometry2.updateMatrix(); matrix = geometry2.matrix; geometry2 = geometry2.geometry; } geometry1.merge( geometry2, matrix, materialIndexOffset ); }, center: function ( geometry ) { console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); return geometry.center(); } }; three.js-r73/src/extras/objects/0000755000175500017550000000000012610076566016502 5ustar debacledebaclethree.js-r73/src/extras/objects/ImmediateRenderObject.js0000644000175500017550000000060212610076566023223 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.ImmediateRenderObject = function ( material ) { THREE.Object3D.call( this ); this.material = material; this.render = function ( renderCallback ) {}; }; THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); THREE.ImmediateRenderObject.prototype.constructor = THREE.ImmediateRenderObject; three.js-r73/src/extras/objects/MorphBlendMesh.js0000644000175500017550000001423712610076566021716 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.MorphBlendMesh = function( geometry, material ) { THREE.Mesh.call( this, geometry, material ); this.animationsMap = {}; this.animationsList = []; // prepare default animation // (all frames played together in 1 second) var numFrames = this.geometry.morphTargets.length; var name = "__default"; var startFrame = 0; var endFrame = numFrames - 1; var fps = numFrames / 1; this.createAnimation( name, startFrame, endFrame, fps ); this.setAnimationWeight( name, 1 ); }; THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.MorphBlendMesh.prototype.constructor = THREE.MorphBlendMesh; THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { var animation = { start: start, end: end, length: end - start + 1, fps: fps, duration: ( end - start ) / fps, lastFrame: 0, currentFrame: 0, active: false, time: 0, direction: 1, weight: 1, directionBackwards: false, mirroredLoop: false }; this.animationsMap[ name ] = animation; this.animationsList.push( animation ); }; THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { var pattern = /([a-z]+)_?(\d+)/; var firstAnimation, frameRanges = {}; var geometry = this.geometry; for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { var morph = geometry.morphTargets[ i ]; var chunks = morph.name.match( pattern ); if ( chunks && chunks.length > 1 ) { var name = chunks[ 1 ]; if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; var range = frameRanges[ name ]; if ( i < range.start ) range.start = i; if ( i > range.end ) range.end = i; if ( ! firstAnimation ) firstAnimation = name; } } for ( var name in frameRanges ) { var range = frameRanges[ name ]; this.createAnimation( name, range.start, range.end, fps ); } this.firstAnimation = firstAnimation; }; THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.direction = 1; animation.directionBackwards = false; } }; THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.direction = - 1; animation.directionBackwards = true; } }; THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.fps = fps; animation.duration = ( animation.end - animation.start ) / animation.fps; } }; THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.duration = duration; animation.fps = ( animation.end - animation.start ) / animation.duration; } }; THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.weight = weight; } }; THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.time = time; } }; THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { var time = 0; var animation = this.animationsMap[ name ]; if ( animation ) { time = animation.time; } return time; }; THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { var duration = - 1; var animation = this.animationsMap[ name ]; if ( animation ) { duration = animation.duration; } return duration; }; THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.time = 0; animation.active = true; } else { console.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); } }; THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.active = false; } }; THREE.MorphBlendMesh.prototype.update = function ( delta ) { for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { var animation = this.animationsList[ i ]; if ( ! animation.active ) continue; var frameTime = animation.duration / animation.length; animation.time += animation.direction * delta; if ( animation.mirroredLoop ) { if ( animation.time > animation.duration || animation.time < 0 ) { animation.direction *= - 1; if ( animation.time > animation.duration ) { animation.time = animation.duration; animation.directionBackwards = true; } if ( animation.time < 0 ) { animation.time = 0; animation.directionBackwards = false; } } } else { animation.time = animation.time % animation.duration; if ( animation.time < 0 ) animation.time += animation.duration; } var keyframe = animation.start + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); var weight = animation.weight; if ( keyframe !== animation.currentFrame ) { this.morphTargetInfluences[ animation.lastFrame ] = 0; this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; this.morphTargetInfluences[ keyframe ] = 0; animation.lastFrame = animation.currentFrame; animation.currentFrame = keyframe; } var mix = ( animation.time % frameTime ) / frameTime; if ( animation.directionBackwards ) mix = 1 - mix; if ( animation.currentFrame !== animation.lastFrame ) { this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; } else { this.morphTargetInfluences[ animation.currentFrame ] = weight; } } }; three.js-r73/src/extras/helpers/0000755000175500017550000000000012610076566016513 5ustar debacledebaclethree.js-r73/src/extras/helpers/AxisHelper.js0000644000175500017550000000153212610076566021116 0ustar debacledebacle/** * @author sroucheray / http://sroucheray.org/ * @author mrdoob / http://mrdoob.com/ */ THREE.AxisHelper = function ( size ) { size = size || 1; var vertices = new Float32Array( [ 0, 0, 0, size, 0, 0, 0, 0, 0, 0, size, 0, 0, 0, 0, 0, 0, size ] ); var colors = new Float32Array( [ 1, 0, 0, 1, 0.6, 0, 0, 1, 0, 0.6, 1, 0, 0, 0, 1, 0, 0.6, 1 ] ); var geometry = new THREE.BufferGeometry(); geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) ); var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); THREE.LineSegments.call( this, geometry, material ); }; THREE.AxisHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.AxisHelper.prototype.constructor = THREE.AxisHelper; three.js-r73/src/extras/helpers/BoxHelper.js0000644000175500017550000000354312610076566020746 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.BoxHelper = function ( object ) { var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); var positions = new Float32Array( 8 * 3 ); var geometry = new THREE.BufferGeometry(); geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) ); geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) ); THREE.LineSegments.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ) ); if ( object !== undefined ) { this.update( object ); } }; THREE.BoxHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.BoxHelper.prototype.constructor = THREE.BoxHelper; THREE.BoxHelper.prototype.update = ( function () { var box = new THREE.Box3(); return function ( object ) { box.setFromObject( object ); if ( box.empty() ) return; var min = box.min; var max = box.max; /* 5____4 1/___0/| | 6__|_7 2/___3/ 0: max.x, max.y, max.z 1: min.x, max.y, max.z 2: min.x, min.y, max.z 3: max.x, min.y, max.z 4: max.x, max.y, min.z 5: min.x, max.y, min.z 6: min.x, min.y, min.z 7: max.x, min.y, min.z */ var position = this.geometry.attributes.position; var array = position.array; array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; position.needsUpdate = true; this.geometry.computeBoundingSphere(); } } )(); three.js-r73/src/extras/helpers/FaceNormalsHelper.js0000644000175500017550000000436412610076566022412 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { // FaceNormalsHelper only supports THREE.Geometry this.object = object; this.size = ( size !== undefined ) ? size : 1; var color = ( hex !== undefined ) ? hex : 0xffff00; var width = ( linewidth !== undefined ) ? linewidth : 1; // var nNormals = 0; var objGeometry = this.object.geometry; if ( objGeometry instanceof THREE.Geometry ) { nNormals = objGeometry.faces.length; } else { console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); } // var geometry = new THREE.BufferGeometry(); var positions = new THREE.Float32Attribute( nNormals * 2 * 3, 3 ); geometry.addAttribute( 'position', positions ); THREE.LineSegments.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ) ); // this.matrixAutoUpdate = false; this.update(); }; THREE.FaceNormalsHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.FaceNormalsHelper.prototype.constructor = THREE.FaceNormalsHelper; THREE.FaceNormalsHelper.prototype.update = ( function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); var normalMatrix = new THREE.Matrix3(); return function update() { this.object.updateMatrixWorld( true ); normalMatrix.getNormalMatrix( this.object.matrixWorld ); var matrixWorld = this.object.matrixWorld; var position = this.geometry.attributes.position; // var objGeometry = this.object.geometry; var vertices = objGeometry.vertices; var faces = objGeometry.faces; var idx = 0; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; var normal = face.normal; v1.copy( vertices[ face.a ] ) .add( vertices[ face.b ] ) .add( vertices[ face.c ] ) .divideScalar( 3 ) .applyMatrix4( matrixWorld ); v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); position.setXYZ( idx, v1.x, v1.y, v1.z ); idx = idx + 1; position.setXYZ( idx, v2.x, v2.y, v2.z ); idx = idx + 1; } position.needsUpdate = true; return this; } }() ); three.js-r73/src/extras/helpers/VertexNormalsHelper.js0000644000175500017550000000602112610076566023021 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { this.object = object; this.size = ( size !== undefined ) ? size : 1; var color = ( hex !== undefined ) ? hex : 0xff0000; var width = ( linewidth !== undefined ) ? linewidth : 1; // var nNormals = 0; var objGeometry = this.object.geometry; if ( objGeometry instanceof THREE.Geometry ) { nNormals = objGeometry.faces.length * 3; } else if ( objGeometry instanceof THREE.BufferGeometry ) { nNormals = objGeometry.attributes.normal.count } // var geometry = new THREE.BufferGeometry(); var positions = new THREE.Float32Attribute( nNormals * 2 * 3, 3 ); geometry.addAttribute( 'position', positions ); THREE.LineSegments.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ) ); // this.matrixAutoUpdate = false; this.update(); }; THREE.VertexNormalsHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.VertexNormalsHelper.prototype.constructor = THREE.VertexNormalsHelper; THREE.VertexNormalsHelper.prototype.update = ( function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); var normalMatrix = new THREE.Matrix3(); return function update() { var keys = [ 'a', 'b', 'c' ]; this.object.updateMatrixWorld( true ); normalMatrix.getNormalMatrix( this.object.matrixWorld ); var matrixWorld = this.object.matrixWorld; var position = this.geometry.attributes.position; // var objGeometry = this.object.geometry; if ( objGeometry instanceof THREE.Geometry ) { var vertices = objGeometry.vertices; var faces = objGeometry.faces; var idx = 0; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { var vertex = vertices[ face[ keys[ j ] ] ]; var normal = face.vertexNormals[ j ]; v1.copy( vertex ).applyMatrix4( matrixWorld ); v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); position.setXYZ( idx, v1.x, v1.y, v1.z ); idx = idx + 1; position.setXYZ( idx, v2.x, v2.y, v2.z ); idx = idx + 1; } } } else if ( objGeometry instanceof THREE.BufferGeometry ) { var objPos = objGeometry.attributes.position; var objNorm = objGeometry.attributes.normal; var idx = 0; // for simplicity, ignore index and drawcalls, and render every normal for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); position.setXYZ( idx, v1.x, v1.y, v1.z ); idx = idx + 1; position.setXYZ( idx, v2.x, v2.y, v2.z ); idx = idx + 1; } } position.needsUpdate = true; return this; } }() ); three.js-r73/src/extras/helpers/ArrowHelper.js0000644000175500017550000000525112610076566021306 0ustar debacledebacle/** * @author WestLangley / http://github.com/WestLangley * @author zz85 / http://github.com/zz85 * @author bhouston / http://clara.io * * Creates an arrow for visualizing directions * * Parameters: * dir - Vector3 * origin - Vector3 * length - Number * color - color in hex value * headLength - Number * headWidth - Number */ THREE.ArrowHelper = ( function () { var lineGeometry = new THREE.Geometry(); lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); coneGeometry.translate( 0, - 0.5, 0 ); return function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { // dir is assumed to be normalized THREE.Object3D.call( this ); if ( color === undefined ) color = 0xffff00; if ( length === undefined ) length = 1; if ( headLength === undefined ) headLength = 0.2 * length; if ( headWidth === undefined ) headWidth = 0.2 * headLength; this.position.copy( origin ); if ( headLength < length ) { this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: color } ) ); this.line.matrixAutoUpdate = false; this.add( this.line ); } this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: color } ) ); this.cone.matrixAutoUpdate = false; this.add( this.cone ); this.setDirection( dir ); this.setLength( length, headLength, headWidth ); } }() ); THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.ArrowHelper.prototype.constructor = THREE.ArrowHelper; THREE.ArrowHelper.prototype.setDirection = ( function () { var axis = new THREE.Vector3(); var radians; return function setDirection( dir ) { // dir is assumed to be normalized if ( dir.y > 0.99999 ) { this.quaternion.set( 0, 0, 0, 1 ); } else if ( dir.y < - 0.99999 ) { this.quaternion.set( 1, 0, 0, 0 ); } else { axis.set( dir.z, 0, - dir.x ).normalize(); radians = Math.acos( dir.y ); this.quaternion.setFromAxisAngle( axis, radians ); } }; }() ); THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { if ( headLength === undefined ) headLength = 0.2 * length; if ( headWidth === undefined ) headWidth = 0.2 * headLength; if ( headLength < length ){ this.line.scale.set( 1, length - headLength, 1 ); this.line.updateMatrix(); } this.cone.scale.set( headWidth, headLength, headWidth ); this.cone.position.y = length; this.cone.updateMatrix(); }; THREE.ArrowHelper.prototype.setColor = function ( color ) { if ( this.line !== undefined ) this.line.material.color.set( color ); this.cone.material.color.set( color ); }; three.js-r73/src/extras/helpers/PointLightHelper.js0000644000175500017550000000323412610076566022274 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.PointLightHelper = function ( light, sphereSize ) { this.light = light; this.light.updateMatrixWorld(); var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); THREE.Mesh.call( this, geometry, material ); this.matrix = this.light.matrixWorld; this.matrixAutoUpdate = false; /* var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); var d = light.distance; if ( d === 0.0 ) { this.lightDistance.visible = false; } else { this.lightDistance.scale.set( d, d, d ); } this.add( this.lightDistance ); */ }; THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); THREE.PointLightHelper.prototype.constructor = THREE.PointLightHelper; THREE.PointLightHelper.prototype.dispose = function () { this.geometry.dispose(); this.material.dispose(); }; THREE.PointLightHelper.prototype.update = function () { this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); /* var d = this.light.distance; if ( d === 0.0 ) { this.lightDistance.visible = false; } else { this.lightDistance.visible = true; this.lightDistance.scale.set( d, d, d ); } */ }; three.js-r73/src/extras/helpers/SkeletonHelper.js0000644000175500017550000000422312610076566021776 0ustar debacledebacle/** * @author Sean Griffin / http://twitter.com/sgrif * @author Michael Guerrero / http://realitymeltdown.com * @author mrdoob / http://mrdoob.com/ * @author ikerr / http://verold.com */ THREE.SkeletonHelper = function ( object ) { this.bones = this.getBoneList( object ); var geometry = new THREE.Geometry(); for ( var i = 0; i < this.bones.length; i ++ ) { var bone = this.bones[ i ]; if ( bone.parent instanceof THREE.Bone ) { geometry.vertices.push( new THREE.Vector3() ); geometry.vertices.push( new THREE.Vector3() ); geometry.colors.push( new THREE.Color( 0, 0, 1 ) ); geometry.colors.push( new THREE.Color( 0, 1, 0 ) ); } } geometry.dynamic = true; var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } ); THREE.LineSegments.call( this, geometry, material ); this.root = object; this.matrix = object.matrixWorld; this.matrixAutoUpdate = false; this.update(); }; THREE.SkeletonHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.SkeletonHelper.prototype.constructor = THREE.SkeletonHelper; THREE.SkeletonHelper.prototype.getBoneList = function( object ) { var boneList = []; if ( object instanceof THREE.Bone ) { boneList.push( object ); } for ( var i = 0; i < object.children.length; i ++ ) { boneList.push.apply( boneList, this.getBoneList( object.children[ i ] ) ); } return boneList; }; THREE.SkeletonHelper.prototype.update = function () { var geometry = this.geometry; var matrixWorldInv = new THREE.Matrix4().getInverse( this.root.matrixWorld ); var boneMatrix = new THREE.Matrix4(); var j = 0; for ( var i = 0; i < this.bones.length; i ++ ) { var bone = this.bones[ i ]; if ( bone.parent instanceof THREE.Bone ) { boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); geometry.vertices[ j ].setFromMatrixPosition( boneMatrix ); boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); geometry.vertices[ j + 1 ].setFromMatrixPosition( boneMatrix ); j += 2; } } geometry.verticesNeedUpdate = true; geometry.computeBoundingSphere(); }; three.js-r73/src/extras/helpers/GridHelper.js0000644000175500017550000000200512610076566021073 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.GridHelper = function ( size, step ) { var geometry = new THREE.Geometry(); var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); this.color1 = new THREE.Color( 0x444444 ); this.color2 = new THREE.Color( 0x888888 ); for ( var i = - size; i <= size; i += step ) { geometry.vertices.push( new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) ); var color = i === 0 ? this.color1 : this.color2; geometry.colors.push( color, color, color, color ); } THREE.LineSegments.call( this, geometry, material ); }; THREE.GridHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.GridHelper.prototype.constructor = THREE.GridHelper; THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { this.color1.set( colorCenterLine ); this.color2.set( colorGrid ); this.geometry.colorsNeedUpdate = true; }; three.js-r73/src/extras/helpers/SpotLightHelper.js0000644000175500017550000000302412610076566022125 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.SpotLightHelper = function ( light ) { THREE.Object3D.call( this ); this.light = light; this.light.updateMatrixWorld(); this.matrix = light.matrixWorld; this.matrixAutoUpdate = false; var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); geometry.translate( 0, - 0.5, 0 ); geometry.rotateX( - Math.PI / 2 ); var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); this.cone = new THREE.Mesh( geometry, material ); this.add( this.cone ); this.update(); }; THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.SpotLightHelper.prototype.constructor = THREE.SpotLightHelper; THREE.SpotLightHelper.prototype.dispose = function () { this.cone.geometry.dispose(); this.cone.material.dispose(); }; THREE.SpotLightHelper.prototype.update = function () { var vector = new THREE.Vector3(); var vector2 = new THREE.Vector3(); return function () { var coneLength = this.light.distance ? this.light.distance : 10000; var coneWidth = coneLength * Math.tan( this.light.angle ); this.cone.scale.set( coneWidth, coneWidth, coneLength ); vector.setFromMatrixPosition( this.light.matrixWorld ); vector2.setFromMatrixPosition( this.light.target.matrixWorld ); this.cone.lookAt( vector2.sub( vector ) ); this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); }; }(); three.js-r73/src/extras/helpers/HemisphereLightHelper.js0000644000175500017550000000302112610076566023266 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.HemisphereLightHelper = function ( light, sphereSize ) { THREE.Object3D.call( this ); this.light = light; this.light.updateMatrixWorld(); this.matrix = light.matrixWorld; this.matrixAutoUpdate = false; this.colors = [ new THREE.Color(), new THREE.Color() ]; var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); geometry.rotateX( - Math.PI / 2 ); for ( var i = 0, il = 8; i < il; i ++ ) { geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; } var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); this.lightSphere = new THREE.Mesh( geometry, material ); this.add( this.lightSphere ); this.update(); }; THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.HemisphereLightHelper.prototype.constructor = THREE.HemisphereLightHelper; THREE.HemisphereLightHelper.prototype.dispose = function () { this.lightSphere.geometry.dispose(); this.lightSphere.material.dispose(); }; THREE.HemisphereLightHelper.prototype.update = function () { var vector = new THREE.Vector3(); return function () { this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); this.lightSphere.geometry.colorsNeedUpdate = true; } }(); three.js-r73/src/extras/helpers/BoundingBoxHelper.js0000644000175500017550000000135312610076566022431 0ustar debacledebacle/** * @author WestLangley / http://github.com/WestLangley */ // a helper to show the world-axis-aligned bounding box for an object THREE.BoundingBoxHelper = function ( object, hex ) { var color = ( hex !== undefined ) ? hex : 0x888888; this.object = object; this.box = new THREE.Box3(); THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); }; THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); THREE.BoundingBoxHelper.prototype.constructor = THREE.BoundingBoxHelper; THREE.BoundingBoxHelper.prototype.update = function () { this.box.setFromObject( this.object ); this.box.size( this.scale ); this.box.center( this.position ); }; three.js-r73/src/extras/helpers/EdgesHelper.js0000644000175500017550000000151512610076566021242 0ustar debacledebacle/** * @author WestLangley / http://github.com/WestLangley * @param object THREE.Mesh whose geometry will be used * @param hex line color * @param thresholdAngle the minimum angle (in degrees), * between the face normals of adjacent faces, * that is required to render an edge. A value of 10 means * an edge is only rendered if the angle is at least 10 degrees. */ THREE.EdgesHelper = function ( object, hex, thresholdAngle ) { var color = ( hex !== undefined ) ? hex : 0xffffff; THREE.LineSegments.call( this, new THREE.EdgesGeometry( object.geometry, thresholdAngle ), new THREE.LineBasicMaterial( { color: color } ) ); this.matrix = object.matrixWorld; this.matrixAutoUpdate = false; }; THREE.EdgesHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.EdgesHelper.prototype.constructor = THREE.EdgesHelper; three.js-r73/src/extras/helpers/CameraHelper.js0000644000175500017550000000736212610076566021411 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * * - shows frustum, line of sight and up of the camera * - suitable for fast updates * - based on frustum visualization in lightgl.js shadowmap example * http://evanw.github.com/lightgl.js/tests/shadowmap.html */ THREE.CameraHelper = function ( camera ) { var geometry = new THREE.Geometry(); var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); var pointMap = {}; // colors var hexFrustum = 0xffaa00; var hexCone = 0xff0000; var hexUp = 0x00aaff; var hexTarget = 0xffffff; var hexCross = 0x333333; // near addLine( "n1", "n2", hexFrustum ); addLine( "n2", "n4", hexFrustum ); addLine( "n4", "n3", hexFrustum ); addLine( "n3", "n1", hexFrustum ); // far addLine( "f1", "f2", hexFrustum ); addLine( "f2", "f4", hexFrustum ); addLine( "f4", "f3", hexFrustum ); addLine( "f3", "f1", hexFrustum ); // sides addLine( "n1", "f1", hexFrustum ); addLine( "n2", "f2", hexFrustum ); addLine( "n3", "f3", hexFrustum ); addLine( "n4", "f4", hexFrustum ); // cone addLine( "p", "n1", hexCone ); addLine( "p", "n2", hexCone ); addLine( "p", "n3", hexCone ); addLine( "p", "n4", hexCone ); // up addLine( "u1", "u2", hexUp ); addLine( "u2", "u3", hexUp ); addLine( "u3", "u1", hexUp ); // target addLine( "c", "t", hexTarget ); addLine( "p", "c", hexCross ); // cross addLine( "cn1", "cn2", hexCross ); addLine( "cn3", "cn4", hexCross ); addLine( "cf1", "cf2", hexCross ); addLine( "cf3", "cf4", hexCross ); function addLine( a, b, hex ) { addPoint( a, hex ); addPoint( b, hex ); } function addPoint( id, hex ) { geometry.vertices.push( new THREE.Vector3() ); geometry.colors.push( new THREE.Color( hex ) ); if ( pointMap[ id ] === undefined ) { pointMap[ id ] = []; } pointMap[ id ].push( geometry.vertices.length - 1 ); } THREE.LineSegments.call( this, geometry, material ); this.camera = camera; this.camera.updateProjectionMatrix(); this.matrix = camera.matrixWorld; this.matrixAutoUpdate = false; this.pointMap = pointMap; this.update(); }; THREE.CameraHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.CameraHelper.prototype.constructor = THREE.CameraHelper; THREE.CameraHelper.prototype.update = function () { var geometry, pointMap; var vector = new THREE.Vector3(); var camera = new THREE.Camera(); function setPoint( point, x, y, z ) { vector.set( x, y, z ).unproject( camera ); var points = pointMap[ point ]; if ( points !== undefined ) { for ( var i = 0, il = points.length; i < il; i ++ ) { geometry.vertices[ points[ i ] ].copy( vector ); } } } return function () { geometry = this.geometry; pointMap = this.pointMap; var w = 1, h = 1; // we need just camera projection matrix // world matrix must be identity camera.projectionMatrix.copy( this.camera.projectionMatrix ); // center / target setPoint( "c", 0, 0, - 1 ); setPoint( "t", 0, 0, 1 ); // near setPoint( "n1", - w, - h, - 1 ); setPoint( "n2", w, - h, - 1 ); setPoint( "n3", - w, h, - 1 ); setPoint( "n4", w, h, - 1 ); // far setPoint( "f1", - w, - h, 1 ); setPoint( "f2", w, - h, 1 ); setPoint( "f3", - w, h, 1 ); setPoint( "f4", w, h, 1 ); // up setPoint( "u1", w * 0.7, h * 1.1, - 1 ); setPoint( "u2", - w * 0.7, h * 1.1, - 1 ); setPoint( "u3", 0, h * 2, - 1 ); // cross setPoint( "cf1", - w, 0, 1 ); setPoint( "cf2", w, 0, 1 ); setPoint( "cf3", 0, - h, 1 ); setPoint( "cf4", 0, h, 1 ); setPoint( "cn1", - w, 0, - 1 ); setPoint( "cn2", w, 0, - 1 ); setPoint( "cn3", 0, - h, - 1 ); setPoint( "cn4", 0, h, - 1 ); geometry.verticesNeedUpdate = true; }; }(); three.js-r73/src/extras/helpers/WireframeHelper.js0000644000175500017550000000077412610076566022142 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WireframeHelper = function ( object, hex ) { var color = ( hex !== undefined ) ? hex : 0xffffff; THREE.LineSegments.call( this, new THREE.WireframeGeometry( object.geometry ), new THREE.LineBasicMaterial( { color: color } ) ); this.matrix = object.matrixWorld; this.matrixAutoUpdate = false; }; THREE.WireframeHelper.prototype = Object.create( THREE.LineSegments.prototype ); THREE.WireframeHelper.prototype.constructor = THREE.WireframeHelper; three.js-r73/src/extras/helpers/DirectionalLightHelper.js0000644000175500017550000000435212610076566023442 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.DirectionalLightHelper = function ( light, size ) { THREE.Object3D.call( this ); this.light = light; this.light.updateMatrixWorld(); this.matrix = light.matrixWorld; this.matrixAutoUpdate = false; size = size || 1; var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3( - size, size, 0 ), new THREE.Vector3( size, size, 0 ), new THREE.Vector3( size, - size, 0 ), new THREE.Vector3( - size, - size, 0 ), new THREE.Vector3( - size, size, 0 ) ); var material = new THREE.LineBasicMaterial( { fog: false } ); material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); this.lightPlane = new THREE.Line( geometry, material ); this.add( this.lightPlane ); geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); material = new THREE.LineBasicMaterial( { fog: false } ); material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); this.targetLine = new THREE.Line( geometry, material ); this.add( this.targetLine ); this.update(); }; THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.DirectionalLightHelper.prototype.constructor = THREE.DirectionalLightHelper; THREE.DirectionalLightHelper.prototype.dispose = function () { this.lightPlane.geometry.dispose(); this.lightPlane.material.dispose(); this.targetLine.geometry.dispose(); this.targetLine.material.dispose(); }; THREE.DirectionalLightHelper.prototype.update = function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); var v3 = new THREE.Vector3(); return function () { v1.setFromMatrixPosition( this.light.matrixWorld ); v2.setFromMatrixPosition( this.light.target.matrixWorld ); v3.subVectors( v2, v1 ); this.lightPlane.lookAt( v3 ); this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); this.targetLine.geometry.vertices[ 1 ].copy( v3 ); this.targetLine.geometry.verticesNeedUpdate = true; this.targetLine.material.color.copy( this.lightPlane.material.color ); }; }(); three.js-r73/src/cameras/0000755000175500017550000000000012610076566015156 5ustar debacledebaclethree.js-r73/src/cameras/CubeCamera.js0000644000175500017550000000476712610076566017521 0ustar debacledebacle/** * Camera for rendering cube maps * - renders scene into axis-aligned cube * * @author alteredq / http://alteredqualia.com/ */ THREE.CubeCamera = function ( near, far, cubeResolution ) { THREE.Object3D.call( this ); this.type = 'CubeCamera'; var fov = 90, aspect = 1; var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraPX.up.set( 0, - 1, 0 ); cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); this.add( cameraPX ); var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraNX.up.set( 0, - 1, 0 ); cameraNX.lookAt( new THREE.Vector3( - 1, 0, 0 ) ); this.add( cameraNX ); var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraPY.up.set( 0, 0, 1 ); cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); this.add( cameraPY ); var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraNY.up.set( 0, 0, - 1 ); cameraNY.lookAt( new THREE.Vector3( 0, - 1, 0 ) ); this.add( cameraNY ); var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraPZ.up.set( 0, - 1, 0 ); cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); this.add( cameraPZ ); var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraNZ.up.set( 0, - 1, 0 ); cameraNZ.lookAt( new THREE.Vector3( 0, 0, - 1 ) ); this.add( cameraNZ ); this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); this.updateCubeMap = function ( renderer, scene ) { if ( this.parent === null ) this.updateMatrixWorld(); var renderTarget = this.renderTarget; var generateMipmaps = renderTarget.texture.generateMipmaps; renderTarget.texture.generateMipmaps = false; renderTarget.activeCubeFace = 0; renderer.render( scene, cameraPX, renderTarget ); renderTarget.activeCubeFace = 1; renderer.render( scene, cameraNX, renderTarget ); renderTarget.activeCubeFace = 2; renderer.render( scene, cameraPY, renderTarget ); renderTarget.activeCubeFace = 3; renderer.render( scene, cameraNY, renderTarget ); renderTarget.activeCubeFace = 4; renderer.render( scene, cameraPZ, renderTarget ); renderTarget.texture.generateMipmaps = generateMipmaps; renderTarget.activeCubeFace = 5; renderer.render( scene, cameraNZ, renderTarget ); renderer.setRenderTarget( null ); }; }; THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); THREE.CubeCamera.prototype.constructor = THREE.CubeCamera; three.js-r73/src/cameras/PerspectiveCamera.js0000644000175500017550000000752412610076566021126 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author greggman / http://games.greggman.com/ * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { THREE.Camera.call( this ); this.type = 'PerspectiveCamera'; this.zoom = 1; this.fov = fov !== undefined ? fov : 50; this.aspect = aspect !== undefined ? aspect : 1; this.near = near !== undefined ? near : 0.1; this.far = far !== undefined ? far : 2000; this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); THREE.PerspectiveCamera.prototype.constructor = THREE.PerspectiveCamera; /** * Uses Focal Length (in mm) to estimate and set FOV * 35mm (full-frame) camera is used if frame size is not specified; * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html */ THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { if ( frameHeight === undefined ) frameHeight = 24; this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); this.updateProjectionMatrix(); }; /** * Sets an offset in a larger frustum. This is useful for multi-window or * multi-monitor/multi-machine setups. * * For example, if you have 3x2 monitors and each monitor is 1920x1080 and * the monitors are in grid like this * * +---+---+---+ * | A | B | C | * +---+---+---+ * | D | E | F | * +---+---+---+ * * then for each monitor you would call it like this * * var w = 1920; * var h = 1080; * var fullWidth = w * 3; * var fullHeight = h * 2; * * --A-- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); * --B-- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); * --C-- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); * --D-- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); * --E-- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); * --F-- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); * * Note there is no reason monitors have to be the same size or in a grid. */ THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { this.fullWidth = fullWidth; this.fullHeight = fullHeight; this.x = x; this.y = y; this.width = width; this.height = height; this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { var fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) ); if ( this.fullWidth ) { var aspect = this.fullWidth / this.fullHeight; var top = Math.tan( THREE.Math.degToRad( fov * 0.5 ) ) * this.near; var bottom = - top; var left = aspect * bottom; var right = aspect * top; var width = Math.abs( right - left ); var height = Math.abs( top - bottom ); this.projectionMatrix.makeFrustum( left + this.x * width / this.fullWidth, left + ( this.x + this.width ) * width / this.fullWidth, top - ( this.y + this.height ) * height / this.fullHeight, top - this.y * height / this.fullHeight, this.near, this.far ); } else { this.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far ); } }; THREE.PerspectiveCamera.prototype.copy = function ( source ) { THREE.Camera.prototype.copy.call( this, source ); this.fov = source.fov; this.aspect = source.aspect; this.near = source.near; this.far = source.far; this.zoom = source.zoom; return this; }; THREE.PerspectiveCamera.prototype.toJSON = function ( meta ) { var data = THREE.Object3D.prototype.toJSON.call( this, meta ); data.object.zoom = this.zoom; data.object.fov = this.fov; data.object.aspect = this.aspect; data.object.near = this.near; data.object.far = this.far; return data; }; three.js-r73/src/cameras/OrthographicCamera.js0000644000175500017550000000320212610076566021253 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { THREE.Camera.call( this ); this.type = 'OrthographicCamera'; this.zoom = 1; this.left = left; this.right = right; this.top = top; this.bottom = bottom; this.near = ( near !== undefined ) ? near : 0.1; this.far = ( far !== undefined ) ? far : 2000; this.updateProjectionMatrix(); }; THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); THREE.OrthographicCamera.prototype.constructor = THREE.OrthographicCamera; THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { var dx = ( this.right - this.left ) / ( 2 * this.zoom ); var dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); var cx = ( this.right + this.left ) / 2; var cy = ( this.top + this.bottom ) / 2; this.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far ); }; THREE.OrthographicCamera.prototype.copy = function ( source ) { THREE.Camera.prototype.copy.call( this, source ); this.left = source.left; this.right = source.right; this.top = source.top; this.bottom = source.bottom; this.near = source.near; this.far = source.far; this.zoom = source.zoom; return this; }; THREE.OrthographicCamera.prototype.toJSON = function ( meta ) { var data = THREE.Object3D.prototype.toJSON.call( this, meta ); data.object.zoom = this.zoom; data.object.left = this.left; data.object.right = this.right; data.object.top = this.top; data.object.bottom = this.bottom; data.object.near = this.near; data.object.far = this.far; return data; }; three.js-r73/src/cameras/Camera.js0000644000175500017550000000257312610076566016713 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ * @author WestLangley / http://github.com/WestLangley */ THREE.Camera = function () { THREE.Object3D.call( this ); this.type = 'Camera'; this.matrixWorldInverse = new THREE.Matrix4(); this.projectionMatrix = new THREE.Matrix4(); }; THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); THREE.Camera.prototype.constructor = THREE.Camera; THREE.Camera.prototype.getWorldDirection = function () { var quaternion = new THREE.Quaternion(); return function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); this.getWorldQuaternion( quaternion ); return result.set( 0, 0, - 1 ).applyQuaternion( quaternion ); }; }(); THREE.Camera.prototype.lookAt = function () { // This routine does not support cameras with rotated and/or translated parent(s) var m1 = new THREE.Matrix4(); return function ( vector ) { m1.lookAt( this.position, vector, this.up ); this.quaternion.setFromRotationMatrix( m1 ); }; }(); THREE.Camera.prototype.clone = function () { return new this.constructor().copy( this ); }; THREE.Camera.prototype.copy = function ( source ) { THREE.Object3D.prototype.copy.call( this, source ); this.matrixWorldInverse.copy( source.matrixWorldInverse ); this.projectionMatrix.copy( source.projectionMatrix ); return this; }; three.js-r73/src/lights/0000755000175500017550000000000012610076566015035 5ustar debacledebaclethree.js-r73/src/lights/SpotLight.js0000644000175500017550000000230712610076566017312 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) { THREE.Light.call( this, color ); this.type = 'SpotLight'; this.position.set( 0, 1, 0 ); this.updateMatrix(); this.target = new THREE.Object3D(); this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; this.exponent = ( exponent !== undefined ) ? exponent : 10; this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. this.shadow = new THREE.LightShadow( new THREE.PerspectiveCamera( 50, 1, 50, 5000 ) ); }; THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); THREE.SpotLight.prototype.constructor = THREE.SpotLight; THREE.SpotLight.prototype.copy = function ( source ) { THREE.Light.prototype.copy.call( this, source ); this.intensity = source.intensity; this.distance = source.distance; this.angle = source.angle; this.exponent = source.exponent; this.decay = source.decay; this.target = source.target.clone(); this.shadow = source.shadow.clone(); return this; }; three.js-r73/src/lights/Light.js0000644000175500017550000000474412610076566016453 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Light = function ( color ) { THREE.Object3D.call( this ); this.type = 'Light'; this.color = new THREE.Color( color ); this.receiveShadow = undefined; }; THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); THREE.Light.prototype.constructor = THREE.Light; Object.defineProperties( THREE.Light.prototype, { onlyShadow: { set: function ( value ) { console.warn( 'THREE.Light: .onlyShadow has been removed.' ); } }, shadowCameraFov: { set: function ( value ) { this.shadow.camera.fov = value; } }, shadowCameraLeft: { set: function ( value ) { this.shadow.camera.left = value; } }, shadowCameraRight: { set: function ( value ) { this.shadow.camera.right = value; } }, shadowCameraTop: { set: function ( value ) { this.shadow.camera.top = value; } }, shadowCameraBottom: { set: function ( value ) { this.shadow.camera.bottom = value; } }, shadowCameraNear: { set: function ( value ) { this.shadow.camera.near = value; } }, shadowCameraFar: { set: function ( value ) { this.shadow.camera.far = value; } }, shadowCameraVisible: { set: function ( value ) { console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow ) instead.' ); } }, shadowBias: { set: function ( value ) { this.shadow.bias = value; } }, shadowDarkness: { set: function ( value ) { this.shadow.darkness = value; } }, shadowMapWidth: { set: function ( value ) { this.shadow.mapSize.width = value; } }, shadowMapHeight: { set: function ( value ) { this.shadow.mapSize.height = value; } } } ); THREE.Light.prototype.copy = function ( source ) { THREE.Object3D.prototype.copy.call( this, source ); this.color.copy( source.color ); return this; }; THREE.Light.prototype.toJSON = function ( meta ) { var data = THREE.Object3D.prototype.toJSON.call( this, meta ); data.object.color = this.color.getHex(); if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); if ( this.intensity !== undefined ) data.object.intensity = this.intensity; if ( this.distance !== undefined ) data.object.distance = this.distance; if ( this.angle !== undefined ) data.object.angle = this.angle; if ( this.decay !== undefined ) data.object.decay = this.decay; if ( this.exponent !== undefined ) data.object.exponent = this.exponent; return data; }; three.js-r73/src/lights/PointLight.js0000644000175500017550000000156712610076566017465 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.PointLight = function ( color, intensity, distance, decay ) { THREE.Light.call( this, color ); this.type = 'PointLight'; this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. this.shadow = new THREE.LightShadow( new THREE.PerspectiveCamera( 90, 1, 1, 500 ) ); }; THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); THREE.PointLight.prototype.constructor = THREE.PointLight; THREE.PointLight.prototype.copy = function ( source ) { THREE.Light.prototype.copy.call( this, source ); this.intensity = source.intensity; this.distance = source.distance; this.decay = source.decay; this.shadow = source.shadow.clone(); return this; }; three.js-r73/src/lights/LightShadow.js0000644000175500017550000000106612610076566017613 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.LightShadow = function ( camera ) { this.camera = camera; this.bias = 0; this.darkness = 1; this.mapSize = new THREE.Vector2( 512, 512 ); this.map = null; this.matrix = null; }; THREE.LightShadow.prototype = { constructor: THREE.LightShadow, copy: function ( source ) { this.camera = source.camera.clone(); this.bias = source.bias; this.darkness = source.darkness; this.mapSize.copy( source.mapSize ); }, clone: function () { return new this.constructor().copy( this ); } }; three.js-r73/src/lights/AmbientLight.js0000644000175500017550000000050512610076566017742 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.AmbientLight = function ( color ) { THREE.Light.call( this, color ); this.type = 'AmbientLight'; this.castShadow = undefined; }; THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); THREE.AmbientLight.prototype.constructor = THREE.AmbientLight; three.js-r73/src/lights/HemisphereLight.js0000644000175500017550000000137412610076566020461 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { THREE.Light.call( this, skyColor ); this.type = 'HemisphereLight'; this.castShadow = undefined; this.position.set( 0, 1, 0 ); this.updateMatrix(); this.groundColor = new THREE.Color( groundColor ); this.intensity = ( intensity !== undefined ) ? intensity : 1; }; THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); THREE.HemisphereLight.prototype.constructor = THREE.HemisphereLight; THREE.HemisphereLight.prototype.copy = function ( source ) { THREE.Light.prototype.copy.call( this, source ); this.groundColor.copy( source.groundColor ); this.intensity = source.intensity; return this; }; three.js-r73/src/lights/DirectionalLight.js0000644000175500017550000000156312610076566020625 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.DirectionalLight = function ( color, intensity ) { THREE.Light.call( this, color ); this.type = 'DirectionalLight'; this.position.set( 0, 1, 0 ); this.updateMatrix(); this.target = new THREE.Object3D(); this.intensity = ( intensity !== undefined ) ? intensity : 1; this.shadow = new THREE.LightShadow( new THREE.OrthographicCamera( - 500, 500, 500, - 500, 50, 5000 ) ); }; THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); THREE.DirectionalLight.prototype.constructor = THREE.DirectionalLight; THREE.DirectionalLight.prototype.copy = function ( source ) { THREE.Light.prototype.copy.call( this, source ); this.intensity = source.intensity; this.target = source.target.clone(); this.shadow = source.shadow.clone(); return this; }; three.js-r73/src/renderers/0000755000175500017550000000000012610076566015534 5ustar debacledebaclethree.js-r73/src/renderers/WebGLRenderer.js0000644000175500017550000024703012610076566020527 0ustar debacledebacle/** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author szimek / https://github.com/szimek/ */ THREE.WebGLRenderer = function ( parameters ) { console.log( 'THREE.WebGLRenderer', THREE.REVISION ); parameters = parameters || {}; var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), _context = parameters.context !== undefined ? parameters.context : null, _width = _canvas.width, _height = _canvas.height, pixelRatio = 1, _alpha = parameters.alpha !== undefined ? parameters.alpha : false, _depth = parameters.depth !== undefined ? parameters.depth : true, _stencil = parameters.stencil !== undefined ? parameters.stencil : true, _antialias = parameters.antialias !== undefined ? parameters.antialias : false, _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, _clearColor = new THREE.Color( 0x000000 ), _clearAlpha = 0; var lights = []; var opaqueObjects = []; var opaqueObjectsLastIndex = - 1; var transparentObjects = []; var transparentObjectsLastIndex = - 1; var morphInfluences = new Float32Array( 8 ); var sprites = []; var lensFlares = []; // public properties this.domElement = _canvas; this.context = null; // clearing this.autoClear = true; this.autoClearColor = true; this.autoClearDepth = true; this.autoClearStencil = true; // scene graph this.sortObjects = true; // physically based shading this.gammaFactor = 2.0; // for backwards compatibility this.gammaInput = false; this.gammaOutput = false; // morphs this.maxMorphTargets = 8; this.maxMorphNormals = 4; // flags this.autoScaleCubemaps = true; // internal properties var _this = this, // internal state cache _currentProgram = null, _currentFramebuffer = null, _currentMaterialId = - 1, _currentGeometryProgram = '', _currentCamera = null, _usedTextureUnits = 0, _viewportX = 0, _viewportY = 0, _viewportWidth = _canvas.width, _viewportHeight = _canvas.height, _currentWidth = 0, _currentHeight = 0, // frustum _frustum = new THREE.Frustum(), // camera matrices cache _projScreenMatrix = new THREE.Matrix4(), _vector3 = new THREE.Vector3(), // light arrays cache _direction = new THREE.Vector3(), _lightsNeedUpdate = true, _lights = { ambient: [ 0, 0, 0 ], directional: { length: 0, colors: [], positions: [] }, point: { length: 0, colors: [], positions: [], distances: [], decays: [] }, spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] }, hemi: { length: 0, skyColors: [], groundColors: [], positions: [] } }, // info _infoMemory = { geometries: 0, textures: 0 }, _infoRender = { calls: 0, vertices: 0, faces: 0, points: 0 }; this.info = { render: _infoRender, memory: _infoMemory, programs: null }; // initialize var _gl; try { var attributes = { alpha: _alpha, depth: _depth, stencil: _stencil, antialias: _antialias, premultipliedAlpha: _premultipliedAlpha, preserveDrawingBuffer: _preserveDrawingBuffer }; _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); if ( _gl === null ) { if ( _canvas.getContext( 'webgl' ) !== null ) { throw 'Error creating WebGL context with your selected attributes.'; } else { throw 'Error creating WebGL context.'; } } _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); } catch ( error ) { console.error( 'THREE.WebGLRenderer: ' + error ); } var extensions = new THREE.WebGLExtensions( _gl ); extensions.get( 'OES_texture_float' ); extensions.get( 'OES_texture_float_linear' ); extensions.get( 'OES_texture_half_float' ); extensions.get( 'OES_texture_half_float_linear' ); extensions.get( 'OES_standard_derivatives' ); extensions.get( 'ANGLE_instanced_arrays' ); if ( extensions.get( 'OES_element_index_uint' ) ) { THREE.BufferGeometry.MaxIndex = 4294967296; } var capabilities = new THREE.WebGLCapabilities( _gl, extensions, parameters ); var state = new THREE.WebGLState( _gl, extensions, paramThreeToGL ); var properties = new THREE.WebGLProperties(); var objects = new THREE.WebGLObjects( _gl, properties, this.info ); var programCache = new THREE.WebGLPrograms( this, capabilities ); this.info.programs = programCache.programs; var bufferRenderer = new THREE.WebGLBufferRenderer( _gl, extensions, _infoRender ); var indexedBufferRenderer = new THREE.WebGLIndexedBufferRenderer( _gl, extensions, _infoRender ); // function glClearColor( r, g, b, a ) { if ( _premultipliedAlpha === true ) { r *= a; g *= a; b *= a; } _gl.clearColor( r, g, b, a ); } function setDefaultGLState() { state.init(); _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); } function resetGLState() { _currentProgram = null; _currentCamera = null; _currentGeometryProgram = ''; _currentMaterialId = - 1; _lightsNeedUpdate = true; state.reset(); } setDefaultGLState(); this.context = _gl; this.capabilities = capabilities; this.extensions = extensions; this.state = state; // shadow map var shadowMap = new THREE.WebGLShadowMap( this, lights, objects ); this.shadowMap = shadowMap; // Plugins var spritePlugin = new THREE.SpritePlugin( this, sprites ); var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares ); // API this.getContext = function () { return _gl; }; this.getContextAttributes = function () { return _gl.getContextAttributes(); }; this.forceContextLoss = function () { extensions.get( 'WEBGL_lose_context' ).loseContext(); }; this.getMaxAnisotropy = ( function () { var value; return function getMaxAnisotropy() { if ( value !== undefined ) return value; var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); if ( extension !== null ) { value = _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); } else { value = 0; } return value; } } )(); this.getPrecision = function () { return capabilities.precision; }; this.getPixelRatio = function () { return pixelRatio; }; this.setPixelRatio = function ( value ) { if ( value !== undefined ) pixelRatio = value; }; this.getSize = function () { return { width: _width, height: _height }; }; this.setSize = function ( width, height, updateStyle ) { _width = width; _height = height; _canvas.width = width * pixelRatio; _canvas.height = height * pixelRatio; if ( updateStyle !== false ) { _canvas.style.width = width + 'px'; _canvas.style.height = height + 'px'; } this.setViewport( 0, 0, width, height ); }; this.setViewport = function ( x, y, width, height ) { _viewportX = x * pixelRatio; _viewportY = y * pixelRatio; _viewportWidth = width * pixelRatio; _viewportHeight = height * pixelRatio; _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); }; this.getViewport = function ( dimensions ) { dimensions.x = _viewportX / pixelRatio; dimensions.y = _viewportY / pixelRatio; dimensions.z = _viewportWidth / pixelRatio; dimensions.w = _viewportHeight / pixelRatio; }; this.setScissor = function ( x, y, width, height ) { _gl.scissor( x * pixelRatio, y * pixelRatio, width * pixelRatio, height * pixelRatio ); }; this.enableScissorTest = function ( boolean ) { state.setScissorTest( boolean ); }; // Clearing this.getClearColor = function () { return _clearColor; }; this.setClearColor = function ( color, alpha ) { _clearColor.set( color ); _clearAlpha = alpha !== undefined ? alpha : 1; glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; this.getClearAlpha = function () { return _clearAlpha; }; this.setClearAlpha = function ( alpha ) { _clearAlpha = alpha; glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; this.clear = function ( color, depth, stencil ) { var bits = 0; if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; _gl.clear( bits ); }; this.clearColor = function () { _gl.clear( _gl.COLOR_BUFFER_BIT ); }; this.clearDepth = function () { _gl.clear( _gl.DEPTH_BUFFER_BIT ); }; this.clearStencil = function () { _gl.clear( _gl.STENCIL_BUFFER_BIT ); }; this.clearTarget = function ( renderTarget, color, depth, stencil ) { this.setRenderTarget( renderTarget ); this.clear( color, depth, stencil ); }; // Reset this.resetGLState = resetGLState; this.dispose = function() { _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); }; // Events function onContextLost( event ) { event.preventDefault(); resetGLState(); setDefaultGLState(); properties.clear(); }; function onTextureDispose( event ) { var texture = event.target; texture.removeEventListener( 'dispose', onTextureDispose ); deallocateTexture( texture ); _infoMemory.textures --; } function onRenderTargetDispose( event ) { var renderTarget = event.target; renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); deallocateRenderTarget( renderTarget ); _infoMemory.textures --; } function onMaterialDispose( event ) { var material = event.target; material.removeEventListener( 'dispose', onMaterialDispose ); deallocateMaterial( material ); } // Buffer deallocation function deallocateTexture( texture ) { var textureProperties = properties.get( texture ); if ( texture.image && textureProperties.__image__webglTextureCube ) { // cube texture _gl.deleteTexture( textureProperties.__image__webglTextureCube ); } else { // 2D texture if ( textureProperties.__webglInit === undefined ) return; _gl.deleteTexture( textureProperties.__webglTexture ); } // remove all webgl properties properties.delete( texture ); } function deallocateRenderTarget( renderTarget ) { var renderTargetProperties = properties.get( renderTarget ); var textureProperties = properties.get( renderTarget.texture ); if ( ! renderTarget || textureProperties.__webglTexture === undefined ) return; _gl.deleteTexture( textureProperties.__webglTexture ); if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { for ( var i = 0; i < 6; i ++ ) { _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); _gl.deleteRenderbuffer( renderTargetProperties.__webglRenderbuffer[ i ] ); } } else { _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); _gl.deleteRenderbuffer( renderTargetProperties.__webglRenderbuffer ); } properties.delete( renderTarget.texture ); properties.delete( renderTarget ); } function deallocateMaterial( material ) { releaseMaterialProgramReference( material ); properties.delete( material ); } function releaseMaterialProgramReference( material ) { var programInfo = properties.get( material ).program; material.program = undefined; if ( programInfo !== undefined ) { programCache.releaseProgram( programInfo ); } } // Buffer rendering this.renderBufferImmediate = function ( object, program, material ) { state.initAttributes(); var buffers = properties.get( object ); if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer(); if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer(); if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); var attributes = program.getAttributes(); if ( object.hasPositions ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); state.enableAttribute( attributes.position ); _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } if ( object.hasNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal ); if ( material.type !== 'MeshPhongMaterial' && material.shading === THREE.FlatShading ) { for ( var i = 0, l = object.count * 3; i < l; i += 9 ) { var array = object.normalArray; var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3; var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3; var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3; array[ i + 0 ] = nx; array[ i + 1 ] = ny; array[ i + 2 ] = nz; array[ i + 3 ] = nx; array[ i + 4 ] = ny; array[ i + 5 ] = nz; array[ i + 6 ] = nx; array[ i + 7 ] = ny; array[ i + 8 ] = nz; } } _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); state.enableAttribute( attributes.normal ); _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } if ( object.hasUvs && material.map ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); state.enableAttribute( attributes.uv ); _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); state.enableAttribute( attributes.color ); _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } state.disableUnusedAttributes(); _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); object.count = 0; }; this.renderBufferDirect = function ( camera, lights, fog, geometry, material, object, group ) { setMaterial( material ); var program = setProgram( camera, lights, fog, material, object ); var updateBuffers = false; var geometryProgram = geometry.id + '_' + program.id + '_' + material.wireframe; if ( geometryProgram !== _currentGeometryProgram ) { _currentGeometryProgram = geometryProgram; updateBuffers = true; } // morph targets var morphTargetInfluences = object.morphTargetInfluences; if ( morphTargetInfluences !== undefined ) { var activeInfluences = []; for ( var i = 0, l = morphTargetInfluences.length; i < l; i ++ ) { var influence = morphTargetInfluences[ i ]; activeInfluences.push( [ influence, i ] ); } activeInfluences.sort( numericalSort ); if ( activeInfluences.length > 8 ) { activeInfluences.length = 8; } var morphAttributes = geometry.morphAttributes; for ( var i = 0, l = activeInfluences.length; i < l; i ++ ) { var influence = activeInfluences[ i ]; morphInfluences[ i ] = influence[ 0 ]; if ( influence[ 0 ] !== 0 ) { var index = influence[ 1 ]; if ( material.morphTargets === true && morphAttributes.position ) geometry.addAttribute( 'morphTarget' + i, morphAttributes.position[ index ] ); if ( material.morphNormals === true && morphAttributes.normal ) geometry.addAttribute( 'morphNormal' + i, morphAttributes.normal[ index ] ); } else { if ( material.morphTargets === true ) geometry.removeAttribute( 'morphTarget' + i ); if ( material.morphNormals === true ) geometry.removeAttribute( 'morphNormal' + i ); } } var uniforms = program.getUniforms(); if ( uniforms.morphTargetInfluences !== null ) { _gl.uniform1fv( uniforms.morphTargetInfluences, morphInfluences ); } updateBuffers = true; } // var index = geometry.index; var position = geometry.attributes.position; if ( material.wireframe === true ) { index = objects.getWireframeAttribute( geometry ); } var renderer; if ( index !== null ) { renderer = indexedBufferRenderer; renderer.setIndex( index ); } else { renderer = bufferRenderer; } if ( updateBuffers ) { setupVertexAttributes( material, program, geometry ); if ( index !== null ) { _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, objects.getAttributeBuffer( index ) ); } } // var dataStart = 0; var dataCount = Infinity; if ( index !== null ) { dataCount = index.count } else if ( position !== undefined ) { dataCount = position.count; } var rangeStart = geometry.drawRange.start; var rangeCount = geometry.drawRange.count; var groupStart = group !== null ? group.start : 0; var groupCount = group !== null ? group.count : Infinity; var drawStart = Math.max( dataStart, rangeStart, groupStart ); var drawEnd = Math.min( dataStart + dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); // if ( object instanceof THREE.Mesh ) { if ( material.wireframe === true ) { state.setLineWidth( material.wireframeLinewidth * pixelRatio ); renderer.setMode( _gl.LINES ); } else { renderer.setMode( _gl.TRIANGLES ); } if ( geometry instanceof THREE.InstancedBufferGeometry && geometry.maxInstancedCount > 0 ) { renderer.renderInstances( geometry ); } else { renderer.render( drawStart, drawCount ); } } else if ( object instanceof THREE.Line ) { var lineWidth = material.linewidth; if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material state.setLineWidth( lineWidth * pixelRatio ); if ( object instanceof THREE.LineSegments ) { renderer.setMode( _gl.LINES ); } else { renderer.setMode( _gl.LINE_STRIP ); } renderer.render( drawStart, drawCount ); } else if ( object instanceof THREE.Points ) { renderer.setMode( _gl.POINTS ); renderer.render( drawStart, drawCount ); } }; function setupVertexAttributes( material, program, geometry, startIndex ) { var extension; if ( geometry instanceof THREE.InstancedBufferGeometry ) { extension = extensions.get( 'ANGLE_instanced_arrays' ); if ( extension === null ) { console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); return; } } if ( startIndex === undefined ) startIndex = 0; state.initAttributes(); var geometryAttributes = geometry.attributes; var programAttributes = program.getAttributes(); var materialDefaultAttributeValues = material.defaultAttributeValues; for ( var name in programAttributes ) { var programAttribute = programAttributes[ name ]; if ( programAttribute >= 0 ) { var geometryAttribute = geometryAttributes[ name ]; if ( geometryAttribute !== undefined ) { var size = geometryAttribute.itemSize; var buffer = objects.getAttributeBuffer( geometryAttribute ); if ( geometryAttribute instanceof THREE.InterleavedBufferAttribute ) { var data = geometryAttribute.data; var stride = data.stride; var offset = geometryAttribute.offset; if ( data instanceof THREE.InstancedInterleavedBuffer ) { state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute, extension ); if ( geometry.maxInstancedCount === undefined ) { geometry.maxInstancedCount = data.meshPerAttribute * data.count; } } else { state.enableAttribute( programAttribute ); } _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, stride * data.array.BYTES_PER_ELEMENT, ( startIndex * stride + offset ) * data.array.BYTES_PER_ELEMENT ); } else { if ( geometryAttribute instanceof THREE.InstancedBufferAttribute ) { state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute, extension ); if ( geometry.maxInstancedCount === undefined ) { geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; } } else { state.enableAttribute( programAttribute ); } _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 } } else if ( materialDefaultAttributeValues !== undefined ) { var value = materialDefaultAttributeValues[ name ]; if ( value !== undefined ) { switch ( value.length ) { case 2: _gl.vertexAttrib2fv( programAttribute, value ); break; case 3: _gl.vertexAttrib3fv( programAttribute, value ); break; case 4: _gl.vertexAttrib4fv( programAttribute, value ); break; default: _gl.vertexAttrib1fv( programAttribute, value ); } } } } } state.disableUnusedAttributes(); } // Sorting function numericalSort ( a, b ) { return b[ 0 ] - a[ 0 ]; } function painterSortStable ( a, b ) { if ( a.object.renderOrder !== b.object.renderOrder ) { return a.object.renderOrder - b.object.renderOrder; } else if ( a.material.id !== b.material.id ) { return a.material.id - b.material.id; } else if ( a.z !== b.z ) { return a.z - b.z; } else { return a.id - b.id; } } function reversePainterSortStable ( a, b ) { if ( a.object.renderOrder !== b.object.renderOrder ) { return a.object.renderOrder - b.object.renderOrder; } if ( a.z !== b.z ) { return b.z - a.z; } else { return a.id - b.id; } } // Rendering this.render = function ( scene, camera, renderTarget, forceClear ) { if ( camera instanceof THREE.Camera === false ) { console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); return; } var fog = scene.fog; // reset caching for this frame _currentGeometryProgram = ''; _currentMaterialId = - 1; _currentCamera = null; _lightsNeedUpdate = true; // update scene graph if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); // update camera matrices and frustum if ( camera.parent === null ) camera.updateMatrixWorld(); camera.matrixWorldInverse.getInverse( camera.matrixWorld ); _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); _frustum.setFromMatrix( _projScreenMatrix ); lights.length = 0; opaqueObjectsLastIndex = - 1; transparentObjectsLastIndex = - 1; sprites.length = 0; lensFlares.length = 0; projectObject( scene, camera ); opaqueObjects.length = opaqueObjectsLastIndex + 1; transparentObjects.length = transparentObjectsLastIndex + 1; if ( _this.sortObjects === true ) { opaqueObjects.sort( painterSortStable ); transparentObjects.sort( reversePainterSortStable ); } // shadowMap.render( scene ); // _infoRender.calls = 0; _infoRender.vertices = 0; _infoRender.faces = 0; _infoRender.points = 0; this.setRenderTarget( renderTarget ); if ( this.autoClear || forceClear ) { this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); } // if ( scene.overrideMaterial ) { var overrideMaterial = scene.overrideMaterial; renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial ); renderObjects( transparentObjects, camera, lights, fog, overrideMaterial ); } else { // opaque pass (front-to-back order) state.setBlending( THREE.NoBlending ); renderObjects( opaqueObjects, camera, lights, fog ); // transparent pass (back-to-front order) renderObjects( transparentObjects, camera, lights, fog ); } // custom render plugins (post pass) spritePlugin.render( scene, camera ); lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight ); // Generate mipmap if we're using any kind of mipmap filtering if ( renderTarget ) { var texture = renderTarget.texture; var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); if ( texture.generateMipmaps && isTargetPowerOfTwo && texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { updateRenderTargetMipmap( renderTarget ); } } // Ensure depth buffer writing is enabled so it can be cleared on next render state.setDepthTest( true ); state.setDepthWrite( true ); state.setColorWrite( true ); // _gl.finish(); }; function pushRenderItem( object, geometry, material, z, group ) { var array, index; // allocate the next position in the appropriate array if ( material.transparent ) { array = transparentObjects; index = ++ transparentObjectsLastIndex; } else { array = opaqueObjects; index = ++ opaqueObjectsLastIndex; } // recycle existing render item or grow the array var renderItem = array[ index ]; if ( renderItem !== undefined ) { renderItem.id = object.id; renderItem.object = object; renderItem.geometry = geometry; renderItem.material = material; renderItem.z = _vector3.z; renderItem.group = group; } else { renderItem = { id: object.id, object: object, geometry: geometry, material: material, z: _vector3.z, group: group }; // assert( index === array.length ); array.push( renderItem ); } } function projectObject( object, camera ) { if ( object.visible === false ) return; if ( ( object.channels.mask & camera.channels.mask ) !== 0 ) { if ( object instanceof THREE.Light ) { lights.push( object ); } else if ( object instanceof THREE.Sprite ) { sprites.push( object ); } else if ( object instanceof THREE.LensFlare ) { lensFlares.push( object ); } else if ( object instanceof THREE.ImmediateRenderObject ) { if ( _this.sortObjects === true ) { _vector3.setFromMatrixPosition( object.matrixWorld ); _vector3.applyProjection( _projScreenMatrix ); } pushRenderItem( object, null, object.material, _vector3.z, null ); } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) { if ( object instanceof THREE.SkinnedMesh ) { object.skeleton.update(); } if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { var material = object.material; if ( material.visible === true ) { if ( _this.sortObjects === true ) { _vector3.setFromMatrixPosition( object.matrixWorld ); _vector3.applyProjection( _projScreenMatrix ); } var geometry = objects.update( object ); if ( material instanceof THREE.MeshFaceMaterial ) { var groups = geometry.groups; var materials = material.materials; for ( var i = 0, l = groups.length; i < l; i ++ ) { var group = groups[ i ]; var groupMaterial = materials[ group.materialIndex ]; if ( groupMaterial.visible === true ) { pushRenderItem( object, geometry, groupMaterial, _vector3.z, group ); } } } else { pushRenderItem( object, geometry, material, _vector3.z, null ); } } } } } var children = object.children; for ( var i = 0, l = children.length; i < l; i ++ ) { projectObject( children[ i ], camera ); } } function renderObjects( renderList, camera, lights, fog, overrideMaterial ) { for ( var i = 0, l = renderList.length; i < l; i ++ ) { var renderItem = renderList[ i ]; var object = renderItem.object; var geometry = renderItem.geometry; var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; var group = renderItem.group; object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); if ( object instanceof THREE.ImmediateRenderObject ) { setMaterial( material ); var program = setProgram( camera, lights, fog, material, object ); _currentGeometryProgram = ''; object.render( function ( object ) { _this.renderBufferImmediate( object, program, material ); } ); } else { _this.renderBufferDirect( camera, lights, fog, geometry, material, object, group ); } } } function initMaterial( material, lights, fog, object ) { var materialProperties = properties.get( material ); var parameters = programCache.getParameters( material, lights, fog, object ); var code = programCache.getProgramCode( material, parameters ); var program = materialProperties.program; var programChange = true; if ( program === undefined ) { // new material material.addEventListener( 'dispose', onMaterialDispose ); } else if ( program.code !== code ) { // changed glsl or parameters releaseMaterialProgramReference( material ); } else if ( parameters.shaderID !== undefined ) { // same glsl and uniform list return; } else { // only rebuild uniform list programChange = false; } if ( programChange ) { if ( parameters.shaderID ) { var shader = THREE.ShaderLib[ parameters.shaderID ]; materialProperties.__webglShader = { name: material.type, uniforms: THREE.UniformsUtils.clone( shader.uniforms ), vertexShader: shader.vertexShader, fragmentShader: shader.fragmentShader }; } else { materialProperties.__webglShader = { name: material.type, uniforms: material.uniforms, vertexShader: material.vertexShader, fragmentShader: material.fragmentShader }; } material.__webglShader = materialProperties.__webglShader; program = programCache.acquireProgram( material, parameters, code ); materialProperties.program = program; material.program = program; } var attributes = program.getAttributes(); if ( material.morphTargets ) { material.numSupportedMorphTargets = 0; for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { if ( attributes[ 'morphTarget' + i ] >= 0 ) { material.numSupportedMorphTargets ++; } } } if ( material.morphNormals ) { material.numSupportedMorphNormals = 0; for ( i = 0; i < _this.maxMorphNormals; i ++ ) { if ( attributes[ 'morphNormal' + i ] >= 0 ) { material.numSupportedMorphNormals ++; } } } materialProperties.uniformsList = []; var uniformLocations = materialProperties.program.getUniforms(); for ( var u in materialProperties.__webglShader.uniforms ) { var location = uniformLocations[ u ]; if ( location ) { materialProperties.uniformsList.push( [ materialProperties.__webglShader.uniforms[ u ], location ] ); } } } function setMaterial( material ) { setMaterialFaces( material ); if ( material.transparent === true ) { state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); } else { state.setBlending( THREE.NoBlending ); } state.setDepthFunc( material.depthFunc ); state.setDepthTest( material.depthTest ); state.setDepthWrite( material.depthWrite ); state.setColorWrite( material.colorWrite ); state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); } function setMaterialFaces( material ) { material.side !== THREE.DoubleSide ? state.enable( _gl.CULL_FACE ) : state.disable( _gl.CULL_FACE ); state.setFlipSided( material.side === THREE.BackSide ); } function setProgram( camera, lights, fog, material, object ) { _usedTextureUnits = 0; var materialProperties = properties.get( material ); if ( material.needsUpdate || ! materialProperties.program ) { initMaterial( material, lights, fog, object ); material.needsUpdate = false; } var refreshProgram = false; var refreshMaterial = false; var refreshLights = false; var program = materialProperties.program, p_uniforms = program.getUniforms(), m_uniforms = materialProperties.__webglShader.uniforms; if ( program.id !== _currentProgram ) { _gl.useProgram( program.program ); _currentProgram = program.id; refreshProgram = true; refreshMaterial = true; refreshLights = true; } if ( material.id !== _currentMaterialId ) { if ( _currentMaterialId === - 1 ) refreshLights = true; _currentMaterialId = material.id; refreshMaterial = true; } if ( refreshProgram || camera !== _currentCamera ) { _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); if ( capabilities.logarithmicDepthBuffer ) { _gl.uniform1f( p_uniforms.logDepthBufFC, 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); } if ( camera !== _currentCamera ) _currentCamera = camera; // load material specific uniforms // (shader material also gets them for the sake of genericity) if ( material instanceof THREE.ShaderMaterial || material instanceof THREE.MeshPhongMaterial || material.envMap ) { if ( p_uniforms.cameraPosition !== undefined ) { _vector3.setFromMatrixPosition( camera.matrixWorld ); _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); } } if ( material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshBasicMaterial || material instanceof THREE.ShaderMaterial || material.skinning ) { if ( p_uniforms.viewMatrix !== undefined ) { _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); } } } // skinning uniforms must be set even if material didn't change // auto-setting of texture unit for bone texture must go before other textures // not sure why, but otherwise weird things happen if ( material.skinning ) { if ( object.bindMatrix && p_uniforms.bindMatrix !== undefined ) { _gl.uniformMatrix4fv( p_uniforms.bindMatrix, false, object.bindMatrix.elements ); } if ( object.bindMatrixInverse && p_uniforms.bindMatrixInverse !== undefined ) { _gl.uniformMatrix4fv( p_uniforms.bindMatrixInverse, false, object.bindMatrixInverse.elements ); } if ( capabilities.floatVertexTextures && object.skeleton && object.skeleton.useVertexTexture ) { if ( p_uniforms.boneTexture !== undefined ) { var textureUnit = getTextureUnit(); _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); _this.setTexture( object.skeleton.boneTexture, textureUnit ); } if ( p_uniforms.boneTextureWidth !== undefined ) { _gl.uniform1i( p_uniforms.boneTextureWidth, object.skeleton.boneTextureWidth ); } if ( p_uniforms.boneTextureHeight !== undefined ) { _gl.uniform1i( p_uniforms.boneTextureHeight, object.skeleton.boneTextureHeight ); } } else if ( object.skeleton && object.skeleton.boneMatrices ) { if ( p_uniforms.boneGlobalMatrices !== undefined ) { _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.skeleton.boneMatrices ); } } } if ( refreshMaterial ) { // refresh uniforms common to several materials if ( fog && material.fog ) { refreshUniformsFog( m_uniforms, fog ); } if ( material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || material.lights ) { if ( _lightsNeedUpdate ) { refreshLights = true; setupLights( lights, camera ); _lightsNeedUpdate = false; } if ( refreshLights ) { refreshUniformsLights( m_uniforms, _lights ); markUniformsLightsNeedsUpdate( m_uniforms, true ); } else { markUniformsLightsNeedsUpdate( m_uniforms, false ); } } if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { refreshUniformsCommon( m_uniforms, material ); } // refresh single material specific uniforms if ( material instanceof THREE.LineBasicMaterial ) { refreshUniformsLine( m_uniforms, material ); } else if ( material instanceof THREE.LineDashedMaterial ) { refreshUniformsLine( m_uniforms, material ); refreshUniformsDash( m_uniforms, material ); } else if ( material instanceof THREE.PointsMaterial ) { refreshUniformsParticle( m_uniforms, material ); } else if ( material instanceof THREE.MeshPhongMaterial ) { refreshUniformsPhong( m_uniforms, material ); } else if ( material instanceof THREE.MeshDepthMaterial ) { m_uniforms.mNear.value = camera.near; m_uniforms.mFar.value = camera.far; m_uniforms.opacity.value = material.opacity; } else if ( material instanceof THREE.MeshNormalMaterial ) { m_uniforms.opacity.value = material.opacity; } if ( object.receiveShadow && ! material._shadowPass ) { refreshUniformsShadow( m_uniforms, lights, camera ); } // load common uniforms loadUniformsGeneric( materialProperties.uniformsList ); } loadUniformsMatrices( p_uniforms, object ); if ( p_uniforms.modelMatrix !== undefined ) { _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); } return program; } // Uniforms (refresh uniforms objects) function refreshUniformsCommon ( uniforms, material ) { uniforms.opacity.value = material.opacity; uniforms.diffuse.value = material.color; if ( material.emissive ) { uniforms.emissive.value = material.emissive; } uniforms.map.value = material.map; uniforms.specularMap.value = material.specularMap; uniforms.alphaMap.value = material.alphaMap; if ( material.aoMap ) { uniforms.aoMap.value = material.aoMap; uniforms.aoMapIntensity.value = material.aoMapIntensity; } // uv repeat and offset setting priorities // 1. color map // 2. specular map // 3. normal map // 4. bump map // 5. alpha map // 6. emissive map var uvScaleMap; if ( material.map ) { uvScaleMap = material.map; } else if ( material.specularMap ) { uvScaleMap = material.specularMap; } else if ( material.displacementMap ) { uvScaleMap = material.displacementMap; } else if ( material.normalMap ) { uvScaleMap = material.normalMap; } else if ( material.bumpMap ) { uvScaleMap = material.bumpMap; } else if ( material.alphaMap ) { uvScaleMap = material.alphaMap; } else if ( material.emissiveMap ) { uvScaleMap = material.emissiveMap; } if ( uvScaleMap !== undefined ) { if ( uvScaleMap instanceof THREE.WebGLRenderTarget ) uvScaleMap = uvScaleMap.texture; var offset = uvScaleMap.offset; var repeat = uvScaleMap.repeat; uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); } uniforms.envMap.value = material.envMap; uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1; uniforms.reflectivity.value = material.reflectivity; uniforms.refractionRatio.value = material.refractionRatio; } function refreshUniformsLine ( uniforms, material ) { uniforms.diffuse.value = material.color; uniforms.opacity.value = material.opacity; } function refreshUniformsDash ( uniforms, material ) { uniforms.dashSize.value = material.dashSize; uniforms.totalSize.value = material.dashSize + material.gapSize; uniforms.scale.value = material.scale; } function refreshUniformsParticle ( uniforms, material ) { uniforms.psColor.value = material.color; uniforms.opacity.value = material.opacity; uniforms.size.value = material.size; uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. uniforms.map.value = material.map; if ( material.map !== null ) { var offset = material.map.offset; var repeat = material.map.repeat; uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); } } function refreshUniformsFog ( uniforms, fog ) { uniforms.fogColor.value = fog.color; if ( fog instanceof THREE.Fog ) { uniforms.fogNear.value = fog.near; uniforms.fogFar.value = fog.far; } else if ( fog instanceof THREE.FogExp2 ) { uniforms.fogDensity.value = fog.density; } } function refreshUniformsPhong ( uniforms, material ) { uniforms.specular.value = material.specular; uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) if ( material.lightMap ) { uniforms.lightMap.value = material.lightMap; uniforms.lightMapIntensity.value = material.lightMapIntensity; } if ( material.emissiveMap ) { uniforms.emissiveMap.value = material.emissiveMap; } if ( material.bumpMap ) { uniforms.bumpMap.value = material.bumpMap; uniforms.bumpScale.value = material.bumpScale; } if ( material.normalMap ) { uniforms.normalMap.value = material.normalMap; uniforms.normalScale.value.copy( material.normalScale ); } if ( material.displacementMap ) { uniforms.displacementMap.value = material.displacementMap; uniforms.displacementScale.value = material.displacementScale; uniforms.displacementBias.value = material.displacementBias; } } function refreshUniformsLights ( uniforms, lights ) { uniforms.ambientLightColor.value = lights.ambient; uniforms.directionalLightColor.value = lights.directional.colors; uniforms.directionalLightDirection.value = lights.directional.positions; uniforms.pointLightColor.value = lights.point.colors; uniforms.pointLightPosition.value = lights.point.positions; uniforms.pointLightDistance.value = lights.point.distances; uniforms.pointLightDecay.value = lights.point.decays; uniforms.spotLightColor.value = lights.spot.colors; uniforms.spotLightPosition.value = lights.spot.positions; uniforms.spotLightDistance.value = lights.spot.distances; uniforms.spotLightDirection.value = lights.spot.directions; uniforms.spotLightAngleCos.value = lights.spot.anglesCos; uniforms.spotLightExponent.value = lights.spot.exponents; uniforms.spotLightDecay.value = lights.spot.decays; uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; uniforms.hemisphereLightDirection.value = lights.hemi.positions; } // If uniforms are marked as clean, they don't need to be loaded to the GPU. function markUniformsLightsNeedsUpdate ( uniforms, value ) { uniforms.ambientLightColor.needsUpdate = value; uniforms.directionalLightColor.needsUpdate = value; uniforms.directionalLightDirection.needsUpdate = value; uniforms.pointLightColor.needsUpdate = value; uniforms.pointLightPosition.needsUpdate = value; uniforms.pointLightDistance.needsUpdate = value; uniforms.pointLightDecay.needsUpdate = value; uniforms.spotLightColor.needsUpdate = value; uniforms.spotLightPosition.needsUpdate = value; uniforms.spotLightDistance.needsUpdate = value; uniforms.spotLightDirection.needsUpdate = value; uniforms.spotLightAngleCos.needsUpdate = value; uniforms.spotLightExponent.needsUpdate = value; uniforms.spotLightDecay.needsUpdate = value; uniforms.hemisphereLightSkyColor.needsUpdate = value; uniforms.hemisphereLightGroundColor.needsUpdate = value; uniforms.hemisphereLightDirection.needsUpdate = value; } function refreshUniformsShadow ( uniforms, lights, camera ) { if ( uniforms.shadowMatrix ) { var j = 0; for ( var i = 0, il = lights.length; i < il; i ++ ) { var light = lights[ i ]; if ( light.castShadow === true ) { if ( light instanceof THREE.PointLight || light instanceof THREE.SpotLight || light instanceof THREE.DirectionalLight ) { var shadow = light.shadow; if ( light instanceof THREE.PointLight ) { // for point lights we set the shadow matrix to be a translation-only matrix // equal to inverse of the light's position _vector3.setFromMatrixPosition( light.matrixWorld ).negate(); shadow.matrix.identity().setPosition( _vector3 ); // for point lights we set the sign of the shadowDarkness uniform to be negative uniforms.shadowDarkness.value[ j ] = - shadow.darkness; } else { uniforms.shadowDarkness.value[ j ] = shadow.darkness; } uniforms.shadowMatrix.value[ j ] = shadow.matrix; uniforms.shadowMap.value[ j ] = shadow.map; uniforms.shadowMapSize.value[ j ] = shadow.mapSize; uniforms.shadowBias.value[ j ] = shadow.bias; j ++; } } } } } // Uniforms (load to GPU) function loadUniformsMatrices ( uniforms, object ) { _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object.modelViewMatrix.elements ); if ( uniforms.normalMatrix ) { _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object.normalMatrix.elements ); } } function getTextureUnit() { var textureUnit = _usedTextureUnits; if ( textureUnit >= capabilities.maxTextures ) { console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); } _usedTextureUnits += 1; return textureUnit; } function loadUniformsGeneric ( uniforms ) { var texture, textureUnit; for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) { var uniform = uniforms[ j ][ 0 ]; // needsUpdate property is not added to all uniforms. if ( uniform.needsUpdate === false ) continue; var type = uniform.type; var value = uniform.value; var location = uniforms[ j ][ 1 ]; switch ( type ) { case '1i': _gl.uniform1i( location, value ); break; case '1f': _gl.uniform1f( location, value ); break; case '2f': _gl.uniform2f( location, value[ 0 ], value[ 1 ] ); break; case '3f': _gl.uniform3f( location, value[ 0 ], value[ 1 ], value[ 2 ] ); break; case '4f': _gl.uniform4f( location, value[ 0 ], value[ 1 ], value[ 2 ], value[ 3 ] ); break; case '1iv': _gl.uniform1iv( location, value ); break; case '3iv': _gl.uniform3iv( location, value ); break; case '1fv': _gl.uniform1fv( location, value ); break; case '2fv': _gl.uniform2fv( location, value ); break; case '3fv': _gl.uniform3fv( location, value ); break; case '4fv': _gl.uniform4fv( location, value ); break; case 'Matrix3fv': _gl.uniformMatrix3fv( location, false, value ); break; case 'Matrix4fv': _gl.uniformMatrix4fv( location, false, value ); break; // case 'i': // single integer _gl.uniform1i( location, value ); break; case 'f': // single float _gl.uniform1f( location, value ); break; case 'v2': // single THREE.Vector2 _gl.uniform2f( location, value.x, value.y ); break; case 'v3': // single THREE.Vector3 _gl.uniform3f( location, value.x, value.y, value.z ); break; case 'v4': // single THREE.Vector4 _gl.uniform4f( location, value.x, value.y, value.z, value.w ); break; case 'c': // single THREE.Color _gl.uniform3f( location, value.r, value.g, value.b ); break; case 'iv1': // flat array of integers (JS or typed array) _gl.uniform1iv( location, value ); break; case 'iv': // flat array of integers with 3 x N size (JS or typed array) _gl.uniform3iv( location, value ); break; case 'fv1': // flat array of floats (JS or typed array) _gl.uniform1fv( location, value ); break; case 'fv': // flat array of floats with 3 x N size (JS or typed array) _gl.uniform3fv( location, value ); break; case 'v2v': // array of THREE.Vector2 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 2 * value.length ); } for ( var i = 0, i2 = 0, il = value.length; i < il; i ++, i2 += 2 ) { uniform._array[ i2 + 0 ] = value[ i ].x; uniform._array[ i2 + 1 ] = value[ i ].y; } _gl.uniform2fv( location, uniform._array ); break; case 'v3v': // array of THREE.Vector3 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 3 * value.length ); } for ( var i = 0, i3 = 0, il = value.length; i < il; i ++, i3 += 3 ) { uniform._array[ i3 + 0 ] = value[ i ].x; uniform._array[ i3 + 1 ] = value[ i ].y; uniform._array[ i3 + 2 ] = value[ i ].z; } _gl.uniform3fv( location, uniform._array ); break; case 'v4v': // array of THREE.Vector4 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 4 * value.length ); } for ( var i = 0, i4 = 0, il = value.length; i < il; i ++, i4 += 4 ) { uniform._array[ i4 + 0 ] = value[ i ].x; uniform._array[ i4 + 1 ] = value[ i ].y; uniform._array[ i4 + 2 ] = value[ i ].z; uniform._array[ i4 + 3 ] = value[ i ].w; } _gl.uniform4fv( location, uniform._array ); break; case 'm3': // single THREE.Matrix3 _gl.uniformMatrix3fv( location, false, value.elements ); break; case 'm3v': // array of THREE.Matrix3 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 9 * value.length ); } for ( var i = 0, il = value.length; i < il; i ++ ) { value[ i ].flattenToArrayOffset( uniform._array, i * 9 ); } _gl.uniformMatrix3fv( location, false, uniform._array ); break; case 'm4': // single THREE.Matrix4 _gl.uniformMatrix4fv( location, false, value.elements ); break; case 'm4v': // array of THREE.Matrix4 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 16 * value.length ); } for ( var i = 0, il = value.length; i < il; i ++ ) { value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); } _gl.uniformMatrix4fv( location, false, uniform._array ); break; case 't': // single THREE.Texture (2d or cube) texture = value; textureUnit = getTextureUnit(); _gl.uniform1i( location, textureUnit ); if ( ! texture ) continue; if ( texture instanceof THREE.CubeTexture || ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/ setCubeTexture( texture, textureUnit ); } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { setCubeTextureDynamic( texture.texture, textureUnit ); } else if ( texture instanceof THREE.WebGLRenderTarget ) { _this.setTexture( texture.texture, textureUnit ); } else { _this.setTexture( texture, textureUnit ); } break; case 'tv': // array of THREE.Texture (2d or cube) if ( uniform._array === undefined ) { uniform._array = []; } for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { uniform._array[ i ] = getTextureUnit(); } _gl.uniform1iv( location, uniform._array ); for ( var i = 0, il = uniform.value.length; i < il; i ++ ) { texture = uniform.value[ i ]; textureUnit = uniform._array[ i ]; if ( ! texture ) continue; if ( texture instanceof THREE.CubeTexture || ( texture.image instanceof Array && texture.image.length === 6 ) ) { // CompressedTexture can have Array in image :/ setCubeTexture( texture, textureUnit ); } else if ( texture instanceof THREE.WebGLRenderTarget ) { _this.setTexture( texture.texture, textureUnit ); } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { setCubeTextureDynamic( texture.texture, textureUnit ); } else { _this.setTexture( texture, textureUnit ); } } break; default: console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); } } } function setColorLinear( array, offset, color, intensity ) { array[ offset + 0 ] = color.r * intensity; array[ offset + 1 ] = color.g * intensity; array[ offset + 2 ] = color.b * intensity; } function setupLights ( lights, camera ) { var l, ll, light, r = 0, g = 0, b = 0, color, skyColor, groundColor, intensity, distance, zlights = _lights, viewMatrix = camera.matrixWorldInverse, dirColors = zlights.directional.colors, dirPositions = zlights.directional.positions, pointColors = zlights.point.colors, pointPositions = zlights.point.positions, pointDistances = zlights.point.distances, pointDecays = zlights.point.decays, spotColors = zlights.spot.colors, spotPositions = zlights.spot.positions, spotDistances = zlights.spot.distances, spotDirections = zlights.spot.directions, spotAnglesCos = zlights.spot.anglesCos, spotExponents = zlights.spot.exponents, spotDecays = zlights.spot.decays, hemiSkyColors = zlights.hemi.skyColors, hemiGroundColors = zlights.hemi.groundColors, hemiPositions = zlights.hemi.positions, dirLength = 0, pointLength = 0, spotLength = 0, hemiLength = 0, dirCount = 0, pointCount = 0, spotCount = 0, hemiCount = 0, dirOffset = 0, pointOffset = 0, spotOffset = 0, hemiOffset = 0; for ( l = 0, ll = lights.length; l < ll; l ++ ) { light = lights[ l ]; color = light.color; intensity = light.intensity; distance = light.distance; if ( light instanceof THREE.AmbientLight ) { if ( ! light.visible ) continue; r += color.r; g += color.g; b += color.b; } else if ( light instanceof THREE.DirectionalLight ) { dirCount += 1; if ( ! light.visible ) continue; _direction.setFromMatrixPosition( light.matrixWorld ); _vector3.setFromMatrixPosition( light.target.matrixWorld ); _direction.sub( _vector3 ); _direction.transformDirection( viewMatrix ); dirOffset = dirLength * 3; dirPositions[ dirOffset + 0 ] = _direction.x; dirPositions[ dirOffset + 1 ] = _direction.y; dirPositions[ dirOffset + 2 ] = _direction.z; setColorLinear( dirColors, dirOffset, color, intensity ); dirLength += 1; } else if ( light instanceof THREE.PointLight ) { pointCount += 1; if ( ! light.visible ) continue; pointOffset = pointLength * 3; setColorLinear( pointColors, pointOffset, color, intensity ); _vector3.setFromMatrixPosition( light.matrixWorld ); _vector3.applyMatrix4( viewMatrix ); pointPositions[ pointOffset + 0 ] = _vector3.x; pointPositions[ pointOffset + 1 ] = _vector3.y; pointPositions[ pointOffset + 2 ] = _vector3.z; // distance is 0 if decay is 0, because there is no attenuation at all. pointDistances[ pointLength ] = distance; pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; pointLength += 1; } else if ( light instanceof THREE.SpotLight ) { spotCount += 1; if ( ! light.visible ) continue; spotOffset = spotLength * 3; setColorLinear( spotColors, spotOffset, color, intensity ); _direction.setFromMatrixPosition( light.matrixWorld ); _vector3.copy( _direction ).applyMatrix4( viewMatrix ); spotPositions[ spotOffset + 0 ] = _vector3.x; spotPositions[ spotOffset + 1 ] = _vector3.y; spotPositions[ spotOffset + 2 ] = _vector3.z; spotDistances[ spotLength ] = distance; _vector3.setFromMatrixPosition( light.target.matrixWorld ); _direction.sub( _vector3 ); _direction.transformDirection( viewMatrix ); spotDirections[ spotOffset + 0 ] = _direction.x; spotDirections[ spotOffset + 1 ] = _direction.y; spotDirections[ spotOffset + 2 ] = _direction.z; spotAnglesCos[ spotLength ] = Math.cos( light.angle ); spotExponents[ spotLength ] = light.exponent; spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; spotLength += 1; } else if ( light instanceof THREE.HemisphereLight ) { hemiCount += 1; if ( ! light.visible ) continue; _direction.setFromMatrixPosition( light.matrixWorld ); _direction.transformDirection( viewMatrix ); hemiOffset = hemiLength * 3; hemiPositions[ hemiOffset + 0 ] = _direction.x; hemiPositions[ hemiOffset + 1 ] = _direction.y; hemiPositions[ hemiOffset + 2 ] = _direction.z; skyColor = light.color; groundColor = light.groundColor; setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); hemiLength += 1; } } // null eventual remains from removed lights // (this is to avoid if in shader) for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; zlights.directional.length = dirLength; zlights.point.length = pointLength; zlights.spot.length = spotLength; zlights.hemi.length = hemiLength; zlights.ambient[ 0 ] = r; zlights.ambient[ 1 ] = g; zlights.ambient[ 2 ] = b; } // GL state setting this.setFaceCulling = function ( cullFace, frontFaceDirection ) { if ( cullFace === THREE.CullFaceNone ) { state.disable( _gl.CULL_FACE ); } else { if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { _gl.frontFace( _gl.CW ); } else { _gl.frontFace( _gl.CCW ); } if ( cullFace === THREE.CullFaceBack ) { _gl.cullFace( _gl.BACK ); } else if ( cullFace === THREE.CullFaceFront ) { _gl.cullFace( _gl.FRONT ); } else { _gl.cullFace( _gl.FRONT_AND_BACK ); } state.enable( _gl.CULL_FACE ); } }; // Textures function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { var extension; if ( isImagePowerOfTwo ) { _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); } else { _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) { console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture ); } _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture ); } } extension = extensions.get( 'EXT_texture_filter_anisotropic' ); if ( extension ) { if ( texture.type === THREE.FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return; if ( texture.type === THREE.HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return; if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); properties.get( texture ).__currentAnisotropy = texture.anisotropy; } } } function uploadTexture( textureProperties, texture, slot ) { if ( textureProperties.__webglInit === undefined ) { textureProperties.__webglInit = true; texture.addEventListener( 'dispose', onTextureDispose ); textureProperties.__webglTexture = _gl.createTexture(); _infoMemory.textures ++; } state.activeTexture( _gl.TEXTURE0 + slot ); state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); texture.image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false ) { texture.image = makePowerOfTwo( texture.image ); } var image = texture.image, isImagePowerOfTwo = isPowerOfTwo( image ), glFormat = paramThreeToGL( texture.format ), glType = paramThreeToGL( texture.type ); setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); var mipmap, mipmaps = texture.mipmaps; if ( texture instanceof THREE.DataTexture ) { // use manually created mipmaps if available // if there are no manual mipmaps // set 0 level mipmap and then use GL to generate other mipmap levels if ( mipmaps.length > 0 && isImagePowerOfTwo ) { for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { mipmap = mipmaps[ i ]; state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } texture.generateMipmaps = false; } else { state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); } } else if ( texture instanceof THREE.CompressedTexture ) { for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { mipmap = mipmaps[ i ]; if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } else { console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); } } else { state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } } } else { // regular Texture (image, video, canvas) // use manually created mipmaps if available // if there are no manual mipmaps // set 0 level mipmap and then use GL to generate other mipmap levels if ( mipmaps.length > 0 && isImagePowerOfTwo ) { for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { mipmap = mipmaps[ i ]; state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); } texture.generateMipmaps = false; } else { state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); } } if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); textureProperties.__version = texture.version; if ( texture.onUpdate ) texture.onUpdate( texture ); } this.setTexture = function ( texture, slot ) { var textureProperties = properties.get( texture ); if ( texture.version > 0 && textureProperties.__version !== texture.version ) { var image = texture.image; if ( image === undefined ) { console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture ); return; } if ( image.complete === false ) { console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture ); return; } uploadTexture( textureProperties, texture, slot ); return; } state.activeTexture( _gl.TEXTURE0 + slot ); state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); }; function clampToMaxSize ( image, maxSize ) { if ( image.width > maxSize || image.height > maxSize ) { // Warning: Scaling through the canvas will only work with images that use // premultiplied alpha. var scale = maxSize / Math.max( image.width, image.height ); var canvas = document.createElement( 'canvas' ); canvas.width = Math.floor( image.width * scale ); canvas.height = Math.floor( image.height * scale ); var context = canvas.getContext( '2d' ); context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); return canvas; } return image; } function isPowerOfTwo( image ) { return THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ); } function textureNeedsPowerOfTwo( texture ) { if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) return true; if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) return true; return false; } function makePowerOfTwo( image ) { if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement ) { var canvas = document.createElement( 'canvas' ); canvas.width = THREE.Math.nearestPowerOfTwo( image.width ); canvas.height = THREE.Math.nearestPowerOfTwo( image.height ); var context = canvas.getContext( '2d' ); context.drawImage( image, 0, 0, canvas.width, canvas.height ); console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); return canvas; } return image; } function setCubeTexture ( texture, slot ) { var textureProperties = properties.get( texture ); if ( texture.image.length === 6 ) { if ( texture.version > 0 && textureProperties.__version !== texture.version ) { if ( ! textureProperties.__image__webglTextureCube ) { texture.addEventListener( 'dispose', onTextureDispose ); textureProperties.__image__webglTextureCube = _gl.createTexture(); _infoMemory.textures ++; } state.activeTexture( _gl.TEXTURE0 + slot ); state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); var isCompressed = texture instanceof THREE.CompressedTexture; var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture; var cubeImage = []; for ( var i = 0; i < 6; i ++ ) { if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) { cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); } else { cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; } } var image = cubeImage[ 0 ], isImagePowerOfTwo = isPowerOfTwo( image ), glFormat = paramThreeToGL( texture.format ), glType = paramThreeToGL( texture.type ); setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); for ( var i = 0; i < 6; i ++ ) { if ( ! isCompressed ) { if ( isDataTexture ) { state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); } else { state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); } } else { var mipmap, mipmaps = cubeImage[ i ].mipmaps; for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { mipmap = mipmaps[ j ]; if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) { if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } else { console.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" ); } } else { state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } } } } if ( texture.generateMipmaps && isImagePowerOfTwo ) { _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); } textureProperties.__version = texture.version; if ( texture.onUpdate ) texture.onUpdate( texture ); } else { state.activeTexture( _gl.TEXTURE0 + slot ); state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube ); } } } function setCubeTextureDynamic ( texture, slot ) { state.activeTexture( _gl.TEXTURE0 + slot ); state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture ); } // Render targets function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); } function setupRenderBuffer ( renderbuffer, renderTarget ) { _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); /* For some reason this is not working. Defaulting to RGBA4. } else if ( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); */ } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); } } this.setRenderTarget = function ( renderTarget ) { var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { var renderTargetProperties = properties.get( renderTarget ); var textureProperties = properties.get( renderTarget.texture ); if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); textureProperties.__webglTexture = _gl.createTexture(); _infoMemory.textures ++; // Setup texture, create render and frame buffers var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ), glFormat = paramThreeToGL( renderTarget.texture.format ), glType = paramThreeToGL( renderTarget.texture.type ); if ( isCube ) { renderTargetProperties.__webglFramebuffer = []; renderTargetProperties.__webglRenderbuffer = []; state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo ); for ( var i = 0; i < 6; i ++ ) { renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); renderTargetProperties.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); setupFrameBuffer( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); setupRenderBuffer( renderTargetProperties.__webglRenderbuffer[ i ], renderTarget ); } if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); } else { renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); if ( renderTarget.shareDepthFrom ) { renderTargetProperties.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; } else { renderTargetProperties.__webglRenderbuffer = _gl.createRenderbuffer(); } state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture ); setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo ); state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); setupFrameBuffer( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); if ( renderTarget.shareDepthFrom ) { if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTargetProperties.__webglRenderbuffer ); } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTargetProperties.__webglRenderbuffer ); } } else { setupRenderBuffer( renderTargetProperties.__webglRenderbuffer, renderTarget ); } if ( renderTarget.texture.generateMipmaps && isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); } // Release everything if ( isCube ) { state.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); } else { state.bindTexture( _gl.TEXTURE_2D, null ); } _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); } var framebuffer, width, height, vx, vy; if ( renderTarget ) { var renderTargetProperties = properties.get( renderTarget ); if ( isCube ) { framebuffer = renderTargetProperties.__webglFramebuffer[ renderTarget.activeCubeFace ]; } else { framebuffer = renderTargetProperties.__webglFramebuffer; } width = renderTarget.width; height = renderTarget.height; vx = 0; vy = 0; } else { framebuffer = null; width = _viewportWidth; height = _viewportHeight; vx = _viewportX; vy = _viewportY; } if ( framebuffer !== _currentFramebuffer ) { _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); _gl.viewport( vx, vy, width, height ); _currentFramebuffer = framebuffer; } if ( isCube ) { var textureProperties = properties.get( renderTarget.texture ); _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, 0 ); } _currentWidth = width; _currentHeight = height; }; this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { if ( renderTarget instanceof THREE.WebGLRenderTarget === false ) { console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); return; } var framebuffer = properties.get( renderTarget ).__webglFramebuffer; if ( framebuffer ) { var restore = false; if ( framebuffer !== _currentFramebuffer ) { _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); restore = true; } try { var texture = renderTarget.texture; if ( texture.format !== THREE.RGBAFormat && paramThreeToGL( texture.format ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); return; } if ( texture.type !== THREE.UnsignedByteType && paramThreeToGL( texture.type ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && ! ( texture.type === THREE.FloatType && extensions.get( 'WEBGL_color_buffer_float' ) ) && ! ( texture.type === THREE.HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) { console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); return; } if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { _gl.readPixels( x, y, width, height, paramThreeToGL( texture.format ), paramThreeToGL( texture.type ), buffer ); } else { console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); } } finally { if ( restore ) { _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); } } } }; function updateRenderTargetMipmap( renderTarget ) { var target = renderTarget instanceof THREE.WebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; var texture = properties.get( renderTarget.texture ).__webglTexture; state.bindTexture( target, texture ); _gl.generateMipmap( target ); state.bindTexture( target, null ); } // Fallback filters for non-power-of-2 textures function filterFallback ( f ) { if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { return _gl.NEAREST; } return _gl.LINEAR; } // Map three.js constants to WebGL constants function paramThreeToGL ( p ) { var extension; if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; if ( p === THREE.NearestFilter ) return _gl.NEAREST; if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; if ( p === THREE.LinearFilter ) return _gl.LINEAR; if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; if ( p === THREE.ByteType ) return _gl.BYTE; if ( p === THREE.ShortType ) return _gl.SHORT; if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; if ( p === THREE.IntType ) return _gl.INT; if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; if ( p === THREE.FloatType ) return _gl.FLOAT; extension = extensions.get( 'OES_texture_half_float' ); if ( extension !== null ) { if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES; } if ( p === THREE.AlphaFormat ) return _gl.ALPHA; if ( p === THREE.RGBFormat ) return _gl.RGB; if ( p === THREE.RGBAFormat ) return _gl.RGBA; if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; if ( p === THREE.ZeroFactor ) return _gl.ZERO; if ( p === THREE.OneFactor ) return _gl.ONE; if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); if ( extension !== null ) { if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; } extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); if ( extension !== null ) { if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; } extension = extensions.get( 'EXT_blend_minmax' ); if ( extension !== null ) { if ( p === THREE.MinEquation ) return extension.MIN_EXT; if ( p === THREE.MaxEquation ) return extension.MAX_EXT; } return 0; } // DEPRECATED this.supportsFloatTextures = function () { console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); return extensions.get( 'OES_texture_float' ); }; this.supportsHalfFloatTextures = function () { console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); return extensions.get( 'OES_texture_half_float' ); }; this.supportsStandardDerivatives = function () { console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); return extensions.get( 'OES_standard_derivatives' ); }; this.supportsCompressedTextureS3TC = function () { console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); return extensions.get( 'WEBGL_compressed_texture_s3tc' ); }; this.supportsCompressedTexturePVRTC = function () { console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); return extensions.get( 'WEBGL_compressed_texture_pvrtc' ); }; this.supportsBlendMinMax = function () { console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); return extensions.get( 'EXT_blend_minmax' ); }; this.supportsVertexTextures = function () { return capabilities.vertexTextures; }; this.supportsInstancedArrays = function () { console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); return extensions.get( 'ANGLE_instanced_arrays' ); }; // this.initMaterial = function () { console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); }; this.addPrePlugin = function () { console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); }; this.addPostPlugin = function () { console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); }; this.updateShadowMap = function () { console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); }; Object.defineProperties( this, { shadowMapEnabled: { get: function () { return shadowMap.enabled; }, set: function ( value ) { console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); shadowMap.enabled = value; } }, shadowMapType: { get: function () { return shadowMap.type; }, set: function ( value ) { console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); shadowMap.type = value; } }, shadowMapCullFace: { get: function () { return shadowMap.cullFace; }, set: function ( value ) { console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.' ); shadowMap.cullFace = value; } }, shadowMapDebug: { get: function () { return shadowMap.debug; }, set: function ( value ) { console.warn( 'THREE.WebGLRenderer: .shadowMapDebug is now .shadowMap.debug.' ); shadowMap.debug = value; } } } ); }; three.js-r73/src/renderers/shaders/0000755000175500017550000000000012610076566017165 5ustar debacledebaclethree.js-r73/src/renderers/shaders/UniformsUtils.js0000644000175500017550000000213312610076566022345 0ustar debacledebacle/** * Uniform Utilities */ THREE.UniformsUtils = { merge: function ( uniforms ) { var merged = {}; for ( var u = 0; u < uniforms.length; u ++ ) { var tmp = this.clone( uniforms[ u ] ); for ( var p in tmp ) { merged[ p ] = tmp[ p ]; } } return merged; }, clone: function ( uniforms_src ) { var uniforms_dst = {}; for ( var u in uniforms_src ) { uniforms_dst[ u ] = {}; for ( var p in uniforms_src[ u ] ) { var parameter_src = uniforms_src[ u ][ p ]; if ( parameter_src instanceof THREE.Color || parameter_src instanceof THREE.Vector2 || parameter_src instanceof THREE.Vector3 || parameter_src instanceof THREE.Vector4 || parameter_src instanceof THREE.Matrix3 || parameter_src instanceof THREE.Matrix4 || parameter_src instanceof THREE.Texture ) { uniforms_dst[ u ][ p ] = parameter_src.clone(); } else if ( Array.isArray( parameter_src ) ) { uniforms_dst[ u ][ p ] = parameter_src.slice(); } else { uniforms_dst[ u ][ p ] = parameter_src; } } } return uniforms_dst; } }; three.js-r73/src/renderers/shaders/UniformsLib.js0000644000175500017550000000613712610076566021763 0ustar debacledebacle/** * Uniforms library for shared webgl shaders */ THREE.UniformsLib = { common: { "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, "opacity" : { type: "f", value: 1.0 }, "map" : { type: "t", value: null }, "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, "specularMap" : { type: "t", value: null }, "alphaMap" : { type: "t", value: null }, "envMap" : { type: "t", value: null }, "flipEnvMap" : { type: "f", value: - 1 }, "reflectivity" : { type: "f", value: 1.0 }, "refractionRatio" : { type: "f", value: 0.98 } }, aomap: { "aoMap" : { type: "t", value: null }, "aoMapIntensity" : { type: "f", value: 1 }, }, lightmap: { "lightMap" : { type: "t", value: null }, "lightMapIntensity" : { type: "f", value: 1 }, }, emissivemap: { "emissiveMap" : { type: "t", value: null }, }, bumpmap: { "bumpMap" : { type: "t", value: null }, "bumpScale" : { type: "f", value: 1 } }, normalmap: { "normalMap" : { type: "t", value: null }, "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } }, displacementmap: { "displacementMap" : { type: "t", value: null }, "displacementScale" : { type: "f", value: 1 }, "displacementBias" : { type: "f", value: 0 } }, fog : { "fogDensity" : { type: "f", value: 0.00025 }, "fogNear" : { type: "f", value: 1 }, "fogFar" : { type: "f", value: 2000 }, "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } }, lights: { "ambientLightColor" : { type: "fv", value: [] }, "directionalLightDirection" : { type: "fv", value: [] }, "directionalLightColor" : { type: "fv", value: [] }, "hemisphereLightDirection" : { type: "fv", value: [] }, "hemisphereLightSkyColor" : { type: "fv", value: [] }, "hemisphereLightGroundColor" : { type: "fv", value: [] }, "pointLightColor" : { type: "fv", value: [] }, "pointLightPosition" : { type: "fv", value: [] }, "pointLightDistance" : { type: "fv1", value: [] }, "pointLightDecay" : { type: "fv1", value: [] }, "spotLightColor" : { type: "fv", value: [] }, "spotLightPosition" : { type: "fv", value: [] }, "spotLightDirection" : { type: "fv", value: [] }, "spotLightDistance" : { type: "fv1", value: [] }, "spotLightAngleCos" : { type: "fv1", value: [] }, "spotLightExponent" : { type: "fv1", value: [] }, "spotLightDecay" : { type: "fv1", value: [] } }, points: { "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, "opacity" : { type: "f", value: 1.0 }, "size" : { type: "f", value: 1.0 }, "scale" : { type: "f", value: 1.0 }, "map" : { type: "t", value: null }, "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, "fogDensity" : { type: "f", value: 0.00025 }, "fogNear" : { type: "f", value: 1 }, "fogFar" : { type: "f", value: 2000 }, "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } }, shadowmap: { "shadowMap": { type: "tv", value: [] }, "shadowMapSize": { type: "v2v", value: [] }, "shadowBias" : { type: "fv1", value: [] }, "shadowDarkness": { type: "fv1", value: [] }, "shadowMatrix" : { type: "m4v", value: [] } } }; three.js-r73/src/renderers/shaders/ShaderChunk/0000755000175500017550000000000012610076566021364 5ustar debacledebaclethree.js-r73/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl0000644000175500017550000000015012610076566025733 0ustar debacledebacle#ifdef USE_LIGHTMAP totalAmbientLight += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity; #endif three.js-r73/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl0000644000175500017550000000011612610076566025713 0ustar debacledebacle#ifdef USE_ALPHAMAP diffuseColor.a *= texture2D( alphaMap, vUv ).g; #endif three.js-r73/src/renderers/shaders/ShaderChunk/uv2_vertex.glsl0000644000175500017550000000011112610076566024351 0ustar debacledebacle#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP ) vUv2 = uv2; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl0000644000175500017550000000435712610076566026630 0ustar debacledebaclevec3 viewDir = normalize( vViewPosition ); vec3 totalDiffuseLight = vec3( 0.0 ); vec3 totalSpecularLight = vec3( 0.0 ); #if MAX_POINT_LIGHTS > 0 for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) { vec3 lightColor = pointLightColor[ i ]; vec3 lightPosition = pointLightPosition[ i ]; vec3 lVector = lightPosition + vViewPosition.xyz; vec3 lightDir = normalize( lVector ); // attenuation float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] ); // diffuse float cosineTerm = saturate( dot( normal, lightDir ) ); totalDiffuseLight += lightColor * attenuation * cosineTerm; // specular vec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir ); totalSpecularLight += brdf * specularStrength * lightColor * attenuation * cosineTerm; } #endif #if MAX_SPOT_LIGHTS > 0 for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) { vec3 lightColor = spotLightColor[ i ]; vec3 lightPosition = spotLightPosition[ i ]; vec3 lVector = lightPosition + vViewPosition.xyz; vec3 lightDir = normalize( lVector ); float spotEffect = dot( spotLightDirection[ i ], lightDir ); if ( spotEffect > spotLightAngleCos[ i ] ) { spotEffect = saturate( pow( saturate( spotEffect ), spotLightExponent[ i ] ) ); // attenuation float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] ); attenuation *= spotEffect; // diffuse float cosineTerm = saturate( dot( normal, lightDir ) ); totalDiffuseLight += lightColor * attenuation * cosineTerm; // specular vec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir ); totalSpecularLight += brdf * specularStrength * lightColor * attenuation * cosineTerm; } } #endif #if MAX_DIR_LIGHTS > 0 for ( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) { vec3 lightColor = directionalLightColor[ i ]; vec3 lightDir = directionalLightDirection[ i ]; // diffuse float cosineTerm = saturate( dot( normal, lightDir ) ); totalDiffuseLight += lightColor * cosineTerm; // specular vec3 brdf = BRDF_BlinnPhong( specular, shininess, normal, lightDir, viewDir ); totalSpecularLight += brdf * specularStrength * lightColor * cosineTerm; } #endif three.js-r73/src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl0000644000175500017550000000050512610076566026202 0ustar debacledebacle#ifdef USE_MORPHNORMALS objectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ]; objectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ]; objectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ]; objectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ]; #endif three.js-r73/src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl0000644000175500017550000000027212610076566026455 0ustar debacledebacle#ifdef USE_EMISSIVEMAP vec4 emissiveColor = texture2D( emissiveMap, vUv ); emissiveColor.rgb = inputToLinear( emissiveColor.rgb ); totalEmissiveLight *= emissiveColor.rgb; #endif three.js-r73/src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl0000644000175500017550000000006012610076566026271 0ustar debacledebacle#ifdef USE_COLOR varying vec3 vColor; #endif three.js-r73/src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl0000644000175500017550000000036712610076566026155 0ustar debacledebacle#ifdef USE_LOGDEPTHBUF gl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC; #ifdef USE_LOGDEPTHBUF_EXT vFragDepth = 1.0 + gl_Position.w; #else gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w; #endif #endifthree.js-r73/src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl0000644000175500017550000000053612610076566026025 0ustar debacledebacle#ifdef USE_SKINNING mat4 skinMatrix = mat4( 0.0 ); skinMatrix += skinWeight.x * boneMatX; skinMatrix += skinWeight.y * boneMatY; skinMatrix += skinWeight.z * boneMatZ; skinMatrix += skinWeight.w * boneMatW; skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix; objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz; #endif three.js-r73/src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl0000644000175500017550000000026112610076566027355 0ustar debacledebacle#if MAX_SPOT_LIGHTS > 0 || defined( USE_ENVMAP ) varying vec3 vWorldPosition; #endif #if MAX_POINT_LIGHTS > 0 uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ]; #endif three.js-r73/src/renderers/shaders/ShaderChunk/fog_fragment.glsl0000644000175500017550000000064712610076566024714 0ustar debacledebacle#ifdef USE_FOG #ifdef USE_LOGDEPTHBUF_EXT float depth = gl_FragDepthEXT / gl_FragCoord.w; #else float depth = gl_FragCoord.z / gl_FragCoord.w; #endif #ifdef FOG_EXP2 float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * depth * depth * LOG2 ) ); #else float fogFactor = smoothstep( fogNear, fogFar, depth ); #endif outgoingLight = mix( outgoingLight, fogColor, fogFactor ); #endifthree.js-r73/src/renderers/shaders/ShaderChunk/aomap_fragment.glsl0000644000175500017550000000015512610076566025230 0ustar debacledebacle#ifdef USE_AOMAP totalAmbientLight *= ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0; #endif three.js-r73/src/renderers/shaders/ShaderChunk/map_fragment.glsl0000644000175500017550000000022412610076566024705 0ustar debacledebacle#ifdef USE_MAP vec4 texelColor = texture2D( map, vUv ); texelColor.xyz = inputToLinear( texelColor.xyz ); diffuseColor *= texelColor; #endif three.js-r73/src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl0000644000175500017550000000005712610076566026011 0ustar debacledebacle#ifdef USE_COLOR varying vec3 vColor; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl0000644000175500017550000000202112610076566026613 0ustar debacledebacle#ifdef USE_BUMPMAP uniform sampler2D bumpMap; uniform float bumpScale; // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) vec2 dHdxy_fwd() { vec2 dSTdx = dFdx( vUv ); vec2 dSTdy = dFdy( vUv ); float Hll = bumpScale * texture2D( bumpMap, vUv ).x; float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll; float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll; return vec2( dBx, dBy ); } vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) { vec3 vSigmaX = dFdx( surf_pos ); vec3 vSigmaY = dFdy( surf_pos ); vec3 vN = surf_norm; // normalized vec3 R1 = cross( vSigmaY, vN ); vec3 R2 = cross( vN, vSigmaX ); float fDet = dot( vSigmaX, R1 ); vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 ); return normalize( abs( fDet ) * surf_norm - vGrad ); } #endif three.js-r73/src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl0000644000175500017550000000033012610076566025437 0ustar debacledebacle#ifdef USE_SKINNING mat4 boneMatX = getBoneMatrix( skinIndex.x ); mat4 boneMatY = getBoneMatrix( skinIndex.y ); mat4 boneMatZ = getBoneMatrix( skinIndex.z ); mat4 boneMatW = getBoneMatrix( skinIndex.w ); #endifthree.js-r73/src/renderers/shaders/ShaderChunk/uv2_pars_vertex.glsl0000644000175500017550000000014512610076566025405 0ustar debacledebacle#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP ) attribute vec2 uv2; varying vec2 vUv2; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/uv_pars_fragment.glsl0000644000175500017550000000027712610076566025617 0ustar debacledebacle#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) varying vec2 vUv; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl0000644000175500017550000000013712610076566026332 0ustar debacledebacle#if MAX_SPOT_LIGHTS > 0 || defined( USE_ENVMAP ) vWorldPosition = worldPosition.xyz; #endif three.js-r73/src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl0000644000175500017550000000005712610076566025736 0ustar debacledebacle#ifdef USE_MAP uniform sampler2D map; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl0000644000175500017550000000226712610076566027653 0ustar debacledebacleuniform vec3 ambientLightColor; #if MAX_DIR_LIGHTS > 0 uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ]; uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ]; #endif #if MAX_HEMI_LIGHTS > 0 uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ]; uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ]; uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ]; #endif #if MAX_POINT_LIGHTS > 0 uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ]; uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ]; uniform float pointLightDistance[ MAX_POINT_LIGHTS ]; uniform float pointLightDecay[ MAX_POINT_LIGHTS ]; #endif #if MAX_SPOT_LIGHTS > 0 uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ]; uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ]; uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ]; uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ]; uniform float spotLightExponent[ MAX_SPOT_LIGHTS ]; uniform float spotLightDistance[ MAX_SPOT_LIGHTS ]; uniform float spotLightDecay[ MAX_SPOT_LIGHTS ]; #endif #if MAX_SPOT_LIGHTS > 0 || defined( USE_ENVMAP ) varying vec3 vWorldPosition; #endif varying vec3 vViewPosition; #ifndef FLAT_SHADED varying vec3 vNormal; #endif three.js-r73/src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl0000644000175500017550000000007212610076566026741 0ustar debacledebacle#ifdef USE_ALPHAMAP uniform sampler2D alphaMap; #endif three.js-r73/src/renderers/shaders/ShaderChunk/envmap_vertex.glsl0000644000175500017550000000067212610076566025137 0ustar debacledebacle#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG ) vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition ); vec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix ); #ifdef ENVMAP_MODE_REFLECTION vReflect = reflect( cameraToVertex, worldNormal ); #else vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/displacementmap_pars_vertex.glsl0000644000175500017550000000021312610076566030033 0ustar debacledebacle#ifdef USE_DISPLACEMENTMAP uniform sampler2D displacementMap; uniform float displacementScale; uniform float displacementBias; #endif three.js-r73/src/renderers/shaders/ShaderChunk/hemilight_fragment.glsl0000644000175500017550000000057612610076566026114 0ustar debacledebacle#if MAX_HEMI_LIGHTS > 0 for ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) { vec3 lightDir = hemisphereLightDirection[ i ]; float dotProduct = dot( normal, lightDir ); float hemiDiffuseWeight = 0.5 * dotProduct + 0.5; vec3 lightColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ); totalAmbientLight += lightColor; } #endif three.js-r73/src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl0000644000175500017550000000476212610076566026655 0ustar debacledebaclevLightFront = vec3( 0.0 ); #ifdef DOUBLE_SIDED vLightBack = vec3( 0.0 ); #endif vec3 normal = normalize( transformedNormal ); #if MAX_POINT_LIGHTS > 0 for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) { vec3 lightColor = pointLightColor[ i ]; vec3 lVector = pointLightPosition[ i ] - mvPosition.xyz; vec3 lightDir = normalize( lVector ); // attenuation float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] ); // diffuse float dotProduct = dot( normal, lightDir ); vLightFront += lightColor * attenuation * saturate( dotProduct ); #ifdef DOUBLE_SIDED vLightBack += lightColor * attenuation * saturate( - dotProduct ); #endif } #endif #if MAX_SPOT_LIGHTS > 0 for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) { vec3 lightColor = spotLightColor[ i ]; vec3 lightPosition = spotLightPosition[ i ]; vec3 lVector = lightPosition - mvPosition.xyz; vec3 lightDir = normalize( lVector ); float spotEffect = dot( spotLightDirection[ i ], lightDir ); if ( spotEffect > spotLightAngleCos[ i ] ) { spotEffect = saturate( pow( saturate( spotEffect ), spotLightExponent[ i ] ) ); // attenuation float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] ); attenuation *= spotEffect; // diffuse float dotProduct = dot( normal, lightDir ); vLightFront += lightColor * attenuation * saturate( dotProduct ); #ifdef DOUBLE_SIDED vLightBack += lightColor * attenuation * saturate( - dotProduct ); #endif } } #endif #if MAX_DIR_LIGHTS > 0 for ( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) { vec3 lightColor = directionalLightColor[ i ]; vec3 lightDir = directionalLightDirection[ i ]; // diffuse float dotProduct = dot( normal, lightDir ); vLightFront += lightColor * saturate( dotProduct ); #ifdef DOUBLE_SIDED vLightBack += lightColor * saturate( - dotProduct ); #endif } #endif #if MAX_HEMI_LIGHTS > 0 for ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) { vec3 lightDir = hemisphereLightDirection[ i ]; // diffuse float dotProduct = dot( normal, lightDir ); float hemiDiffuseWeight = 0.5 * dotProduct + 0.5; vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ); #ifdef DOUBLE_SIDED float hemiDiffuseWeightBack = - 0.5 * dotProduct + 0.5; vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack ); #endif } #endif three.js-r73/src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl0000644000175500017550000000024012610076566025726 0ustar debacledebacle#ifdef USE_FOG uniform vec3 fogColor; #ifdef FOG_EXP2 uniform float fogDensity; #else uniform float fogNear; uniform float fogFar; #endif #endifthree.js-r73/src/renderers/shaders/ShaderChunk/color_fragment.glsl0000644000175500017550000000006612610076566025252 0ustar debacledebacle#ifdef USE_COLOR diffuseColor.rgb *= vColor; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl0000644000175500017550000000037712610076566025524 0ustar debacledebacle#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP ) #ifdef USE_SKINNING vec4 worldPosition = modelMatrix * skinned; #else vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 ); #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl0000644000175500017550000000007712610076566027477 0ustar debacledebacle#ifdef USE_SPECULARMAP uniform sampler2D specularMap; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/emissivemap_pars_fragment.glsl0000644000175500017550000000010012610076566027470 0ustar debacledebacle#ifdef USE_EMISSIVEMAP uniform sampler2D emissiveMap; #endif three.js-r73/src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl0000644000175500017550000000176512610076566026522 0ustar debacledebacle#ifdef USE_SKINNING uniform mat4 bindMatrix; uniform mat4 bindMatrixInverse; #ifdef BONE_TEXTURE uniform sampler2D boneTexture; uniform int boneTextureWidth; uniform int boneTextureHeight; mat4 getBoneMatrix( const in float i ) { float j = i * 4.0; float x = mod( j, float( boneTextureWidth ) ); float y = floor( j / float( boneTextureWidth ) ); float dx = 1.0 / float( boneTextureWidth ); float dy = 1.0 / float( boneTextureHeight ); y = dy * ( y + 0.5 ); vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) ); vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) ); vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) ); vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) ); mat4 bone = mat4( v1, v2, v3, v4 ); return bone; } #else uniform mat4 boneGlobalMatrices[ MAX_BONES ]; mat4 getBoneMatrix( const in float i ) { mat4 bone = boneGlobalMatrices[ int(i) ]; return bone; } #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl0000644000175500017550000000127412610076566027151 0ustar debacledebacle#ifdef USE_NORMALMAP uniform sampler2D normalMap; uniform vec2 normalScale; // Per-Pixel Tangent Space Normal Mapping // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) { vec3 q0 = dFdx( eye_pos.xyz ); vec3 q1 = dFdy( eye_pos.xyz ); vec2 st0 = dFdx( vUv.st ); vec2 st1 = dFdy( vUv.st ); vec3 S = normalize( q0 * st1.t - q1 * st0.t ); vec3 T = normalize( -q0 * st1.s + q1 * st0.s ); vec3 N = normalize( surf_norm ); vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; mapN.xy = normalScale * mapN.xy; mat3 tsn = mat3( S, T, N ); return normalize( tsn * mapN ); } #endif three.js-r73/src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl0000644000175500017550000000026312610076566026447 0ustar debacledebaclefloat specularStrength; #ifdef USE_SPECULARMAP vec4 texelSpecular = texture2D( specularMap, vUv ); specularStrength = texelSpecular.r; #else specularStrength = 1.0; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl0000644000175500017550000000006312610076566027247 0ustar debacledebacle outgoingLight = linearToOutput( outgoingLight ); three.js-r73/src/renderers/shaders/ShaderChunk/project_vertex.glsl0000644000175500017550000000030012610076566025303 0ustar debacledebacle#ifdef USE_SKINNING vec4 mvPosition = modelViewMatrix * skinned; #else vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 ); #endif gl_Position = projectionMatrix * mvPosition; three.js-r73/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl0000644000175500017550000000020112610076566027453 0ustar debacledebacle#ifdef USE_LOGDEPTHBUF uniform float logDepthBufFC; #ifdef USE_LOGDEPTHBUF_EXT varying float vFragDepth; #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl0000644000175500017550000000010612610076566026114 0ustar debacledebacle#ifdef ALPHATEST if ( diffuseColor.a < ALPHATEST ) discard; #endif three.js-r73/src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl0000644000175500017550000000020012610076566027164 0ustar debacledebacle#ifdef USE_LOGDEPTHBUF #ifdef USE_LOGDEPTHBUF_EXT varying float vFragDepth; #endif uniform float logDepthBufFC; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl0000644000175500017550000000021712610076566026572 0ustar debacledebacle#ifdef USE_MAP diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy ); #endif three.js-r73/src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl0000644000175500017550000000021412610076566027007 0ustar debacledebacle#ifdef USE_DISPLACEMENTMAP transformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias ); #endif three.js-r73/src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl0000644000175500017550000000025412610076566026160 0ustar debacledebacle#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG ) varying vec3 vReflect; uniform float refractionRatio; #endif three.js-r73/src/renderers/shaders/ShaderChunk/color_vertex.glsl0000644000175500017550000000006212610076566024760 0ustar debacledebacle#ifdef USE_COLOR vColor.xyz = color.xyz; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl0000644000175500017550000000011412610076566027613 0ustar debacledebacle#ifdef USE_MAP uniform vec4 offsetRepeat; uniform sampler2D map; #endif three.js-r73/src/renderers/shaders/ShaderChunk/common.glsl0000644000175500017550000000545412610076566023547 0ustar debacledebacle#define PI 3.14159 #define PI2 6.28318 #define RECIPROCAL_PI2 0.15915494 #define LOG2 1.442695 #define EPSILON 1e-6 #define saturate(a) clamp( a, 0.0, 1.0 ) #define whiteCompliment(a) ( 1.0 - saturate( a ) ) vec3 transformDirection( in vec3 normal, in mat4 matrix ) { return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz ); } // http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations vec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) { return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz ); } vec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) { float distance = dot( planeNormal, point - pointOnPlane ); return - distance * planeNormal + point; } float sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) { return sign( dot( point - pointOnPlane, planeNormal ) ); } vec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) { return lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine; } float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) { if ( decayExponent > 0.0 ) { return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent ); } return 1.0; } vec3 F_Schlick( in vec3 specularColor, in float dotLH ) { // Original approximation by Christophe Schlick '94 //;float fresnel = pow( 1.0 - dotLH, 5.0 ); // Optimized variant (presented by Epic at SIGGRAPH '13) float fresnel = exp2( ( -5.55437 * dotLH - 6.98316 ) * dotLH ); return ( 1.0 - specularColor ) * fresnel + specularColor; } float G_BlinnPhong_Implicit( /* in float dotNL, in float dotNV */ ) { // geometry term is (nâ‹…l)(nâ‹…v) / 4(nâ‹…l)(nâ‹…v) return 0.25; } float D_BlinnPhong( in float shininess, in float dotNH ) { // factor of 1/PI in distribution term omitted return ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess ); } vec3 BRDF_BlinnPhong( in vec3 specularColor, in float shininess, in vec3 normal, in vec3 lightDir, in vec3 viewDir ) { vec3 halfDir = normalize( lightDir + viewDir ); //float dotNL = saturate( dot( normal, lightDir ) ); //float dotNV = saturate( dot( normal, viewDir ) ); float dotNH = saturate( dot( normal, halfDir ) ); float dotLH = saturate( dot( lightDir, halfDir ) ); vec3 F = F_Schlick( specularColor, dotLH ); float G = G_BlinnPhong_Implicit( /* dotNL, dotNV */ ); float D = D_BlinnPhong( shininess, dotNH ); return F * G * D; } vec3 inputToLinear( in vec3 a ) { #ifdef GAMMA_INPUT return pow( a, vec3( float( GAMMA_FACTOR ) ) ); #else return a; #endif } vec3 linearToOutput( in vec3 a ) { #ifdef GAMMA_OUTPUT return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) ); #else return a; #endif } three.js-r73/src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl0000644000175500017550000000024312610076566027224 0ustar debacledebacle#ifdef USE_MORPHTARGETS #ifndef USE_MORPHNORMALS uniform float morphTargetInfluences[ 8 ]; #else uniform float morphTargetInfluences[ 4 ]; #endif #endifthree.js-r73/src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl0000644000175500017550000000013312610076566026761 0ustar debacledebacle#ifdef USE_LIGHTMAP uniform sampler2D lightMap; uniform float lightMapIntensity; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl0000644000175500017550000000525112610076566027145 0ustar debacledebacle#ifdef USE_SHADOWMAP uniform sampler2D shadowMap[ MAX_SHADOWS ]; uniform vec2 shadowMapSize[ MAX_SHADOWS ]; uniform float shadowDarkness[ MAX_SHADOWS ]; uniform float shadowBias[ MAX_SHADOWS ]; varying vec4 vShadowCoord[ MAX_SHADOWS ]; float unpackDepth( const in vec4 rgba_depth ) { const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 ); float depth = dot( rgba_depth, bit_shift ); return depth; } #if defined(POINT_LIGHT_SHADOWS) // adjustShadowValue1K() upacks the depth value stored in @textureData, adds @bias to it, and then // comapres the result with @testDepth. If @testDepth is larger than or equal to that result, then // @shadowValue is incremented by 1.0. void adjustShadowValue1K( const float testDepth, const vec4 textureData, const float bias, inout float shadowValue ) { const vec4 bitSh = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 ); if ( testDepth >= dot( textureData, bitSh ) * 1000.0 + bias ) shadowValue += 1.0; } // cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D // vector suitable for 2D texture mapping. This code uses the following layout for the // 2D texture: // // xzXZ // y Y // // Y - Positive y direction // y - Negative y direction // X - Positive x direction // x - Negative x direction // Z - Positive z direction // z - Negative z direction // // Source and test bed: // https://gist.github.com/tschw/da10c43c467ce8afd0c4 vec2 cubeToUV( vec3 v, float texelSizeY ) { // Number of texels to avoid at the edge of each square vec3 absV = abs( v ); // Intersect unit cube float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) ); absV *= scaleToCube; // Apply scale to avoid seams // two texels less per square (one texel will do for NEAREST) v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY ); // Unwrap // space: -1 ... 1 range for each square // // #X## dim := ( 4 , 2 ) // # # center := ( 1 , 1 ) vec2 planar = v.xy; float almostATexel = 1.5 * texelSizeY; float almostOne = 1.0 - almostATexel; if ( absV.z >= almostOne ) { if ( v.z > 0.0 ) planar.x = 4.0 - v.x; } else if ( absV.x >= almostOne ) { float signX = sign( v.x ); planar.x = v.z * signX + 2.0 * signX; } else if ( absV.y >= almostOne ) { float signY = sign( v.y ); planar.x = v.x + 2.0 * signY + 2.0; planar.y = v.z * signY - 2.0; } // Transform to UV space // scale := 0.5 / dim // translate := ( center + 0.5 ) / dim return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 ); } #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl0000644000175500017550000002466412610076566026131 0ustar debacledebacle#ifdef USE_SHADOWMAP for ( int i = 0; i < MAX_SHADOWS; i ++ ) { float texelSizeY = 1.0 / shadowMapSize[ i ].y; float shadow = 0.0; #if defined( POINT_LIGHT_SHADOWS ) // to save on uniform space, we use the sign of @shadowDarkness[ i ] to determine // whether or not this light is a point light ( shadowDarkness[ i ] < 0 == point light) bool isPointLight = shadowDarkness[ i ] < 0.0; if ( isPointLight ) { // get the real shadow darkness float realShadowDarkness = abs( shadowDarkness[ i ] ); // for point lights, the uniform @vShadowCoord is re-purposed to hold // the distance from the light to the world-space position of the fragment. vec3 lightToPosition = vShadowCoord[ i ].xyz; #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) // bd3D = base direction 3D vec3 bd3D = normalize( lightToPosition ); // dp = distance from light to fragment position float dp = length( lightToPosition ); // base measurement adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow ); // Dr = disk radius #if defined( SHADOWMAP_TYPE_PCF ) const float Dr = 1.25; #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) const float Dr = 2.25; #endif // os = offset scale float os = Dr * 2.0 * texelSizeY; const vec3 Gsd = vec3( - 1, 0, 1 ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzx * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxx * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxx * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzx * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzy * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxy * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxy * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzy * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zyz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xyz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zyx * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xyx * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yzz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yxz * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yxx * os, texelSizeY ) ), shadowBias[ i ], shadow ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yzx * os, texelSizeY ) ), shadowBias[ i ], shadow ); shadow *= realShadowDarkness * ( 1.0 / 21.0 ); #else // no percentage-closer filtering: vec3 bd3D = normalize( lightToPosition ); float dp = length( lightToPosition ); adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow ); shadow *= realShadowDarkness; #endif } else { #endif // POINT_LIGHT_SHADOWS float texelSizeX = 1.0 / shadowMapSize[ i ].x; vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w; // if ( something && something ) breaks ATI OpenGL shader compiler // if ( all( something, something ) ) using this instead bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 ); bool inFrustum = all( inFrustumVec ); bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 ); bool frustumTest = all( frustumTestVec ); if ( frustumTest ) { #if defined( SHADOWMAP_TYPE_PCF ) // Percentage-close filtering // (9 pixel kernel) // http://fabiensanglard.net/shadowmappingPCF/ /* // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL // must enroll loop manually for ( float y = -1.25; y <= 1.25; y += 1.25 ) for ( float x = -1.25; x <= 1.25; x += 1.25 ) { vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ); // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) ); float fDepth = unpackDepth( rgbaDepth ); if ( fDepth < shadowCoord.z ) shadow += 1.0; } shadow /= 9.0; */ shadowCoord.z += shadowBias[ i ]; const float ShadowDelta = 1.0 / 9.0; float xPixelOffset = texelSizeX; float yPixelOffset = texelSizeY; float dx0 = - 1.25 * xPixelOffset; float dy0 = - 1.25 * yPixelOffset; float dx1 = 1.25 * xPixelOffset; float dy1 = 1.25 * yPixelOffset; float fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; shadow *= shadowDarkness[ i ]; #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) // Percentage-close filtering // (9 pixel kernel) // http://fabiensanglard.net/shadowmappingPCF/ shadowCoord.z += shadowBias[ i ]; float xPixelOffset = texelSizeX; float yPixelOffset = texelSizeY; float dx0 = - 1.0 * xPixelOffset; float dy0 = - 1.0 * yPixelOffset; float dx1 = 1.0 * xPixelOffset; float dy1 = 1.0 * yPixelOffset; mat3 shadowKernel; mat3 depthKernel; depthKernel[ 0 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); depthKernel[ 0 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); depthKernel[ 0 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); depthKernel[ 1 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); depthKernel[ 1 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) ); depthKernel[ 1 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); depthKernel[ 2 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); depthKernel[ 2 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); depthKernel[ 2 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); vec3 shadowZ = vec3( shadowCoord.z ); shadowKernel[ 0 ] = vec3( lessThan( depthKernel[ 0 ], shadowZ ) ); shadowKernel[ 0 ] *= vec3( 0.25 ); shadowKernel[ 1 ] = vec3( lessThan( depthKernel[ 1 ], shadowZ ) ); shadowKernel[ 1 ] *= vec3( 0.25 ); shadowKernel[ 2 ] = vec3( lessThan( depthKernel[ 2 ], shadowZ ) ); shadowKernel[ 2 ] *= vec3( 0.25 ); vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[ i ].xy ); shadowKernel[ 0 ] = mix( shadowKernel[ 1 ], shadowKernel[ 0 ], fractionalCoord.x ); shadowKernel[ 1 ] = mix( shadowKernel[ 2 ], shadowKernel[ 1 ], fractionalCoord.x ); vec4 shadowValues; shadowValues.x = mix( shadowKernel[ 0 ][ 1 ], shadowKernel[ 0 ][ 0 ], fractionalCoord.y ); shadowValues.y = mix( shadowKernel[ 0 ][ 2 ], shadowKernel[ 0 ][ 1 ], fractionalCoord.y ); shadowValues.z = mix( shadowKernel[ 1 ][ 1 ], shadowKernel[ 1 ][ 0 ], fractionalCoord.y ); shadowValues.w = mix( shadowKernel[ 1 ][ 2 ], shadowKernel[ 1 ][ 1 ], fractionalCoord.y ); shadow = dot( shadowValues, vec4( 1.0 ) ) * shadowDarkness[ i ]; #else // no percentage-closer filtering: shadowCoord.z += shadowBias[ i ]; vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy ); float fDepth = unpackDepth( rgbaDepth ); if ( fDepth < shadowCoord.z ) shadow = shadowDarkness[ i ]; #endif } #ifdef SHADOWMAP_DEBUG if ( inFrustum ) { if ( i == 0 ) { outgoingLight *= vec3( 1.0, 0.5, 0.0 ); } else if ( i == 1 ) { outgoingLight *= vec3( 0.0, 1.0, 0.8 ); } else { outgoingLight *= vec3( 0.0, 0.5, 1.0 ); } } #endif #if defined( POINT_LIGHT_SHADOWS ) } #endif shadowMask = shadowMask * vec3( 1.0 - shadow ); } #endif three.js-r73/src/renderers/shaders/ShaderChunk/uv_vertex.glsl0000644000175500017550000000033312610076566024275 0ustar debacledebacle#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) vUv = uv * offsetRepeat.zw + offsetRepeat.xy; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl0000644000175500017550000000021012610076566025620 0ustar debacledebacle#ifdef USE_SHADOWMAP for ( int i = 0; i < MAX_SHADOWS; i ++ ) { vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition; } #endifthree.js-r73/src/renderers/shaders/ShaderChunk/begin_vertex.glsl0000644000175500017550000000004612610076566024730 0ustar debacledebacle vec3 transformed = vec3( position ); three.js-r73/src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl0000644000175500017550000000051712610076566026450 0ustar debacledebacle#ifdef USE_ENVMAP uniform float reflectivity; #ifdef ENVMAP_TYPE_CUBE uniform samplerCube envMap; #else uniform sampler2D envMap; #endif uniform float flipEnvMap; #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) uniform float refractionRatio; #else varying vec3 vReflect; #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl0000644000175500017550000000016112610076566026477 0ustar debacledebacle#ifdef FLIP_SIDED objectNormal = -objectNormal; #endif vec3 transformedNormal = normalMatrix * objectNormal; three.js-r73/src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl0000644000175500017550000000004512610076566026140 0ustar debacledebacle vec3 objectNormal = vec3( normal ); three.js-r73/src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl0000644000175500017550000000020012610076566026425 0ustar debacledebacle#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT) gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl0000644000175500017550000000033412610076566025323 0ustar debacledebacle#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) varying vec2 vUv; uniform vec4 offsetRepeat; #endif three.js-r73/src/renderers/shaders/ShaderChunk/normal_phong_fragment.glsl0000644000175500017550000000072612610076566026622 0ustar debacledebacle#ifndef FLAT_SHADED vec3 normal = normalize( vNormal ); #ifdef DOUBLE_SIDED normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) ); #endif #else vec3 fdx = dFdx( vViewPosition ); vec3 fdy = dFdy( vViewPosition ); vec3 normal = normalize( cross( fdx, fdy ) ); #endif #ifdef USE_NORMALMAP normal = perturbNormal2Arb( -vViewPosition, normal ); #elif defined( USE_BUMPMAP ) normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() ); #endif three.js-r73/src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl0000644000175500017550000000024112610076566026651 0ustar debacledebacle#ifdef USE_SHADOWMAP uniform float shadowDarkness[ MAX_SHADOWS ]; uniform mat4 shadowMatrix[ MAX_SHADOWS ]; varying vec4 vShadowCoord[ MAX_SHADOWS ]; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl0000644000175500017550000000330012610076566025414 0ustar debacledebacle#ifdef USE_ENVMAP #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition ); // Transforming Normal Vectors with the Inverse Transformation vec3 worldNormal = inverseTransformDirection( normal, viewMatrix ); #ifdef ENVMAP_MODE_REFLECTION vec3 reflectVec = reflect( cameraToVertex, worldNormal ); #else vec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio ); #endif #else vec3 reflectVec = vReflect; #endif #ifdef DOUBLE_SIDED float flipNormal = ( float( gl_FrontFacing ) * 2.0 - 1.0 ); #else float flipNormal = 1.0; #endif #ifdef ENVMAP_TYPE_CUBE vec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) ); #elif defined( ENVMAP_TYPE_EQUIREC ) vec2 sampleUV; sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 ); sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5; vec4 envColor = texture2D( envMap, sampleUV ); #elif defined( ENVMAP_TYPE_SPHERE ) vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0)); vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 ); #endif envColor.xyz = inputToLinear( envColor.xyz ); #ifdef ENVMAP_BLENDING_MULTIPLY outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity ); #elif defined( ENVMAP_BLENDING_MIX ) outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity ); #elif defined( ENVMAP_BLENDING_ADD ) outgoingLight += envColor.xyz * specularStrength * reflectivity; #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/uv2_pars_fragment.glsl0000644000175500017550000000012012610076566025664 0ustar debacledebacle#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP ) varying vec2 vUv2; #endifthree.js-r73/src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl0000644000175500017550000000122612610076566026201 0ustar debacledebacle#ifdef USE_MORPHTARGETS transformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ]; transformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ]; transformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ]; transformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ]; #ifndef USE_MORPHNORMALS transformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ]; transformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ]; transformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ]; transformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ]; #endif #endif three.js-r73/src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl0000644000175500017550000000175212610076566027676 0ustar debacledebacle#if MAX_DIR_LIGHTS > 0 uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ]; uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ]; #endif #if MAX_HEMI_LIGHTS > 0 uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ]; uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ]; uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ]; #endif #if MAX_POINT_LIGHTS > 0 uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ]; uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ]; uniform float pointLightDistance[ MAX_POINT_LIGHTS ]; uniform float pointLightDecay[ MAX_POINT_LIGHTS ]; #endif #if MAX_SPOT_LIGHTS > 0 uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ]; uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ]; uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ]; uniform float spotLightDistance[ MAX_SPOT_LIGHTS ]; uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ]; uniform float spotLightExponent[ MAX_SPOT_LIGHTS ]; uniform float spotLightDecay[ MAX_SPOT_LIGHTS ]; #endif three.js-r73/src/renderers/shaders/ShaderChunk/skinning_vertex.glsl0000644000175500017550000000054612610076566025471 0ustar debacledebacle#ifdef USE_SKINNING vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); vec4 skinned = vec4( 0.0 ); skinned += boneMatX * skinVertex * skinWeight.x; skinned += boneMatY * skinVertex * skinWeight.y; skinned += boneMatZ * skinVertex * skinWeight.z; skinned += boneMatW * skinVertex * skinWeight.w; skinned = bindMatrixInverse * skinned; #endif three.js-r73/src/renderers/shaders/ShaderChunk/aomap_pars_fragment.glsl0000644000175500017550000000012212610076566026247 0ustar debacledebacle#ifdef USE_AOMAP uniform sampler2D aoMap; uniform float aoMapIntensity; #endifthree.js-r73/src/renderers/shaders/ShaderChunk.js0000644000175500017550000000003012610076566021713 0ustar debacledebacleTHREE.ShaderChunk = {}; three.js-r73/src/renderers/shaders/ShaderLib.js0000644000175500017550000005505212610076566021367 0ustar debacledebacle/** * Webgl Shader Library for three.js * * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ */ THREE.ShaderLib = { 'basic': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "aomap" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "shadowmap" ] ] ), vertexShader: [ THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "uv_pars_vertex" ], THREE.ShaderChunk[ "uv2_pars_vertex" ], THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "uv_vertex" ], THREE.ShaderChunk[ "uv2_vertex" ], THREE.ShaderChunk[ "color_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ], " #ifdef USE_ENVMAP", THREE.ShaderChunk[ "beginnormal_vertex" ], THREE.ShaderChunk[ "morphnormal_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], " #endif", THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "logdepthbuf_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform vec3 diffuse;", "uniform float opacity;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "uv_pars_fragment" ], THREE.ShaderChunk[ "uv2_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "alphamap_pars_fragment" ], THREE.ShaderChunk[ "aomap_pars_fragment" ], THREE.ShaderChunk[ "envmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "specularmap_pars_fragment" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", " vec3 outgoingLight = vec3( 0.0 );", " vec4 diffuseColor = vec4( diffuse, opacity );", " vec3 totalAmbientLight = vec3( 1.0 );", // hardwired " vec3 shadowMask = vec3( 1.0 );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], THREE.ShaderChunk[ "aomap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], " outgoingLight = diffuseColor.rgb * totalAmbientLight * shadowMask;", THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", "}" ].join( "\n" ) }, 'lambert': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "lights" ], THREE.UniformsLib[ "shadowmap" ], { "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) } } ] ), vertexShader: [ "#define LAMBERT", "varying vec3 vLightFront;", "#ifdef DOUBLE_SIDED", " varying vec3 vLightBack;", "#endif", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "uv_pars_vertex" ], THREE.ShaderChunk[ "uv2_pars_vertex" ], THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "uv_vertex" ], THREE.ShaderChunk[ "uv2_vertex" ], THREE.ShaderChunk[ "color_vertex" ], THREE.ShaderChunk[ "beginnormal_vertex" ], THREE.ShaderChunk[ "morphnormal_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "logdepthbuf_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "lights_lambert_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform vec3 diffuse;", "uniform vec3 emissive;", "uniform float opacity;", "uniform vec3 ambientLightColor;", "varying vec3 vLightFront;", "#ifdef DOUBLE_SIDED", " varying vec3 vLightBack;", "#endif", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "uv_pars_fragment" ], THREE.ShaderChunk[ "uv2_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "alphamap_pars_fragment" ], THREE.ShaderChunk[ "envmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "specularmap_pars_fragment" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does " vec4 diffuseColor = vec4( diffuse, opacity );", " vec3 totalAmbientLight = ambientLightColor;", " vec3 shadowMask = vec3( 1.0 );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], " #ifdef DOUBLE_SIDED", " if ( gl_FrontFacing )", " outgoingLight += diffuseColor.rgb * ( vLightFront * shadowMask + totalAmbientLight ) + emissive;", " else", " outgoingLight += diffuseColor.rgb * ( vLightBack * shadowMask + totalAmbientLight ) + emissive;", " #else", " outgoingLight += diffuseColor.rgb * ( vLightFront * shadowMask + totalAmbientLight ) + emissive;", " #endif", THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", "}" ].join( "\n" ) }, 'phong': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "aomap" ], THREE.UniformsLib[ "lightmap" ], THREE.UniformsLib[ "emissivemap" ], THREE.UniformsLib[ "bumpmap" ], THREE.UniformsLib[ "normalmap" ], THREE.UniformsLib[ "displacementmap" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "lights" ], THREE.UniformsLib[ "shadowmap" ], { "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, "shininess": { type: "f", value: 30 } } ] ), vertexShader: [ "#define PHONG", "varying vec3 vViewPosition;", "#ifndef FLAT_SHADED", " varying vec3 vNormal;", "#endif", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "uv_pars_vertex" ], THREE.ShaderChunk[ "uv2_pars_vertex" ], THREE.ShaderChunk[ "displacementmap_pars_vertex" ], THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "lights_phong_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "uv_vertex" ], THREE.ShaderChunk[ "uv2_vertex" ], THREE.ShaderChunk[ "color_vertex" ], THREE.ShaderChunk[ "beginnormal_vertex" ], THREE.ShaderChunk[ "morphnormal_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED " vNormal = normalize( transformedNormal );", "#endif", THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "displacementmap_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "logdepthbuf_vertex" ], " vViewPosition = - mvPosition.xyz;", THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "lights_phong_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "#define PHONG", "uniform vec3 diffuse;", "uniform vec3 emissive;", "uniform vec3 specular;", "uniform float shininess;", "uniform float opacity;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "uv_pars_fragment" ], THREE.ShaderChunk[ "uv2_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "alphamap_pars_fragment" ], THREE.ShaderChunk[ "aomap_pars_fragment" ], THREE.ShaderChunk[ "lightmap_pars_fragment" ], THREE.ShaderChunk[ "emissivemap_pars_fragment" ], THREE.ShaderChunk[ "envmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "lights_phong_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "bumpmap_pars_fragment" ], THREE.ShaderChunk[ "normalmap_pars_fragment" ], THREE.ShaderChunk[ "specularmap_pars_fragment" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", " vec3 outgoingLight = vec3( 0.0 );", " vec4 diffuseColor = vec4( diffuse, opacity );", " vec3 totalAmbientLight = ambientLightColor;", " vec3 totalEmissiveLight = emissive;", " vec3 shadowMask = vec3( 1.0 );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], THREE.ShaderChunk[ "normal_phong_fragment" ], THREE.ShaderChunk[ "lightmap_fragment" ], THREE.ShaderChunk[ "hemilight_fragment" ], THREE.ShaderChunk[ "aomap_fragment" ], THREE.ShaderChunk[ "emissivemap_fragment" ], THREE.ShaderChunk[ "lights_phong_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], "totalDiffuseLight *= shadowMask;", "totalSpecularLight *= shadowMask;", "#ifdef METAL", " outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalAmbientLight ) * specular + totalSpecularLight + totalEmissiveLight;", "#else", " outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalAmbientLight ) + totalSpecularLight + totalEmissiveLight;", "#endif", THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", "}" ].join( "\n" ) }, 'points': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "points" ], THREE.UniformsLib[ "shadowmap" ] ] ), vertexShader: [ "uniform float size;", "uniform float scale;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "color_vertex" ], " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", " #ifdef USE_SIZEATTENUATION", " gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", " #else", " gl_PointSize = size;", " #endif", " gl_Position = projectionMatrix * mvPosition;", THREE.ShaderChunk[ "logdepthbuf_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform vec3 psColor;", "uniform float opacity;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_particle_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", " vec3 outgoingLight = vec3( 0.0 );", " vec4 diffuseColor = vec4( psColor, opacity );", " vec3 shadowMask = vec3( 1.0 );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_particle_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], " outgoingLight = diffuseColor.rgb * shadowMask;", THREE.ShaderChunk[ "fog_fragment" ], " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", "}" ].join( "\n" ) }, 'dashed': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "fog" ], { "scale" : { type: "f", value: 1 }, "dashSize" : { type: "f", value: 1 }, "totalSize": { type: "f", value: 2 } } ] ), vertexShader: [ "uniform float scale;", "attribute float lineDistance;", "varying float vLineDistance;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "color_vertex" ], " vLineDistance = scale * lineDistance;", " vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", " gl_Position = projectionMatrix * mvPosition;", THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform vec3 diffuse;", "uniform float opacity;", "uniform float dashSize;", "uniform float totalSize;", "varying float vLineDistance;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", " if ( mod( vLineDistance, totalSize ) > dashSize ) {", " discard;", " }", " vec3 outgoingLight = vec3( 0.0 );", " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "color_fragment" ], " outgoingLight = diffuseColor.rgb;", // simple shader THREE.ShaderChunk[ "fog_fragment" ], " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", "}" ].join( "\n" ) }, 'depth': { uniforms: { "mNear": { type: "f", value: 1.0 }, "mFar" : { type: "f", value: 2000.0 }, "opacity" : { type: "f", value: 1.0 } }, vertexShader: [ THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform float mNear;", "uniform float mFar;", "uniform float opacity;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", THREE.ShaderChunk[ "logdepthbuf_fragment" ], " #ifdef USE_LOGDEPTHBUF_EXT", " float depth = gl_FragDepthEXT / gl_FragCoord.w;", " #else", " float depth = gl_FragCoord.z / gl_FragCoord.w;", " #endif", " float color = 1.0 - smoothstep( mNear, mFar, depth );", " gl_FragColor = vec4( vec3( color ), opacity );", "}" ].join( "\n" ) }, 'normal': { uniforms: { "opacity" : { type: "f", value: 1.0 } }, vertexShader: [ "varying vec3 vNormal;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", " vNormal = normalize( normalMatrix * normal );", THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform float opacity;", "varying vec3 vNormal;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", " gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], "}" ].join( "\n" ) }, /* ------------------------------------------------------------------------- // Cube map shader ------------------------------------------------------------------------- */ 'cube': { uniforms: { "tCube": { type: "t", value: null }, "tFlip": { type: "f", value: - 1 } }, vertexShader: [ "varying vec3 vWorldPosition;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", " vWorldPosition = transformDirection( position, modelMatrix );", " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform samplerCube tCube;", "uniform float tFlip;", "varying vec3 vWorldPosition;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], "}" ].join( "\n" ) }, /* ------------------------------------------------------------------------- // Cube map shader ------------------------------------------------------------------------- */ 'equirect': { uniforms: { "tEquirect": { type: "t", value: null }, "tFlip": { type: "f", value: - 1 } }, vertexShader: [ "varying vec3 vWorldPosition;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", " vWorldPosition = transformDirection( position, modelMatrix );", " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" ].join( "\n" ), fragmentShader: [ "uniform sampler2D tEquirect;", "uniform float tFlip;", "varying vec3 vWorldPosition;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "void main() {", // " gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", "vec3 direction = normalize( vWorldPosition );", "vec2 sampleUV;", "sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );", "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", "gl_FragColor = texture2D( tEquirect, sampleUV );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], "}" ].join( "\n" ) }, /* Depth encoding into RGBA texture * * based on SpiderGL shadow map example * http://spidergl.org/example.php?id=6 * * originally from * http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD * * see also * http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ */ 'depthRGBA': { uniforms: {}, vertexShader: [ THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "logdepthbuf_vertex" ], "}" ].join( "\n" ), fragmentShader: [ THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ], "vec4 pack_depth( const in float depth ) {", " const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", " const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", " vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );", // " vec4 res = fract( depth * bit_shift );", " res -= res.xxyz * bit_mask;", " return res;", "}", "void main() {", THREE.ShaderChunk[ "logdepthbuf_fragment" ], " #ifdef USE_LOGDEPTHBUF_EXT", " gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );", " #else", " gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", " #endif", //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", //"gl_FragData[ 0 ] = pack_depth( z );", //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", "}" ].join( "\n" ) }, 'distanceRGBA': { uniforms: { "lightPos": { type: "v3", value: new THREE.Vector3( 0, 0, 0 ) } }, vertexShader: [ "varying vec4 vWorldPosition;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "begin_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "project_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], "vWorldPosition = worldPosition;", "}" ].join( "\n" ), fragmentShader: [ "uniform vec3 lightPos;", "varying vec4 vWorldPosition;", THREE.ShaderChunk[ "common" ], "vec4 pack1K ( float depth ) {", " depth /= 1000.0;", " const vec4 bitSh = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", " const vec4 bitMsk = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", " vec4 res = fract( depth * bitSh );", " res -= res.xxyz * bitMsk;", " return res; ", "}", "float unpack1K ( vec4 color ) {", " const vec4 bitSh = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", " return dot( color, bitSh ) * 1000.0;", "}", "void main () {", " gl_FragColor = pack1K( length( vWorldPosition.xyz - lightPos.xyz ) );", "}" ].join( "\n" ) } }; three.js-r73/src/renderers/webgl/0000755000175500017550000000000012610076566016634 5ustar debacledebaclethree.js-r73/src/renderers/webgl/WebGLState.js0000644000175500017550000002301212610076566021131 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLState = function ( gl, extensions, paramThreeToGL ) { var _this = this; var newAttributes = new Uint8Array( 16 ); var enabledAttributes = new Uint8Array( 16 ); var attributeDivisors = new Uint8Array( 16 ); var capabilities = {}; var compressedTextureFormats = null; var currentBlending = null; var currentBlendEquation = null; var currentBlendSrc = null; var currentBlendDst = null; var currentBlendEquationAlpha = null; var currentBlendSrcAlpha = null; var currentBlendDstAlpha = null; var currentDepthFunc = null; var currentDepthWrite = null; var currentColorWrite = null; var currentFlipSided = null; var currentLineWidth = null; var currentPolygonOffsetFactor = null; var currentPolygonOffsetUnits = null; var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); var currentTextureSlot = undefined; var currentBoundTextures = {}; this.init = function () { gl.clearColor( 0, 0, 0, 1 ); gl.clearDepth( 1 ); gl.clearStencil( 0 ); this.enable( gl.DEPTH_TEST ); gl.depthFunc( gl.LEQUAL ); gl.frontFace( gl.CCW ); gl.cullFace( gl.BACK ); this.enable( gl.CULL_FACE ); this.enable( gl.BLEND ); gl.blendEquation( gl.FUNC_ADD ); gl.blendFunc( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA ); }; this.initAttributes = function () { for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { newAttributes[ i ] = 0; } }; this.enableAttribute = function ( attribute ) { newAttributes[ attribute ] = 1; if ( enabledAttributes[ attribute ] === 0 ) { gl.enableVertexAttribArray( attribute ); enabledAttributes[ attribute ] = 1; } if ( attributeDivisors[ attribute ] !== 0 ) { var extension = extensions.get( 'ANGLE_instanced_arrays' ); extension.vertexAttribDivisorANGLE( attribute, 0 ); attributeDivisors[ attribute ] = 0; } }; this.enableAttributeAndDivisor = function ( attribute, meshPerAttribute, extension ) { newAttributes[ attribute ] = 1; if ( enabledAttributes[ attribute ] === 0 ) { gl.enableVertexAttribArray( attribute ); enabledAttributes[ attribute ] = 1; } if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute ); attributeDivisors[ attribute ] = meshPerAttribute; } }; this.disableUnusedAttributes = function () { for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) { if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { gl.disableVertexAttribArray( i ); enabledAttributes[ i ] = 0; } } }; this.enable = function ( id ) { if ( capabilities[ id ] !== true ) { gl.enable( id ); capabilities[ id ] = true; } }; this.disable = function ( id ) { if ( capabilities[ id ] !== false ) { gl.disable( id ); capabilities[ id ] = false; } }; this.getCompressedTextureFormats = function () { if ( compressedTextureFormats === null ) { compressedTextureFormats = []; if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) { var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS ); for ( var i = 0; i < formats.length; i ++ ) { compressedTextureFormats.push( formats[ i ] ); } } } return compressedTextureFormats; }; this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { if ( blending !== currentBlending ) { if ( blending === THREE.NoBlending ) { this.disable( gl.BLEND ); } else if ( blending === THREE.AdditiveBlending ) { this.enable( gl.BLEND ); gl.blendEquation( gl.FUNC_ADD ); gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); } else if ( blending === THREE.SubtractiveBlending ) { // TODO: Find blendFuncSeparate() combination this.enable( gl.BLEND ); gl.blendEquation( gl.FUNC_ADD ); gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR ); } else if ( blending === THREE.MultiplyBlending ) { // TODO: Find blendFuncSeparate() combination this.enable( gl.BLEND ); gl.blendEquation( gl.FUNC_ADD ); gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); } else if ( blending === THREE.CustomBlending ) { this.enable( gl.BLEND ); } else { this.enable( gl.BLEND ); gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD ); gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); } currentBlending = blending; } if ( blending === THREE.CustomBlending ) { blendEquationAlpha = blendEquationAlpha || blendEquation; blendSrcAlpha = blendSrcAlpha || blendSrc; blendDstAlpha = blendDstAlpha || blendDst; if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); currentBlendEquation = blendEquation; currentBlendEquationAlpha = blendEquationAlpha; } if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); currentBlendSrc = blendSrc; currentBlendDst = blendDst; currentBlendSrcAlpha = blendSrcAlpha; currentBlendDstAlpha = blendDstAlpha; } } else { currentBlendEquation = null; currentBlendSrc = null; currentBlendDst = null; currentBlendEquationAlpha = null; currentBlendSrcAlpha = null; currentBlendDstAlpha = null; } }; this.setDepthFunc = function ( depthFunc ) { if ( currentDepthFunc !== depthFunc ) { if ( depthFunc ) { switch ( depthFunc ) { case THREE.NeverDepth: gl.depthFunc( gl.NEVER ); break; case THREE.AlwaysDepth: gl.depthFunc( gl.ALWAYS ); break; case THREE.LessDepth: gl.depthFunc( gl.LESS ); break; case THREE.LessEqualDepth: gl.depthFunc( gl.LEQUAL ); break; case THREE.EqualDepth: gl.depthFunc( gl.EQUAL ); break; case THREE.GreaterEqualDepth: gl.depthFunc( gl.GEQUAL ); break; case THREE.GreaterDepth: gl.depthFunc( gl.GREATER ); break; case THREE.NotEqualDepth: gl.depthFunc( gl.NOTEQUAL ); break; default: gl.depthFunc( gl.LEQUAL ); } } else { gl.depthFunc( gl.LEQUAL ); } currentDepthFunc = depthFunc; } }; this.setDepthTest = function ( depthTest ) { if ( depthTest ) { this.enable( gl.DEPTH_TEST ); } else { this.disable( gl.DEPTH_TEST ); } }; this.setDepthWrite = function ( depthWrite ) { if ( currentDepthWrite !== depthWrite ) { gl.depthMask( depthWrite ); currentDepthWrite = depthWrite; } }; this.setColorWrite = function ( colorWrite ) { if ( currentColorWrite !== colorWrite ) { gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite ); currentColorWrite = colorWrite; } }; this.setFlipSided = function ( flipSided ) { if ( currentFlipSided !== flipSided ) { if ( flipSided ) { gl.frontFace( gl.CW ); } else { gl.frontFace( gl.CCW ); } currentFlipSided = flipSided; } }; this.setLineWidth = function ( width ) { if ( width !== currentLineWidth ) { gl.lineWidth( width ); currentLineWidth = width; } }; this.setPolygonOffset = function ( polygonOffset, factor, units ) { if ( polygonOffset ) { this.enable( gl.POLYGON_OFFSET_FILL ); } else { this.disable( gl.POLYGON_OFFSET_FILL ); } if ( polygonOffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) { gl.polygonOffset( factor, units ); currentPolygonOffsetFactor = factor; currentPolygonOffsetUnits = units; } }; this.setScissorTest = function ( scissorTest ) { if ( scissorTest ) { this.enable( gl.SCISSOR_TEST ); } else { this.disable( gl.SCISSOR_TEST ); } }; // texture this.activeTexture = function ( webglSlot ) { if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; if ( currentTextureSlot !== webglSlot ) { gl.activeTexture( webglSlot ); currentTextureSlot = webglSlot; } } this.bindTexture = function ( webglType, webglTexture ) { if ( currentTextureSlot === undefined ) { _this.activeTexture(); } var boundTexture = currentBoundTextures[ currentTextureSlot ]; if ( boundTexture === undefined ) { boundTexture = { type: undefined, texture: undefined }; currentBoundTextures[ currentTextureSlot ] = boundTexture; } if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { gl.bindTexture( webglType, webglTexture ); boundTexture.type = webglType; boundTexture.texture = webglTexture; } }; this.compressedTexImage2D = function () { try { gl.compressedTexImage2D.apply( gl, arguments ); } catch ( error ) { console.error( error ); } }; this.texImage2D = function () { try { gl.texImage2D.apply( gl, arguments ); } catch ( error ) { console.error( error ); } }; // this.reset = function () { for ( var i = 0; i < enabledAttributes.length; i ++ ) { if ( enabledAttributes[ i ] === 1 ) { gl.disableVertexAttribArray( i ); enabledAttributes[ i ] = 0; } } capabilities = {}; compressedTextureFormats = null; currentBlending = null; currentDepthWrite = null; currentColorWrite = null; currentFlipSided = null; }; }; three.js-r73/src/renderers/webgl/WebGLCapabilities.js0000644000175500017550000000400312610076566022441 0ustar debacledebacleTHREE.WebGLCapabilities = function ( gl, extensions, parameters ) { function getMaxPrecision( precision ) { if ( precision === 'highp' ) { if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { return 'highp'; } precision = 'mediump'; } if ( precision === 'mediump' ) { if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { return 'mediump'; } } return 'lowp'; } this.getMaxPrecision = getMaxPrecision; this.precision = parameters.precision !== undefined ? parameters.precision : 'highp', this.logarithmicDepthBuffer = parameters.logarithmicDepthBuffer !== undefined ? parameters.logarithmicDepthBuffer : false; this.maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); this.maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); this.maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); this.maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); this.maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); this.maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); this.maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); this.maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); this.vertexTextures = this.maxVertexTextures > 0; this.floatFragmentTextures = !! extensions.get( 'OES_texture_float' ); this.floatVertexTextures = this.vertexTextures && this.floatFragmentTextures; var _maxPrecision = getMaxPrecision( this.precision ); if ( _maxPrecision !== this.precision ) { console.warn( 'THREE.WebGLRenderer:', this.precision, 'not supported, using', _maxPrecision, 'instead.' ); this.precision = _maxPrecision; } if ( this.logarithmicDepthBuffer ) { this.logarithmicDepthBuffer = !! extensions.get( 'EXT_frag_depth' ); } }; three.js-r73/src/renderers/webgl/WebGLPrograms.js0000644000175500017550000001613612610076566021654 0ustar debacledebacleTHREE.WebGLPrograms = function ( renderer, capabilities ) { var programs = []; var shaderIDs = { MeshDepthMaterial: 'depth', MeshNormalMaterial: 'normal', MeshBasicMaterial: 'basic', MeshLambertMaterial: 'lambert', MeshPhongMaterial: 'phong', LineBasicMaterial: 'basic', LineDashedMaterial: 'dashed', PointsMaterial: 'points' }; var parameterNames = [ "precision", "supportsVertexTextures", "map", "envMap", "envMapMode", "lightMap", "aoMap", "emissiveMap", "bumpMap", "normalMap", "displacementMap", "specularMap", "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", "maxBones", "useVertexTexture", "morphTargets", "morphNormals", "maxMorphTargets", "maxMorphNormals", "maxDirLights", "maxPointLights", "maxSpotLights", "maxHemiLights", "maxShadows", "shadowMapEnabled", "pointLightShadows", "shadowMapType", "shadowMapDebug", "alphaTest", "metal", "doubleSided", "flipSided" ]; function allocateBones ( object ) { if ( capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture ) { return 1024; } else { // default for when object is not specified // ( for example when prebuilding shader to be used with multiple objects ) // // - leave some extra space for other uniforms // - limit here is ANGLE's 254 max uniform vectors // (up to 54 should be safe) var nVertexUniforms = capabilities.maxVertexUniforms; var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); var maxBones = nVertexMatrices; if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { maxBones = Math.min( object.skeleton.bones.length, maxBones ); if ( maxBones < object.skeleton.bones.length ) { console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); } } return maxBones; } } function allocateLights( lights ) { var dirLights = 0; var pointLights = 0; var spotLights = 0; var hemiLights = 0; for ( var l = 0, ll = lights.length; l < ll; l ++ ) { var light = lights[ l ]; if ( light.visible === false ) continue; if ( light instanceof THREE.DirectionalLight ) dirLights ++; if ( light instanceof THREE.PointLight ) pointLights ++; if ( light instanceof THREE.SpotLight ) spotLights ++; if ( light instanceof THREE.HemisphereLight ) hemiLights ++; } return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights }; } function allocateShadows( lights ) { var maxShadows = 0; var pointLightShadows = 0; for ( var l = 0, ll = lights.length; l < ll; l ++ ) { var light = lights[ l ]; if ( ! light.castShadow ) continue; if ( light instanceof THREE.SpotLight || light instanceof THREE.DirectionalLight ) maxShadows ++; if ( light instanceof THREE.PointLight ) { maxShadows ++; pointLightShadows ++; } } return { 'maxShadows': maxShadows, 'pointLightShadows': pointLightShadows }; } this.getParameters = function ( material, lights, fog, object ) { var shaderID = shaderIDs[ material.type ]; // heuristics to create shader parameters according to lights in the scene // (not to blow over maxLights budget) var maxLightCount = allocateLights( lights ); var allocatedShadows = allocateShadows( lights ); var maxBones = allocateBones( object ); var precision = renderer.getPrecision(); if ( material.precision !== null ) { precision = capabilities.getMaxPrecision( material.precision ); if ( precision !== material.precision ) { console.warn( 'THREE.WebGLRenderer.initMaterial:', material.precision, 'not supported, using', precision, 'instead.' ); } } var parameters = { shaderID: shaderID, precision: precision, supportsVertexTextures: capabilities.vertexTextures, map: !! material.map, envMap: !! material.envMap, envMapMode: material.envMap && material.envMap.mapping, lightMap: !! material.lightMap, aoMap: !! material.aoMap, emissiveMap: !! material.emissiveMap, bumpMap: !! material.bumpMap, normalMap: !! material.normalMap, displacementMap: !! material.displacementMap, specularMap: !! material.specularMap, alphaMap: !! material.alphaMap, combine: material.combine, vertexColors: material.vertexColors, fog: fog, useFog: material.fog, fogExp: fog instanceof THREE.FogExp2, flatShading: material.shading === THREE.FlatShading, sizeAttenuation: material.sizeAttenuation, logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, skinning: material.skinning, maxBones: maxBones, useVertexTexture: capabilities.floatVertexTextures && object && object.skeleton && object.skeleton.useVertexTexture, morphTargets: material.morphTargets, morphNormals: material.morphNormals, maxMorphTargets: renderer.maxMorphTargets, maxMorphNormals: renderer.maxMorphNormals, maxDirLights: maxLightCount.directional, maxPointLights: maxLightCount.point, maxSpotLights: maxLightCount.spot, maxHemiLights: maxLightCount.hemi, maxShadows: allocatedShadows.maxShadows, pointLightShadows: allocatedShadows.pointLightShadows, shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && allocatedShadows.maxShadows > 0, shadowMapType: renderer.shadowMap.type, shadowMapDebug: renderer.shadowMap.debug, alphaTest: material.alphaTest, metal: material.metal, doubleSided: material.side === THREE.DoubleSide, flipSided: material.side === THREE.BackSide }; return parameters; }; this.getProgramCode = function ( material, parameters ) { var chunks = []; if ( parameters.shaderID ) { chunks.push( parameters.shaderID ); } else { chunks.push( material.fragmentShader ); chunks.push( material.vertexShader ); } if ( material.defines !== undefined ) { for ( var name in material.defines ) { chunks.push( name ); chunks.push( material.defines[ name ] ); } } for ( var i = 0; i < parameterNames.length; i ++ ) { var parameterName = parameterNames[ i ]; chunks.push( parameterName ); chunks.push( parameters[ parameterName ] ); } return chunks.join(); }; this.acquireProgram = function ( material, parameters, code ) { var program; // Check if code has been already compiled for ( var p = 0, pl = programs.length; p < pl; p ++ ) { var programInfo = programs[ p ]; if ( programInfo.code === code ) { program = programInfo; ++ program.usedTimes; break; } } if ( program === undefined ) { program = new THREE.WebGLProgram( renderer, code, material, parameters ); programs.push( program ); } return program; }; this.releaseProgram = function( program ) { if ( -- program.usedTimes === 0 ) { // Remove from unordered set var i = programs.indexOf( program ); programs[ i ] = programs[ programs.length - 1 ]; programs.pop(); // Free WebGL resources program.destroy(); } }; // Exposed for resource monitoring & error feedback via renderer.info: this.programs = programs; }; three.js-r73/src/renderers/webgl/WebGLProperties.js0000644000175500017550000000067312610076566022215 0ustar debacledebacle/** * @author fordacious / fordacious.github.io */ THREE.WebGLProperties = function () { var properties = {}; this.get = function ( object ) { var uuid = object.uuid; var map = properties[ uuid ]; if ( map === undefined ) { map = {}; properties[ uuid ] = map; } return map; }; this.delete = function ( object ) { delete properties[ object.uuid ]; }; this.clear = function () { properties = {}; }; }; three.js-r73/src/renderers/webgl/WebGLProgram.js0000644000175500017550000003121112610076566021460 0ustar debacledebacleTHREE.WebGLProgram = ( function () { var programIdCount = 0; function generateDefines( defines ) { var chunks = []; for ( var name in defines ) { var value = defines[ name ]; if ( value === false ) continue; chunks.push( '#define ' + name + ' ' + value ); } return chunks.join( '\n' ); } function fetchUniformLocations( gl, program, identifiers ) { var uniforms = {}; var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); for ( var i = 0; i < n; i ++ ) { var info = gl.getActiveUniform( program, i ); var name = info.name; var location = gl.getUniformLocation( program, name ); // console.log("THREE.WebGLProgram: ACTIVE UNIFORM:", name); var suffixPos = name.lastIndexOf( '[0]' ); if ( suffixPos !== - 1 && suffixPos === name.length - 3 ) { uniforms[ name.substr( 0, suffixPos ) ] = location; } uniforms[ name ] = location; } return uniforms; } function fetchAttributeLocations( gl, program, identifiers ) { var attributes = {}; var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); for ( var i = 0; i < n; i ++ ) { var info = gl.getActiveAttrib( program, i ); var name = info.name; // console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name, i ); attributes[ name ] = gl.getAttribLocation( program, name ); } return attributes; } function filterEmptyLine( string ) { return string !== ''; } return function WebGLProgram( renderer, code, material, parameters ) { var gl = renderer.context; var defines = material.defines; var vertexShader = material.__webglShader.vertexShader; var fragmentShader = material.__webglShader.fragmentShader; var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; if ( parameters.shadowMapType === THREE.PCFShadowMap ) { shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; } var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; if ( parameters.envMap ) { switch ( material.envMap.mapping ) { case THREE.CubeReflectionMapping: case THREE.CubeRefractionMapping: envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; break; case THREE.EquirectangularReflectionMapping: case THREE.EquirectangularRefractionMapping: envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; break; case THREE.SphericalReflectionMapping: envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; break; } switch ( material.envMap.mapping ) { case THREE.CubeRefractionMapping: case THREE.EquirectangularRefractionMapping: envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; break; } switch ( material.combine ) { case THREE.MultiplyOperation: envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; break; case THREE.MixOperation: envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; break; case THREE.AddOperation: envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; break; } } var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; // console.log( 'building new program ' ); // var customDefines = generateDefines( defines ); // var program = gl.createProgram(); var prefixVertex, prefixFragment; if ( material instanceof THREE.RawShaderMaterial ) { prefixVertex = ''; prefixFragment = ''; } else { prefixVertex = [ 'precision ' + parameters.precision + ' float;', 'precision ' + parameters.precision + ' int;', '#define SHADER_NAME ' + material.__webglShader.name, customDefines, parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', renderer.gammaInput ? '#define GAMMA_INPUT' : '', renderer.gammaOutput ? '#define GAMMA_OUTPUT' : '', '#define GAMMA_FACTOR ' + gammaFactorDefine, '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, '#define MAX_SHADOWS ' + parameters.maxShadows, '#define MAX_BONES ' + parameters.maxBones, parameters.map ? '#define USE_MAP' : '', parameters.envMap ? '#define USE_ENVMAP' : '', parameters.envMap ? '#define ' + envMapModeDefine : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.vertexColors ? '#define USE_COLOR' : '', parameters.flatShading ? '#define FLAT_SHADED' : '', parameters.skinning ? '#define USE_SKINNING' : '', parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', parameters.doubleSided ? '#define DOUBLE_SIDED' : '', parameters.flipSided ? '#define FLIP_SIDED' : '', parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', parameters.pointLightShadows > 0 ? '#define POINT_LIGHT_SHADOWS' : '', parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', 'uniform mat4 modelMatrix;', 'uniform mat4 modelViewMatrix;', 'uniform mat4 projectionMatrix;', 'uniform mat4 viewMatrix;', 'uniform mat3 normalMatrix;', 'uniform vec3 cameraPosition;', 'attribute vec3 position;', 'attribute vec3 normal;', 'attribute vec2 uv;', '#ifdef USE_COLOR', ' attribute vec3 color;', '#endif', '#ifdef USE_MORPHTARGETS', ' attribute vec3 morphTarget0;', ' attribute vec3 morphTarget1;', ' attribute vec3 morphTarget2;', ' attribute vec3 morphTarget3;', ' #ifdef USE_MORPHNORMALS', ' attribute vec3 morphNormal0;', ' attribute vec3 morphNormal1;', ' attribute vec3 morphNormal2;', ' attribute vec3 morphNormal3;', ' #else', ' attribute vec3 morphTarget4;', ' attribute vec3 morphTarget5;', ' attribute vec3 morphTarget6;', ' attribute vec3 morphTarget7;', ' #endif', '#endif', '#ifdef USE_SKINNING', ' attribute vec4 skinIndex;', ' attribute vec4 skinWeight;', '#endif', '\n' ].filter( filterEmptyLine ).join( '\n' ); prefixFragment = [ parameters.bumpMap || parameters.normalMap || parameters.flatShading || material.derivatives ? '#extension GL_OES_standard_derivatives : enable' : '', parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', 'precision ' + parameters.precision + ' float;', 'precision ' + parameters.precision + ' int;', '#define SHADER_NAME ' + material.__webglShader.name, customDefines, '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, '#define MAX_SPOT_LIGHTS ' + parameters.maxSpotLights, '#define MAX_HEMI_LIGHTS ' + parameters.maxHemiLights, '#define MAX_SHADOWS ' + parameters.maxShadows, parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', renderer.gammaInput ? '#define GAMMA_INPUT' : '', renderer.gammaOutput ? '#define GAMMA_OUTPUT' : '', '#define GAMMA_FACTOR ' + gammaFactorDefine, ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', parameters.map ? '#define USE_MAP' : '', parameters.envMap ? '#define USE_ENVMAP' : '', parameters.envMap ? '#define ' + envMapTypeDefine : '', parameters.envMap ? '#define ' + envMapModeDefine : '', parameters.envMap ? '#define ' + envMapBlendingDefine : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.vertexColors ? '#define USE_COLOR' : '', parameters.flatShading ? '#define FLAT_SHADED' : '', parameters.metal ? '#define METAL' : '', parameters.doubleSided ? '#define DOUBLE_SIDED' : '', parameters.flipSided ? '#define FLIP_SIDED' : '', parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', parameters.shadowMapDebug ? '#define SHADOWMAP_DEBUG' : '', parameters.pointLightShadows > 0 ? '#define POINT_LIGHT_SHADOWS' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', parameters.logarithmicDepthBuffer && renderer.extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '', 'uniform mat4 viewMatrix;', 'uniform vec3 cameraPosition;', '\n' ].filter( filterEmptyLine ).join( '\n' ); } var vertexGlsl = prefixVertex + vertexShader; var fragmentGlsl = prefixFragment + fragmentShader; var glVertexShader = THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); var glFragmentShader = THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); gl.attachShader( program, glVertexShader ); gl.attachShader( program, glFragmentShader ); // Force a particular attribute to index 0. if ( material.index0AttributeName !== undefined ) { gl.bindAttribLocation( program, 0, material.index0AttributeName ); } else if ( parameters.morphTargets === true ) { // programs with morphTargets displace position out of attribute 0 gl.bindAttribLocation( program, 0, 'position' ); } gl.linkProgram( program ); var programLog = gl.getProgramInfoLog( program ); var vertexLog = gl.getShaderInfoLog( glVertexShader ); var fragmentLog = gl.getShaderInfoLog( glFragmentShader ); var runnable = true; var haveDiagnostics = true; if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { runnable = false; console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); } else if ( programLog !== '' ) { console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); } else if ( vertexLog === '' || fragmentLog === '' ) { haveDiagnostics = false; } if ( haveDiagnostics ) { this.diagnostics = { runnable: runnable, material: material, programLog: programLog, vertexShader: { log: vertexLog, prefix: prefixVertex }, fragmentShader: { log: fragmentLog, prefix: prefixFragment } }; } // clean up gl.deleteShader( glVertexShader ); gl.deleteShader( glFragmentShader ); // set up caching for uniform locations var cachedUniforms; this.getUniforms = function() { if ( cachedUniforms === undefined ) { cachedUniforms = fetchUniformLocations( gl, program ); } return cachedUniforms; }; // set up caching for attribute locations var cachedAttributes; this.getAttributes = function() { if ( cachedAttributes === undefined ) { cachedAttributes = fetchAttributeLocations( gl, program ); } return cachedAttributes; }; // free resource this.destroy = function() { gl.deleteProgram( program ); this.program = undefined; }; // DEPRECATED Object.defineProperties( this, { uniforms: { get: function() { console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' ); return this.getUniforms(); } }, attributes: { get: function() { console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' ); return this.getAttributes(); } } } ); // this.id = programIdCount ++; this.code = code; this.usedTimes = 1; this.program = program; this.vertexShader = glVertexShader; this.fragmentShader = glFragmentShader; return this; }; } )(); three.js-r73/src/renderers/webgl/WebGLShader.js0000644000175500017550000000167412610076566021271 0ustar debacledebacleTHREE.WebGLShader = ( function () { function addLineNumbers( string ) { var lines = string.split( '\n' ); for ( var i = 0; i < lines.length; i ++ ) { lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; } return lines.join( '\n' ); } return function WebGLShader( gl, type, string ) { var shader = gl.createShader( type ); gl.shaderSource( shader, string ); gl.compileShader( shader ); if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); } if ( gl.getShaderInfoLog( shader ) !== '' ) { console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); } // --enable-privileged-webgl-extension // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); return shader; }; } )(); three.js-r73/src/renderers/webgl/WebGLShadowMap.js0000644000175500017550000002404112610076566021737 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { var _gl = _renderer.context, _state = _renderer.state, _frustum = new THREE.Frustum(), _projScreenMatrix = new THREE.Matrix4(), _min = new THREE.Vector3(), _max = new THREE.Vector3(), _lookTarget = new THREE.Vector3(), _lightPositionWorld = new THREE.Vector3(), _renderList = [], _MorphingFlag = 1, _SkinningFlag = 2, _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, _depthMaterials = new Array( _NumberOfMaterialVariants ), _distanceMaterials = new Array( _NumberOfMaterialVariants ); var cubeDirections = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( - 1, 0, 0 ), new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 0, 0, - 1 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, - 1, 0 ) ]; var cubeUps = [ new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 0, 0, - 1 ) ]; var cube2DViewPorts = [ new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4() ]; var _vector4 = new THREE.Vector4(); // init var depthShader = THREE.ShaderLib[ "depthRGBA" ]; var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); var distanceShader = THREE.ShaderLib[ "distanceRGBA" ]; var distanceUniforms = THREE.UniformsUtils.clone( distanceShader.uniforms ); for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { var useMorphing = ( i & _MorphingFlag ) !== 0; var useSkinning = ( i & _SkinningFlag ) !== 0; var depthMaterial = new THREE.ShaderMaterial( { uniforms: depthUniforms, vertexShader: depthShader.vertexShader, fragmentShader: depthShader.fragmentShader, morphTargets: useMorphing, skinning: useSkinning } ); depthMaterial._shadowPass = true; _depthMaterials[ i ] = depthMaterial; var distanceMaterial = new THREE.ShaderMaterial( { uniforms: distanceUniforms, vertexShader: distanceShader.vertexShader, fragmentShader: distanceShader.fragmentShader, morphTargets: useMorphing, skinning: useSkinning } ); distanceMaterial._shadowPass = true; _distanceMaterials[ i ] = distanceMaterial; } // var scope = this; this.enabled = false; this.autoUpdate = true; this.needsUpdate = false; this.type = THREE.PCFShadowMap; this.cullFace = THREE.CullFaceFront; this.render = function ( scene ) { var faceCount, isPointLight; if ( scope.enabled === false ) return; if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; // Set GL state for depth map. _gl.clearColor( 1, 1, 1, 1 ); _state.disable( _gl.BLEND ); _state.enable( _gl.CULL_FACE ); _gl.frontFace( _gl.CCW ); _gl.cullFace( scope.cullFace === THREE.CullFaceFront ? _gl.FRONT : _gl.BACK ); _state.setDepthTest( true ); // save the existing viewport so it can be restored later _renderer.getViewport( _vector4 ); // render depth map for ( var i = 0, il = _lights.length; i < il; i ++ ) { var light = _lights[ i ]; if ( light.castShadow === true ) { var shadow = light.shadow; var shadowCamera = shadow.camera; var shadowMapSize = shadow.mapSize; if ( light instanceof THREE.PointLight ) { faceCount = 6; isPointLight = true; var vpWidth = shadowMapSize.x / 4.0; var vpHeight = shadowMapSize.y / 2.0; // These viewports map a cube-map onto a 2D texture with the // following orientation: // // xzXZ // y Y // // X - Positive x direction // x - Negative x direction // Y - Positive y direction // y - Negative y direction // Z - Positive z direction // z - Negative z direction // positive X cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); // negative X cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight ); // positive Z cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight ); // negative Z cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight ); // positive Y cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); // negative Y cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight ); } else { faceCount = 1; isPointLight = false; } if ( shadow.map === null ) { var shadowFilter = THREE.LinearFilter; if ( scope.type === THREE.PCFSoftShadowMap ) { shadowFilter = THREE.NearestFilter; } var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; shadow.map = new THREE.WebGLRenderTarget( shadowMapSize.x, shadowMapSize.y, pars ); shadow.matrix = new THREE.Matrix4(); // if ( light instanceof THREE.SpotLight ) { shadowCamera.aspect = shadowMapSize.x / shadowMapSize.y; } shadowCamera.updateProjectionMatrix(); } var shadowMap = shadow.map; var shadowMatrix = shadow.matrix; _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); shadowCamera.position.copy( _lightPositionWorld ); _renderer.setRenderTarget( shadowMap ); _renderer.clear(); // render shadow map for each cube face (if omni-directional) or // run a single pass if not for ( var face = 0; face < faceCount; face ++ ) { if ( isPointLight ) { _lookTarget.copy( shadowCamera.position ); _lookTarget.add( cubeDirections[ face ] ); shadowCamera.up.copy( cubeUps[ face ] ); shadowCamera.lookAt( _lookTarget ); var vpDimensions = cube2DViewPorts[ face ]; _renderer.setViewport( vpDimensions.x, vpDimensions.y, vpDimensions.z, vpDimensions.w ); } else { _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); shadowCamera.lookAt( _lookTarget ); } shadowCamera.updateMatrixWorld(); shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); // compute shadow matrix shadowMatrix.set( 0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0 ); shadowMatrix.multiply( shadowCamera.projectionMatrix ); shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); // update camera matrices and frustum _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); _frustum.setFromMatrix( _projScreenMatrix ); // set object matrices & frustum culling _renderList.length = 0; projectObject( scene, shadowCamera ); // render shadow map // render regular objects for ( var j = 0, jl = _renderList.length; j < jl; j ++ ) { var object = _renderList[ j ]; var geometry = _objects.update( object ); var material = object.material; if ( material instanceof THREE.MeshFaceMaterial ) { var groups = geometry.groups; var materials = material.materials; for ( var k = 0, kl = groups.length; k < kl; k ++ ) { var group = groups[ k ]; var groupMaterial = materials[ group.materialIndex ]; if ( groupMaterial.visible === true ) { var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld ); _renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, group ); } } } else { var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld ); _renderer.renderBufferDirect( shadowCamera, _lights, null, geometry, depthMaterial, object, null ); } } } // We must call _renderer.resetGLState() at the end of each iteration of // the light loop in order to force material updates for each light. _renderer.resetGLState(); } } _renderer.setViewport( _vector4.x, _vector4.y, _vector4.z, _vector4.w ); // Restore GL state. var clearColor = _renderer.getClearColor(), clearAlpha = _renderer.getClearAlpha(); _renderer.setClearColor( clearColor, clearAlpha ); _state.enable( _gl.BLEND ); if ( scope.cullFace === THREE.CullFaceFront ) { _gl.cullFace( _gl.BACK ); } _renderer.resetGLState(); scope.needsUpdate = false; }; function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) { var geometry = object.geometry; var newMaterial = null; var materialVariants = _depthMaterials; var customMaterial = object.customDepthMaterial; if ( isPointLight ) { materialVariants = _distanceMaterials; customMaterial = object.customDistanceMaterial; } if ( ! customMaterial ) { var useMorphing = geometry.morphTargets !== undefined && geometry.morphTargets.length > 0 && material.morphTargets; var useSkinning = object instanceof THREE.SkinnedMesh && material.skinning; var variantIndex = 0; if ( useMorphing ) variantIndex |= _MorphingFlag; if ( useSkinning ) variantIndex |= _SkinningFlag; newMaterial = materialVariants[ variantIndex ]; } else { newMaterial = customMaterial; } newMaterial.visible = material.visible; newMaterial.wireframe = material.wireframe; newMaterial.wireframeLinewidth = material.wireframeLinewidth; if ( isPointLight && newMaterial.uniforms.lightPos !== undefined ) { newMaterial.uniforms.lightPos.value.copy( lightPositionWorld ); } return newMaterial; } function projectObject( object, camera ) { if ( object.visible === false ) return; if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) { if ( object.castShadow && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) { var material = object.material; if ( material.visible === true ) { object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); _renderList.push( object ); } } } var children = object.children; for ( var i = 0, l = children.length; i < l; i ++ ) { projectObject( children[ i ], camera ); } } }; three.js-r73/src/renderers/webgl/WebGLIndexedBufferRenderer.js0000644000175500017550000000230312610076566024252 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLIndexedBufferRenderer = function ( _gl, extensions, _infoRender ) { var mode; function setMode( value ) { mode = value; } var type, size; function setIndex( index ) { if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) { type = _gl.UNSIGNED_INT; size = 4; } else { type = _gl.UNSIGNED_SHORT; size = 2; } } function render( start, count ) { _gl.drawElements( mode, count, type, start * size ); _infoRender.calls ++; _infoRender.vertices += count; if ( mode === _gl.TRIANGLES ) _infoRender.faces += count / 3; } function renderInstances( geometry ) { var extension = extensions.get( 'ANGLE_instanced_arrays' ); if ( extension === null ) { console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); return; } var index = geometry.index; extension.drawElementsInstancedANGLE( mode, index.array.length, type, 0, geometry.maxInstancedCount ); } this.setMode = setMode; this.setIndex = setIndex; this.render = render; this.renderInstances = renderInstances; }; three.js-r73/src/renderers/webgl/WebGLExtensions.js0000644000175500017550000000222712610076566022215 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLExtensions = function ( gl ) { var extensions = {}; this.get = function ( name ) { if ( extensions[ name ] !== undefined ) { return extensions[ name ]; } var extension; switch ( name ) { case 'EXT_texture_filter_anisotropic': extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); break; case 'WEBGL_compressed_texture_s3tc': extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); break; case 'WEBGL_compressed_texture_pvrtc': extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); break; default: extension = gl.getExtension( name ); } if ( extension === null ) { console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); } extensions[ name ] = extension; return extension; }; }; three.js-r73/src/renderers/webgl/WebGLBufferRenderer.js0000644000175500017550000000212512610076566022753 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLBufferRenderer = function ( _gl, extensions, _infoRender ) { var mode; function setMode( value ) { mode = value; } function render( start, count ) { _gl.drawArrays( mode, start, count ); _infoRender.calls ++; _infoRender.vertices += count; if ( mode === _gl.TRIANGLES ) _infoRender.faces += count / 3; } function renderInstances( geometry ) { var extension = extensions.get( 'ANGLE_instanced_arrays' ); if ( extension === null ) { console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); return; } var position = geometry.attributes.position; if ( position instanceof THREE.InterleavedBufferAttribute ) { extension.drawArraysInstancedANGLE( mode, 0, position.data.count, geometry.maxInstancedCount ); } else { extension.drawArraysInstancedANGLE( mode, 0, position.count, geometry.maxInstancedCount ); } } this.setMode = setMode; this.render = render; this.renderInstances = renderInstances; }; three.js-r73/src/renderers/webgl/plugins/0000755000175500017550000000000012610076566020315 5ustar debacledebaclethree.js-r73/src/renderers/webgl/plugins/SpritePlugin.js0000644000175500017550000002057112610076566023305 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.SpritePlugin = function ( renderer, sprites ) { var gl = renderer.context; var state = renderer.state; var vertexBuffer, elementBuffer; var program, attributes, uniforms; var texture; // decompose matrixWorld var spritePosition = new THREE.Vector3(); var spriteRotation = new THREE.Quaternion(); var spriteScale = new THREE.Vector3(); function init() { var vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0, 0.5, - 0.5, 1, 0, 0.5, 0.5, 1, 1, - 0.5, 0.5, 0, 1 ] ); var faces = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ); vertexBuffer = gl.createBuffer(); elementBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); program = createProgram(); attributes = { position: gl.getAttribLocation ( program, 'position' ), uv: gl.getAttribLocation ( program, 'uv' ) }; uniforms = { uvOffset: gl.getUniformLocation( program, 'uvOffset' ), uvScale: gl.getUniformLocation( program, 'uvScale' ), rotation: gl.getUniformLocation( program, 'rotation' ), scale: gl.getUniformLocation( program, 'scale' ), color: gl.getUniformLocation( program, 'color' ), map: gl.getUniformLocation( program, 'map' ), opacity: gl.getUniformLocation( program, 'opacity' ), modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ), projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ), fogType: gl.getUniformLocation( program, 'fogType' ), fogDensity: gl.getUniformLocation( program, 'fogDensity' ), fogNear: gl.getUniformLocation( program, 'fogNear' ), fogFar: gl.getUniformLocation( program, 'fogFar' ), fogColor: gl.getUniformLocation( program, 'fogColor' ), alphaTest: gl.getUniformLocation( program, 'alphaTest' ) }; var canvas = document.createElement( 'canvas' ); canvas.width = 8; canvas.height = 8; var context = canvas.getContext( '2d' ); context.fillStyle = 'white'; context.fillRect( 0, 0, 8, 8 ); texture = new THREE.Texture( canvas ); texture.needsUpdate = true; } this.render = function ( scene, camera ) { if ( sprites.length === 0 ) return; // setup gl if ( program === undefined ) { init(); } gl.useProgram( program ); state.initAttributes(); state.enableAttribute( attributes.position ); state.enableAttribute( attributes.uv ); state.disableUnusedAttributes(); state.disable( gl.CULL_FACE ); state.enable( gl.BLEND ); gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 ); gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); state.activeTexture( gl.TEXTURE0 ); gl.uniform1i( uniforms.map, 0 ); var oldFogType = 0; var sceneFogType = 0; var fog = scene.fog; if ( fog ) { gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); if ( fog instanceof THREE.Fog ) { gl.uniform1f( uniforms.fogNear, fog.near ); gl.uniform1f( uniforms.fogFar, fog.far ); gl.uniform1i( uniforms.fogType, 1 ); oldFogType = 1; sceneFogType = 1; } else if ( fog instanceof THREE.FogExp2 ) { gl.uniform1f( uniforms.fogDensity, fog.density ); gl.uniform1i( uniforms.fogType, 2 ); oldFogType = 2; sceneFogType = 2; } } else { gl.uniform1i( uniforms.fogType, 0 ); oldFogType = 0; sceneFogType = 0; } // update positions and sort for ( var i = 0, l = sprites.length; i < l; i ++ ) { var sprite = sprites[ i ]; sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); sprite.z = - sprite.modelViewMatrix.elements[ 14 ]; } sprites.sort( painterSortStable ); // render all sprites var scale = []; for ( var i = 0, l = sprites.length; i < l; i ++ ) { var sprite = sprites[ i ]; var material = sprite.material; gl.uniform1f( uniforms.alphaTest, material.alphaTest ); gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements ); sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale ); scale[ 0 ] = spriteScale.x; scale[ 1 ] = spriteScale.y; var fogType = 0; if ( scene.fog && material.fog ) { fogType = sceneFogType; } if ( oldFogType !== fogType ) { gl.uniform1i( uniforms.fogType, fogType ); oldFogType = fogType; } if ( material.map !== null ) { gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); } else { gl.uniform2f( uniforms.uvOffset, 0, 0 ); gl.uniform2f( uniforms.uvScale, 1, 1 ); } gl.uniform1f( uniforms.opacity, material.opacity ); gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); gl.uniform1f( uniforms.rotation, material.rotation ); gl.uniform2fv( uniforms.scale, scale ); state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); state.setDepthTest( material.depthTest ); state.setDepthWrite( material.depthWrite ); if ( material.map && material.map.image && material.map.image.width ) { renderer.setTexture( material.map, 0 ); } else { renderer.setTexture( texture, 0 ); } gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); } // restore gl state.enable( gl.CULL_FACE ); renderer.resetGLState(); }; function createProgram () { var program = gl.createProgram(); var vertexShader = gl.createShader( gl.VERTEX_SHADER ); var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); gl.shaderSource( vertexShader, [ 'precision ' + renderer.getPrecision() + ' float;', 'uniform mat4 modelViewMatrix;', 'uniform mat4 projectionMatrix;', 'uniform float rotation;', 'uniform vec2 scale;', 'uniform vec2 uvOffset;', 'uniform vec2 uvScale;', 'attribute vec2 position;', 'attribute vec2 uv;', 'varying vec2 vUV;', 'void main() {', 'vUV = uvOffset + uv * uvScale;', 'vec2 alignedPosition = position * scale;', 'vec2 rotatedPosition;', 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', 'vec4 finalPosition;', 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', 'finalPosition.xy += rotatedPosition;', 'finalPosition = projectionMatrix * finalPosition;', 'gl_Position = finalPosition;', '}' ].join( '\n' ) ); gl.shaderSource( fragmentShader, [ 'precision ' + renderer.getPrecision() + ' float;', 'uniform vec3 color;', 'uniform sampler2D map;', 'uniform float opacity;', 'uniform int fogType;', 'uniform vec3 fogColor;', 'uniform float fogDensity;', 'uniform float fogNear;', 'uniform float fogFar;', 'uniform float alphaTest;', 'varying vec2 vUV;', 'void main() {', 'vec4 texture = texture2D( map, vUV );', 'if ( texture.a < alphaTest ) discard;', 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', 'if ( fogType > 0 ) {', 'float depth = gl_FragCoord.z / gl_FragCoord.w;', 'float fogFactor = 0.0;', 'if ( fogType == 1 ) {', 'fogFactor = smoothstep( fogNear, fogFar, depth );', '} else {', 'const float LOG2 = 1.442695;', 'fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', '}', 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', '}', '}' ].join( '\n' ) ); gl.compileShader( vertexShader ); gl.compileShader( fragmentShader ); gl.attachShader( program, vertexShader ); gl.attachShader( program, fragmentShader ); gl.linkProgram( program ); return program; } function painterSortStable ( a, b ) { if ( a.z !== b.z ) { return b.z - a.z; } else { return b.id - a.id; } } }; three.js-r73/src/renderers/webgl/plugins/LensFlarePlugin.js0000644000175500017550000003011512610076566023705 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.LensFlarePlugin = function ( renderer, flares ) { var gl = renderer.context; var state = renderer.state; var vertexBuffer, elementBuffer; var program, attributes, uniforms; var hasVertexTexture; var tempTexture, occlusionTexture; function init() { var vertices = new Float32Array( [ - 1, - 1, 0, 0, 1, - 1, 1, 0, 1, 1, 1, 1, - 1, 1, 0, 1 ] ); var faces = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ); // buffers vertexBuffer = gl.createBuffer(); elementBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW ); // textures tempTexture = gl.createTexture(); occlusionTexture = gl.createTexture(); state.bindTexture( gl.TEXTURE_2D, tempTexture ); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); hasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0; var shader; if ( hasVertexTexture ) { shader = { vertexShader: [ "uniform lowp int renderType;", "uniform vec3 screenPosition;", "uniform vec2 scale;", "uniform float rotation;", "uniform sampler2D occlusionMap;", "attribute vec2 position;", "attribute vec2 uv;", "varying vec2 vUV;", "varying float vVisibility;", "void main() {", "vUV = uv;", "vec2 pos = position;", "if ( renderType == 2 ) {", "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", "vVisibility = visibility.r / 9.0;", "vVisibility *= 1.0 - visibility.g / 9.0;", "vVisibility *= visibility.b / 9.0;", "vVisibility *= 1.0 - visibility.a / 9.0;", "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", "}", "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", "}" ].join( "\n" ), fragmentShader: [ "uniform lowp int renderType;", "uniform sampler2D map;", "uniform float opacity;", "uniform vec3 color;", "varying vec2 vUV;", "varying float vVisibility;", "void main() {", // pink square "if ( renderType == 0 ) {", "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", // restore "} else if ( renderType == 1 ) {", "gl_FragColor = texture2D( map, vUV );", // flare "} else {", "vec4 texture = texture2D( map, vUV );", "texture.a *= opacity * vVisibility;", "gl_FragColor = texture;", "gl_FragColor.rgb *= color;", "}", "}" ].join( "\n" ) }; } else { shader = { vertexShader: [ "uniform lowp int renderType;", "uniform vec3 screenPosition;", "uniform vec2 scale;", "uniform float rotation;", "attribute vec2 position;", "attribute vec2 uv;", "varying vec2 vUV;", "void main() {", "vUV = uv;", "vec2 pos = position;", "if ( renderType == 2 ) {", "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", "}", "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", "}" ].join( "\n" ), fragmentShader: [ "precision mediump float;", "uniform lowp int renderType;", "uniform sampler2D map;", "uniform sampler2D occlusionMap;", "uniform float opacity;", "uniform vec3 color;", "varying vec2 vUV;", "void main() {", // pink square "if ( renderType == 0 ) {", "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", // restore "} else if ( renderType == 1 ) {", "gl_FragColor = texture2D( map, vUV );", // flare "} else {", "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", "visibility = ( 1.0 - visibility / 4.0 );", "vec4 texture = texture2D( map, vUV );", "texture.a *= opacity * visibility;", "gl_FragColor = texture;", "gl_FragColor.rgb *= color;", "}", "}" ].join( "\n" ) }; } program = createProgram( shader ); attributes = { vertex: gl.getAttribLocation ( program, "position" ), uv: gl.getAttribLocation ( program, "uv" ) }; uniforms = { renderType: gl.getUniformLocation( program, "renderType" ), map: gl.getUniformLocation( program, "map" ), occlusionMap: gl.getUniformLocation( program, "occlusionMap" ), opacity: gl.getUniformLocation( program, "opacity" ), color: gl.getUniformLocation( program, "color" ), scale: gl.getUniformLocation( program, "scale" ), rotation: gl.getUniformLocation( program, "rotation" ), screenPosition: gl.getUniformLocation( program, "screenPosition" ) }; } /* * Render lens flares * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, * reads these back and calculates occlusion. */ this.render = function ( scene, camera, viewportWidth, viewportHeight ) { if ( flares.length === 0 ) return; var tempPosition = new THREE.Vector3(); var invAspect = viewportHeight / viewportWidth, halfViewportWidth = viewportWidth * 0.5, halfViewportHeight = viewportHeight * 0.5; var size = 16 / viewportHeight, scale = new THREE.Vector2( size * invAspect, size ); var screenPosition = new THREE.Vector3( 1, 1, 0 ), screenPositionPixels = new THREE.Vector2( 1, 1 ); if ( program === undefined ) { init(); } gl.useProgram( program ); state.initAttributes(); state.enableAttribute( attributes.vertex ); state.enableAttribute( attributes.uv ); state.disableUnusedAttributes(); // loop through all lens flares to update their occlusion and positions // setup gl and common used attribs/uniforms gl.uniform1i( uniforms.occlusionMap, 0 ); gl.uniform1i( uniforms.map, 1 ); gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer ); gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 ); gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); state.disable( gl.CULL_FACE ); gl.depthMask( false ); for ( var i = 0, l = flares.length; i < l; i ++ ) { size = 16 / viewportHeight; scale.set( size * invAspect, size ); // calc object screen position var flare = flares[ i ]; tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] ); tempPosition.applyMatrix4( camera.matrixWorldInverse ); tempPosition.applyProjection( camera.projectionMatrix ); // setup arrays for gl programs screenPosition.copy( tempPosition ); screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; // screen cull if ( hasVertexTexture || ( screenPositionPixels.x > 0 && screenPositionPixels.x < viewportWidth && screenPositionPixels.y > 0 && screenPositionPixels.y < viewportHeight ) ) { // save current RGB to temp texture state.activeTexture( gl.TEXTURE0 ); state.bindTexture( gl.TEXTURE_2D, null ); state.activeTexture( gl.TEXTURE1 ); state.bindTexture( gl.TEXTURE_2D, tempTexture ); gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); // render pink quad gl.uniform1i( uniforms.renderType, 0 ); gl.uniform2f( uniforms.scale, scale.x, scale.y ); gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); state.disable( gl.BLEND ); state.enable( gl.DEPTH_TEST ); gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); // copy result to occlusionMap state.activeTexture( gl.TEXTURE0 ); state.bindTexture( gl.TEXTURE_2D, occlusionTexture ); gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); // restore graphics gl.uniform1i( uniforms.renderType, 1 ); state.disable( gl.DEPTH_TEST ); state.activeTexture( gl.TEXTURE1 ); state.bindTexture( gl.TEXTURE_2D, tempTexture ); gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); // update object positions flare.positionScreen.copy( screenPosition ); if ( flare.customUpdateCallback ) { flare.customUpdateCallback( flare ); } else { flare.updateLensFlares(); } // render flares gl.uniform1i( uniforms.renderType, 2 ); state.enable( gl.BLEND ); for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { var sprite = flare.lensFlares[ j ]; if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { screenPosition.x = sprite.x; screenPosition.y = sprite.y; screenPosition.z = sprite.z; size = sprite.size * sprite.scale / viewportHeight; scale.x = size * invAspect; scale.y = size; gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); gl.uniform2f( uniforms.scale, scale.x, scale.y ); gl.uniform1f( uniforms.rotation, sprite.rotation ); gl.uniform1f( uniforms.opacity, sprite.opacity ); gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); renderer.setTexture( sprite.texture, 1 ); gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); } } } } // restore gl state.enable( gl.CULL_FACE ); state.enable( gl.DEPTH_TEST ); gl.depthMask( true ); renderer.resetGLState(); }; function createProgram ( shader ) { var program = gl.createProgram(); var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); var vertexShader = gl.createShader( gl.VERTEX_SHADER ); var prefix = "precision " + renderer.getPrecision() + " float;\n"; gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); gl.shaderSource( vertexShader, prefix + shader.vertexShader ); gl.compileShader( fragmentShader ); gl.compileShader( vertexShader ); gl.attachShader( program, fragmentShader ); gl.attachShader( program, vertexShader ); gl.linkProgram( program ); return program; } }; three.js-r73/src/renderers/webgl/WebGLObjects.js0000644000175500017550000001074512610076566021453 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLObjects = function ( gl, properties, info ) { var geometries = new THREE.WebGLGeometries( gl, properties, info ); // function update( object ) { // TODO: Avoid updating twice (when using shadowMap). Maybe add frame counter. var geometry = geometries.get( object ); if ( object.geometry instanceof THREE.Geometry ) { geometry.updateFromObject( object ); } var index = geometry.index; var attributes = geometry.attributes; if ( index !== null ) { updateAttribute( index, gl.ELEMENT_ARRAY_BUFFER ); } for ( var name in attributes ) { updateAttribute( attributes[ name ], gl.ARRAY_BUFFER ); } // morph targets var morphAttributes = geometry.morphAttributes; for ( var name in morphAttributes ) { var array = morphAttributes[ name ]; for ( var i = 0, l = array.length; i < l; i ++ ) { updateAttribute( array[ i ], gl.ARRAY_BUFFER ); } } return geometry; } function updateAttribute( attribute, bufferType ) { var data = ( attribute instanceof THREE.InterleavedBufferAttribute ) ? attribute.data : attribute; var attributeProperties = properties.get( data ); if ( attributeProperties.__webglBuffer === undefined ) { createBuffer( attributeProperties, data, bufferType ); } else if ( attributeProperties.version !== data.version ) { updateBuffer( attributeProperties, data, bufferType ); } } function createBuffer( attributeProperties, data, bufferType ) { attributeProperties.__webglBuffer = gl.createBuffer(); gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); var usage = data.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW; gl.bufferData( bufferType, data.array, usage ); attributeProperties.version = data.version; } function updateBuffer( attributeProperties, data, bufferType ) { gl.bindBuffer( bufferType, attributeProperties.__webglBuffer ); if ( data.dynamic === false || data.updateRange.count === - 1 ) { // Not using update ranges gl.bufferSubData( bufferType, 0, data.array ); } else if ( data.updateRange.count === 0 ) { console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' ); } else { gl.bufferSubData( bufferType, data.updateRange.offset * data.array.BYTES_PER_ELEMENT, data.array.subarray( data.updateRange.offset, data.updateRange.offset + data.updateRange.count ) ); data.updateRange.count = 0; // reset range } attributeProperties.version = data.version; } function getAttributeBuffer( attribute ) { if ( attribute instanceof THREE.InterleavedBufferAttribute ) { return properties.get( attribute.data ).__webglBuffer; } return properties.get( attribute ).__webglBuffer; } function getWireframeAttribute( geometry ) { var property = properties.get( geometry ); if ( property.wireframe !== undefined ) { return property.wireframe; } var indices = []; var index = geometry.index; var attributes = geometry.attributes; var position = attributes.position; // console.time( 'wireframe' ); if ( index !== null ) { var edges = {}; var array = index.array; for ( var i = 0, l = array.length; i < l; i += 3 ) { var a = array[ i + 0 ]; var b = array[ i + 1 ]; var c = array[ i + 2 ]; if ( checkEdge( edges, a, b ) ) indices.push( a, b ); if ( checkEdge( edges, b, c ) ) indices.push( b, c ); if ( checkEdge( edges, c, a ) ) indices.push( c, a ); } } else { var array = attributes.position.array; for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { var a = i + 0; var b = i + 1; var c = i + 2; indices.push( a, b, b, c, c, a ); } } // console.timeEnd( 'wireframe' ); var TypeArray = position.count > 65535 ? Uint32Array : Uint16Array; var attribute = new THREE.BufferAttribute( new TypeArray( indices ), 1 ); updateAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER ); property.wireframe = attribute; return attribute; } function checkEdge( edges, a, b ) { if ( a > b ) { var tmp = a; a = b; b = tmp; } var list = edges[ a ]; if ( list === undefined ) { edges[ a ] = [ b ]; return true; } else if ( list.indexOf( b ) === -1 ) { list.push( b ); return true; } return false; } this.getAttributeBuffer = getAttributeBuffer; this.getWireframeAttribute = getWireframeAttribute; this.update = update; }; three.js-r73/src/renderers/webgl/WebGLGeometries.js0000644000175500017550000000376012610076566022164 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.WebGLGeometries = function ( gl, properties, info ) { var geometries = {}; function get( object ) { var geometry = object.geometry; if ( geometries[ geometry.id ] !== undefined ) { return geometries[ geometry.id ]; } geometry.addEventListener( 'dispose', onGeometryDispose ); var buffergeometry; if ( geometry instanceof THREE.BufferGeometry ) { buffergeometry = geometry; } else if ( geometry instanceof THREE.Geometry ) { if ( geometry._bufferGeometry === undefined ) { geometry._bufferGeometry = new THREE.BufferGeometry().setFromObject( object ); } buffergeometry = geometry._bufferGeometry; } geometries[ geometry.id ] = buffergeometry; info.memory.geometries ++; return buffergeometry; } function onGeometryDispose( event ) { var geometry = event.target; var buffergeometry = geometries[ geometry.id ]; deleteAttributes( buffergeometry.attributes ); geometry.removeEventListener( 'dispose', onGeometryDispose ); delete geometries[ geometry.id ]; var property = properties.get( geometry ); if ( property.wireframe ) deleteAttribute( property.wireframe ); info.memory.geometries --; } function getAttributeBuffer( attribute ) { if ( attribute instanceof THREE.InterleavedBufferAttribute ) { return properties.get( attribute.data ).__webglBuffer; } return properties.get( attribute ).__webglBuffer; } function deleteAttribute( attribute ) { var buffer = getAttributeBuffer( attribute ); if ( buffer !== undefined ) { gl.deleteBuffer( buffer ); removeAttributeBuffer( attribute ); } } function deleteAttributes( attributes ) { for ( var name in attributes ) { deleteAttribute( attributes[ name ] ); } } function removeAttributeBuffer( attribute ) { if ( attribute instanceof THREE.InterleavedBufferAttribute ) { properties.delete( attribute.data ); } else { properties.delete( attribute ); } } this.get = get; }; three.js-r73/src/renderers/WebGLRenderTargetCube.js0000644000175500017550000000065712610076566022150 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com */ THREE.WebGLRenderTargetCube = function ( width, height, options ) { THREE.WebGLRenderTarget.call( this, width, height, options ); this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 }; THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); THREE.WebGLRenderTargetCube.prototype.constructor = THREE.WebGLRenderTargetCube; three.js-r73/src/renderers/WebGLRenderTarget.js0000644000175500017550000001052312610076566021342 0ustar debacledebacle/** * @author szimek / https://github.com/szimek/ * @author alteredq / http://alteredqualia.com/ */ THREE.WebGLRenderTarget = function ( width, height, options ) { this.uuid = THREE.Math.generateUUID(); this.width = width; this.height = height; options = options || {}; if ( options.minFilter === undefined ) options.minFilter = THREE.LinearFilter; this.texture = new THREE.Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy ); this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; this.shareDepthFrom = options.shareDepthFrom !== undefined ? options.shareDepthFrom : null; }; THREE.WebGLRenderTarget.prototype = { constructor: THREE.WebGLRenderTarget, get wrapS() { console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); return this.texture.wrapS; }, set wrapS( value ) { console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); this.texture.wrapS = value; }, get wrapT() { console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); return this.texture.wrapT; }, set wrapT( value ) { console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); this.texture.wrapT = value; }, get magFilter() { console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); return this.texture.magFilter; }, set magFilter( value ) { console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); this.texture.magFilter = value; }, get minFilter() { console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); return this.texture.minFilter; }, set minFilter( value ) { console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); this.texture.minFilter = value; }, get anisotropy() { console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); return this.texture.anisotropy; }, set anisotropy( value ) { console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); this.texture.anisotropy = value; }, get offset() { console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); return this.texture.offset; }, set offset( value ) { console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); this.texture.offset = value; }, get repeat() { console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); return this.texture.repeat; }, set repeat( value ) { console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); this.texture.repeat = value; }, get format() { console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); return this.texture.format; }, set format( value ) { console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); this.texture.format = value; }, get type() { console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); return this.texture.type; }, set type( value ) { console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); this.texture.type = value; }, get generateMipmaps() { console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); return this.texture.generateMipmaps; }, set generateMipmaps( value ) { console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); this.texture.generateMipmaps = value; }, // setSize: function ( width, height ) { if ( this.width !== width || this.height !== height ) { this.width = width; this.height = height; this.dispose(); } }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( source ) { this.width = source.width; this.height = source.height; this.texture = source.texture.clone(); this.depthBuffer = source.depthBuffer; this.stencilBuffer = source.stencilBuffer; this.shareDepthFrom = source.shareDepthFrom; return this; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); three.js-r73/src/core/0000755000175500017550000000000012610076566014473 5ustar debacledebaclethree.js-r73/src/core/Raycaster.js0000644000175500017550000000516312610076566016773 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author bhouston / http://clara.io/ * @author stephomi / http://stephaneginier.com/ */ ( function ( THREE ) { THREE.Raycaster = function ( origin, direction, near, far ) { this.ray = new THREE.Ray( origin, direction ); // direction is assumed to be normalized (for accurate distance calculations) this.near = near || 0; this.far = far || Infinity; this.params = { Mesh: {}, Line: {}, LOD: {}, Points: { threshold: 1 }, Sprite: {} }; Object.defineProperties( this.params, { PointCloud: { get: function () { console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); return this.Points; } } } ); }; function descSort( a, b ) { return a.distance - b.distance; } function intersectObject( object, raycaster, intersects, recursive ) { if ( object.visible === false ) return; object.raycast( raycaster, intersects ); if ( recursive === true ) { var children = object.children; for ( var i = 0, l = children.length; i < l; i ++ ) { intersectObject( children[ i ], raycaster, intersects, true ); } } } // THREE.Raycaster.prototype = { constructor: THREE.Raycaster, linePrecision: 1, set: function ( origin, direction ) { // direction is assumed to be normalized (for accurate distance calculations) this.ray.set( origin, direction ); }, setFromCamera: function ( coords, camera ) { if ( camera instanceof THREE.PerspectiveCamera ) { this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); } else if ( camera instanceof THREE.OrthographicCamera ) { this.ray.origin.set( coords.x, coords.y, - 1 ).unproject( camera ); this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); } else { console.error( 'THREE.Raycaster: Unsupported camera type.' ); } }, intersectObject: function ( object, recursive ) { var intersects = []; intersectObject( object, this, intersects, recursive ); intersects.sort( descSort ); return intersects; }, intersectObjects: function ( objects, recursive ) { var intersects = []; if ( Array.isArray( objects ) === false ) { console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); return intersects; } for ( var i = 0, l = objects.length; i < l; i ++ ) { intersectObject( objects[ i ], this, intersects, recursive ); } intersects.sort( descSort ); return intersects; } }; }( THREE ) ); three.js-r73/src/core/InterleavedBuffer.js0000644000175500017550000000237412610076566020433 0ustar debacledebacle/** * @author benaadams / https://twitter.com/ben_a_adams */ THREE.InterleavedBuffer = function ( array, stride ) { this.uuid = THREE.Math.generateUUID(); this.array = array; this.stride = stride; this.dynamic = false; this.updateRange = { offset: 0, count: - 1 }; this.version = 0; }; THREE.InterleavedBuffer.prototype = { constructor: THREE.InterleavedBuffer, get length () { return this.array.length; }, get count () { return this.array.length / this.stride; }, set needsUpdate( value ) { if ( value === true ) this.version ++; }, setDynamic: function ( value ) { this.dynamic = value; return this; }, copy: function ( source ) { this.array = new source.array.constructor( source.array ); this.stride = source.stride; this.dynamic = source.dynamic; }, copyAt: function ( index1, attribute, index2 ) { index1 *= this.stride; index2 *= attribute.stride; for ( var i = 0, l = this.stride; i < l; i ++ ) { this.array[ index1 + i ] = attribute.array[ index2 + i ]; } return this; }, set: function ( value, offset ) { if ( offset === undefined ) offset = 0; this.array.set( value, offset ); return this; }, clone: function () { return new this.constructor().copy( this ); } }; three.js-r73/src/core/Object3D.js0000644000175500017550000003314312610076566016432 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley * @author elephantatwork / www.elephantatwork.ch */ THREE.Object3D = function () { Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } ); this.uuid = THREE.Math.generateUUID(); this.name = ''; this.type = 'Object3D'; this.parent = null; this.channels = new THREE.Channels(); this.children = []; this.up = THREE.Object3D.DefaultUp.clone(); var position = new THREE.Vector3(); var rotation = new THREE.Euler(); var quaternion = new THREE.Quaternion(); var scale = new THREE.Vector3( 1, 1, 1 ); function onRotationChange() { quaternion.setFromEuler( rotation, false ); } function onQuaternionChange() { rotation.setFromQuaternion( quaternion, undefined, false ); } rotation.onChange( onRotationChange ); quaternion.onChange( onQuaternionChange ); Object.defineProperties( this, { position: { enumerable: true, value: position }, rotation: { enumerable: true, value: rotation }, quaternion: { enumerable: true, value: quaternion }, scale: { enumerable: true, value: scale }, modelViewMatrix: { value: new THREE.Matrix4() }, normalMatrix: { value: new THREE.Matrix3() } } ); this.rotationAutoUpdate = true; this.matrix = new THREE.Matrix4(); this.matrixWorld = new THREE.Matrix4(); this.matrixAutoUpdate = THREE.Object3D.DefaultMatrixAutoUpdate; this.matrixWorldNeedsUpdate = false; this.visible = true; this.castShadow = false; this.receiveShadow = false; this.frustumCulled = true; this.renderOrder = 0; this.userData = {}; }; THREE.Object3D.DefaultUp = new THREE.Vector3( 0, 1, 0 ); THREE.Object3D.DefaultMatrixAutoUpdate = true; THREE.Object3D.prototype = { constructor: THREE.Object3D, get eulerOrder () { console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); return this.rotation.order; }, set eulerOrder ( value ) { console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); this.rotation.order = value; }, get useQuaternion () { console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); }, set useQuaternion ( value ) { console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); }, set renderDepth ( value ) { console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); }, // applyMatrix: function ( matrix ) { this.matrix.multiplyMatrices( matrix, this.matrix ); this.matrix.decompose( this.position, this.quaternion, this.scale ); }, setRotationFromAxisAngle: function ( axis, angle ) { // assumes axis is normalized this.quaternion.setFromAxisAngle( axis, angle ); }, setRotationFromEuler: function ( euler ) { this.quaternion.setFromEuler( euler, true ); }, setRotationFromMatrix: function ( m ) { // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) this.quaternion.setFromRotationMatrix( m ); }, setRotationFromQuaternion: function ( q ) { // assumes q is normalized this.quaternion.copy( q ); }, rotateOnAxis: function () { // rotate object on axis in object space // axis is assumed to be normalized var q1 = new THREE.Quaternion(); return function ( axis, angle ) { q1.setFromAxisAngle( axis, angle ); this.quaternion.multiply( q1 ); return this; }; }(), rotateX: function () { var v1 = new THREE.Vector3( 1, 0, 0 ); return function ( angle ) { return this.rotateOnAxis( v1, angle ); }; }(), rotateY: function () { var v1 = new THREE.Vector3( 0, 1, 0 ); return function ( angle ) { return this.rotateOnAxis( v1, angle ); }; }(), rotateZ: function () { var v1 = new THREE.Vector3( 0, 0, 1 ); return function ( angle ) { return this.rotateOnAxis( v1, angle ); }; }(), translateOnAxis: function () { // translate object by distance along axis in object space // axis is assumed to be normalized var v1 = new THREE.Vector3(); return function ( axis, distance ) { v1.copy( axis ).applyQuaternion( this.quaternion ); this.position.add( v1.multiplyScalar( distance ) ); return this; }; }(), translate: function ( distance, axis ) { console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); return this.translateOnAxis( axis, distance ); }, translateX: function () { var v1 = new THREE.Vector3( 1, 0, 0 ); return function ( distance ) { return this.translateOnAxis( v1, distance ); }; }(), translateY: function () { var v1 = new THREE.Vector3( 0, 1, 0 ); return function ( distance ) { return this.translateOnAxis( v1, distance ); }; }(), translateZ: function () { var v1 = new THREE.Vector3( 0, 0, 1 ); return function ( distance ) { return this.translateOnAxis( v1, distance ); }; }(), localToWorld: function ( vector ) { return vector.applyMatrix4( this.matrixWorld ); }, worldToLocal: function () { var m1 = new THREE.Matrix4(); return function ( vector ) { return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); }; }(), lookAt: function () { // This routine does not support objects with rotated and/or translated parent(s) var m1 = new THREE.Matrix4(); return function ( vector ) { m1.lookAt( vector, this.position, this.up ); this.quaternion.setFromRotationMatrix( m1 ); }; }(), add: function ( object ) { if ( arguments.length > 1 ) { for ( var i = 0; i < arguments.length; i ++ ) { this.add( arguments[ i ] ); } return this; } if ( object === this ) { console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); return this; } if ( object instanceof THREE.Object3D ) { if ( object.parent !== null ) { object.parent.remove( object ); } object.parent = this; object.dispatchEvent( { type: 'added' } ); this.children.push( object ); } else { console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); } return this; }, remove: function ( object ) { if ( arguments.length > 1 ) { for ( var i = 0; i < arguments.length; i ++ ) { this.remove( arguments[ i ] ); } } var index = this.children.indexOf( object ); if ( index !== - 1 ) { object.parent = null; object.dispatchEvent( { type: 'removed' } ); this.children.splice( index, 1 ); } }, getChildByName: function ( name ) { console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); return this.getObjectByName( name ); }, getObjectById: function ( id ) { return this.getObjectByProperty( 'id', id ); }, getObjectByName: function ( name ) { return this.getObjectByProperty( 'name', name ); }, getObjectByProperty: function ( name, value ) { if ( this[ name ] === value ) return this; for ( var i = 0, l = this.children.length; i < l; i ++ ) { var child = this.children[ i ]; var object = child.getObjectByProperty( name, value ); if ( object !== undefined ) { return object; } } return undefined; }, getWorldPosition: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); this.updateMatrixWorld( true ); return result.setFromMatrixPosition( this.matrixWorld ); }, getWorldQuaternion: function () { var position = new THREE.Vector3(); var scale = new THREE.Vector3(); return function ( optionalTarget ) { var result = optionalTarget || new THREE.Quaternion(); this.updateMatrixWorld( true ); this.matrixWorld.decompose( position, result, scale ); return result; }; }(), getWorldRotation: function () { var quaternion = new THREE.Quaternion(); return function ( optionalTarget ) { var result = optionalTarget || new THREE.Euler(); this.getWorldQuaternion( quaternion ); return result.setFromQuaternion( quaternion, this.rotation.order, false ); }; }(), getWorldScale: function () { var position = new THREE.Vector3(); var quaternion = new THREE.Quaternion(); return function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); this.updateMatrixWorld( true ); this.matrixWorld.decompose( position, quaternion, result ); return result; }; }(), getWorldDirection: function () { var quaternion = new THREE.Quaternion(); return function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); this.getWorldQuaternion( quaternion ); return result.set( 0, 0, 1 ).applyQuaternion( quaternion ); }; }(), raycast: function () {}, traverse: function ( callback ) { callback( this ); var children = this.children; for ( var i = 0, l = children.length; i < l; i ++ ) { children[ i ].traverse( callback ); } }, traverseVisible: function ( callback ) { if ( this.visible === false ) return; callback( this ); var children = this.children; for ( var i = 0, l = children.length; i < l; i ++ ) { children[ i ].traverseVisible( callback ); } }, traverseAncestors: function ( callback ) { var parent = this.parent; if ( parent !== null ) { callback( parent ); parent.traverseAncestors( callback ); } }, updateMatrix: function () { this.matrix.compose( this.position, this.quaternion, this.scale ); this.matrixWorldNeedsUpdate = true; }, updateMatrixWorld: function ( force ) { if ( this.matrixAutoUpdate === true ) this.updateMatrix(); if ( this.matrixWorldNeedsUpdate === true || force === true ) { if ( this.parent === null ) { this.matrixWorld.copy( this.matrix ); } else { this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); } this.matrixWorldNeedsUpdate = false; force = true; } // update children for ( var i = 0, l = this.children.length; i < l; i ++ ) { this.children[ i ].updateMatrixWorld( force ); } }, toJSON: function ( meta ) { var isRootObject = ( meta === undefined ); var output = {}; // meta is a hash used to collect geometries, materials. // not providing it implies that this is the root object // being serialized. if ( isRootObject ) { // initialize meta obj meta = { geometries: {}, materials: {}, textures: {}, images: {} }; output.metadata = { version: 4.4, type: 'Object', generator: 'Object3D.toJSON' }; } // standard Object3D serialization var object = {}; object.uuid = this.uuid; object.type = this.type; if ( this.name !== '' ) object.name = this.name; if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; if ( this.castShadow === true ) object.castShadow = true; if ( this.receiveShadow === true ) object.receiveShadow = true; if ( this.visible === false ) object.visible = false; object.matrix = this.matrix.toArray(); // if ( this.geometry !== undefined ) { if ( meta.geometries[ this.geometry.uuid ] === undefined ) { meta.geometries[ this.geometry.uuid ] = this.geometry.toJSON( meta ); } object.geometry = this.geometry.uuid; } if ( this.material !== undefined ) { if ( meta.materials[ this.material.uuid ] === undefined ) { meta.materials[ this.material.uuid ] = this.material.toJSON( meta ); } object.material = this.material.uuid; } // if ( this.children.length > 0 ) { object.children = []; for ( var i = 0; i < this.children.length; i ++ ) { object.children.push( this.children[ i ].toJSON( meta ).object ); } } if ( isRootObject ) { var geometries = extractFromCache( meta.geometries ); var materials = extractFromCache( meta.materials ); var textures = extractFromCache( meta.textures ); var images = extractFromCache( meta.images ); if ( geometries.length > 0 ) output.geometries = geometries; if ( materials.length > 0 ) output.materials = materials; if ( textures.length > 0 ) output.textures = textures; if ( images.length > 0 ) output.images = images; } output.object = object; return output; // extract data from the cache hash // remove metadata on each item // and return as array function extractFromCache ( cache ) { var values = []; for ( var key in cache ) { var data = cache[ key ]; delete data.metadata; values.push( data ); } return values; } }, clone: function ( recursive ) { return new this.constructor().copy( this, recursive ); }, copy: function ( source, recursive ) { if ( recursive === undefined ) recursive = true; this.name = source.name; this.up.copy( source.up ); this.position.copy( source.position ); this.quaternion.copy( source.quaternion ); this.scale.copy( source.scale ); this.rotationAutoUpdate = source.rotationAutoUpdate; this.matrix.copy( source.matrix ); this.matrixWorld.copy( source.matrixWorld ); this.matrixAutoUpdate = source.matrixAutoUpdate; this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; this.visible = source.visible; this.castShadow = source.castShadow; this.receiveShadow = source.receiveShadow; this.frustumCulled = source.frustumCulled; this.renderOrder = source.renderOrder; this.userData = JSON.parse( JSON.stringify( source.userData ) ); if ( recursive === true ) { for ( var i = 0; i < source.children.length; i ++ ) { var child = source.children[ i ]; this.add( child.clone() ); } } return this; } }; THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); THREE.Object3DIdCount = 0; three.js-r73/src/core/InstancedBufferAttribute.js0000644000175500017550000000117512610076566021763 0ustar debacledebacle/** * @author benaadams / https://twitter.com/ben_a_adams */ THREE.InstancedBufferAttribute = function ( array, itemSize, meshPerAttribute ) { THREE.BufferAttribute.call( this, array, itemSize ); this.meshPerAttribute = meshPerAttribute || 1; }; THREE.InstancedBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); THREE.InstancedBufferAttribute.prototype.constructor = THREE.InstancedBufferAttribute; THREE.InstancedBufferAttribute.prototype.copy = function ( source ) { THREE.BufferAttribute.prototype.copy.call( this, source ); this.meshPerAttribute = source.meshPerAttribute; return this; }; three.js-r73/src/core/EventDispatcher.js0000644000175500017550000000364712610076566020133 0ustar debacledebacle/** * https://github.com/mrdoob/eventdispatcher.js/ */ THREE.EventDispatcher = function () {}; THREE.EventDispatcher.prototype = { constructor: THREE.EventDispatcher, apply: function ( object ) { object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; }, addEventListener: function ( type, listener ) { if ( this._listeners === undefined ) this._listeners = {}; var listeners = this._listeners; if ( listeners[ type ] === undefined ) { listeners[ type ] = []; } if ( listeners[ type ].indexOf( listener ) === - 1 ) { listeners[ type ].push( listener ); } }, hasEventListener: function ( type, listener ) { if ( this._listeners === undefined ) return false; var listeners = this._listeners; if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { return true; } return false; }, removeEventListener: function ( type, listener ) { if ( this._listeners === undefined ) return; var listeners = this._listeners; var listenerArray = listeners[ type ]; if ( listenerArray !== undefined ) { var index = listenerArray.indexOf( listener ); if ( index !== - 1 ) { listenerArray.splice( index, 1 ); } } }, dispatchEvent: function ( event ) { if ( this._listeners === undefined ) return; var listeners = this._listeners; var listenerArray = listeners[ event.type ]; if ( listenerArray !== undefined ) { event.target = this; var array = []; var length = listenerArray.length; for ( var i = 0; i < length; i ++ ) { array[ i ] = listenerArray[ i ]; } for ( var i = 0; i < length; i ++ ) { array[ i ].call( this, event ); } } } }; three.js-r73/src/core/Face3.js0000644000175500017550000000225512610076566015756 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { this.a = a; this.b = b; this.c = c; this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); this.vertexNormals = Array.isArray( normal ) ? normal : []; this.color = color instanceof THREE.Color ? color : new THREE.Color(); this.vertexColors = Array.isArray( color ) ? color : []; this.materialIndex = materialIndex !== undefined ? materialIndex : 0; }; THREE.Face3.prototype = { constructor: THREE.Face3, clone: function () { return new this.constructor().copy( this ); }, copy: function ( source ) { this.a = source.a; this.b = source.b; this.c = source.c; this.normal.copy( source.normal ); this.color.copy( source.color ); this.materialIndex = source.materialIndex; for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); } for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { this.vertexColors[ i ] = source.vertexColors[ i ].clone(); } return this; } }; three.js-r73/src/core/Channels.js0000644000175500017550000000066712610076566016575 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Channels = function () { this.mask = 1; }; THREE.Channels.prototype = { constructor: THREE.Channels, set: function ( channel ) { this.mask = 1 << channel; }, enable: function ( channel ) { this.mask |= 1 << channel; }, toggle: function ( channel ) { this.mask ^= 1 << channel; }, disable: function ( channel ) { this.mask &= ~ ( 1 << channel ); } }; three.js-r73/src/core/InstancedBufferGeometry.js0000644000175500017550000000225112610076566021607 0ustar debacledebacle/** * @author benaadams / https://twitter.com/ben_a_adams */ THREE.InstancedBufferGeometry = function () { THREE.BufferGeometry.call( this ); this.type = 'InstancedBufferGeometry'; this.maxInstancedCount = undefined; }; THREE.InstancedBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); THREE.InstancedBufferGeometry.prototype.constructor = THREE.InstancedBufferGeometry; THREE.InstancedBufferGeometry.prototype.addGroup = function ( start, count, instances ) { this.groups.push( { start: start, count: count, instances: instances } ); }; THREE.InstancedBufferGeometry.prototype.copy = function ( source ) { var index = source.index; if ( index !== null ) { this.setIndex( index.clone() ); } var attributes = source.attributes; for ( var name in attributes ) { var attribute = attributes[ name ]; this.addAttribute( name, attribute.clone() ); } var groups = source.groups; for ( var i = 0, l = groups.length; i < l; i ++ ) { var group = groups[ i ]; this.addGroup( group.start, group.count, group.instances ); } return this; }; THREE.EventDispatcher.prototype.apply( THREE.InstancedBufferGeometry.prototype ); three.js-r73/src/core/InterleavedBufferAttribute.js0000644000175500017550000000417312610076566022316 0ustar debacledebacle/** * @author benaadams / https://twitter.com/ben_a_adams */ THREE.InterleavedBufferAttribute = function ( interleavedBuffer, itemSize, offset ) { this.uuid = THREE.Math.generateUUID(); this.data = interleavedBuffer; this.itemSize = itemSize; this.offset = offset; }; THREE.InterleavedBufferAttribute.prototype = { constructor: THREE.InterleavedBufferAttribute, get length() { console.warn( 'THREE.BufferAttribute: .length has been deprecated. Please use .count.' ); return this.array.length; }, get count() { return this.data.array.length / this.data.stride; }, setX: function ( index, x ) { this.data.array[ index * this.data.stride + this.offset ] = x; return this; }, setY: function ( index, y ) { this.data.array[ index * this.data.stride + this.offset + 1 ] = y; return this; }, setZ: function ( index, z ) { this.data.array[ index * this.data.stride + this.offset + 2 ] = z; return this; }, setW: function ( index, w ) { this.data.array[ index * this.data.stride + this.offset + 3 ] = w; return this; }, getX: function ( index ) { return this.data.array[ index * this.data.stride + this.offset ]; }, getY: function ( index ) { return this.data.array[ index * this.data.stride + this.offset + 1 ]; }, getZ: function ( index ) { return this.data.array[ index * this.data.stride + this.offset + 2 ]; }, getW: function ( index ) { return this.data.array[ index * this.data.stride + this.offset + 3 ]; }, setXY: function ( index, x, y ) { index = index * this.data.stride + this.offset; this.data.array[ index + 0 ] = x; this.data.array[ index + 1 ] = y; return this; }, setXYZ: function ( index, x, y, z ) { index = index * this.data.stride + this.offset; this.data.array[ index + 0 ] = x; this.data.array[ index + 1 ] = y; this.data.array[ index + 2 ] = z; return this; }, setXYZW: function ( index, x, y, z, w ) { index = index * this.data.stride + this.offset; this.data.array[ index + 0 ] = x; this.data.array[ index + 1 ] = y; this.data.array[ index + 2 ] = z; this.data.array[ index + 3 ] = w; return this; } }; three.js-r73/src/core/DirectGeometry.js0000644000175500017550000001314712610076566017765 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.DirectGeometry = function () { Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); this.uuid = THREE.Math.generateUUID(); this.name = ''; this.type = 'DirectGeometry'; this.indices = []; this.vertices = []; this.normals = []; this.colors = []; this.uvs = []; this.uvs2 = []; this.groups = []; this.morphTargets = {}; this.skinWeights = []; this.skinIndices = []; // this.lineDistances = []; this.boundingBox = null; this.boundingSphere = null; // update flags this.verticesNeedUpdate = false; this.normalsNeedUpdate = false; this.colorsNeedUpdate = false; this.uvsNeedUpdate = false; this.groupsNeedUpdate = false; }; THREE.DirectGeometry.prototype = { constructor: THREE.DirectGeometry, computeBoundingBox: THREE.Geometry.prototype.computeBoundingBox, computeBoundingSphere: THREE.Geometry.prototype.computeBoundingSphere, computeFaceNormals: function () { console.warn( 'THREE.DirectGeometry: computeFaceNormals() is not a method of this type of geometry.' ); }, computeVertexNormals: function () { console.warn( 'THREE.DirectGeometry: computeVertexNormals() is not a method of this type of geometry.' ); }, computeGroups: function ( geometry ) { var group; var groups = []; var materialIndex; var faces = geometry.faces; for ( var i = 0; i < faces.length; i ++ ) { var face = faces[ i ]; // materials if ( face.materialIndex !== materialIndex ) { materialIndex = face.materialIndex; if ( group !== undefined ) { group.count = ( i * 3 ) - group.start; groups.push( group ); } group = { start: i * 3, materialIndex: materialIndex }; } } if ( group !== undefined ) { group.count = ( i * 3 ) - group.start; groups.push( group ); } this.groups = groups; }, fromGeometry: function ( geometry ) { var faces = geometry.faces; var vertices = geometry.vertices; var faceVertexUvs = geometry.faceVertexUvs; var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; // morphs var morphTargets = geometry.morphTargets; var morphTargetsLength = morphTargets.length; if ( morphTargetsLength > 0 ) { var morphTargetsPosition = []; for ( var i = 0; i < morphTargetsLength; i ++ ) { morphTargetsPosition[ i ] = []; } this.morphTargets.position = morphTargetsPosition; } var morphNormals = geometry.morphNormals; var morphNormalsLength = morphNormals.length; if ( morphNormalsLength > 0 ) { var morphTargetsNormal = []; for ( var i = 0; i < morphNormalsLength; i ++ ) { morphTargetsNormal[ i ] = []; } this.morphTargets.normal = morphTargetsNormal; } // skins var skinIndices = geometry.skinIndices; var skinWeights = geometry.skinWeights; var hasSkinIndices = skinIndices.length === vertices.length; var hasSkinWeights = skinWeights.length === vertices.length; // for ( var i = 0; i < faces.length; i ++ ) { var face = faces[ i ]; this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); var vertexNormals = face.vertexNormals; if ( vertexNormals.length === 3 ) { this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); } else { var normal = face.normal; this.normals.push( normal, normal, normal ); } var vertexColors = face.vertexColors; if ( vertexColors.length === 3 ) { this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); } else { var color = face.color; this.colors.push( color, color, color ); } if ( hasFaceVertexUv === true ) { var vertexUvs = faceVertexUvs[ 0 ][ i ]; if ( vertexUvs !== undefined ) { this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); } else { console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); this.uvs.push( new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ); } } if ( hasFaceVertexUv2 === true ) { var vertexUvs = faceVertexUvs[ 1 ][ i ]; if ( vertexUvs !== undefined ) { this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); } else { console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); this.uvs2.push( new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ); } } // morphs for ( var j = 0; j < morphTargetsLength; j ++ ) { var morphTarget = morphTargets[ j ].vertices; morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); } for ( var j = 0; j < morphNormalsLength; j ++ ) { var morphNormal = morphNormals[ j ].vertexNormals[ i ]; morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c ); } // skins if ( hasSkinIndices ) { this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); } if ( hasSkinWeights ) { this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); } } this.computeGroups( geometry ); this.verticesNeedUpdate = geometry.verticesNeedUpdate; this.normalsNeedUpdate = geometry.normalsNeedUpdate; this.colorsNeedUpdate = geometry.colorsNeedUpdate; this.uvsNeedUpdate = geometry.uvsNeedUpdate; this.groupsNeedUpdate = geometry.groupsNeedUpdate; return this; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.DirectGeometry.prototype ); three.js-r73/src/core/BufferGeometry.js0000644000175500017550000004563712610076566017775 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.BufferGeometry = function () { Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); this.uuid = THREE.Math.generateUUID(); this.name = ''; this.type = 'BufferGeometry'; this.index = null; this.attributes = {}; this.morphAttributes = {}; this.groups = []; this.boundingBox = null; this.boundingSphere = null; this.drawRange = { start: 0, count: Infinity }; }; THREE.BufferGeometry.prototype = { constructor: THREE.BufferGeometry, addIndex: function ( index ) { console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); this.setIndex( index ); }, getIndex: function () { return this.index; }, setIndex: function ( index ) { this.index = index; }, addAttribute: function ( name, attribute ) { if ( attribute instanceof THREE.BufferAttribute === false && attribute instanceof THREE.InterleavedBufferAttribute === false ) { console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); this.addAttribute( name, new THREE.BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); return; } if ( name === 'index' ) { console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); this.setIndex( attribute ); return; } this.attributes[ name ] = attribute; }, getAttribute: function ( name ) { return this.attributes[ name ]; }, removeAttribute: function ( name ) { delete this.attributes[ name ]; }, get drawcalls() { console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); return this.groups; }, get offsets() { console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); return this.groups; }, addDrawCall: function ( start, count, indexOffset ) { if ( indexOffset !== undefined ) { console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); } console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); this.addGroup( start, count ); }, clearDrawCalls: function () { console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); this.clearGroups(); }, addGroup: function ( start, count, materialIndex ) { this.groups.push( { start: start, count: count, materialIndex: materialIndex !== undefined ? materialIndex : 0 } ); }, clearGroups: function () { this.groups = []; }, setDrawRange: function ( start, count ) { this.drawRange.start = start; this.drawRange.count = count; }, applyMatrix: function ( matrix ) { var position = this.attributes.position; if ( position !== undefined ) { matrix.applyToVector3Array( position.array ); position.needsUpdate = true; } var normal = this.attributes.normal; if ( normal !== undefined ) { var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); normalMatrix.applyToVector3Array( normal.array ); normal.needsUpdate = true; } if ( this.boundingBox !== null ) { this.computeBoundingBox(); } if ( this.boundingSphere !== null ) { this.computeBoundingSphere(); } }, rotateX: function () { // rotate geometry around world x-axis var m1; return function rotateX( angle ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeRotationX( angle ); this.applyMatrix( m1 ); return this; }; }(), rotateY: function () { // rotate geometry around world y-axis var m1; return function rotateY( angle ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeRotationY( angle ); this.applyMatrix( m1 ); return this; }; }(), rotateZ: function () { // rotate geometry around world z-axis var m1; return function rotateZ( angle ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeRotationZ( angle ); this.applyMatrix( m1 ); return this; }; }(), translate: function () { // translate geometry var m1; return function translate( x, y, z ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeTranslation( x, y, z ); this.applyMatrix( m1 ); return this; }; }(), scale: function () { // scale geometry var m1; return function scale( x, y, z ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeScale( x, y, z ); this.applyMatrix( m1 ); return this; }; }(), lookAt: function () { var obj; return function lookAt( vector ) { if ( obj === undefined ) obj = new THREE.Object3D(); obj.lookAt( vector ); obj.updateMatrix(); this.applyMatrix( obj.matrix ); }; }(), center: function () { this.computeBoundingBox(); var offset = this.boundingBox.center().negate(); this.translate( offset.x, offset.y, offset.z ); return offset; }, setFromObject: function ( object ) { // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); var geometry = object.geometry; if ( object instanceof THREE.Points || object instanceof THREE.Line ) { var positions = new THREE.Float32Attribute( geometry.vertices.length * 3, 3 ); var colors = new THREE.Float32Attribute( geometry.colors.length * 3, 3 ); this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { var lineDistances = new THREE.Float32Attribute( geometry.lineDistances.length, 1 ); this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); } if ( geometry.boundingSphere !== null ) { this.boundingSphere = geometry.boundingSphere.clone(); } if ( geometry.boundingBox !== null ) { this.boundingBox = geometry.boundingBox.clone(); } } else if ( object instanceof THREE.Mesh ) { if ( geometry instanceof THREE.Geometry ) { this.fromGeometry( geometry ); } } return this; }, updateFromObject: function ( object ) { var geometry = object.geometry; if ( object instanceof THREE.Mesh ) { var direct = geometry.__directGeometry; if ( direct === undefined ) { return this.fromGeometry( geometry ); } direct.verticesNeedUpdate = geometry.verticesNeedUpdate; direct.normalsNeedUpdate = geometry.normalsNeedUpdate; direct.colorsNeedUpdate = geometry.colorsNeedUpdate; direct.uvsNeedUpdate = geometry.uvsNeedUpdate; direct.groupsNeedUpdate = geometry.groupsNeedUpdate; geometry.verticesNeedUpdate = false; geometry.normalsNeedUpdate = false; geometry.colorsNeedUpdate = false; geometry.uvsNeedUpdate = false; geometry.groupsNeedUpdate = false; geometry = direct; } if ( geometry.verticesNeedUpdate === true ) { var attribute = this.attributes.position; if ( attribute !== undefined ) { attribute.copyVector3sArray( geometry.vertices ); attribute.needsUpdate = true; } geometry.verticesNeedUpdate = false; } if ( geometry.normalsNeedUpdate === true ) { var attribute = this.attributes.normal; if ( attribute !== undefined ) { attribute.copyVector3sArray( geometry.normals ); attribute.needsUpdate = true; } geometry.normalsNeedUpdate = false; } if ( geometry.colorsNeedUpdate === true ) { var attribute = this.attributes.color; if ( attribute !== undefined ) { attribute.copyColorsArray( geometry.colors ); attribute.needsUpdate = true; } geometry.colorsNeedUpdate = false; } if ( geometry.uvsNeedUpdate ) { var attribute = this.attributes.uv; if ( attribute !== undefined ) { attribute.copyVector2sArray( geometry.uvs ); attribute.needsUpdate = true; } geometry.uvsNeedUpdate = false; } if ( geometry.lineDistancesNeedUpdate ) { var attribute = this.attributes.lineDistance; if ( attribute !== undefined ) { attribute.copyArray( geometry.lineDistances ); attribute.needsUpdate = true; } geometry.lineDistancesNeedUpdate = false; } if ( geometry.groupsNeedUpdate ) { geometry.computeGroups( object.geometry ); this.groups = geometry.groups; geometry.groupsNeedUpdate = false; } return this; }, fromGeometry: function ( geometry ) { geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry ); return this.fromDirectGeometry( geometry.__directGeometry ); }, fromDirectGeometry: function ( geometry ) { var positions = new Float32Array( geometry.vertices.length * 3 ); this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); if ( geometry.normals.length > 0 ) { var normals = new Float32Array( geometry.normals.length * 3 ); this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); } if ( geometry.colors.length > 0 ) { var colors = new Float32Array( geometry.colors.length * 3 ); this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); } if ( geometry.uvs.length > 0 ) { var uvs = new Float32Array( geometry.uvs.length * 2 ); this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); } if ( geometry.uvs2.length > 0 ) { var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); this.addAttribute( 'uv2', new THREE.BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); } if ( geometry.indices.length > 0 ) { var TypeArray = geometry.vertices.length > 65535 ? Uint32Array : Uint16Array; var indices = new TypeArray( geometry.indices.length * 3 ); this.setIndex( new THREE.BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) ); } // groups this.groups = geometry.groups; // morphs for ( var name in geometry.morphTargets ) { var array = []; var morphTargets = geometry.morphTargets[ name ]; for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { var morphTarget = morphTargets[ i ]; var attribute = new THREE.Float32Attribute( morphTarget.length * 3, 3 ); array.push( attribute.copyVector3sArray( morphTarget ) ); } this.morphAttributes[ name ] = array; } // skinning if ( geometry.skinIndices.length > 0 ) { var skinIndices = new THREE.Float32Attribute( geometry.skinIndices.length * 4, 4 ); this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); } if ( geometry.skinWeights.length > 0 ) { var skinWeights = new THREE.Float32Attribute( geometry.skinWeights.length * 4, 4 ); this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); } // if ( geometry.boundingSphere !== null ) { this.boundingSphere = geometry.boundingSphere.clone(); } if ( geometry.boundingBox !== null ) { this.boundingBox = geometry.boundingBox.clone(); } return this; }, computeBoundingBox: function () { var vector = new THREE.Vector3(); return function () { if ( this.boundingBox === null ) { this.boundingBox = new THREE.Box3(); } var positions = this.attributes.position.array; if ( positions ) { var bb = this.boundingBox; bb.makeEmpty(); for ( var i = 0, il = positions.length; i < il; i += 3 ) { vector.fromArray( positions, i ); bb.expandByPoint( vector ); } } if ( positions === undefined || positions.length === 0 ) { this.boundingBox.min.set( 0, 0, 0 ); this.boundingBox.max.set( 0, 0, 0 ); } if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); } }; }(), computeBoundingSphere: function () { var box = new THREE.Box3(); var vector = new THREE.Vector3(); return function () { if ( this.boundingSphere === null ) { this.boundingSphere = new THREE.Sphere(); } var positions = this.attributes.position.array; if ( positions ) { box.makeEmpty(); var center = this.boundingSphere.center; for ( var i = 0, il = positions.length; i < il; i += 3 ) { vector.fromArray( positions, i ); box.expandByPoint( vector ); } box.center( center ); // hoping to find a boundingSphere with a radius smaller than the // boundingSphere of the boundingBox: sqrt(3) smaller in the best case var maxRadiusSq = 0; for ( var i = 0, il = positions.length; i < il; i += 3 ) { vector.fromArray( positions, i ); maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); } this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); if ( isNaN( this.boundingSphere.radius ) ) { console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); } } }; }(), computeFaceNormals: function () { // backwards compatibility }, computeVertexNormals: function () { var index = this.index; var attributes = this.attributes; var groups = this.groups; if ( attributes.position ) { var positions = attributes.position.array; if ( attributes.normal === undefined ) { this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) ); } else { // reset existing normals to zero var normals = attributes.normal.array; for ( var i = 0, il = normals.length; i < il; i ++ ) { normals[ i ] = 0; } } var normals = attributes.normal.array; var vA, vB, vC, pA = new THREE.Vector3(), pB = new THREE.Vector3(), pC = new THREE.Vector3(), cb = new THREE.Vector3(), ab = new THREE.Vector3(); // indexed elements if ( index ) { var indices = index.array; if ( groups.length === 0 ) { this.addGroup( 0, indices.length ); } for ( var j = 0, jl = groups.length; j < jl; ++ j ) { var group = groups[ j ]; var start = group.start; var count = group.count; for ( var i = start, il = start + count; i < il; i += 3 ) { vA = indices[ i + 0 ] * 3; vB = indices[ i + 1 ] * 3; vC = indices[ i + 2 ] * 3; pA.fromArray( positions, vA ); pB.fromArray( positions, vB ); pC.fromArray( positions, vC ); cb.subVectors( pC, pB ); ab.subVectors( pA, pB ); cb.cross( ab ); normals[ vA ] += cb.x; normals[ vA + 1 ] += cb.y; normals[ vA + 2 ] += cb.z; normals[ vB ] += cb.x; normals[ vB + 1 ] += cb.y; normals[ vB + 2 ] += cb.z; normals[ vC ] += cb.x; normals[ vC + 1 ] += cb.y; normals[ vC + 2 ] += cb.z; } } } else { // non-indexed elements (unconnected triangle soup) for ( var i = 0, il = positions.length; i < il; i += 9 ) { pA.fromArray( positions, i ); pB.fromArray( positions, i + 3 ); pC.fromArray( positions, i + 6 ); cb.subVectors( pC, pB ); ab.subVectors( pA, pB ); cb.cross( ab ); normals[ i ] = cb.x; normals[ i + 1 ] = cb.y; normals[ i + 2 ] = cb.z; normals[ i + 3 ] = cb.x; normals[ i + 4 ] = cb.y; normals[ i + 5 ] = cb.z; normals[ i + 6 ] = cb.x; normals[ i + 7 ] = cb.y; normals[ i + 8 ] = cb.z; } } this.normalizeNormals(); attributes.normal.needsUpdate = true; } }, computeTangents: function () { console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); }, computeOffsets: function ( size ) { console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.') }, merge: function ( geometry, offset ) { if ( geometry instanceof THREE.BufferGeometry === false ) { console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); return; } if ( offset === undefined ) offset = 0; var attributes = this.attributes; for ( var key in attributes ) { if ( geometry.attributes[ key ] === undefined ) continue; var attribute1 = attributes[ key ]; var attributeArray1 = attribute1.array; var attribute2 = geometry.attributes[ key ]; var attributeArray2 = attribute2.array; var attributeSize = attribute2.itemSize; for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { attributeArray1[ j ] = attributeArray2[ i ]; } } return this; }, normalizeNormals: function () { var normals = this.attributes.normal.array; var x, y, z, n; for ( var i = 0, il = normals.length; i < il; i += 3 ) { x = normals[ i ]; y = normals[ i + 1 ]; z = normals[ i + 2 ]; n = 1.0 / Math.sqrt( x * x + y * y + z * z ); normals[ i ] *= n; normals[ i + 1 ] *= n; normals[ i + 2 ] *= n; } }, toJSON: function () { var data = { metadata: { version: 4.4, type: 'BufferGeometry', generator: 'BufferGeometry.toJSON' } }; // standard BufferGeometry serialization data.uuid = this.uuid; data.type = this.type; if ( this.name !== '' ) data.name = this.name; if ( this.parameters !== undefined ) { var parameters = this.parameters; for ( var key in parameters ) { if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; } return data; } data.data = { attributes: {} }; var index = this.index; if ( index !== null ) { var array = Array.prototype.slice.call( index.array ); data.data.index = { type: index.array.constructor.name, array: array }; } var attributes = this.attributes; for ( var key in attributes ) { var attribute = attributes[ key ]; var array = Array.prototype.slice.call( attribute.array ); data.data.attributes[ key ] = { itemSize: attribute.itemSize, type: attribute.array.constructor.name, array: array }; } var groups = this.groups; if ( groups.length > 0 ) { data.data.groups = JSON.parse( JSON.stringify( groups ) ); } var boundingSphere = this.boundingSphere; if ( boundingSphere !== null ) { data.data.boundingSphere = { center: boundingSphere.center.toArray(), radius: boundingSphere.radius }; } return data; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( source ) { var index = source.index; if ( index !== null ) { this.setIndex( index.clone() ); } var attributes = source.attributes; for ( var name in attributes ) { var attribute = attributes[ name ]; this.addAttribute( name, attribute.clone() ); } var groups = source.groups; for ( var i = 0, l = groups.length; i < l; i ++ ) { var group = groups[ i ]; this.addGroup( group.start, group.count ); } return this; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); THREE.BufferGeometry.MaxIndex = 65535; three.js-r73/src/core/Face4.js0000644000175500017550000000042612610076566015755 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); return new THREE.Face3( a, b, c, normal, color, materialIndex ); }; three.js-r73/src/core/Geometry.js0000644000175500017550000005457012610076566016637 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author kile / http://kile.stravaganza.org/ * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author zz85 / http://www.lab4games.net/zz85/blog * @author bhouston / http://clara.io */ THREE.Geometry = function () { Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } ); this.uuid = THREE.Math.generateUUID(); this.name = ''; this.type = 'Geometry'; this.vertices = []; this.colors = []; this.faces = []; this.faceVertexUvs = [ [] ]; this.morphTargets = []; this.morphNormals = []; this.skinWeights = []; this.skinIndices = []; this.lineDistances = []; this.boundingBox = null; this.boundingSphere = null; // update flags this.verticesNeedUpdate = false; this.elementsNeedUpdate = false; this.uvsNeedUpdate = false; this.normalsNeedUpdate = false; this.colorsNeedUpdate = false; this.lineDistancesNeedUpdate = false; this.groupsNeedUpdate = false; }; THREE.Geometry.prototype = { constructor: THREE.Geometry, applyMatrix: function ( matrix ) { var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { var vertex = this.vertices[ i ]; vertex.applyMatrix4( matrix ); } for ( var i = 0, il = this.faces.length; i < il; i ++ ) { var face = this.faces[ i ]; face.normal.applyMatrix3( normalMatrix ).normalize(); for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); } } if ( this.boundingBox !== null ) { this.computeBoundingBox(); } if ( this.boundingSphere !== null ) { this.computeBoundingSphere(); } this.verticesNeedUpdate = true; this.normalsNeedUpdate = true; }, rotateX: function () { // rotate geometry around world x-axis var m1; return function rotateX( angle ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeRotationX( angle ); this.applyMatrix( m1 ); return this; }; }(), rotateY: function () { // rotate geometry around world y-axis var m1; return function rotateY( angle ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeRotationY( angle ); this.applyMatrix( m1 ); return this; }; }(), rotateZ: function () { // rotate geometry around world z-axis var m1; return function rotateZ( angle ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeRotationZ( angle ); this.applyMatrix( m1 ); return this; }; }(), translate: function () { // translate geometry var m1; return function translate( x, y, z ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeTranslation( x, y, z ); this.applyMatrix( m1 ); return this; }; }(), scale: function () { // scale geometry var m1; return function scale( x, y, z ) { if ( m1 === undefined ) m1 = new THREE.Matrix4(); m1.makeScale( x, y, z ); this.applyMatrix( m1 ); return this; }; }(), lookAt: function () { var obj; return function lookAt( vector ) { if ( obj === undefined ) obj = new THREE.Object3D(); obj.lookAt( vector ); obj.updateMatrix(); this.applyMatrix( obj.matrix ); }; }(), fromBufferGeometry: function ( geometry ) { var scope = this; var indices = geometry.index !== null ? geometry.index.array : undefined; var attributes = geometry.attributes; var vertices = attributes.position.array; var normals = attributes.normal !== undefined ? attributes.normal.array : undefined; var colors = attributes.color !== undefined ? attributes.color.array : undefined; var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined; var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined; if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; var tempNormals = []; var tempUVs = []; var tempUVs2 = []; for ( var i = 0, j = 0, k = 0; i < vertices.length; i += 3, j += 2, k += 4 ) { scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) ); if ( normals !== undefined ) { tempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) ); } if ( colors !== undefined ) { scope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) ); } if ( uvs !== undefined ) { tempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) ); } if ( uvs2 !== undefined ) { tempUVs2.push( new THREE.Vector2( uvs2[ j ], uvs2[ j + 1 ] ) ); } } function addFace( a, b, c ) { var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : []; var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : []; var face = new THREE.Face3( a, b, c, vertexNormals, vertexColors ); scope.faces.push( face ); if ( uvs !== undefined ) { scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] ); } if ( uvs2 !== undefined ) { scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] ); } }; if ( indices !== undefined ) { var groups = geometry.groups; if ( groups.length > 0 ) { for ( var i = 0; i < groups.length; i ++ ) { var group = groups[ i ]; var start = group.start; var count = group.count; for ( var j = start, jl = start + count; j < jl; j += 3 ) { addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ] ); } } } else { for ( var i = 0; i < indices.length; i += 3 ) { addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); } } } else { for ( var i = 0; i < vertices.length / 3; i += 3 ) { addFace( i, i + 1, i + 2 ); } } this.computeFaceNormals(); if ( geometry.boundingBox !== null ) { this.boundingBox = geometry.boundingBox.clone(); } if ( geometry.boundingSphere !== null ) { this.boundingSphere = geometry.boundingSphere.clone(); } return this; }, center: function () { this.computeBoundingBox(); var offset = this.boundingBox.center().negate(); this.translate( offset.x, offset.y, offset.z ); return offset; }, normalize: function () { this.computeBoundingSphere(); var center = this.boundingSphere.center; var radius = this.boundingSphere.radius; var s = radius === 0 ? 1 : 1.0 / radius; var matrix = new THREE.Matrix4(); matrix.set( s, 0, 0, - s * center.x, 0, s, 0, - s * center.y, 0, 0, s, - s * center.z, 0, 0, 0, 1 ); this.applyMatrix( matrix ); return this; }, computeFaceNormals: function () { var cb = new THREE.Vector3(), ab = new THREE.Vector3(); for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { var face = this.faces[ f ]; var vA = this.vertices[ face.a ]; var vB = this.vertices[ face.b ]; var vC = this.vertices[ face.c ]; cb.subVectors( vC, vB ); ab.subVectors( vA, vB ); cb.cross( ab ); cb.normalize(); face.normal.copy( cb ); } }, computeVertexNormals: function ( areaWeighted ) { var v, vl, f, fl, face, vertices; vertices = new Array( this.vertices.length ); for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { vertices[ v ] = new THREE.Vector3(); } if ( areaWeighted ) { // vertex normals weighted by triangle areas // http://www.iquilezles.org/www/articles/normals/normals.htm var vA, vB, vC; var cb = new THREE.Vector3(), ab = new THREE.Vector3(); for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; vA = this.vertices[ face.a ]; vB = this.vertices[ face.b ]; vC = this.vertices[ face.c ]; cb.subVectors( vC, vB ); ab.subVectors( vA, vB ); cb.cross( ab ); vertices[ face.a ].add( cb ); vertices[ face.b ].add( cb ); vertices[ face.c ].add( cb ); } } else { for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; vertices[ face.a ].add( face.normal ); vertices[ face.b ].add( face.normal ); vertices[ face.c ].add( face.normal ); } } for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { vertices[ v ].normalize(); } for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; var vertexNormals = face.vertexNormals; if ( vertexNormals.length === 3 ) { vertexNormals[ 0 ].copy( vertices[ face.a ] ); vertexNormals[ 1 ].copy( vertices[ face.b ] ); vertexNormals[ 2 ].copy( vertices[ face.c ] ); } else { vertexNormals[ 0 ] = vertices[ face.a ].clone(); vertexNormals[ 1 ] = vertices[ face.b ].clone(); vertexNormals[ 2 ] = vertices[ face.c ].clone(); } } }, computeMorphNormals: function () { var i, il, f, fl, face; // save original normals // - create temp variables on first access // otherwise just copy (for faster repeated calls) for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; if ( ! face.__originalFaceNormal ) { face.__originalFaceNormal = face.normal.clone(); } else { face.__originalFaceNormal.copy( face.normal ); } if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { if ( ! face.__originalVertexNormals[ i ] ) { face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); } else { face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); } } } // use temp geometry to compute face and vertex normals for each morph var tmpGeo = new THREE.Geometry(); tmpGeo.faces = this.faces; for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { // create on first access if ( ! this.morphNormals[ i ] ) { this.morphNormals[ i ] = {}; this.morphNormals[ i ].faceNormals = []; this.morphNormals[ i ].vertexNormals = []; var dstNormalsFace = this.morphNormals[ i ].faceNormals; var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; var faceNormal, vertexNormals; for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { faceNormal = new THREE.Vector3(); vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; dstNormalsFace.push( faceNormal ); dstNormalsVertex.push( vertexNormals ); } } var morphNormals = this.morphNormals[ i ]; // set vertices to morph target tmpGeo.vertices = this.morphTargets[ i ].vertices; // compute morph normals tmpGeo.computeFaceNormals(); tmpGeo.computeVertexNormals(); // store morph normals var faceNormal, vertexNormals; for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; faceNormal = morphNormals.faceNormals[ f ]; vertexNormals = morphNormals.vertexNormals[ f ]; faceNormal.copy( face.normal ); vertexNormals.a.copy( face.vertexNormals[ 0 ] ); vertexNormals.b.copy( face.vertexNormals[ 1 ] ); vertexNormals.c.copy( face.vertexNormals[ 2 ] ); } } // restore original normals for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; face.normal = face.__originalFaceNormal; face.vertexNormals = face.__originalVertexNormals; } }, computeTangents: function () { console.warn( 'THREE.Geometry: .computeTangents() has been removed.' ); }, computeLineDistances: function () { var d = 0; var vertices = this.vertices; for ( var i = 0, il = vertices.length; i < il; i ++ ) { if ( i > 0 ) { d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); } this.lineDistances[ i ] = d; } }, computeBoundingBox: function () { if ( this.boundingBox === null ) { this.boundingBox = new THREE.Box3(); } this.boundingBox.setFromPoints( this.vertices ); }, computeBoundingSphere: function () { if ( this.boundingSphere === null ) { this.boundingSphere = new THREE.Sphere(); } this.boundingSphere.setFromPoints( this.vertices ); }, merge: function ( geometry, matrix, materialIndexOffset ) { if ( geometry instanceof THREE.Geometry === false ) { console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); return; } var normalMatrix, vertexOffset = this.vertices.length, vertices1 = this.vertices, vertices2 = geometry.vertices, faces1 = this.faces, faces2 = geometry.faces, uvs1 = this.faceVertexUvs[ 0 ], uvs2 = geometry.faceVertexUvs[ 0 ]; if ( materialIndexOffset === undefined ) materialIndexOffset = 0; if ( matrix !== undefined ) { normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); } // vertices for ( var i = 0, il = vertices2.length; i < il; i ++ ) { var vertex = vertices2[ i ]; var vertexCopy = vertex.clone(); if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); vertices1.push( vertexCopy ); } // faces for ( i = 0, il = faces2.length; i < il; i ++ ) { var face = faces2[ i ], faceCopy, normal, color, faceVertexNormals = face.vertexNormals, faceVertexColors = face.vertexColors; faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); faceCopy.normal.copy( face.normal ); if ( normalMatrix !== undefined ) { faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); } for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { normal = faceVertexNormals[ j ].clone(); if ( normalMatrix !== undefined ) { normal.applyMatrix3( normalMatrix ).normalize(); } faceCopy.vertexNormals.push( normal ); } faceCopy.color.copy( face.color ); for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { color = faceVertexColors[ j ]; faceCopy.vertexColors.push( color.clone() ); } faceCopy.materialIndex = face.materialIndex + materialIndexOffset; faces1.push( faceCopy ); } // uvs for ( i = 0, il = uvs2.length; i < il; i ++ ) { var uv = uvs2[ i ], uvCopy = []; if ( uv === undefined ) { continue; } for ( var j = 0, jl = uv.length; j < jl; j ++ ) { uvCopy.push( uv[ j ].clone() ); } uvs1.push( uvCopy ); } }, mergeMesh: function ( mesh ) { if ( mesh instanceof THREE.Mesh === false ) { console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); return; } mesh.matrixAutoUpdate && mesh.updateMatrix(); this.merge( mesh.geometry, mesh.matrix ); }, /* * Checks for duplicate vertices with hashmap. * Duplicated vertices are removed * and faces' vertices are updated. */ mergeVertices: function () { var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) var unique = [], changes = []; var v, key; var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001 var precision = Math.pow( 10, precisionPoints ); var i, il, face; var indices, j, jl; for ( i = 0, il = this.vertices.length; i < il; i ++ ) { v = this.vertices[ i ]; key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); if ( verticesMap[ key ] === undefined ) { verticesMap[ key ] = i; unique.push( this.vertices[ i ] ); changes[ i ] = unique.length - 1; } else { //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); changes[ i ] = changes[ verticesMap[ key ] ]; } } // if faces are completely degenerate after merging vertices, we // have to remove them from the geometry. var faceIndicesToRemove = []; for ( i = 0, il = this.faces.length; i < il; i ++ ) { face = this.faces[ i ]; face.a = changes[ face.a ]; face.b = changes[ face.b ]; face.c = changes[ face.c ]; indices = [ face.a, face.b, face.c ]; var dupIndex = - 1; // if any duplicate vertices are found in a Face3 // we have to remove the face as nothing can be saved for ( var n = 0; n < 3; n ++ ) { if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { dupIndex = n; faceIndicesToRemove.push( i ); break; } } } for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { var idx = faceIndicesToRemove[ i ]; this.faces.splice( idx, 1 ); for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { this.faceVertexUvs[ j ].splice( idx, 1 ); } } // Use unique set of vertices var diff = this.vertices.length - unique.length; this.vertices = unique; return diff; }, sortFacesByMaterialIndex: function () { var faces = this.faces; var length = faces.length; // tag faces for ( var i = 0; i < length; i ++ ) { faces[ i ]._id = i; } // sort faces function materialIndexSort( a, b ) { return a.materialIndex - b.materialIndex; } faces.sort( materialIndexSort ); // sort uvs var uvs1 = this.faceVertexUvs[ 0 ]; var uvs2 = this.faceVertexUvs[ 1 ]; var newUvs1, newUvs2; if ( uvs1 && uvs1.length === length ) newUvs1 = []; if ( uvs2 && uvs2.length === length ) newUvs2 = []; for ( var i = 0; i < length; i ++ ) { var id = faces[ i ]._id; if ( newUvs1 ) newUvs1.push( uvs1[ id ] ); if ( newUvs2 ) newUvs2.push( uvs2[ id ] ); } if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1; if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2; }, toJSON: function () { var data = { metadata: { version: 4.4, type: 'Geometry', generator: 'Geometry.toJSON' } }; // standard Geometry serialization data.uuid = this.uuid; data.type = this.type; if ( this.name !== '' ) data.name = this.name; if ( this.parameters !== undefined ) { var parameters = this.parameters; for ( var key in parameters ) { if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; } return data; } var vertices = []; for ( var i = 0; i < this.vertices.length; i ++ ) { var vertex = this.vertices[ i ]; vertices.push( vertex.x, vertex.y, vertex.z ); } var faces = []; var normals = []; var normalsHash = {}; var colors = []; var colorsHash = {}; var uvs = []; var uvsHash = {}; for ( var i = 0; i < this.faces.length; i ++ ) { var face = this.faces[ i ]; var hasMaterial = false; // face.materialIndex !== undefined; var hasFaceUv = false; // deprecated var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined; var hasFaceNormal = face.normal.length() > 0; var hasFaceVertexNormal = face.vertexNormals.length > 0; var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1; var hasFaceVertexColor = face.vertexColors.length > 0; var faceType = 0; faceType = setBit( faceType, 0, 0 ); faceType = setBit( faceType, 1, hasMaterial ); faceType = setBit( faceType, 2, hasFaceUv ); faceType = setBit( faceType, 3, hasFaceVertexUv ); faceType = setBit( faceType, 4, hasFaceNormal ); faceType = setBit( faceType, 5, hasFaceVertexNormal ); faceType = setBit( faceType, 6, hasFaceColor ); faceType = setBit( faceType, 7, hasFaceVertexColor ); faces.push( faceType ); faces.push( face.a, face.b, face.c ); if ( hasFaceVertexUv ) { var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; faces.push( getUvIndex( faceVertexUvs[ 0 ] ), getUvIndex( faceVertexUvs[ 1 ] ), getUvIndex( faceVertexUvs[ 2 ] ) ); } if ( hasFaceNormal ) { faces.push( getNormalIndex( face.normal ) ); } if ( hasFaceVertexNormal ) { var vertexNormals = face.vertexNormals; faces.push( getNormalIndex( vertexNormals[ 0 ] ), getNormalIndex( vertexNormals[ 1 ] ), getNormalIndex( vertexNormals[ 2 ] ) ); } if ( hasFaceColor ) { faces.push( getColorIndex( face.color ) ); } if ( hasFaceVertexColor ) { var vertexColors = face.vertexColors; faces.push( getColorIndex( vertexColors[ 0 ] ), getColorIndex( vertexColors[ 1 ] ), getColorIndex( vertexColors[ 2 ] ) ); } } function setBit( value, position, enabled ) { return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); } function getNormalIndex( normal ) { var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); if ( normalsHash[ hash ] !== undefined ) { return normalsHash[ hash ]; } normalsHash[ hash ] = normals.length / 3; normals.push( normal.x, normal.y, normal.z ); return normalsHash[ hash ]; } function getColorIndex( color ) { var hash = color.r.toString() + color.g.toString() + color.b.toString(); if ( colorsHash[ hash ] !== undefined ) { return colorsHash[ hash ]; } colorsHash[ hash ] = colors.length; colors.push( color.getHex() ); return colorsHash[ hash ]; } function getUvIndex( uv ) { var hash = uv.x.toString() + uv.y.toString(); if ( uvsHash[ hash ] !== undefined ) { return uvsHash[ hash ]; } uvsHash[ hash ] = uvs.length / 2; uvs.push( uv.x, uv.y ); return uvsHash[ hash ]; } data.data = {}; data.data.vertices = vertices; data.data.normals = normals; if ( colors.length > 0 ) data.data.colors = colors; if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility data.data.faces = faces; return data; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( source ) { this.vertices = []; this.faces = []; this.faceVertexUvs = [ [] ]; var vertices = source.vertices; for ( var i = 0, il = vertices.length; i < il; i ++ ) { this.vertices.push( vertices[ i ].clone() ); } var faces = source.faces; for ( var i = 0, il = faces.length; i < il; i ++ ) { this.faces.push( faces[ i ].clone() ); } for ( var i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { var faceVertexUvs = source.faceVertexUvs[ i ]; if ( this.faceVertexUvs[ i ] === undefined ) { this.faceVertexUvs[ i ] = []; } for ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { var uvs = faceVertexUvs[ j ], uvsCopy = []; for ( var k = 0, kl = uvs.length; k < kl; k ++ ) { var uv = uvs[ k ]; uvsCopy.push( uv.clone() ); } this.faceVertexUvs[ i ].push( uvsCopy ); } } return this; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); THREE.GeometryIdCount = 0; three.js-r73/src/core/Clock.js0000644000175500017550000000161712610076566016071 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.Clock = function ( autoStart ) { this.autoStart = ( autoStart !== undefined ) ? autoStart : true; this.startTime = 0; this.oldTime = 0; this.elapsedTime = 0; this.running = false; }; THREE.Clock.prototype = { constructor: THREE.Clock, start: function () { this.startTime = self.performance.now(); this.oldTime = this.startTime; this.running = true; }, stop: function () { this.getElapsedTime(); this.running = false; }, getElapsedTime: function () { this.getDelta(); return this.elapsedTime; }, getDelta: function () { var diff = 0; if ( this.autoStart && ! this.running ) { this.start(); } if ( this.running ) { var newTime = self.performance.now(); diff = 0.001 * ( newTime - this.oldTime ); this.oldTime = newTime; this.elapsedTime += diff; } return diff; } }; three.js-r73/src/core/InstancedInterleavedBuffer.js0000644000175500017550000000121112610076566022251 0ustar debacledebacle/** * @author benaadams / https://twitter.com/ben_a_adams */ THREE.InstancedInterleavedBuffer = function ( array, stride, meshPerAttribute ) { THREE.InterleavedBuffer.call( this, array, stride ); this.meshPerAttribute = meshPerAttribute || 1; }; THREE.InstancedInterleavedBuffer.prototype = Object.create( THREE.InterleavedBuffer.prototype ); THREE.InstancedInterleavedBuffer.prototype.constructor = THREE.InstancedInterleavedBuffer; THREE.InstancedInterleavedBuffer.prototype.copy = function ( source ) { THREE.InterleavedBuffer.prototype.copy.call( this, source ); this.meshPerAttribute = source.meshPerAttribute; return this; }; three.js-r73/src/core/BufferAttribute.js0000644000175500017550000001434612610076566020136 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.BufferAttribute = function ( array, itemSize ) { this.uuid = THREE.Math.generateUUID(); this.array = array; this.itemSize = itemSize; this.dynamic = false; this.updateRange = { offset: 0, count: - 1 }; this.version = 0; }; THREE.BufferAttribute.prototype = { constructor: THREE.BufferAttribute, get length() { console.warn( 'THREE.BufferAttribute: .length has been deprecated. Please use .count.' ); return this.array.length; }, get count() { return this.array.length / this.itemSize; }, set needsUpdate( value ) { if ( value === true ) this.version ++; }, setDynamic: function ( value ) { this.dynamic = value; return this; }, copy: function ( source ) { this.array = new source.array.constructor( source.array ); this.itemSize = source.itemSize; this.dynamic = source.dynamic; return this; }, copyAt: function ( index1, attribute, index2 ) { index1 *= this.itemSize; index2 *= attribute.itemSize; for ( var i = 0, l = this.itemSize; i < l; i ++ ) { this.array[ index1 + i ] = attribute.array[ index2 + i ]; } return this; }, copyArray: function ( array ) { this.array.set( array ); return this; }, copyColorsArray: function ( colors ) { var array = this.array, offset = 0; for ( var i = 0, l = colors.length; i < l; i ++ ) { var color = colors[ i ]; if ( color === undefined ) { console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); color = new THREE.Color(); } array[ offset ++ ] = color.r; array[ offset ++ ] = color.g; array[ offset ++ ] = color.b; } return this; }, copyIndicesArray: function ( indices ) { var array = this.array, offset = 0; for ( var i = 0, l = indices.length; i < l; i ++ ) { var index = indices[ i ]; array[ offset ++ ] = index.a; array[ offset ++ ] = index.b; array[ offset ++ ] = index.c; } return this; }, copyVector2sArray: function ( vectors ) { var array = this.array, offset = 0; for ( var i = 0, l = vectors.length; i < l; i ++ ) { var vector = vectors[ i ]; if ( vector === undefined ) { console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); vector = new THREE.Vector2(); } array[ offset ++ ] = vector.x; array[ offset ++ ] = vector.y; } return this; }, copyVector3sArray: function ( vectors ) { var array = this.array, offset = 0; for ( var i = 0, l = vectors.length; i < l; i ++ ) { var vector = vectors[ i ]; if ( vector === undefined ) { console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); vector = new THREE.Vector3(); } array[ offset ++ ] = vector.x; array[ offset ++ ] = vector.y; array[ offset ++ ] = vector.z; } return this; }, copyVector4sArray: function ( vectors ) { var array = this.array, offset = 0; for ( var i = 0, l = vectors.length; i < l; i ++ ) { var vector = vectors[ i ]; if ( vector === undefined ) { console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); vector = new THREE.Vector4(); } array[ offset ++ ] = vector.x; array[ offset ++ ] = vector.y; array[ offset ++ ] = vector.z; array[ offset ++ ] = vector.w; } return this; }, set: function ( value, offset ) { if ( offset === undefined ) offset = 0; this.array.set( value, offset ); return this; }, getX: function ( index ) { return this.array[ index * this.itemSize ]; }, setX: function ( index, x ) { this.array[ index * this.itemSize ] = x; return this; }, getY: function ( index ) { return this.array[ index * this.itemSize + 1 ]; }, setY: function ( index, y ) { this.array[ index * this.itemSize + 1 ] = y; return this; }, getZ: function ( index ) { return this.array[ index * this.itemSize + 2 ]; }, setZ: function ( index, z ) { this.array[ index * this.itemSize + 2 ] = z; return this; }, getW: function ( index ) { return this.array[ index * this.itemSize + 3 ]; }, setW: function ( index, w ) { this.array[ index * this.itemSize + 3 ] = w; return this; }, setXY: function ( index, x, y ) { index *= this.itemSize; this.array[ index + 0 ] = x; this.array[ index + 1 ] = y; return this; }, setXYZ: function ( index, x, y, z ) { index *= this.itemSize; this.array[ index + 0 ] = x; this.array[ index + 1 ] = y; this.array[ index + 2 ] = z; return this; }, setXYZW: function ( index, x, y, z, w ) { index *= this.itemSize; this.array[ index + 0 ] = x; this.array[ index + 1 ] = y; this.array[ index + 2 ] = z; this.array[ index + 3 ] = w; return this; }, clone: function () { return new this.constructor().copy( this ); } }; // THREE.Int8Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Int8Array( array ), itemSize ); }; THREE.Uint8Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Uint8Array( array ), itemSize ); }; THREE.Uint8ClampedAttribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Uint8ClampedArray( array ), itemSize ); }; THREE.Int16Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Int16Array( array ), itemSize ); }; THREE.Uint16Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Uint16Array( array ), itemSize ); }; THREE.Int32Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Int32Array( array ), itemSize ); }; THREE.Uint32Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Uint32Array( array ), itemSize ); }; THREE.Float32Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Float32Array( array ), itemSize ); }; THREE.Float64Attribute = function ( array, itemSize ) { return new THREE.BufferAttribute( new Float64Array( array ), itemSize ); }; // Deprecated THREE.DynamicBufferAttribute = function ( array, itemSize ) { console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' ); return new THREE.BufferAttribute( array, itemSize ).setDynamic( true ); }; three.js-r73/src/scenes/0000755000175500017550000000000012610076566015023 5ustar debacledebaclethree.js-r73/src/scenes/Fog.js0000644000175500017550000000063712610076566016102 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Fog = function ( color, near, far ) { this.name = ''; this.color = new THREE.Color( color ); this.near = ( near !== undefined ) ? near : 1; this.far = ( far !== undefined ) ? far : 1000; }; THREE.Fog.prototype.clone = function () { return new THREE.Fog( this.color.getHex(), this.near, this.far ); }; three.js-r73/src/scenes/Scene.js0000644000175500017550000000132612610076566016420 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Scene = function () { THREE.Object3D.call( this ); this.type = 'Scene'; this.fog = null; this.overrideMaterial = null; this.autoUpdate = true; // checked by the renderer }; THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); THREE.Scene.prototype.constructor = THREE.Scene; THREE.Scene.prototype.copy = function ( source ) { THREE.Object3D.prototype.copy.call( this, source ); if ( source.fog !== null ) this.fog = source.fog.clone(); if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); this.autoUpdate = source.autoUpdate; this.matrixAutoUpdate = source.matrixAutoUpdate; return this; }; three.js-r73/src/scenes/FogExp2.js0000644000175500017550000000060012610076566016627 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.FogExp2 = function ( color, density ) { this.name = ''; this.color = new THREE.Color( color ); this.density = ( density !== undefined ) ? density : 0.00025; }; THREE.FogExp2.prototype.clone = function () { return new THREE.FogExp2( this.color.getHex(), this.density ); }; three.js-r73/src/loaders/0000755000175500017550000000000012610076566015174 5ustar debacledebaclethree.js-r73/src/loaders/Cache.js0000644000175500017550000000107612610076566016541 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Cache = { enabled: false, files: {}, add: function ( key, file ) { if ( this.enabled === false ) return; // console.log( 'THREE.Cache', 'Adding key:', key ); this.files[ key ] = file; }, get: function ( key ) { if ( this.enabled === false ) return; // console.log( 'THREE.Cache', 'Checking key:', key ); return this.files[ key ]; }, remove: function ( key ) { delete this.files[ key ]; }, clear: function () { this.files = {}; } }; three.js-r73/src/loaders/TextureLoader.js0000644000175500017550000000134212610076566020321 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.TextureLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.TextureLoader.prototype = { constructor: THREE.TextureLoader, load: function ( url, onLoad, onProgress, onError ) { var texture = new THREE.Texture(); var loader = new THREE.ImageLoader( this.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( image ) { texture.image = image; texture.needsUpdate = true; if ( onLoad !== undefined ) { onLoad( texture ); } }, onProgress, onError ); return texture; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } }; three.js-r73/src/loaders/BinaryTextureLoader.js0000644000175500017550000000406112610076566021467 0ustar debacledebacle/** * @author Nikos M. / https://github.com/foo123/ * * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) */ THREE.DataTextureLoader = THREE.BinaryTextureLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; // override in sub classes this._parser = null; }; THREE.BinaryTextureLoader.prototype = { constructor: THREE.BinaryTextureLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var texture = new THREE.DataTexture(); var loader = new THREE.XHRLoader( this.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.setResponseType( 'arraybuffer' ); loader.load( url, function ( buffer ) { var texData = scope._parser( buffer ); if ( ! texData ) return; if ( undefined !== texData.image ) { texture.image = texData.image; } else if ( undefined !== texData.data ) { texture.image.width = texData.width; texture.image.height = texData.height; texture.image.data = texData.data; } texture.wrapS = undefined !== texData.wrapS ? texData.wrapS : THREE.ClampToEdgeWrapping; texture.wrapT = undefined !== texData.wrapT ? texData.wrapT : THREE.ClampToEdgeWrapping; texture.magFilter = undefined !== texData.magFilter ? texData.magFilter : THREE.LinearFilter; texture.minFilter = undefined !== texData.minFilter ? texData.minFilter : THREE.LinearMipMapLinearFilter; texture.anisotropy = undefined !== texData.anisotropy ? texData.anisotropy : 1; if ( undefined !== texData.format ) { texture.format = texData.format; } if ( undefined !== texData.type ) { texture.type = texData.type; } if ( undefined !== texData.mipmaps ) { texture.mipmaps = texData.mipmaps; } if ( 1 === texData.mipmapCount ) { texture.minFilter = THREE.LinearFilter; } texture.needsUpdate = true; if ( onLoad ) onLoad( texture, texData ); }, onProgress, onError ); return texture; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } }; three.js-r73/src/loaders/XHRLoader.js0000644000175500017550000000321212610076566017320 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.XHRLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.XHRLoader.prototype = { constructor: THREE.XHRLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var cached = THREE.Cache.get( url ); if ( cached !== undefined ) { if ( onLoad ) { setTimeout( function () { onLoad( cached ); }, 0 ); } return cached; } var request = new XMLHttpRequest(); request.open( 'GET', url, true ); request.addEventListener( 'load', function ( event ) { var response = event.target.response; THREE.Cache.add( url, response ); if ( onLoad ) onLoad( response ); scope.manager.itemEnd( url ); }, false ); if ( onProgress !== undefined ) { request.addEventListener( 'progress', function ( event ) { onProgress( event ); }, false ); } request.addEventListener( 'error', function ( event ) { if ( onError ) onError( event ); scope.manager.itemError( url ); }, false ); if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; if ( this.responseType !== undefined ) request.responseType = this.responseType; if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; request.send( null ); scope.manager.itemStart( url ); return request; }, setResponseType: function ( value ) { this.responseType = value; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, setWithCredentials: function ( value ) { this.withCredentials = value; } }; three.js-r73/src/loaders/ObjectLoader.js0000755000175500017550000002720212610076566020075 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.ObjectLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; this.texturePath = ''; }; THREE.ObjectLoader.prototype = { constructor: THREE.ObjectLoader, load: function ( url, onLoad, onProgress, onError ) { if ( this.texturePath === '' ) { this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); } var scope = this; var loader = new THREE.XHRLoader( scope.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { scope.parse( JSON.parse( text ), onLoad ); }, onProgress, onError ); }, setTexturePath: function ( value ) { this.texturePath = value; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, parse: function ( json, onLoad ) { var geometries = this.parseGeometries( json.geometries ); var images = this.parseImages( json.images, function () { if ( onLoad !== undefined ) onLoad( object ); } ); var textures = this.parseTextures( json.textures, images ); var materials = this.parseMaterials( json.materials, textures ); var object = this.parseObject( json.object, geometries, materials ); if ( json.animations ) { object.animations = this.parseAnimations( json.animations ); } if ( json.images === undefined || json.images.length === 0 ) { if ( onLoad !== undefined ) onLoad( object ); } return object; }, parseGeometries: function ( json ) { var geometries = {}; if ( json !== undefined ) { var geometryLoader = new THREE.JSONLoader(); var bufferGeometryLoader = new THREE.BufferGeometryLoader(); for ( var i = 0, l = json.length; i < l; i ++ ) { var geometry; var data = json[ i ]; switch ( data.type ) { case 'PlaneGeometry': case 'PlaneBufferGeometry': geometry = new THREE[ data.type ]( data.width, data.height, data.widthSegments, data.heightSegments ); break; case 'BoxGeometry': case 'CubeGeometry': // backwards compatible geometry = new THREE.BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); break; case 'CircleBufferGeometry': geometry = new THREE.CircleBufferGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); break; case 'CircleGeometry': geometry = new THREE.CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); break; case 'CylinderGeometry': geometry = new THREE.CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); break; case 'SphereGeometry': geometry = new THREE.SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); break; case 'SphereBufferGeometry': geometry = new THREE.SphereBufferGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); break; case 'DodecahedronGeometry': geometry = new THREE.DodecahedronGeometry( data.radius, data.detail ); break; case 'IcosahedronGeometry': geometry = new THREE.IcosahedronGeometry( data.radius, data.detail ); break; case 'OctahedronGeometry': geometry = new THREE.OctahedronGeometry( data.radius, data.detail ); break; case 'TetrahedronGeometry': geometry = new THREE.TetrahedronGeometry( data.radius, data.detail ); break; case 'RingGeometry': geometry = new THREE.RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); break; case 'TorusGeometry': geometry = new THREE.TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); break; case 'TorusKnotGeometry': geometry = new THREE.TorusKnotGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.p, data.q, data.heightScale ); break; case 'BufferGeometry': geometry = bufferGeometryLoader.parse( data ); break; case 'Geometry': geometry = geometryLoader.parse( data.data, this.texturePath ).geometry; break; default: console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); continue; } geometry.uuid = data.uuid; if ( data.name !== undefined ) geometry.name = data.name; geometries[ data.uuid ] = geometry; } } return geometries; }, parseMaterials: function ( json, textures ) { var materials = {}; if ( json !== undefined ) { var loader = new THREE.MaterialLoader(); loader.setTextures( textures ); for ( var i = 0, l = json.length; i < l; i ++ ) { var material = loader.parse( json[ i ] ); materials[ material.uuid ] = material; } } return materials; }, parseAnimations: function ( json ) { var animations = []; for ( var i = 0; i < json.length; i ++ ) { var clip = THREE.AnimationClip.parse( json[i] ); animations.push( clip ); } return animations; }, parseImages: function ( json, onLoad ) { var scope = this; var images = {}; function loadImage( url ) { scope.manager.itemStart( url ); return loader.load( url, function () { scope.manager.itemEnd( url ); } ); } if ( json !== undefined && json.length > 0 ) { var manager = new THREE.LoadingManager( onLoad ); var loader = new THREE.ImageLoader( manager ); loader.setCrossOrigin( this.crossOrigin ); for ( var i = 0, l = json.length; i < l; i ++ ) { var image = json[ i ]; var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; images[ image.uuid ] = loadImage( path ); } } return images; }, parseTextures: function ( json, images ) { function parseConstant( value ) { if ( typeof( value ) === 'number' ) return value; console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); return THREE[ value ]; } var textures = {}; if ( json !== undefined ) { for ( var i = 0, l = json.length; i < l; i ++ ) { var data = json[ i ]; if ( data.image === undefined ) { console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); } if ( images[ data.image ] === undefined ) { console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); } var texture = new THREE.Texture( images[ data.image ] ); texture.needsUpdate = true; texture.uuid = data.uuid; if ( data.name !== undefined ) texture.name = data.name; if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping ); if ( data.offset !== undefined ) texture.offset = new THREE.Vector2( data.offset[ 0 ], data.offset[ 1 ] ); if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] ); if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter ); if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter ); if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; if ( Array.isArray( data.wrap ) ) { texture.wrapS = parseConstant( data.wrap[ 0 ] ); texture.wrapT = parseConstant( data.wrap[ 1 ] ); } textures[ data.uuid ] = texture; } } return textures; }, parseObject: function () { var matrix = new THREE.Matrix4(); return function ( data, geometries, materials ) { var object; function getGeometry( name ) { if ( geometries[ name ] === undefined ) { console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); } return geometries[ name ]; } function getMaterial( name ) { if ( name === undefined ) return undefined; if ( materials[ name ] === undefined ) { console.warn( 'THREE.ObjectLoader: Undefined material', name ); } return materials[ name ]; } switch ( data.type ) { case 'Scene': object = new THREE.Scene(); break; case 'PerspectiveCamera': object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); break; case 'OrthographicCamera': object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); break; case 'AmbientLight': object = new THREE.AmbientLight( data.color ); break; case 'DirectionalLight': object = new THREE.DirectionalLight( data.color, data.intensity ); break; case 'PointLight': object = new THREE.PointLight( data.color, data.intensity, data.distance, data.decay ); break; case 'SpotLight': object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent, data.decay ); break; case 'HemisphereLight': object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); break; case 'Mesh': object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) ); break; case 'LOD': object = new THREE.LOD(); break; case 'Line': object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); break; case 'PointCloud': case 'Points': object = new THREE.Points( getGeometry( data.geometry ), getMaterial( data.material ) ); break; case 'Sprite': object = new THREE.Sprite( getMaterial( data.material ) ); break; case 'Group': object = new THREE.Group(); break; default: object = new THREE.Object3D(); } object.uuid = data.uuid; if ( data.name !== undefined ) object.name = data.name; if ( data.matrix !== undefined ) { matrix.fromArray( data.matrix ); matrix.decompose( object.position, object.quaternion, object.scale ); } else { if ( data.position !== undefined ) object.position.fromArray( data.position ); if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); } if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; if ( data.visible !== undefined ) object.visible = data.visible; if ( data.userData !== undefined ) object.userData = data.userData; if ( data.children !== undefined ) { for ( var child in data.children ) { object.add( this.parseObject( data.children[ child ], geometries, materials ) ); } } if ( data.type === 'LOD' ) { var levels = data.levels; for ( var l = 0; l < levels.length; l ++ ) { var level = levels[ l ]; var child = object.getObjectByProperty( 'uuid', level.object ); if ( child !== undefined ) { object.addLevel( child, level.distance ); } } } return object; } }() }; three.js-r73/src/loaders/CubeTextureLoader.js0000644000175500017550000000162412610076566021123 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.CubeTextureLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.CubeTextureLoader.prototype = { constructor: THREE.CubeTextureLoader, load: function ( urls, onLoad, onProgress, onError ) { var texture = new THREE.CubeTexture( [] ); var loader = new THREE.ImageLoader(); loader.setCrossOrigin( this.crossOrigin ); var loaded = 0; function loadTexture( i ) { loader.load( urls[ i ], function ( image ) { texture.images[ i ] = image; loaded ++; if ( loaded === 6 ) { texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } }, undefined, onError ); } for ( var i = 0; i < urls.length; ++ i ) { loadTexture( i ); } return texture; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } }; three.js-r73/src/loaders/LoadingManager.js0000644000175500017550000000173612610076566020411 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.LoadingManager = function ( onLoad, onProgress, onError ) { var scope = this; var isLoading = false, itemsLoaded = 0, itemsTotal = 0; this.onStart = undefined; this.onLoad = onLoad; this.onProgress = onProgress; this.onError = onError; this.itemStart = function ( url ) { itemsTotal ++; if ( isLoading === false ) { if ( scope.onStart !== undefined ) { scope.onStart( url, itemsLoaded, itemsTotal ); } } isLoading = true; }; this.itemEnd = function ( url ) { itemsLoaded ++; if ( scope.onProgress !== undefined ) { scope.onProgress( url, itemsLoaded, itemsTotal ); } if ( itemsLoaded === itemsTotal ) { isLoading = false; if ( scope.onLoad !== undefined ) { scope.onLoad(); } } }; this.itemError = function ( url ) { if ( scope.onError !== undefined ) { scope.onError( url ); } }; }; THREE.DefaultLoadingManager = new THREE.LoadingManager(); three.js-r73/src/loaders/JSONLoader.js0000644000175500017550000003036612610076566017442 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.JSONLoader = function ( manager ) { if ( typeof manager === 'boolean' ) { console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); manager = undefined; } this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; this.withCredentials = false; }; THREE.JSONLoader.prototype = { constructor: THREE.JSONLoader, // Deprecated get statusDomElement () { if ( this._statusDomElement === undefined ) { this._statusDomElement = document.createElement( 'div' ); } console.warn( 'THREE.JSONLoader: .statusDomElement has been removed.' ); return this._statusDomElement; }, load: function( url, onLoad, onProgress, onError ) { var scope = this; var texturePath = this.texturePath && ( typeof this.texturePath === "string" ) ? this.texturePath : THREE.Loader.prototype.extractUrlBase( url ); var loader = new THREE.XHRLoader( this.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.setWithCredentials( this.withCredentials ); loader.load( url, function ( text ) { var json = JSON.parse( text ); var metadata = json.metadata; if ( metadata !== undefined ) { if ( metadata.type === 'object' ) { console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); return; } if ( metadata.type === 'scene' ) { console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); return; } } var object = scope.parse( json, texturePath ); onLoad( object.geometry, object.materials ); } ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, setTexturePath: function ( value ) { this.texturePath = value; }, parse: function ( json, texturePath ) { var geometry = new THREE.Geometry(), scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; parseModel( scale ); parseSkin(); parseMorphing( scale ); parseAnimations(); geometry.computeFaceNormals(); geometry.computeBoundingSphere(); function parseModel( scale ) { function isBitSet( value, position ) { return value & ( 1 << position ); } var i, j, fi, offset, zLength, colorIndex, normalIndex, uvIndex, materialIndex, type, isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor, vertex, face, faceA, faceB, hex, normal, uvLayer, uv, u, v, faces = json.faces, vertices = json.vertices, normals = json.normals, colors = json.colors, nUvLayers = 0; if ( json.uvs !== undefined ) { // disregard empty arrays for ( i = 0; i < json.uvs.length; i ++ ) { if ( json.uvs[ i ].length ) nUvLayers ++; } for ( i = 0; i < nUvLayers; i ++ ) { geometry.faceVertexUvs[ i ] = []; } } offset = 0; zLength = vertices.length; while ( offset < zLength ) { vertex = new THREE.Vector3(); vertex.x = vertices[ offset ++ ] * scale; vertex.y = vertices[ offset ++ ] * scale; vertex.z = vertices[ offset ++ ] * scale; geometry.vertices.push( vertex ); } offset = 0; zLength = faces.length; while ( offset < zLength ) { type = faces[ offset ++ ]; isQuad = isBitSet( type, 0 ); hasMaterial = isBitSet( type, 1 ); hasFaceVertexUv = isBitSet( type, 3 ); hasFaceNormal = isBitSet( type, 4 ); hasFaceVertexNormal = isBitSet( type, 5 ); hasFaceColor = isBitSet( type, 6 ); hasFaceVertexColor = isBitSet( type, 7 ); // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); if ( isQuad ) { faceA = new THREE.Face3(); faceA.a = faces[ offset ]; faceA.b = faces[ offset + 1 ]; faceA.c = faces[ offset + 3 ]; faceB = new THREE.Face3(); faceB.a = faces[ offset + 1 ]; faceB.b = faces[ offset + 2 ]; faceB.c = faces[ offset + 3 ]; offset += 4; if ( hasMaterial ) { materialIndex = faces[ offset ++ ]; faceA.materialIndex = materialIndex; faceB.materialIndex = materialIndex; } // to get face <=> uv index correspondence fi = geometry.faces.length; if ( hasFaceVertexUv ) { for ( i = 0; i < nUvLayers; i ++ ) { uvLayer = json.uvs[ i ]; geometry.faceVertexUvs[ i ][ fi ] = []; geometry.faceVertexUvs[ i ][ fi + 1 ] = []; for ( j = 0; j < 4; j ++ ) { uvIndex = faces[ offset ++ ]; u = uvLayer[ uvIndex * 2 ]; v = uvLayer[ uvIndex * 2 + 1 ]; uv = new THREE.Vector2( u, v ); if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); } } } if ( hasFaceNormal ) { normalIndex = faces[ offset ++ ] * 3; faceA.normal.set( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); faceB.normal.copy( faceA.normal ); } if ( hasFaceVertexNormal ) { for ( i = 0; i < 4; i ++ ) { normalIndex = faces[ offset ++ ] * 3; normal = new THREE.Vector3( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); if ( i !== 2 ) faceA.vertexNormals.push( normal ); if ( i !== 0 ) faceB.vertexNormals.push( normal ); } } if ( hasFaceColor ) { colorIndex = faces[ offset ++ ]; hex = colors[ colorIndex ]; faceA.color.setHex( hex ); faceB.color.setHex( hex ); } if ( hasFaceVertexColor ) { for ( i = 0; i < 4; i ++ ) { colorIndex = faces[ offset ++ ]; hex = colors[ colorIndex ]; if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); } } geometry.faces.push( faceA ); geometry.faces.push( faceB ); } else { face = new THREE.Face3(); face.a = faces[ offset ++ ]; face.b = faces[ offset ++ ]; face.c = faces[ offset ++ ]; if ( hasMaterial ) { materialIndex = faces[ offset ++ ]; face.materialIndex = materialIndex; } // to get face <=> uv index correspondence fi = geometry.faces.length; if ( hasFaceVertexUv ) { for ( i = 0; i < nUvLayers; i ++ ) { uvLayer = json.uvs[ i ]; geometry.faceVertexUvs[ i ][ fi ] = []; for ( j = 0; j < 3; j ++ ) { uvIndex = faces[ offset ++ ]; u = uvLayer[ uvIndex * 2 ]; v = uvLayer[ uvIndex * 2 + 1 ]; uv = new THREE.Vector2( u, v ); geometry.faceVertexUvs[ i ][ fi ].push( uv ); } } } if ( hasFaceNormal ) { normalIndex = faces[ offset ++ ] * 3; face.normal.set( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); } if ( hasFaceVertexNormal ) { for ( i = 0; i < 3; i ++ ) { normalIndex = faces[ offset ++ ] * 3; normal = new THREE.Vector3( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); face.vertexNormals.push( normal ); } } if ( hasFaceColor ) { colorIndex = faces[ offset ++ ]; face.color.setHex( colors[ colorIndex ] ); } if ( hasFaceVertexColor ) { for ( i = 0; i < 3; i ++ ) { colorIndex = faces[ offset ++ ]; face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); } } geometry.faces.push( face ); } } }; function parseSkin() { var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; if ( json.skinWeights ) { for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { var x = json.skinWeights[ i ]; var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); } } if ( json.skinIndices ) { for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { var a = json.skinIndices[ i ]; var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); } } geometry.bones = json.bones; if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); } }; function parseMorphing( scale ) { if ( json.morphTargets !== undefined ) { for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { geometry.morphTargets[ i ] = {}; geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; geometry.morphTargets[ i ].vertices = []; var dstVertices = geometry.morphTargets[ i ].vertices; var srcVertices = json.morphTargets[ i ].vertices; for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { var vertex = new THREE.Vector3(); vertex.x = srcVertices[ v ] * scale; vertex.y = srcVertices[ v + 1 ] * scale; vertex.z = srcVertices[ v + 2 ] * scale; dstVertices.push( vertex ); } } } if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); var faces = geometry.faces; var morphColors = json.morphColors[ 0 ].colors; for ( var i = 0, l = faces.length; i < l; i ++ ) { faces[ i ].color.fromArray( morphColors, i * 3 ); } } } function parseAnimations() { var outputAnimations = []; // parse old style Bone/Hierarchy animations var animations = []; if ( json.animation !== undefined ) { animations.push( json.animation ); } if ( json.animations !== undefined ) { if ( json.animations.length ) { animations = animations.concat( json.animations ); } else { animations.push( json.animations ); } } for ( var i = 0; i < animations.length; i ++ ) { var clip = THREE.AnimationClip.parseAnimation( animations[i], geometry.bones ); if ( clip ) outputAnimations.push( clip ); } // parse implicit morph animations if ( geometry.morphTargets ) { // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. var morphAnimationClips = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); outputAnimations = outputAnimations.concat( morphAnimationClips ); } if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; }; if ( json.materials === undefined || json.materials.length === 0 ) { return { geometry: geometry }; } else { var materials = THREE.Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); return { geometry: geometry, materials: materials }; } } }; three.js-r73/src/loaders/CompressedTextureLoader.js0000644000175500017550000000502512610076566022350 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * * Abstract Base class to block based textures loader (dds, pvr, ...) */ THREE.CompressedTextureLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; // override in sub classes this._parser = null; }; THREE.CompressedTextureLoader.prototype = { constructor: THREE.CompressedTextureLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var images = []; var texture = new THREE.CompressedTexture(); texture.image = images; var loader = new THREE.XHRLoader( this.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.setResponseType( 'arraybuffer' ); if ( Array.isArray( url ) ) { var loaded = 0; var loadTexture = function ( i ) { loader.load( url[ i ], function ( buffer ) { var texDatas = scope._parser( buffer, true ); images[ i ] = { width: texDatas.width, height: texDatas.height, format: texDatas.format, mipmaps: texDatas.mipmaps }; loaded += 1; if ( loaded === 6 ) { if ( texDatas.mipmapCount === 1 ) texture.minFilter = THREE.LinearFilter; texture.format = texDatas.format; texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } }, onProgress, onError ); }; for ( var i = 0, il = url.length; i < il; ++ i ) { loadTexture( i ); } } else { // compressed cubemap texture stored in a single DDS file loader.load( url, function ( buffer ) { var texDatas = scope._parser( buffer, true ); if ( texDatas.isCubemap ) { var faces = texDatas.mipmaps.length / texDatas.mipmapCount; for ( var f = 0; f < faces; f ++ ) { images[ f ] = { mipmaps : [] }; for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); images[ f ].format = texDatas.format; images[ f ].width = texDatas.width; images[ f ].height = texDatas.height; } } } else { texture.image.width = texDatas.width; texture.image.height = texDatas.height; texture.mipmaps = texDatas.mipmaps; } if ( texDatas.mipmapCount === 1 ) { texture.minFilter = THREE.LinearFilter; } texture.format = texDatas.format; texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); }, onProgress, onError ); } return texture; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } }; three.js-r73/src/loaders/ImageLoader.js0000644000175500017550000000254112610076566017705 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.ImageLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.ImageLoader.prototype = { constructor: THREE.ImageLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var cached = THREE.Cache.get( url ); if ( cached !== undefined ) { scope.manager.itemStart( url ); if ( onLoad ) { setTimeout( function () { onLoad( cached ); scope.manager.itemEnd( url ); }, 0 ); } else { scope.manager.itemEnd( url ); } return cached; } var image = document.createElement( 'img' ); image.addEventListener( 'load', function ( event ) { THREE.Cache.add( url, this ); if ( onLoad ) onLoad( this ); scope.manager.itemEnd( url ); }, false ); if ( onProgress !== undefined ) { image.addEventListener( 'progress', function ( event ) { onProgress( event ); }, false ); } image.addEventListener( 'error', function ( event ) { if ( onError ) onError( event ); scope.manager.itemError( url ); }, false ); if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; scope.manager.itemStart( url ); image.src = url; return image; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } }; three.js-r73/src/loaders/AnimationLoader.js0000644000175500017550000000153112610076566020600 0ustar debacledebacle/** * @author bhouston / http://clara.io/ */ THREE.AnimationLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.AnimationLoader.prototype = { constructor: THREE.AnimationLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader( scope.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); }, onProgress, onError ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, parse: function ( json, onLoad ) { var animations = []; for ( var i = 0; i < json.length; i ++ ) { var clip = THREE.AnimationClip.parse( json[i] ); animations.push( clip ); } onLoad( animations ); } }; three.js-r73/src/loaders/Loader.js0000644000175500017550000001537012610076566016746 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.Loader = function () { this.onLoadStart = function () {}; this.onLoadProgress = function () {}; this.onLoadComplete = function () {}; }; THREE.Loader.prototype = { constructor: THREE.Loader, crossOrigin: undefined, extractUrlBase: function ( url ) { var parts = url.split( '/' ); if ( parts.length === 1 ) return './'; parts.pop(); return parts.join( '/' ) + '/'; }, initMaterials: function ( materials, texturePath, crossOrigin ) { var array = []; for ( var i = 0; i < materials.length; ++ i ) { array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); } return array; }, createMaterial: ( function () { var color, textureLoader, materialLoader; return function ( m, texturePath, crossOrigin ) { if ( color === undefined ) color = new THREE.Color(); if ( textureLoader === undefined ) textureLoader = new THREE.TextureLoader(); if ( materialLoader === undefined ) materialLoader = new THREE.MaterialLoader(); // convert from old material format var textures = {}; function loadTexture( path, repeat, offset, wrap, anisotropy ) { var fullPath = texturePath + path; var loader = THREE.Loader.Handlers.get( fullPath ); var texture; if ( loader !== null ) { texture = loader.load( fullPath ); } else { textureLoader.setCrossOrigin( crossOrigin ); texture = textureLoader.load( fullPath ); } if ( repeat !== undefined ) { texture.repeat.fromArray( repeat ); if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; } if ( offset !== undefined ) { texture.offset.fromArray( offset ); } if ( wrap !== undefined ) { if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = THREE.RepeatWrapping; if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = THREE.MirroredRepeatWrapping; if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = THREE.RepeatWrapping; if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = THREE.MirroredRepeatWrapping; } if ( anisotropy !== undefined ) { texture.anisotropy = anisotropy; } var uuid = THREE.Math.generateUUID(); textures[ uuid ] = texture; return uuid; } // var json = { uuid: THREE.Math.generateUUID(), type: 'MeshLambertMaterial' }; for ( var name in m ) { var value = m[ name ]; switch ( name ) { case 'DbgColor': json.color = value; break; case 'DbgIndex': case 'opticalDensity': case 'illumination': // These were never supported break; case 'DbgName': json.name = value; break; case 'blending': json.blending = THREE[ value ]; break; case 'colorDiffuse': json.color = color.fromArray( value ).getHex(); break; case 'colorSpecular': json.specular = color.fromArray( value ).getHex(); break; case 'colorEmissive': json.emissive = color.fromArray( value ).getHex(); break; case 'specularCoef': json.shininess = value; break; case 'shading': if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; break; case 'mapDiffuse': json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); break; case 'mapDiffuseRepeat': case 'mapDiffuseOffset': case 'mapDiffuseWrap': case 'mapDiffuseAnisotropy': break; case 'mapLight': json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); break; case 'mapLightRepeat': case 'mapLightOffset': case 'mapLightWrap': case 'mapLightAnisotropy': break; case 'mapAO': json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); break; case 'mapAORepeat': case 'mapAOOffset': case 'mapAOWrap': case 'mapAOAnisotropy': break; case 'mapBump': json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); break; case 'mapBumpScale': json.bumpScale = value; break; case 'mapBumpRepeat': case 'mapBumpOffset': case 'mapBumpWrap': case 'mapBumpAnisotropy': break; case 'mapNormal': json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); break; case 'mapNormalFactor': json.normalScale = [ value, value ]; break; case 'mapNormalRepeat': case 'mapNormalOffset': case 'mapNormalWrap': case 'mapNormalAnisotropy': break; case 'mapSpecular': json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); break; case 'mapSpecularRepeat': case 'mapSpecularOffset': case 'mapSpecularWrap': case 'mapSpecularAnisotropy': break; case 'mapAlpha': json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); break; case 'mapAlphaRepeat': case 'mapAlphaOffset': case 'mapAlphaWrap': case 'mapAlphaAnisotropy': break; case 'flipSided': json.side = THREE.BackSide; break; case 'doubleSided': json.side = THREE.DoubleSide; break; case 'transparency': console.warn( 'THREE.Loader: transparency has been renamed to opacity' ); json.opacity = value; break; case 'opacity': case 'transparent': case 'depthTest': case 'depthWrite': case 'transparent': case 'visible': case 'wireframe': json[ name ] = value; break; case 'vertexColors': if ( value === true ) json.vertexColors = THREE.VertexColors; if ( value === 'face' ) json.vertexColors = THREE.FaceColors; break; default: console.error( 'Loader.createMaterial: Unsupported', name, value ); break; } } if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; if ( json.opacity < 1 ) json.transparent = true; materialLoader.setTextures( textures ); return materialLoader.parse( json ); }; } )() }; THREE.Loader.Handlers = { handlers: [], add: function ( regex, loader ) { this.handlers.push( regex, loader ); }, get: function ( file ) { var handlers = this.handlers; for ( var i = 0, l = handlers.length; i < l; i += 2 ) { var regex = handlers[ i ]; var loader = handlers[ i + 1 ]; if ( regex.test( file ) ) { return loader; } } return null; } }; three.js-r73/src/loaders/BufferGeometryLoader.js0000644000175500017550000000355512610076566021616 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.BufferGeometryLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.BufferGeometryLoader.prototype = { constructor: THREE.BufferGeometryLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader( scope.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); }, onProgress, onError ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, parse: function ( json ) { var geometry = new THREE.BufferGeometry(); var index = json.data.index; if ( index !== undefined ) { var typedArray = new self[ index.type ]( index.array ); geometry.setIndex( new THREE.BufferAttribute( typedArray, 1 ) ); } var attributes = json.data.attributes; for ( var key in attributes ) { var attribute = attributes[ key ]; var typedArray = new self[ attribute.type ]( attribute.array ); geometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) ); } var groups = json.data.groups || json.data.drawcalls || json.data.offsets; if ( groups !== undefined ) { for ( var i = 0, n = groups.length; i !== n; ++ i ) { var group = groups[ i ]; geometry.addGroup( group.start, group.count ); } } var boundingSphere = json.data.boundingSphere; if ( boundingSphere !== undefined ) { var center = new THREE.Vector3(); if ( boundingSphere.center !== undefined ) { center.fromArray( boundingSphere.center ); } geometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius ); } return geometry; } }; three.js-r73/src/loaders/MaterialLoader.js0000644000175500017550000001100412610076566020413 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.MaterialLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; this.textures = {}; }; THREE.MaterialLoader.prototype = { constructor: THREE.MaterialLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader( scope.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); }, onProgress, onError ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, setTextures: function ( value ) { this.textures = value; }, getTexture: function ( name ) { var textures = this.textures; if ( textures[ name ] === undefined ) { console.warn( 'THREE.MaterialLoader: Undefined texture', name ); } return textures[ name ]; }, parse: function ( json ) { var material = new THREE[ json.type ]; material.uuid = json.uuid; if ( json.name !== undefined ) material.name = json.name; if ( json.color !== undefined ) material.color.setHex( json.color ); if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); if ( json.specular !== undefined ) material.specular.setHex( json.specular ); if ( json.shininess !== undefined ) material.shininess = json.shininess; if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; if ( json.shading !== undefined ) material.shading = json.shading; if ( json.blending !== undefined ) material.blending = json.blending; if ( json.side !== undefined ) material.side = json.side; if ( json.opacity !== undefined ) material.opacity = json.opacity; if ( json.transparent !== undefined ) material.transparent = json.transparent; if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; // for PointsMaterial if ( json.size !== undefined ) material.size = json.size; if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; // maps if ( json.map !== undefined ) material.map = this.getTexture( json.map ); if ( json.alphaMap !== undefined ) { material.alphaMap = this.getTexture( json.alphaMap ); material.transparent = true; } if ( json.bumpMap !== undefined ) material.bumpMap = this.getTexture( json.bumpMap ); if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; if ( json.normalMap !== undefined ) material.normalMap = this.getTexture( json.normalMap ); if ( json.normalScale ) material.normalScale = new THREE.Vector2( json.normalScale, json.normalScale ); if ( json.displacementMap !== undefined ) material.displacementMap = this.getTexture( json.displacementMap ); if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; if ( json.specularMap !== undefined ) material.specularMap = this.getTexture( json.specularMap ); if ( json.envMap !== undefined ) { material.envMap = this.getTexture( json.envMap ); material.combine = THREE.MultiplyOperation; } if ( json.reflectivity ) material.reflectivity = json.reflectivity; if ( json.lightMap !== undefined ) material.lightMap = this.getTexture( json.lightMap ); if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; if ( json.aoMap !== undefined ) material.aoMap = this.getTexture( json.aoMap ); if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; // MeshFaceMaterial if ( json.materials !== undefined ) { for ( var i = 0, l = json.materials.length; i < l; i ++ ) { material.materials.push( this.parse( json.materials[ i ] ) ); } } return material; } }; three.js-r73/src/materials/0000755000175500017550000000000012610076566015524 5ustar debacledebaclethree.js-r73/src/materials/LineBasicMaterial.js0000644000175500017550000000224712610076566021377 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * linewidth: , * linecap: "round", * linejoin: "round", * * vertexColors: * * fog: * } */ THREE.LineBasicMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'LineBasicMaterial'; this.color = new THREE.Color( 0xffffff ); this.linewidth = 1; this.linecap = 'round'; this.linejoin = 'round'; this.vertexColors = THREE.NoColors; this.fog = true; this.setValues( parameters ); }; THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.LineBasicMaterial.prototype.constructor = THREE.LineBasicMaterial; THREE.LineBasicMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.color.copy( source.color ); this.linewidth = source.linewidth; this.linecap = source.linecap; this.linejoin = source.linejoin; this.vertexColors = source.vertexColors; this.fog = source.fog; return this; }; three.js-r73/src/materials/MeshDepthMaterial.js0000644000175500017550000000161612610076566021426 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * opacity: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: * } */ THREE.MeshDepthMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'MeshDepthMaterial'; this.morphTargets = false; this.wireframe = false; this.wireframeLinewidth = 1; this.setValues( parameters ); }; THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshDepthMaterial.prototype.constructor = THREE.MeshDepthMaterial; THREE.MeshDepthMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.wireframe = source.wireframe; this.wireframeLinewidth = source.wireframeLinewidth; return this; }; three.js-r73/src/materials/MeshBasicMaterial.js0000644000175500017550000000506112610076566021401 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * aoMap: new THREE.Texture( ), * aoMapIntensity: * * specularMap: new THREE.Texture( ), * * alphaMap: new THREE.Texture( ), * * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * * fog: * } */ THREE.MeshBasicMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'MeshBasicMaterial'; this.color = new THREE.Color( 0xffffff ); // emissive this.map = null; this.aoMap = null; this.aoMapIntensity = 1.0; this.specularMap = null; this.alphaMap = null; this.envMap = null; this.combine = THREE.MultiplyOperation; this.reflectivity = 1; this.refractionRatio = 0.98; this.fog = true; this.shading = THREE.SmoothShading; this.wireframe = false; this.wireframeLinewidth = 1; this.wireframeLinecap = 'round'; this.wireframeLinejoin = 'round'; this.vertexColors = THREE.NoColors; this.skinning = false; this.morphTargets = false; this.setValues( parameters ); }; THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshBasicMaterial.prototype.constructor = THREE.MeshBasicMaterial; THREE.MeshBasicMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.color.copy( source.color ); this.map = source.map; this.aoMap = source.aoMap; this.aoMapIntensity = source.aoMapIntensity; this.specularMap = source.specularMap; this.alphaMap = source.alphaMap; this.envMap = source.envMap; this.combine = source.combine; this.reflectivity = source.reflectivity; this.refractionRatio = source.refractionRatio; this.fog = source.fog; this.shading = source.shading; this.wireframe = source.wireframe; this.wireframeLinewidth = source.wireframeLinewidth; this.wireframeLinecap = source.wireframeLinecap; this.wireframeLinejoin = source.wireframeLinejoin; this.vertexColors = source.vertexColors; this.skinning = source.skinning; this.morphTargets = source.morphTargets; return this; }; three.js-r73/src/materials/MultiMaterial.js0000644000175500017550000000201512610076566020631 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.MultiMaterial = function ( materials ) { this.uuid = THREE.Math.generateUUID(); this.type = 'MultiMaterial'; this.materials = materials instanceof Array ? materials : []; this.visible = true; }; THREE.MultiMaterial.prototype = { constructor: THREE.MultiMaterial, toJSON: function () { var output = { metadata: { version: 4.2, type: 'material', generator: 'MaterialExporter' }, uuid: this.uuid, type: this.type, materials: [] }; for ( var i = 0, l = this.materials.length; i < l; i ++ ) { output.materials.push( this.materials[ i ].toJSON() ); } output.visible = this.visible; return output; }, clone: function () { var material = new this.constructor(); for ( var i = 0; i < this.materials.length; i ++ ) { material.materials.push( this.materials[ i ].clone() ); } material.visible = this.visible; return material; } }; // backwards compatibility THREE.MeshFaceMaterial = THREE.MultiMaterial; three.js-r73/src/materials/MeshLambertMaterial.js0000644000175500017550000000473212610076566021752 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * emissive: , * opacity: , * * map: new THREE.Texture( ), * * specularMap: new THREE.Texture( ), * * alphaMap: new THREE.Texture( ), * * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * morphNormals: , * * fog: * } */ THREE.MeshLambertMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'MeshLambertMaterial'; this.color = new THREE.Color( 0xffffff ); // diffuse this.emissive = new THREE.Color( 0x000000 ); this.map = null; this.specularMap = null; this.alphaMap = null; this.envMap = null; this.combine = THREE.MultiplyOperation; this.reflectivity = 1; this.refractionRatio = 0.98; this.fog = true; this.wireframe = false; this.wireframeLinewidth = 1; this.wireframeLinecap = 'round'; this.wireframeLinejoin = 'round'; this.vertexColors = THREE.NoColors; this.skinning = false; this.morphTargets = false; this.morphNormals = false; this.setValues( parameters ); }; THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshLambertMaterial.prototype.constructor = THREE.MeshLambertMaterial; THREE.MeshLambertMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.color.copy( source.color ); this.emissive.copy( source.emissive ); this.map = source.map; this.specularMap = source.specularMap; this.alphaMap = source.alphaMap; this.envMap = source.envMap; this.combine = source.combine; this.reflectivity = source.reflectivity; this.refractionRatio = source.refractionRatio; this.fog = source.fog; this.wireframe = source.wireframe; this.wireframeLinewidth = source.wireframeLinewidth; this.wireframeLinecap = source.wireframeLinecap; this.wireframeLinejoin = source.wireframeLinejoin; this.vertexColors = source.vertexColors; this.skinning = source.skinning; this.morphTargets = source.morphTargets; this.morphNormals = source.morphNormals; return this; }; three.js-r73/src/materials/LineDashedMaterial.js0000644000175500017550000000227012610076566021542 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * linewidth: , * * scale: , * dashSize: , * gapSize: , * * vertexColors: * * fog: * } */ THREE.LineDashedMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'LineDashedMaterial'; this.color = new THREE.Color( 0xffffff ); this.linewidth = 1; this.scale = 1; this.dashSize = 3; this.gapSize = 1; this.vertexColors = false; this.fog = true; this.setValues( parameters ); }; THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.LineDashedMaterial.prototype.constructor = THREE.LineDashedMaterial; THREE.LineDashedMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.color.copy( source.color ); this.linewidth = source.linewidth; this.scale = source.scale; this.dashSize = source.dashSize; this.gapSize = source.gapSize; this.vertexColors = source.vertexColors; this.fog = source.fog; return this; }; three.js-r73/src/materials/ShaderMaterial.js0000644000175500017550000000630712610076566020755 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * * parameters = { * defines: { "label" : "value" }, * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, * * fragmentShader: , * vertexShader: , * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * lights: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * morphNormals: , * * fog: * } */ THREE.ShaderMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'ShaderMaterial'; this.defines = {}; this.uniforms = {}; this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}'; this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}'; this.shading = THREE.SmoothShading; this.linewidth = 1; this.wireframe = false; this.wireframeLinewidth = 1; this.fog = false; // set to use scene fog this.lights = false; // set to use scene lights this.vertexColors = THREE.NoColors; // set to use "color" attribute stream this.skinning = false; // set to use skinning attribute streams this.morphTargets = false; // set to use morph targets this.morphNormals = false; // set to use morph normals this.derivatives = false; // set to use derivatives // When rendered geometry doesn't include these attributes but the material does, // use these default values in WebGL. This avoids errors when buffer data is missing. this.defaultAttributeValues = { 'color': [ 1, 1, 1 ], 'uv': [ 0, 0 ], 'uv2': [ 0, 0 ] }; this.index0AttributeName = undefined; if ( parameters !== undefined ) { if ( parameters.attributes !== undefined ) { console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); } this.setValues( parameters ); } }; THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.ShaderMaterial.prototype.constructor = THREE.ShaderMaterial; THREE.ShaderMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.fragmentShader = source.fragmentShader; this.vertexShader = source.vertexShader; this.uniforms = THREE.UniformsUtils.clone( source.uniforms ); this.attributes = source.attributes; this.defines = source.defines; this.shading = source.shading; this.wireframe = source.wireframe; this.wireframeLinewidth = source.wireframeLinewidth; this.fog = source.fog; this.lights = source.lights; this.vertexColors = source.vertexColors; this.skinning = source.skinning; this.morphTargets = source.morphTargets; this.morphNormals = source.morphNormals; this.derivatives = source.derivatives; return this; }; THREE.ShaderMaterial.prototype.toJSON = function ( meta ) { var data = THREE.Material.prototype.toJSON.call( this, meta ); data.uniforms = this.uniforms; data.attributes = this.attributes; data.vertexShader = this.vertexShader; data.fragmentShader = this.fragmentShader; return data; }; three.js-r73/src/materials/RawShaderMaterial.js0000644000175500017550000000053212610076566021421 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.RawShaderMaterial = function ( parameters ) { THREE.ShaderMaterial.call( this, parameters ); this.type = 'RawShaderMaterial'; }; THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype ); THREE.RawShaderMaterial.prototype.constructor = THREE.RawShaderMaterial;three.js-r73/src/materials/SpriteMaterial.js0000644000175500017550000000175512610076566021017 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * uvOffset: new THREE.Vector2(), * uvScale: new THREE.Vector2(), * * fog: * } */ THREE.SpriteMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'SpriteMaterial'; this.color = new THREE.Color( 0xffffff ); this.map = null; this.rotation = 0; this.fog = false; // set parameters this.setValues( parameters ); }; THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.SpriteMaterial.prototype.constructor = THREE.SpriteMaterial; THREE.SpriteMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.color.copy( source.color ); this.map = source.map; this.rotation = source.rotation; this.fog = source.fog; return this; }; three.js-r73/src/materials/PointsMaterial.js0000644000175500017550000000341612610076566021021 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * size: , * sizeAttenuation: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * vertexColors: , * * fog: * } */ THREE.PointsMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'PointsMaterial'; this.color = new THREE.Color( 0xffffff ); this.map = null; this.size = 1; this.sizeAttenuation = true; this.vertexColors = THREE.NoColors; this.fog = true; this.setValues( parameters ); }; THREE.PointsMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.PointsMaterial.prototype.constructor = THREE.PointsMaterial; THREE.PointsMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.color.copy( source.color ); this.map = source.map; this.size = source.size; this.sizeAttenuation = source.sizeAttenuation; this.vertexColors = source.vertexColors; this.fog = source.fog; return this; }; // backwards compatibility THREE.PointCloudMaterial = function ( parameters ) { console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); return new THREE.PointsMaterial( parameters ); }; THREE.ParticleBasicMaterial = function ( parameters ) { console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); return new THREE.PointsMaterial( parameters ); }; THREE.ParticleSystemMaterial = function ( parameters ) { console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' ); return new THREE.PointsMaterial( parameters ); }; three.js-r73/src/materials/MeshPhongMaterial.js0000644000175500017550000001007712610076566021436 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * emissive: , * specular: , * shininess: , * opacity: , * * map: new THREE.Texture( ), * * lightMap: new THREE.Texture( ), * lightMapIntensity: * * aoMap: new THREE.Texture( ), * aoMapIntensity: * * emissiveMap: new THREE.Texture( ), * * bumpMap: new THREE.Texture( ), * bumpScale: , * * normalMap: new THREE.Texture( ), * normalScale: , * * displacementMap: new THREE.Texture( ), * displacementScale: , * displacementBias: , * * specularMap: new THREE.Texture( ), * * alphaMap: new THREE.Texture( ), * * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * morphNormals: , * * fog: * } */ THREE.MeshPhongMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'MeshPhongMaterial'; this.color = new THREE.Color( 0xffffff ); // diffuse this.emissive = new THREE.Color( 0x000000 ); this.specular = new THREE.Color( 0x111111 ); this.shininess = 30; this.metal = false; this.map = null; this.lightMap = null; this.lightMapIntensity = 1.0; this.aoMap = null; this.aoMapIntensity = 1.0; this.emissiveMap = null; this.bumpMap = null; this.bumpScale = 1; this.normalMap = null; this.normalScale = new THREE.Vector2( 1, 1 ); this.displacementMap = null; this.displacementScale = 1; this.displacementBias = 0; this.specularMap = null; this.alphaMap = null; this.envMap = null; this.combine = THREE.MultiplyOperation; this.reflectivity = 1; this.refractionRatio = 0.98; this.fog = true; this.shading = THREE.SmoothShading; this.wireframe = false; this.wireframeLinewidth = 1; this.wireframeLinecap = 'round'; this.wireframeLinejoin = 'round'; this.vertexColors = THREE.NoColors; this.skinning = false; this.morphTargets = false; this.morphNormals = false; this.setValues( parameters ); }; THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshPhongMaterial.prototype.constructor = THREE.MeshPhongMaterial; THREE.MeshPhongMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.color.copy( source.color ); this.emissive.copy( source.emissive ); this.specular.copy( source.specular ); this.shininess = source.shininess; this.metal = source.metal; this.map = source.map; this.lightMap = source.lightMap; this.lightMapIntensity = source.lightMapIntensity; this.aoMap = source.aoMap; this.aoMapIntensity = source.aoMapIntensity; this.emissiveMap = source.emissiveMap; this.bumpMap = source.bumpMap; this.bumpScale = source.bumpScale; this.normalMap = source.normalMap; this.normalScale.copy( source.normalScale ); this.displacementMap = source.displacementMap; this.displacementScale = source.displacementScale; this.displacementBias = source.displacementBias; this.specularMap = source.specularMap; this.alphaMap = source.alphaMap; this.envMap = source.envMap; this.combine = source.combine; this.reflectivity = source.reflectivity; this.refractionRatio = source.refractionRatio; this.fog = source.fog; this.shading = source.shading; this.wireframe = source.wireframe; this.wireframeLinewidth = source.wireframeLinewidth; this.wireframeLinecap = source.wireframeLinecap; this.wireframeLinejoin = source.wireframeLinejoin; this.vertexColors = source.vertexColors; this.skinning = source.skinning; this.morphTargets = source.morphTargets; this.morphNormals = source.morphNormals; return this; }; three.js-r73/src/materials/Material.js0000644000175500017550000001451712610076566017630 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Material = function () { Object.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } ); this.uuid = THREE.Math.generateUUID(); this.name = ''; this.type = 'Material'; this.side = THREE.FrontSide; this.opacity = 1; this.transparent = false; this.blending = THREE.NormalBlending; this.blendSrc = THREE.SrcAlphaFactor; this.blendDst = THREE.OneMinusSrcAlphaFactor; this.blendEquation = THREE.AddEquation; this.blendSrcAlpha = null; this.blendDstAlpha = null; this.blendEquationAlpha = null; this.depthFunc = THREE.LessEqualDepth; this.depthTest = true; this.depthWrite = true; this.colorWrite = true; this.precision = null; // override the renderer's default precision for this material this.polygonOffset = false; this.polygonOffsetFactor = 0; this.polygonOffsetUnits = 0; this.alphaTest = 0; this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer this.visible = true; this._needsUpdate = true; }; THREE.Material.prototype = { constructor: THREE.Material, get needsUpdate () { return this._needsUpdate; }, set needsUpdate ( value ) { if ( value === true ) this.update(); this._needsUpdate = value; }, setValues: function ( values ) { if ( values === undefined ) return; for ( var key in values ) { var newValue = values[ key ]; if ( newValue === undefined ) { console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); continue; } var currentValue = this[ key ]; if ( currentValue === undefined ) { console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); continue; } if ( currentValue instanceof THREE.Color ) { currentValue.set( newValue ); } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { currentValue.copy( newValue ); } else if ( key === 'overdraw' ) { // ensure overdraw is backwards-compatible with legacy boolean type this[ key ] = Number( newValue ); } else { this[ key ] = newValue; } } }, toJSON: function ( meta ) { var data = { metadata: { version: 4.4, type: 'Material', generator: 'Material.toJSON' } }; // standard Material serialization data.uuid = this.uuid; data.type = this.type; if ( this.name !== '' ) data.name = this.name; if ( this.color instanceof THREE.Color ) data.color = this.color.getHex(); if ( this.emissive instanceof THREE.Color ) data.emissive = this.emissive.getHex(); if ( this.specular instanceof THREE.Color ) data.specular = this.specular.getHex(); if ( this.shininess !== undefined ) data.shininess = this.shininess; if ( this.map instanceof THREE.Texture ) data.map = this.map.toJSON( meta ).uuid; if ( this.alphaMap instanceof THREE.Texture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; if ( this.lightMap instanceof THREE.Texture ) data.lightMap = this.lightMap.toJSON( meta ).uuid; if ( this.bumpMap instanceof THREE.Texture ) { data.bumpMap = this.bumpMap.toJSON( meta ).uuid; data.bumpScale = this.bumpScale; } if ( this.normalMap instanceof THREE.Texture ) { data.normalMap = this.normalMap.toJSON( meta ).uuid; data.normalScale = this.normalScale; // Removed for now, causes issue in editor ui.js } if ( this.displacementMap instanceof THREE.Texture ) { data.displacementMap = this.displacementMap.toJSON( meta ).uuid; data.displacementScale = this.displacementScale; data.displacementBias = this.displacementBias; } if ( this.specularMap instanceof THREE.Texture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; if ( this.envMap instanceof THREE.Texture ) { data.envMap = this.envMap.toJSON( meta ).uuid; data.reflectivity = this.reflectivity; // Scale behind envMap } if ( this.size !== undefined ) data.size = this.size; if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; if ( this.vertexColors !== undefined && this.vertexColors !== THREE.NoColors ) data.vertexColors = this.vertexColors; if ( this.shading !== undefined && this.shading !== THREE.SmoothShading ) data.shading = this.shading; if ( this.blending !== undefined && this.blending !== THREE.NormalBlending ) data.blending = this.blending; if ( this.side !== undefined && this.side !== THREE.FrontSide ) data.side = this.side; if ( this.opacity < 1 ) data.opacity = this.opacity; if ( this.transparent === true ) data.transparent = this.transparent; if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; if ( this.wireframe === true ) data.wireframe = this.wireframe; if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; return data; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( source ) { this.name = source.name; this.side = source.side; this.opacity = source.opacity; this.transparent = source.transparent; this.blending = source.blending; this.blendSrc = source.blendSrc; this.blendDst = source.blendDst; this.blendEquation = source.blendEquation; this.blendSrcAlpha = source.blendSrcAlpha; this.blendDstAlpha = source.blendDstAlpha; this.blendEquationAlpha = source.blendEquationAlpha; this.depthFunc = source.depthFunc; this.depthTest = source.depthTest; this.depthWrite = source.depthWrite; this.precision = source.precision; this.polygonOffset = source.polygonOffset; this.polygonOffsetFactor = source.polygonOffsetFactor; this.polygonOffsetUnits = source.polygonOffsetUnits; this.alphaTest = source.alphaTest; this.overdraw = source.overdraw; this.visible = source.visible; return this; }, update: function () { this.dispatchEvent( { type: 'update' } ); }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); }, // Deprecated get wrapAround () { console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); }, set wrapAround ( boolean ) { console.warn( 'THREE.' + this.type + ': .wrapAround has been removed.' ); }, get wrapRGB () { console.warn( 'THREE.' + this.type + ': .wrapRGB has been removed.' ); return new THREE.Color(); } }; THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); THREE.MaterialIdCount = 0; three.js-r73/src/materials/MeshNormalMaterial.js0000644000175500017550000000162112610076566021606 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * * parameters = { * opacity: , * * shading: THREE.FlatShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: * } */ THREE.MeshNormalMaterial = function ( parameters ) { THREE.Material.call( this, parameters ); this.type = 'MeshNormalMaterial'; this.wireframe = false; this.wireframeLinewidth = 1; this.morphTargets = false; this.setValues( parameters ); }; THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshNormalMaterial.prototype.constructor = THREE.MeshNormalMaterial; THREE.MeshNormalMaterial.prototype.copy = function ( source ) { THREE.Material.prototype.copy.call( this, source ); this.wireframe = source.wireframe; this.wireframeLinewidth = source.wireframeLinewidth; return this; }; three.js-r73/src/math/0000755000175500017550000000000012610076566014474 5ustar debacledebaclethree.js-r73/src/math/Quaternion.js0000644000175500017550000002303512610076566017162 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley * @author bhouston / http://clara.io */ THREE.Quaternion = function ( x, y, z, w ) { this._x = x || 0; this._y = y || 0; this._z = z || 0; this._w = ( w !== undefined ) ? w : 1; }; THREE.Quaternion.prototype = { constructor: THREE.Quaternion, get x () { return this._x; }, set x ( value ) { this._x = value; this.onChangeCallback(); }, get y () { return this._y; }, set y ( value ) { this._y = value; this.onChangeCallback(); }, get z () { return this._z; }, set z ( value ) { this._z = value; this.onChangeCallback(); }, get w () { return this._w; }, set w ( value ) { this._w = value; this.onChangeCallback(); }, set: function ( x, y, z, w ) { this._x = x; this._y = y; this._z = z; this._w = w; this.onChangeCallback(); return this; }, clone: function () { return new this.constructor( this._x, this._y, this._z, this._w ); }, copy: function ( quaternion ) { this._x = quaternion.x; this._y = quaternion.y; this._z = quaternion.z; this._w = quaternion.w; this.onChangeCallback(); return this; }, setFromEuler: function ( euler, update ) { if ( euler instanceof THREE.Euler === false ) { throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } // http://www.mathworks.com/matlabcentral/fileexchange/ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ // content/SpinCalc.m var c1 = Math.cos( euler._x / 2 ); var c2 = Math.cos( euler._y / 2 ); var c3 = Math.cos( euler._z / 2 ); var s1 = Math.sin( euler._x / 2 ); var s2 = Math.sin( euler._y / 2 ); var s3 = Math.sin( euler._z / 2 ); var order = euler.order; if ( order === 'XYZ' ) { this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; } else if ( order === 'YXZ' ) { this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; } else if ( order === 'ZXY' ) { this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; } else if ( order === 'ZYX' ) { this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; } else if ( order === 'YZX' ) { this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; } else if ( order === 'XZY' ) { this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; } if ( update !== false ) this.onChangeCallback(); return this; }, setFromAxisAngle: function ( axis, angle ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm // assumes axis is normalized var halfAngle = angle / 2, s = Math.sin( halfAngle ); this._x = axis.x * s; this._y = axis.y * s; this._z = axis.z * s; this._w = Math.cos( halfAngle ); this.onChangeCallback(); return this; }, setFromRotationMatrix: function ( m ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var te = m.elements, m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], trace = m11 + m22 + m33, s; if ( trace > 0 ) { s = 0.5 / Math.sqrt( trace + 1.0 ); this._w = 0.25 / s; this._x = ( m32 - m23 ) * s; this._y = ( m13 - m31 ) * s; this._z = ( m21 - m12 ) * s; } else if ( m11 > m22 && m11 > m33 ) { s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); this._w = ( m32 - m23 ) / s; this._x = 0.25 * s; this._y = ( m12 + m21 ) / s; this._z = ( m13 + m31 ) / s; } else if ( m22 > m33 ) { s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); this._w = ( m13 - m31 ) / s; this._x = ( m12 + m21 ) / s; this._y = 0.25 * s; this._z = ( m23 + m32 ) / s; } else { s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); this._w = ( m21 - m12 ) / s; this._x = ( m13 + m31 ) / s; this._y = ( m23 + m32 ) / s; this._z = 0.25 * s; } this.onChangeCallback(); return this; }, setFromUnitVectors: function () { // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final // assumes direction vectors vFrom and vTo are normalized var v1, r; var EPS = 0.000001; return function ( vFrom, vTo ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); r = vFrom.dot( vTo ) + 1; if ( r < EPS ) { r = 0; if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { v1.set( - vFrom.y, vFrom.x, 0 ); } else { v1.set( 0, - vFrom.z, vFrom.y ); } } else { v1.crossVectors( vFrom, vTo ); } this._x = v1.x; this._y = v1.y; this._z = v1.z; this._w = r; this.normalize(); return this; } }(), inverse: function () { this.conjugate().normalize(); return this; }, conjugate: function () { this._x *= - 1; this._y *= - 1; this._z *= - 1; this.onChangeCallback(); return this; }, dot: function ( v ) { return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; }, lengthSq: function () { return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; }, length: function () { return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); }, normalize: function () { var l = this.length(); if ( l === 0 ) { this._x = 0; this._y = 0; this._z = 0; this._w = 1; } else { l = 1 / l; this._x = this._x * l; this._y = this._y * l; this._z = this._z * l; this._w = this._w * l; } this.onChangeCallback(); return this; }, multiply: function ( q, p ) { if ( p !== undefined ) { console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); return this.multiplyQuaternions( q, p ); } return this.multiplyQuaternions( this, q ); }, multiplyQuaternions: function ( a, b ) { // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; this.onChangeCallback(); return this; }, multiplyVector3: function ( vector ) { console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); return vector.applyQuaternion( this ); }, slerp: function ( qb, t ) { if ( t === 0 ) return this; if ( t === 1 ) return this.copy( qb ); var x = this._x, y = this._y, z = this._z, w = this._w; // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; if ( cosHalfTheta < 0 ) { this._w = - qb._w; this._x = - qb._x; this._y = - qb._y; this._z = - qb._z; cosHalfTheta = - cosHalfTheta; } else { this.copy( qb ); } if ( cosHalfTheta >= 1.0 ) { this._w = w; this._x = x; this._y = y; this._z = z; return this; } var halfTheta = Math.acos( cosHalfTheta ); var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); if ( Math.abs( sinHalfTheta ) < 0.001 ) { this._w = 0.5 * ( w + this._w ); this._x = 0.5 * ( x + this._x ); this._y = 0.5 * ( y + this._y ); this._z = 0.5 * ( z + this._z ); return this; } var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; this._w = ( w * ratioA + this._w * ratioB ); this._x = ( x * ratioA + this._x * ratioB ); this._y = ( y * ratioA + this._y * ratioB ); this._z = ( z * ratioA + this._z * ratioB ); this.onChangeCallback(); return this; }, equals: function ( quaternion ) { return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); }, fromArray: function ( array, offset ) { if ( offset === undefined ) offset = 0; this._x = array[ offset ]; this._y = array[ offset + 1 ]; this._z = array[ offset + 2 ]; this._w = array[ offset + 3 ]; this.onChangeCallback(); return this; }, toArray: function ( array, offset ) { if ( array === undefined ) array = []; if ( offset === undefined ) offset = 0; array[ offset ] = this._x; array[ offset + 1 ] = this._y; array[ offset + 2 ] = this._z; array[ offset + 3 ] = this._w; return array; }, onChange: function ( callback ) { this.onChangeCallback = callback; return this; }, onChangeCallback: function () {} }; THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { return qm.copy( qa ).slerp( qb, t ); }; three.js-r73/src/math/Spline.js0000644000175500017550000000741612610076566016274 0ustar debacledebacle/** * Spline from Tween.js, slightly optimized (and trashed) * http://sole.github.com/tween.js/examples/05_spline.html * * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Spline = function ( points ) { this.points = points; var c = [], v3 = { x: 0, y: 0, z: 0 }, point, intPoint, weight, w2, w3, pa, pb, pc, pd; this.initFromArray = function ( a ) { this.points = []; for ( var i = 0; i < a.length; i ++ ) { this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; } }; this.getPoint = function ( k ) { point = ( this.points.length - 1 ) * k; intPoint = Math.floor( point ); weight = point - intPoint; c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; c[ 1 ] = intPoint; c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; pa = this.points[ c[ 0 ] ]; pb = this.points[ c[ 1 ] ]; pc = this.points[ c[ 2 ] ]; pd = this.points[ c[ 3 ] ]; w2 = weight * weight; w3 = weight * w2; v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); return v3; }; this.getControlPointsArray = function () { var i, p, l = this.points.length, coords = []; for ( i = 0; i < l; i ++ ) { p = this.points[ i ]; coords[ i ] = [ p.x, p.y, p.z ]; } return coords; }; // approximate length by summing linear segments this.getLength = function ( nSubDivisions ) { var i, index, nSamples, position, point = 0, intPoint = 0, oldIntPoint = 0, oldPosition = new THREE.Vector3(), tmpVec = new THREE.Vector3(), chunkLengths = [], totalLength = 0; // first point has 0 length chunkLengths[ 0 ] = 0; if ( ! nSubDivisions ) nSubDivisions = 100; nSamples = this.points.length * nSubDivisions; oldPosition.copy( this.points[ 0 ] ); for ( i = 1; i < nSamples; i ++ ) { index = i / nSamples; position = this.getPoint( index ); tmpVec.copy( position ); totalLength += tmpVec.distanceTo( oldPosition ); oldPosition.copy( position ); point = ( this.points.length - 1 ) * index; intPoint = Math.floor( point ); if ( intPoint !== oldIntPoint ) { chunkLengths[ intPoint ] = totalLength; oldIntPoint = intPoint; } } // last point ends with total length chunkLengths[ chunkLengths.length ] = totalLength; return { chunks: chunkLengths, total: totalLength }; }; this.reparametrizeByArcLength = function ( samplingCoef ) { var i, j, index, indexCurrent, indexNext, realDistance, sampling, position, newpoints = [], tmpVec = new THREE.Vector3(), sl = this.getLength(); newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); for ( i = 1; i < this.points.length; i ++ ) { //tmpVec.copy( this.points[ i - 1 ] ); //linearDistance = tmpVec.distanceTo( this.points[ i ] ); realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; sampling = Math.ceil( samplingCoef * realDistance / sl.total ); indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); indexNext = i / ( this.points.length - 1 ); for ( j = 1; j < sampling - 1; j ++ ) { index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); position = this.getPoint( index ); newpoints.push( tmpVec.copy( position ).clone() ); } newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); } this.points = newpoints; }; // Catmull-Rom function interpolate( p0, p1, p2, p3, t, t2, t3 ) { var v0 = ( p2 - p0 ) * 0.5, v1 = ( p3 - p1 ) * 0.5; return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; } }; three.js-r73/src/math/Math.js0000644000175500017550000000572512610076566015734 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.Math = { generateUUID: function () { // http://www.broofa.com/Tools/Math.uuid.htm var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' ); var uuid = new Array( 36 ); var rnd = 0, r; return function () { for ( var i = 0; i < 36; i ++ ) { if ( i === 8 || i === 13 || i === 18 || i === 23 ) { uuid[ i ] = '-'; } else if ( i === 14 ) { uuid[ i ] = '4'; } else { if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; r = rnd & 0xf; rnd = rnd >> 4; uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ]; } } return uuid.join( '' ); }; }(), clamp: function ( value, min, max ) { return Math.max( min, Math.min( max, value ) ); }, // compute euclidian modulo of m % n // https://en.wikipedia.org/wiki/Modulo_operation euclideanModulo: function ( n, m ) { return ( ( n % m ) + m ) % m; }, // Linear mapping from range to range mapLinear: function ( x, a1, a2, b1, b2 ) { return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); }, // http://en.wikipedia.org/wiki/Smoothstep smoothstep: function ( x, min, max ) { if ( x <= min ) return 0; if ( x >= max ) return 1; x = ( x - min ) / ( max - min ); return x * x * ( 3 - 2 * x ); }, smootherstep: function ( x, min, max ) { if ( x <= min ) return 0; if ( x >= max ) return 1; x = ( x - min ) / ( max - min ); return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); }, // Random float from <0, 1> with 16 bits of randomness // (standard Math.random() creates repetitive patterns when applied over larger space) random16: function () { return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; }, // Random integer from interval randInt: function ( low, high ) { return low + Math.floor( Math.random() * ( high - low + 1 ) ); }, // Random float from interval randFloat: function ( low, high ) { return low + Math.random() * ( high - low ); }, // Random float from <-range/2, range/2> interval randFloatSpread: function ( range ) { return range * ( 0.5 - Math.random() ); }, degToRad: function () { var degreeToRadiansFactor = Math.PI / 180; return function ( degrees ) { return degrees * degreeToRadiansFactor; }; }(), radToDeg: function () { var radianToDegreesFactor = 180 / Math.PI; return function ( radians ) { return radians * radianToDegreesFactor; }; }(), isPowerOfTwo: function ( value ) { return ( value & ( value - 1 ) ) === 0 && value !== 0; }, nearestPowerOfTwo: function ( value ) { return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) ); }, nextPowerOfTwo: function ( value ) { value --; value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; value ++; return value; } }; three.js-r73/src/math/Line3.js0000644000175500017550000000427012610076566016007 0ustar debacledebacle/** * @author bhouston / http://clara.io */ THREE.Line3 = function ( start, end ) { this.start = ( start !== undefined ) ? start : new THREE.Vector3(); this.end = ( end !== undefined ) ? end : new THREE.Vector3(); }; THREE.Line3.prototype = { constructor: THREE.Line3, set: function ( start, end ) { this.start.copy( start ); this.end.copy( end ); return this; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( line ) { this.start.copy( line.start ); this.end.copy( line.end ); return this; }, center: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); }, delta: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.subVectors( this.end, this.start ); }, distanceSq: function () { return this.start.distanceToSquared( this.end ); }, distance: function () { return this.start.distanceTo( this.end ); }, at: function ( t, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return this.delta( result ).multiplyScalar( t ).add( this.start ); }, closestPointToPointParameter: function () { var startP = new THREE.Vector3(); var startEnd = new THREE.Vector3(); return function ( point, clampToLine ) { startP.subVectors( point, this.start ); startEnd.subVectors( this.end, this.start ); var startEnd2 = startEnd.dot( startEnd ); var startEnd_startP = startEnd.dot( startP ); var t = startEnd_startP / startEnd2; if ( clampToLine ) { t = THREE.Math.clamp( t, 0, 1 ); } return t; }; }(), closestPointToPoint: function ( point, clampToLine, optionalTarget ) { var t = this.closestPointToPointParameter( point, clampToLine ); var result = optionalTarget || new THREE.Vector3(); return this.delta( result ).multiplyScalar( t ).add( this.start ); }, applyMatrix4: function ( matrix ) { this.start.applyMatrix4( matrix ); this.end.applyMatrix4( matrix ); return this; }, equals: function ( line ) { return line.start.equals( this.start ) && line.end.equals( this.end ); } }; three.js-r73/src/math/Frustum.js0000644000175500017550000000710712610076566016504 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author bhouston / http://clara.io */ THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { this.planes = [ ( p0 !== undefined ) ? p0 : new THREE.Plane(), ( p1 !== undefined ) ? p1 : new THREE.Plane(), ( p2 !== undefined ) ? p2 : new THREE.Plane(), ( p3 !== undefined ) ? p3 : new THREE.Plane(), ( p4 !== undefined ) ? p4 : new THREE.Plane(), ( p5 !== undefined ) ? p5 : new THREE.Plane() ]; }; THREE.Frustum.prototype = { constructor: THREE.Frustum, set: function ( p0, p1, p2, p3, p4, p5 ) { var planes = this.planes; planes[ 0 ].copy( p0 ); planes[ 1 ].copy( p1 ); planes[ 2 ].copy( p2 ); planes[ 3 ].copy( p3 ); planes[ 4 ].copy( p4 ); planes[ 5 ].copy( p5 ); return this; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( frustum ) { var planes = this.planes; for ( var i = 0; i < 6; i ++ ) { planes[ i ].copy( frustum.planes[ i ] ); } return this; }, setFromMatrix: function ( m ) { var planes = this.planes; var me = m.elements; var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); return this; }, intersectsObject: function () { var sphere = new THREE.Sphere(); return function ( object ) { var geometry = object.geometry; if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( object.matrixWorld ); return this.intersectsSphere( sphere ); }; }(), intersectsSphere: function ( sphere ) { var planes = this.planes; var center = sphere.center; var negRadius = - sphere.radius; for ( var i = 0; i < 6; i ++ ) { var distance = planes[ i ].distanceToPoint( center ); if ( distance < negRadius ) { return false; } } return true; }, intersectsBox: function () { var p1 = new THREE.Vector3(), p2 = new THREE.Vector3(); return function ( box ) { var planes = this.planes; for ( var i = 0; i < 6 ; i ++ ) { var plane = planes[ i ]; p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; var d1 = plane.distanceToPoint( p1 ); var d2 = plane.distanceToPoint( p2 ); // if both outside plane, no intersection if ( d1 < 0 && d2 < 0 ) { return false; } } return true; }; }(), containsPoint: function ( point ) { var planes = this.planes; for ( var i = 0; i < 6; i ++ ) { if ( planes[ i ].distanceToPoint( point ) < 0 ) { return false; } } return true; } }; three.js-r73/src/math/Vector4.js0000644000175500017550000002516612610076566016372 0ustar debacledebacle/** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ * @author egraether / http://egraether.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.Vector4 = function ( x, y, z, w ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; this.w = ( w !== undefined ) ? w : 1; }; THREE.Vector4.prototype = { constructor: THREE.Vector4, set: function ( x, y, z, w ) { this.x = x; this.y = y; this.z = z; this.w = w; return this; }, setX: function ( x ) { this.x = x; return this; }, setY: function ( y ) { this.y = y; return this; }, setZ: function ( z ) { this.z = z; return this; }, setW: function ( w ) { this.w = w; return this; }, setComponent: function ( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; case 2: this.z = value; break; case 3: this.w = value; break; default: throw new Error( 'index is out of range: ' + index ); } }, getComponent: function ( index ) { switch ( index ) { case 0: return this.x; case 1: return this.y; case 2: return this.z; case 3: return this.w; default: throw new Error( 'index is out of range: ' + index ); } }, clone: function () { return new this.constructor( this.x, this.y, this.z, this.w ); }, copy: function ( v ) { this.x = v.x; this.y = v.y; this.z = v.z; this.w = ( v.w !== undefined ) ? v.w : 1; return this; }, add: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } this.x += v.x; this.y += v.y; this.z += v.z; this.w += v.w; return this; }, addScalar: function ( s ) { this.x += s; this.y += s; this.z += s; this.w += s; return this; }, addVectors: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; this.z = a.z + b.z; this.w = a.w + b.w; return this; }, addScaledVector: function ( v, s ) { this.x += v.x * s; this.y += v.y * s; this.z += v.z * s; this.w += v.w * s; return this; }, sub: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } this.x -= v.x; this.y -= v.y; this.z -= v.z; this.w -= v.w; return this; }, subScalar: function ( s ) { this.x -= s; this.y -= s; this.z -= s; this.w -= s; return this; }, subVectors: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; this.z = a.z - b.z; this.w = a.w - b.w; return this; }, multiplyScalar: function ( scalar ) { if ( isFinite( scalar ) ) { this.x *= scalar; this.y *= scalar; this.z *= scalar; this.w *= scalar; } else { this.x = 0; this.y = 0; this.z = 0; this.w = 0; } return this; }, applyMatrix4: function ( m ) { var x = this.x; var y = this.y; var z = this.z; var w = this.w; var e = m.elements; this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; return this; }, divideScalar: function ( scalar ) { return this.multiplyScalar( 1 / scalar ); }, setAxisAngleFromQuaternion: function ( q ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm // q is assumed to be normalized this.w = 2 * Math.acos( q.w ); var s = Math.sqrt( 1 - q.w * q.w ); if ( s < 0.0001 ) { this.x = 1; this.y = 0; this.z = 0; } else { this.x = q.x / s; this.y = q.y / s; this.z = q.z / s; } return this; }, setAxisAngleFromRotationMatrix: function ( m ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var angle, x, y, z, // variables for result epsilon = 0.01, // margin to allow for rounding errors epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees te = m.elements, m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; if ( ( Math.abs( m12 - m21 ) < epsilon ) && ( Math.abs( m13 - m31 ) < epsilon ) && ( Math.abs( m23 - m32 ) < epsilon ) ) { // singularity found // first check for identity matrix which must have +1 for all terms // in leading diagonal and zero in other terms if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && ( Math.abs( m13 + m31 ) < epsilon2 ) && ( Math.abs( m23 + m32 ) < epsilon2 ) && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { // this singularity is identity matrix so angle = 0 this.set( 1, 0, 0, 0 ); return this; // zero angle, arbitrary axis } // otherwise this singularity is angle = 180 angle = Math.PI; var xx = ( m11 + 1 ) / 2; var yy = ( m22 + 1 ) / 2; var zz = ( m33 + 1 ) / 2; var xy = ( m12 + m21 ) / 4; var xz = ( m13 + m31 ) / 4; var yz = ( m23 + m32 ) / 4; if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term if ( xx < epsilon ) { x = 0; y = 0.707106781; z = 0.707106781; } else { x = Math.sqrt( xx ); y = xy / x; z = xz / x; } } else if ( yy > zz ) { // m22 is the largest diagonal term if ( yy < epsilon ) { x = 0.707106781; y = 0; z = 0.707106781; } else { y = Math.sqrt( yy ); x = xy / y; z = yz / y; } } else { // m33 is the largest diagonal term so base result on this if ( zz < epsilon ) { x = 0.707106781; y = 0.707106781; z = 0; } else { z = Math.sqrt( zz ); x = xz / z; y = yz / z; } } this.set( x, y, z, angle ); return this; // return 180 deg rotation } // as we have reached here there are no singularities so we can handle normally var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + ( m13 - m31 ) * ( m13 - m31 ) + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize if ( Math.abs( s ) < 0.001 ) s = 1; // prevent divide by zero, should not happen if matrix is orthogonal and should be // caught by singularity test above, but I've left it in just in case this.x = ( m32 - m23 ) / s; this.y = ( m13 - m31 ) / s; this.z = ( m21 - m12 ) / s; this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); return this; }, min: function ( v ) { this.x = Math.min( this.x, v.x ); this.y = Math.min( this.y, v.y ); this.z = Math.min( this.z, v.z ); this.w = Math.min( this.w, v.w ); return this; }, max: function ( v ) { this.x = Math.max( this.x, v.x ); this.y = Math.max( this.y, v.y ); this.z = Math.max( this.z, v.z ); this.w = Math.max( this.w, v.w ); return this; }, clamp: function ( min, max ) { // This function assumes min < max, if this assumption isn't true it will not operate correctly this.x = Math.max( min.x, Math.min( max.x, this.x ) ); this.y = Math.max( min.y, Math.min( max.y, this.y ) ); this.z = Math.max( min.z, Math.min( max.z, this.z ) ); this.w = Math.max( min.w, Math.min( max.w, this.w ) ); return this; }, clampScalar: function () { var min, max; return function clampScalar( minVal, maxVal ) { if ( min === undefined ) { min = new THREE.Vector4(); max = new THREE.Vector4(); } min.set( minVal, minVal, minVal, minVal ); max.set( maxVal, maxVal, maxVal, maxVal ); return this.clamp( min, max ); }; }(), floor: function () { this.x = Math.floor( this.x ); this.y = Math.floor( this.y ); this.z = Math.floor( this.z ); this.w = Math.floor( this.w ); return this; }, ceil: function () { this.x = Math.ceil( this.x ); this.y = Math.ceil( this.y ); this.z = Math.ceil( this.z ); this.w = Math.ceil( this.w ); return this; }, round: function () { this.x = Math.round( this.x ); this.y = Math.round( this.y ); this.z = Math.round( this.z ); this.w = Math.round( this.w ); return this; }, roundToZero: function () { this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); return this; }, negate: function () { this.x = - this.x; this.y = - this.y; this.z = - this.z; this.w = - this.w; return this; }, dot: function ( v ) { return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; }, lengthSq: function () { return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; }, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); }, lengthManhattan: function () { return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); }, normalize: function () { return this.divideScalar( this.length() ); }, setLength: function ( length ) { return this.multiplyScalar( length / this.length() ); }, lerp: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; this.z += ( v.z - this.z ) * alpha; this.w += ( v.w - this.w ) * alpha; return this; }, lerpVectors: function ( v1, v2, alpha ) { this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); return this; }, equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); }, fromArray: function ( array, offset ) { if ( offset === undefined ) offset = 0; this.x = array[ offset ]; this.y = array[ offset + 1 ]; this.z = array[ offset + 2 ]; this.w = array[ offset + 3 ]; return this; }, toArray: function ( array, offset ) { if ( array === undefined ) array = []; if ( offset === undefined ) offset = 0; array[ offset ] = this.x; array[ offset + 1 ] = this.y; array[ offset + 2 ] = this.z; array[ offset + 3 ] = this.w; return array; }, fromAttribute: function ( attribute, index, offset ) { if ( offset === undefined ) offset = 0; index = index * attribute.itemSize + offset; this.x = attribute.array[ index ]; this.y = attribute.array[ index + 1 ]; this.z = attribute.array[ index + 2 ]; this.w = attribute.array[ index + 3 ]; return this; } }; three.js-r73/src/math/Plane.js0000644000175500017550000001051512610076566016073 0ustar debacledebacle/** * @author bhouston / http://clara.io */ THREE.Plane = function ( normal, constant ) { this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); this.constant = ( constant !== undefined ) ? constant : 0; }; THREE.Plane.prototype = { constructor: THREE.Plane, set: function ( normal, constant ) { this.normal.copy( normal ); this.constant = constant; return this; }, setComponents: function ( x, y, z, w ) { this.normal.set( x, y, z ); this.constant = w; return this; }, setFromNormalAndCoplanarPoint: function ( normal, point ) { this.normal.copy( normal ); this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized return this; }, setFromCoplanarPoints: function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); return function ( a, b, c ) { var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? this.setFromNormalAndCoplanarPoint( normal, a ); return this; }; }(), clone: function () { return new this.constructor().copy( this ); }, copy: function ( plane ) { this.normal.copy( plane.normal ); this.constant = plane.constant; return this; }, normalize: function () { // Note: will lead to a divide by zero if the plane is invalid. var inverseNormalLength = 1.0 / this.normal.length(); this.normal.multiplyScalar( inverseNormalLength ); this.constant *= inverseNormalLength; return this; }, negate: function () { this.constant *= - 1; this.normal.negate(); return this; }, distanceToPoint: function ( point ) { return this.normal.dot( point ) + this.constant; }, distanceToSphere: function ( sphere ) { return this.distanceToPoint( sphere.center ) - sphere.radius; }, projectPoint: function ( point, optionalTarget ) { return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); }, orthoPoint: function ( point, optionalTarget ) { var perpendicularMagnitude = this.distanceToPoint( point ); var result = optionalTarget || new THREE.Vector3(); return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); }, isIntersectionLine: function ( line ) { // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. var startSign = this.distanceToPoint( line.start ); var endSign = this.distanceToPoint( line.end ); return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); }, intersectLine: function () { var v1 = new THREE.Vector3(); return function ( line, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); var direction = line.delta( v1 ); var denominator = this.normal.dot( direction ); if ( denominator === 0 ) { // line is coplanar, return origin if ( this.distanceToPoint( line.start ) === 0 ) { return result.copy( line.start ); } // Unsure if this is the correct method to handle this case. return undefined; } var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; if ( t < 0 || t > 1 ) { return undefined; } return result.copy( direction ).multiplyScalar( t ).add( line.start ); }; }(), coplanarPoint: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.copy( this.normal ).multiplyScalar( - this.constant ); }, applyMatrix4: function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); var m1 = new THREE.Matrix3(); return function ( matrix, optionalNormalMatrix ) { // compute new normal based on theory here: // http://www.songho.ca/opengl/gl_normaltransform.html var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); var newCoplanarPoint = this.coplanarPoint( v2 ); newCoplanarPoint.applyMatrix4( matrix ); this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); return this; }; }(), translate: function ( offset ) { this.constant = this.constant - offset.dot( this.normal ); return this; }, equals: function ( plane ) { return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); } }; three.js-r73/src/math/Box3.js0000644000175500017550000001537512610076566015660 0ustar debacledebacle/** * @author bhouston / http://clara.io * @author WestLangley / http://github.com/WestLangley */ THREE.Box3 = function ( min, max ) { this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); this.max = ( max !== undefined ) ? max : new THREE.Vector3( - Infinity, - Infinity, - Infinity ); }; THREE.Box3.prototype = { constructor: THREE.Box3, set: function ( min, max ) { this.min.copy( min ); this.max.copy( max ); return this; }, setFromPoints: function ( points ) { this.makeEmpty(); for ( var i = 0, il = points.length; i < il; i ++ ) { this.expandByPoint( points[ i ] ); } return this; }, setFromCenterAndSize: function () { var v1 = new THREE.Vector3(); return function ( center, size ) { var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); this.min.copy( center ).sub( halfSize ); this.max.copy( center ).add( halfSize ); return this; }; }(), setFromObject: function () { // Computes the world-axis-aligned bounding box of an object (including its children), // accounting for both the object's, and children's, world transforms var v1 = new THREE.Vector3(); return function ( object ) { var scope = this; object.updateMatrixWorld( true ); this.makeEmpty(); object.traverse( function ( node ) { var geometry = node.geometry; if ( geometry !== undefined ) { if ( geometry instanceof THREE.Geometry ) { var vertices = geometry.vertices; for ( var i = 0, il = vertices.length; i < il; i ++ ) { v1.copy( vertices[ i ] ); v1.applyMatrix4( node.matrixWorld ); scope.expandByPoint( v1 ); } } else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) { var positions = geometry.attributes[ 'position' ].array; for ( var i = 0, il = positions.length; i < il; i += 3 ) { v1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); v1.applyMatrix4( node.matrixWorld ); scope.expandByPoint( v1 ); } } } } ); return this; }; }(), clone: function () { return new this.constructor().copy( this ); }, copy: function ( box ) { this.min.copy( box.min ); this.max.copy( box.max ); return this; }, makeEmpty: function () { this.min.x = this.min.y = this.min.z = Infinity; this.max.x = this.max.y = this.max.z = - Infinity; return this; }, empty: function () { // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); }, center: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); }, size: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.subVectors( this.max, this.min ); }, expandByPoint: function ( point ) { this.min.min( point ); this.max.max( point ); return this; }, expandByVector: function ( vector ) { this.min.sub( vector ); this.max.add( vector ); return this; }, expandByScalar: function ( scalar ) { this.min.addScalar( - scalar ); this.max.addScalar( scalar ); return this; }, containsPoint: function ( point ) { if ( point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y || point.z < this.min.z || point.z > this.max.z ) { return false; } return true; }, containsBox: function ( box ) { if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) && ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) { return true; } return false; }, getParameter: function ( point, optionalTarget ) { // This can potentially have a divide by zero if the box // has a size dimension of 0. var result = optionalTarget || new THREE.Vector3(); return result.set( ( point.x - this.min.x ) / ( this.max.x - this.min.x ), ( point.y - this.min.y ) / ( this.max.y - this.min.y ), ( point.z - this.min.z ) / ( this.max.z - this.min.z ) ); }, isIntersectionBox: function ( box ) { // using 6 splitting planes to rule out intersections. if ( box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y || box.max.z < this.min.z || box.min.z > this.max.z ) { return false; } return true; }, clampPoint: function ( point, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.copy( point ).clamp( this.min, this.max ); }, distanceToPoint: function () { var v1 = new THREE.Vector3(); return function ( point ) { var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); return clampedPoint.sub( point ).length(); }; }(), getBoundingSphere: function () { var v1 = new THREE.Vector3(); return function ( optionalTarget ) { var result = optionalTarget || new THREE.Sphere(); result.center = this.center(); result.radius = this.size( v1 ).length() * 0.5; return result; }; }(), intersect: function ( box ) { this.min.max( box.min ); this.max.min( box.max ); return this; }, union: function ( box ) { this.min.min( box.min ); this.max.max( box.max ); return this; }, applyMatrix4: function () { var points = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; return function ( matrix ) { // NOTE: I am using a binary pattern to specify all 2^3 combinations below points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 this.makeEmpty(); this.setFromPoints( points ); return this; }; }(), translate: function ( offset ) { this.min.add( offset ); this.max.add( offset ); return this; }, equals: function ( box ) { return box.min.equals( this.min ) && box.max.equals( this.max ); } }; three.js-r73/src/math/Box2.js0000644000175500017550000000752112610076566015651 0ustar debacledebacle/** * @author bhouston / http://clara.io */ THREE.Box2 = function ( min, max ) { this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); this.max = ( max !== undefined ) ? max : new THREE.Vector2( - Infinity, - Infinity ); }; THREE.Box2.prototype = { constructor: THREE.Box2, set: function ( min, max ) { this.min.copy( min ); this.max.copy( max ); return this; }, setFromPoints: function ( points ) { this.makeEmpty(); for ( var i = 0, il = points.length; i < il; i ++ ) { this.expandByPoint( points[ i ] ) } return this; }, setFromCenterAndSize: function () { var v1 = new THREE.Vector2(); return function ( center, size ) { var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); this.min.copy( center ).sub( halfSize ); this.max.copy( center ).add( halfSize ); return this; }; }(), clone: function () { return new this.constructor().copy( this ); }, copy: function ( box ) { this.min.copy( box.min ); this.max.copy( box.max ); return this; }, makeEmpty: function () { this.min.x = this.min.y = Infinity; this.max.x = this.max.y = - Infinity; return this; }, empty: function () { // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); }, center: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector2(); return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); }, size: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector2(); return result.subVectors( this.max, this.min ); }, expandByPoint: function ( point ) { this.min.min( point ); this.max.max( point ); return this; }, expandByVector: function ( vector ) { this.min.sub( vector ); this.max.add( vector ); return this; }, expandByScalar: function ( scalar ) { this.min.addScalar( - scalar ); this.max.addScalar( scalar ); return this; }, containsPoint: function ( point ) { if ( point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y ) { return false; } return true; }, containsBox: function ( box ) { if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { return true; } return false; }, getParameter: function ( point, optionalTarget ) { // This can potentially have a divide by zero if the box // has a size dimension of 0. var result = optionalTarget || new THREE.Vector2(); return result.set( ( point.x - this.min.x ) / ( this.max.x - this.min.x ), ( point.y - this.min.y ) / ( this.max.y - this.min.y ) ); }, isIntersectionBox: function ( box ) { // using 6 splitting planes to rule out intersections. if ( box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y ) { return false; } return true; }, clampPoint: function ( point, optionalTarget ) { var result = optionalTarget || new THREE.Vector2(); return result.copy( point ).clamp( this.min, this.max ); }, distanceToPoint: function () { var v1 = new THREE.Vector2(); return function ( point ) { var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); return clampedPoint.sub( point ).length(); }; }(), intersect: function ( box ) { this.min.max( box.min ); this.max.min( box.max ); return this; }, union: function ( box ) { this.min.min( box.min ); this.max.max( box.max ); return this; }, translate: function ( offset ) { this.min.add( offset ); this.max.add( offset ); return this; }, equals: function ( box ) { return box.min.equals( this.min ) && box.max.equals( this.max ); } }; three.js-r73/src/math/Ray.js0000644000175500017550000002556312610076566015600 0ustar debacledebacle/** * @author bhouston / http://clara.io */ THREE.Ray = function ( origin, direction ) { this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); }; THREE.Ray.prototype = { constructor: THREE.Ray, set: function ( origin, direction ) { this.origin.copy( origin ); this.direction.copy( direction ); return this; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( ray ) { this.origin.copy( ray.origin ); this.direction.copy( ray.direction ); return this; }, at: function ( t, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); }, recast: function () { var v1 = new THREE.Vector3(); return function ( t ) { this.origin.copy( this.at( t, v1 ) ); return this; }; }(), closestPointToPoint: function ( point, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); result.subVectors( point, this.origin ); var directionDistance = result.dot( this.direction ); if ( directionDistance < 0 ) { return result.copy( this.origin ); } return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); }, distanceToPoint: function ( point ) { return Math.sqrt( this.distanceSqToPoint( point ) ); }, distanceSqToPoint: function () { var v1 = new THREE.Vector3(); return function ( point ) { var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); // point behind the ray if ( directionDistance < 0 ) { return this.origin.distanceToSquared( point ); } v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); return v1.distanceToSquared( point ); }; }(), distanceSqToSegment: function () { var segCenter = new THREE.Vector3(); var segDir = new THREE.Vector3(); var diff = new THREE.Vector3(); return function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp // It returns the min distance between the ray and the segment // defined by v0 and v1 // It can also set two optional targets : // - The closest point on the ray // - The closest point on the segment segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); segDir.copy( v1 ).sub( v0 ).normalize(); diff.copy( this.origin ).sub( segCenter ); var segExtent = v0.distanceTo( v1 ) * 0.5; var a01 = - this.direction.dot( segDir ); var b0 = diff.dot( this.direction ); var b1 = - diff.dot( segDir ); var c = diff.lengthSq(); var det = Math.abs( 1 - a01 * a01 ); var s0, s1, sqrDist, extDet; if ( det > 0 ) { // The ray and segment are not parallel. s0 = a01 * b1 - b0; s1 = a01 * b0 - b1; extDet = segExtent * det; if ( s0 >= 0 ) { if ( s1 >= - extDet ) { if ( s1 <= extDet ) { // region 0 // Minimum at interior points of ray and segment. var invDet = 1 / det; s0 *= invDet; s1 *= invDet; sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; } else { // region 1 s1 = segExtent; s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } } else { // region 5 s1 = - segExtent; s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } } else { if ( s1 <= - extDet ) { // region 4 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } else if ( s1 <= extDet ) { // region 3 s0 = 0; s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); sqrDist = s1 * ( s1 + 2 * b1 ) + c; } else { // region 2 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } } } else { // Ray and segment are parallel. s1 = ( a01 > 0 ) ? - segExtent : segExtent; s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } if ( optionalPointOnRay ) { optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); } if ( optionalPointOnSegment ) { optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); } return sqrDist; }; }(), isIntersectionSphere: function ( sphere ) { return this.distanceToPoint( sphere.center ) <= sphere.radius; }, intersectSphere: function () { // from http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-sphere-intersection/ var v1 = new THREE.Vector3(); return function ( sphere, optionalTarget ) { v1.subVectors( sphere.center, this.origin ); var tca = v1.dot( this.direction ); var d2 = v1.dot( v1 ) - tca * tca; var radius2 = sphere.radius * sphere.radius; if ( d2 > radius2 ) return null; var thc = Math.sqrt( radius2 - d2 ); // t0 = first intersect point - entrance on front of sphere var t0 = tca - thc; // t1 = second intersect point - exit point on back of sphere var t1 = tca + thc; // test to see if both t0 and t1 are behind the ray - if so, return null if ( t0 < 0 && t1 < 0 ) return null; // test to see if t0 is behind the ray: // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, // in order to always return an intersect point that is in front of the ray. if ( t0 < 0 ) return this.at( t1, optionalTarget ); // else t0 is in front of the ray, so return the first collision point scaled by t0 return this.at( t0, optionalTarget ); } }(), isIntersectionPlane: function ( plane ) { // check if the ray lies on the plane first var distToPoint = plane.distanceToPoint( this.origin ); if ( distToPoint === 0 ) { return true; } var denominator = plane.normal.dot( this.direction ); if ( denominator * distToPoint < 0 ) { return true; } // ray origin is behind the plane (and is pointing behind it) return false; }, distanceToPlane: function ( plane ) { var denominator = plane.normal.dot( this.direction ); if ( denominator === 0 ) { // line is coplanar, return origin if ( plane.distanceToPoint( this.origin ) === 0 ) { return 0; } // Null is preferable to undefined since undefined means.... it is undefined return null; } var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; // Return if the ray never intersects the plane return t >= 0 ? t : null; }, intersectPlane: function ( plane, optionalTarget ) { var t = this.distanceToPlane( plane ); if ( t === null ) { return null; } return this.at( t, optionalTarget ); }, isIntersectionBox: function () { var v = new THREE.Vector3(); return function ( box ) { return this.intersectBox( box, v ) !== null; }; }(), intersectBox: function ( box, optionalTarget ) { // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ var tmin, tmax, tymin, tymax, tzmin, tzmax; var invdirx = 1 / this.direction.x, invdiry = 1 / this.direction.y, invdirz = 1 / this.direction.z; var origin = this.origin; if ( invdirx >= 0 ) { tmin = ( box.min.x - origin.x ) * invdirx; tmax = ( box.max.x - origin.x ) * invdirx; } else { tmin = ( box.max.x - origin.x ) * invdirx; tmax = ( box.min.x - origin.x ) * invdirx; } if ( invdiry >= 0 ) { tymin = ( box.min.y - origin.y ) * invdiry; tymax = ( box.max.y - origin.y ) * invdiry; } else { tymin = ( box.max.y - origin.y ) * invdiry; tymax = ( box.min.y - origin.y ) * invdiry; } if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; // These lines also handle the case where tmin or tmax is NaN // (result of 0 * Infinity). x !== x returns true if x is NaN if ( tymin > tmin || tmin !== tmin ) tmin = tymin; if ( tymax < tmax || tmax !== tmax ) tmax = tymax; if ( invdirz >= 0 ) { tzmin = ( box.min.z - origin.z ) * invdirz; tzmax = ( box.max.z - origin.z ) * invdirz; } else { tzmin = ( box.max.z - origin.z ) * invdirz; tzmax = ( box.min.z - origin.z ) * invdirz; } if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; //return point closest to the ray (positive side) if ( tmax < 0 ) return null; return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); }, intersectTriangle: function () { // Compute the offset origin, edges, and normal. var diff = new THREE.Vector3(); var edge1 = new THREE.Vector3(); var edge2 = new THREE.Vector3(); var normal = new THREE.Vector3(); return function ( a, b, c, backfaceCulling, optionalTarget ) { // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp edge1.subVectors( b, a ); edge2.subVectors( c, a ); normal.crossVectors( edge1, edge2 ); // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) var DdN = this.direction.dot( normal ); var sign; if ( DdN > 0 ) { if ( backfaceCulling ) return null; sign = 1; } else if ( DdN < 0 ) { sign = - 1; DdN = - DdN; } else { return null; } diff.subVectors( this.origin, a ); var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); // b1 < 0, no intersection if ( DdQxE2 < 0 ) { return null; } var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); // b2 < 0, no intersection if ( DdE1xQ < 0 ) { return null; } // b1+b2 > 1, no intersection if ( DdQxE2 + DdE1xQ > DdN ) { return null; } // Line intersects triangle, check if ray does. var QdN = - sign * diff.dot( normal ); // t < 0, no intersection if ( QdN < 0 ) { return null; } // Ray intersects triangle. return this.at( QdN / DdN, optionalTarget ); }; }(), applyMatrix4: function ( matrix4 ) { this.direction.add( this.origin ).applyMatrix4( matrix4 ); this.origin.applyMatrix4( matrix4 ); this.direction.sub( this.origin ); this.direction.normalize(); return this; }, equals: function ( ray ) { return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); } }; three.js-r73/src/math/Matrix4.js0000644000175500017550000005471012610076566016371 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ * @author philogb / http://blog.thejit.org/ * @author jordi_ros / http://plattsoft.com * @author D1plo1d / http://github.com/D1plo1d * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author timknip / http://www.floorplanner.com/ * @author bhouston / http://clara.io * @author WestLangley / http://github.com/WestLangley */ THREE.Matrix4 = function () { this.elements = new Float32Array( [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] ); if ( arguments.length > 0 ) { console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); } }; THREE.Matrix4.prototype = { constructor: THREE.Matrix4, set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { var te = this.elements; te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; return this; }, identity: function () { this.set( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); return this; }, clone: function () { return new THREE.Matrix4().fromArray( this.elements ); }, copy: function ( m ) { this.elements.set( m.elements ); return this; }, extractPosition: function ( m ) { console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); return this.copyPosition( m ); }, copyPosition: function ( m ) { var te = this.elements; var me = m.elements; te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; return this; }, extractBasis: function ( xAxis, yAxis, zAxis ) { var te = this.elements; xAxis.set( te[ 0 ], te[ 1 ], te[ 2 ] ); yAxis.set( te[ 4 ], te[ 5 ], te[ 6 ] ); zAxis.set( te[ 8 ], te[ 9 ], te[ 10 ] ); return this; }, makeBasis: function ( xAxis, yAxis, zAxis ) { this.set( xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, 0, 0, 0, 1 ); return this; }, extractRotation: function () { var v1; return function ( m ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); var te = this.elements; var me = m.elements; var scaleX = 1 / v1.set( me[ 0 ], me[ 1 ], me[ 2 ] ).length(); var scaleY = 1 / v1.set( me[ 4 ], me[ 5 ], me[ 6 ] ).length(); var scaleZ = 1 / v1.set( me[ 8 ], me[ 9 ], me[ 10 ] ).length(); te[ 0 ] = me[ 0 ] * scaleX; te[ 1 ] = me[ 1 ] * scaleX; te[ 2 ] = me[ 2 ] * scaleX; te[ 4 ] = me[ 4 ] * scaleY; te[ 5 ] = me[ 5 ] * scaleY; te[ 6 ] = me[ 6 ] * scaleY; te[ 8 ] = me[ 8 ] * scaleZ; te[ 9 ] = me[ 9 ] * scaleZ; te[ 10 ] = me[ 10 ] * scaleZ; return this; }; }(), makeRotationFromEuler: function ( euler ) { if ( euler instanceof THREE.Euler === false ) { console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } var te = this.elements; var x = euler.x, y = euler.y, z = euler.z; var a = Math.cos( x ), b = Math.sin( x ); var c = Math.cos( y ), d = Math.sin( y ); var e = Math.cos( z ), f = Math.sin( z ); if ( euler.order === 'XYZ' ) { var ae = a * e, af = a * f, be = b * e, bf = b * f; te[ 0 ] = c * e; te[ 4 ] = - c * f; te[ 8 ] = d; te[ 1 ] = af + be * d; te[ 5 ] = ae - bf * d; te[ 9 ] = - b * c; te[ 2 ] = bf - ae * d; te[ 6 ] = be + af * d; te[ 10 ] = a * c; } else if ( euler.order === 'YXZ' ) { var ce = c * e, cf = c * f, de = d * e, df = d * f; te[ 0 ] = ce + df * b; te[ 4 ] = de * b - cf; te[ 8 ] = a * d; te[ 1 ] = a * f; te[ 5 ] = a * e; te[ 9 ] = - b; te[ 2 ] = cf * b - de; te[ 6 ] = df + ce * b; te[ 10 ] = a * c; } else if ( euler.order === 'ZXY' ) { var ce = c * e, cf = c * f, de = d * e, df = d * f; te[ 0 ] = ce - df * b; te[ 4 ] = - a * f; te[ 8 ] = de + cf * b; te[ 1 ] = cf + de * b; te[ 5 ] = a * e; te[ 9 ] = df - ce * b; te[ 2 ] = - a * d; te[ 6 ] = b; te[ 10 ] = a * c; } else if ( euler.order === 'ZYX' ) { var ae = a * e, af = a * f, be = b * e, bf = b * f; te[ 0 ] = c * e; te[ 4 ] = be * d - af; te[ 8 ] = ae * d + bf; te[ 1 ] = c * f; te[ 5 ] = bf * d + ae; te[ 9 ] = af * d - be; te[ 2 ] = - d; te[ 6 ] = b * c; te[ 10 ] = a * c; } else if ( euler.order === 'YZX' ) { var ac = a * c, ad = a * d, bc = b * c, bd = b * d; te[ 0 ] = c * e; te[ 4 ] = bd - ac * f; te[ 8 ] = bc * f + ad; te[ 1 ] = f; te[ 5 ] = a * e; te[ 9 ] = - b * e; te[ 2 ] = - d * e; te[ 6 ] = ad * f + bc; te[ 10 ] = ac - bd * f; } else if ( euler.order === 'XZY' ) { var ac = a * c, ad = a * d, bc = b * c, bd = b * d; te[ 0 ] = c * e; te[ 4 ] = - f; te[ 8 ] = d * e; te[ 1 ] = ac * f + bd; te[ 5 ] = a * e; te[ 9 ] = ad * f - bc; te[ 2 ] = bc * f - ad; te[ 6 ] = b * e; te[ 10 ] = bd * f + ac; } // last column te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; // bottom row te[ 12 ] = 0; te[ 13 ] = 0; te[ 14 ] = 0; te[ 15 ] = 1; return this; }, setRotationFromQuaternion: function ( q ) { console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); return this.makeRotationFromQuaternion( q ); }, makeRotationFromQuaternion: function ( q ) { var te = this.elements; var x = q.x, y = q.y, z = q.z, w = q.w; var x2 = x + x, y2 = y + y, z2 = z + z; var xx = x * x2, xy = x * y2, xz = x * z2; var yy = y * y2, yz = y * z2, zz = z * z2; var wx = w * x2, wy = w * y2, wz = w * z2; te[ 0 ] = 1 - ( yy + zz ); te[ 4 ] = xy - wz; te[ 8 ] = xz + wy; te[ 1 ] = xy + wz; te[ 5 ] = 1 - ( xx + zz ); te[ 9 ] = yz - wx; te[ 2 ] = xz - wy; te[ 6 ] = yz + wx; te[ 10 ] = 1 - ( xx + yy ); // last column te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; // bottom row te[ 12 ] = 0; te[ 13 ] = 0; te[ 14 ] = 0; te[ 15 ] = 1; return this; }, lookAt: function () { var x, y, z; return function ( eye, target, up ) { if ( x === undefined ) x = new THREE.Vector3(); if ( y === undefined ) y = new THREE.Vector3(); if ( z === undefined ) z = new THREE.Vector3(); var te = this.elements; z.subVectors( eye, target ).normalize(); if ( z.lengthSq() === 0 ) { z.z = 1; } x.crossVectors( up, z ).normalize(); if ( x.lengthSq() === 0 ) { z.x += 0.0001; x.crossVectors( up, z ).normalize(); } y.crossVectors( z, x ); te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x; te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y; te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z; return this; }; }(), multiply: function ( m, n ) { if ( n !== undefined ) { console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); return this.multiplyMatrices( m, n ); } return this.multiplyMatrices( this, m ); }, multiplyMatrices: function ( a, b ) { var ae = a.elements; var be = b.elements; var te = this.elements; var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; return this; }, multiplyToArray: function ( a, b, r ) { var te = this.elements; this.multiplyMatrices( a, b ); r[ 0 ] = te[ 0 ]; r[ 1 ] = te[ 1 ]; r[ 2 ] = te[ 2 ]; r[ 3 ] = te[ 3 ]; r[ 4 ] = te[ 4 ]; r[ 5 ] = te[ 5 ]; r[ 6 ] = te[ 6 ]; r[ 7 ] = te[ 7 ]; r[ 8 ] = te[ 8 ]; r[ 9 ] = te[ 9 ]; r[ 10 ] = te[ 10 ]; r[ 11 ] = te[ 11 ]; r[ 12 ] = te[ 12 ]; r[ 13 ] = te[ 13 ]; r[ 14 ] = te[ 14 ]; r[ 15 ] = te[ 15 ]; return this; }, multiplyScalar: function ( s ) { var te = this.elements; te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; return this; }, multiplyVector3: function ( vector ) { console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); return vector.applyProjection( this ); }, multiplyVector4: function ( vector ) { console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, multiplyVector3Array: function ( a ) { console.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); return this.applyToVector3Array( a ); }, applyToVector3Array: function () { var v1; return function ( array, offset, length ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); if ( offset === undefined ) offset = 0; if ( length === undefined ) length = array.length; for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { v1.fromArray( array, j ); v1.applyMatrix4( this ); v1.toArray( array, j ); } return array; }; }(), applyToBuffer: function () { var v1; return function applyToBuffer( buffer, offset, length ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); if ( offset === undefined ) offset = 0; if ( length === undefined ) length = buffer.length / buffer.itemSize; for ( var i = 0, j = offset; i < length; i ++, j ++ ) { v1.x = buffer.getX( j ); v1.y = buffer.getY( j ); v1.z = buffer.getZ( j ); v1.applyMatrix4( this ); buffer.setXYZ( v1.x, v1.y, v1.z ); } return buffer; }; }(), rotateAxis: function ( v ) { console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); v.transformDirection( this ); }, crossVector: function ( vector ) { console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, determinant: function () { var te = this.elements; var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; //TODO: make this more efficient //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) return ( n41 * ( + n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34 ) + n42 * ( + n11 * n23 * n34 - n11 * n24 * n33 + n14 * n21 * n33 - n13 * n21 * n34 + n13 * n24 * n31 - n14 * n23 * n31 ) + n43 * ( + n11 * n24 * n32 - n11 * n22 * n34 - n14 * n21 * n32 + n12 * n21 * n34 + n14 * n22 * n31 - n12 * n24 * n31 ) + n44 * ( - n13 * n22 * n31 - n11 * n23 * n32 + n11 * n22 * n33 + n13 * n21 * n32 - n12 * n21 * n33 + n12 * n23 * n31 ) ); }, transpose: function () { var te = this.elements; var tmp; tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; return this; }, flattenToArrayOffset: function ( array, offset ) { var te = this.elements; array[ offset ] = te[ 0 ]; array[ offset + 1 ] = te[ 1 ]; array[ offset + 2 ] = te[ 2 ]; array[ offset + 3 ] = te[ 3 ]; array[ offset + 4 ] = te[ 4 ]; array[ offset + 5 ] = te[ 5 ]; array[ offset + 6 ] = te[ 6 ]; array[ offset + 7 ] = te[ 7 ]; array[ offset + 8 ] = te[ 8 ]; array[ offset + 9 ] = te[ 9 ]; array[ offset + 10 ] = te[ 10 ]; array[ offset + 11 ] = te[ 11 ]; array[ offset + 12 ] = te[ 12 ]; array[ offset + 13 ] = te[ 13 ]; array[ offset + 14 ] = te[ 14 ]; array[ offset + 15 ] = te[ 15 ]; return array; }, getPosition: function () { var v1; return function () { if ( v1 === undefined ) v1 = new THREE.Vector3(); console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); var te = this.elements; return v1.set( te[ 12 ], te[ 13 ], te[ 14 ] ); }; }(), setPosition: function ( v ) { var te = this.elements; te[ 12 ] = v.x; te[ 13 ] = v.y; te[ 14 ] = v.z; return this; }, getInverse: function ( m, throwOnInvertible ) { // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm var te = this.elements; var me = m.elements; var n11 = me[ 0 ], n12 = me[ 4 ], n13 = me[ 8 ], n14 = me[ 12 ]; var n21 = me[ 1 ], n22 = me[ 5 ], n23 = me[ 9 ], n24 = me[ 13 ]; var n31 = me[ 2 ], n32 = me[ 6 ], n33 = me[ 10 ], n34 = me[ 14 ]; var n41 = me[ 3 ], n42 = me[ 7 ], n43 = me[ 11 ], n44 = me[ 15 ]; te[ 0 ] = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44; te[ 4 ] = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44; te[ 8 ] = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44; te[ 12 ] = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; te[ 1 ] = n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44; te[ 5 ] = n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44; te[ 9 ] = n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44; te[ 13 ] = n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34; te[ 2 ] = n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44; te[ 6 ] = n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44; te[ 10 ] = n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44; te[ 14 ] = n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34; te[ 3 ] = n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43; te[ 7 ] = n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43; te[ 11 ] = n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43; te[ 15 ] = n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33; var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; if ( det === 0 ) { var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; if ( throwOnInvertible || false ) { throw new Error( msg ); } else { console.warn( msg ); } this.identity(); return this; } this.multiplyScalar( 1 / det ); return this; }, translate: function ( v ) { console.error( 'THREE.Matrix4: .translate() has been removed.' ); }, rotateX: function ( angle ) { console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); }, rotateY: function ( angle ) { console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); }, rotateZ: function ( angle ) { console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); }, rotateByAxis: function ( axis, angle ) { console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); }, scale: function ( v ) { var te = this.elements; var x = v.x, y = v.y, z = v.z; te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; return this; }, getMaxScaleOnAxis: function () { var te = this.elements; var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); }, makeTranslation: function ( x, y, z ) { this.set( 1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1 ); return this; }, makeRotationX: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( 1, 0, 0, 0, 0, c, - s, 0, 0, s, c, 0, 0, 0, 0, 1 ); return this; }, makeRotationY: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( c, 0, s, 0, 0, 1, 0, 0, - s, 0, c, 0, 0, 0, 0, 1 ); return this; }, makeRotationZ: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( c, - s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); return this; }, makeRotationAxis: function ( axis, angle ) { // Based on http://www.gamedev.net/reference/articles/article1199.asp var c = Math.cos( angle ); var s = Math.sin( angle ); var t = 1 - c; var x = axis.x, y = axis.y, z = axis.z; var tx = t * x, ty = t * y; this.set( tx * x + c, tx * y - s * z, tx * z + s * y, 0, tx * y + s * z, ty * y + c, ty * z - s * x, 0, tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 0, 0, 0, 1 ); return this; }, makeScale: function ( x, y, z ) { this.set( x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 ); return this; }, compose: function ( position, quaternion, scale ) { this.makeRotationFromQuaternion( quaternion ); this.scale( scale ); this.setPosition( position ); return this; }, decompose: function () { var vector, matrix; return function ( position, quaternion, scale ) { if ( vector === undefined ) vector = new THREE.Vector3(); if ( matrix === undefined ) matrix = new THREE.Matrix4(); var te = this.elements; var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); // if determine is negative, we need to invert one scale var det = this.determinant(); if ( det < 0 ) { sx = - sx; } position.x = te[ 12 ]; position.y = te[ 13 ]; position.z = te[ 14 ]; // scale the rotation part matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() var invSX = 1 / sx; var invSY = 1 / sy; var invSZ = 1 / sz; matrix.elements[ 0 ] *= invSX; matrix.elements[ 1 ] *= invSX; matrix.elements[ 2 ] *= invSX; matrix.elements[ 4 ] *= invSY; matrix.elements[ 5 ] *= invSY; matrix.elements[ 6 ] *= invSY; matrix.elements[ 8 ] *= invSZ; matrix.elements[ 9 ] *= invSZ; matrix.elements[ 10 ] *= invSZ; quaternion.setFromRotationMatrix( matrix ); scale.x = sx; scale.y = sy; scale.z = sz; return this; }; }(), makeFrustum: function ( left, right, bottom, top, near, far ) { var te = this.elements; var x = 2 * near / ( right - left ); var y = 2 * near / ( top - bottom ); var a = ( right + left ) / ( right - left ); var b = ( top + bottom ) / ( top - bottom ); var c = - ( far + near ) / ( far - near ); var d = - 2 * far * near / ( far - near ); te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; return this; }, makePerspective: function ( fov, aspect, near, far ) { var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); var ymin = - ymax; var xmin = ymin * aspect; var xmax = ymax * aspect; return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); }, makeOrthographic: function ( left, right, top, bottom, near, far ) { var te = this.elements; var w = right - left; var h = top - bottom; var p = far - near; var x = ( right + left ) / w; var y = ( top + bottom ) / h; var z = ( far + near ) / p; te[ 0 ] = 2 / w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; te[ 1 ] = 0; te[ 5 ] = 2 / h; te[ 9 ] = 0; te[ 13 ] = - y; te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 / p; te[ 14 ] = - z; te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; return this; }, equals: function ( matrix ) { var te = this.elements; var me = matrix.elements; for ( var i = 0; i < 16; i ++ ) { if ( te[ i ] !== me[ i ] ) return false; } return true; }, fromArray: function ( array ) { this.elements.set( array ); return this; }, toArray: function () { var te = this.elements; return [ te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] ]; } }; three.js-r73/src/math/Color.js0000644000175500017550000002622312610076566016115 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Color = function ( color ) { if ( arguments.length === 3 ) { return this.fromArray( arguments ); } return this.set( color ); }; THREE.Color.prototype = { constructor: THREE.Color, r: 1, g: 1, b: 1, set: function ( value ) { if ( value instanceof THREE.Color ) { this.copy( value ); } else if ( typeof value === 'number' ) { this.setHex( value ); } else if ( typeof value === 'string' ) { this.setStyle( value ); } return this; }, setHex: function ( hex ) { hex = Math.floor( hex ); this.r = ( hex >> 16 & 255 ) / 255; this.g = ( hex >> 8 & 255 ) / 255; this.b = ( hex & 255 ) / 255; return this; }, setRGB: function ( r, g, b ) { this.r = r; this.g = g; this.b = b; return this; }, setHSL: function () { function hue2rgb( p, q, t ) { if ( t < 0 ) t += 1; if ( t > 1 ) t -= 1; if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; if ( t < 1 / 2 ) return q; if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); return p; } return function ( h, s, l ) { // h,s,l ranges are in 0.0 - 1.0 h = THREE.Math.euclideanModulo( h, 1 ); s = THREE.Math.clamp( s, 0, 1 ); l = THREE.Math.clamp( l, 0, 1 ); if ( s === 0 ) { this.r = this.g = this.b = l; } else { var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); var q = ( 2 * l ) - p; this.r = hue2rgb( q, p, h + 1 / 3 ); this.g = hue2rgb( q, p, h ); this.b = hue2rgb( q, p, h - 1 / 3 ); } return this; }; }(), setStyle: function ( style ) { function handleAlpha( string ) { if ( string === undefined ) return; if ( parseFloat( string ) < 1 ) { console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); } } var m; if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { // rgb / hsl var color; var name = m[ 1 ]; var components = m[ 2 ]; switch ( name ) { case 'rgb': case 'rgba': if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { // rgb(255,0,0) rgba(255,0,0,0.5) this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; handleAlpha( color[ 5 ] ); return this; } if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; handleAlpha( color[ 5 ] ); return this; } break; case 'hsl': case 'hsla': if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { // hsl(120,50%,50%) hsla(120,50%,50%,0.5) var h = parseFloat( color[ 1 ] ) / 360; var s = parseInt( color[ 2 ], 10 ) / 100; var l = parseInt( color[ 3 ], 10 ) / 100; handleAlpha( color[ 5 ] ); return this.setHSL( h, s, l ); } break; } } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { // hex color var hex = m[ 1 ]; var size = hex.length; if ( size === 3 ) { // #ff0 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; return this; } else if ( size === 6 ) { // #ff0000 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; return this; } } if ( style && style.length > 0 ) { // color keywords var hex = THREE.ColorKeywords[ style ]; if ( hex !== undefined ) { // red this.setHex( hex ); } else { // unknown color console.warn( 'THREE.Color: Unknown color ' + style ); } } return this; }, clone: function () { return new this.constructor( this.r, this.g, this.b ); }, copy: function ( color ) { this.r = color.r; this.g = color.g; this.b = color.b; return this; }, copyGammaToLinear: function ( color, gammaFactor ) { if ( gammaFactor === undefined ) gammaFactor = 2.0; this.r = Math.pow( color.r, gammaFactor ); this.g = Math.pow( color.g, gammaFactor ); this.b = Math.pow( color.b, gammaFactor ); return this; }, copyLinearToGamma: function ( color, gammaFactor ) { if ( gammaFactor === undefined ) gammaFactor = 2.0; var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; this.r = Math.pow( color.r, safeInverse ); this.g = Math.pow( color.g, safeInverse ); this.b = Math.pow( color.b, safeInverse ); return this; }, convertGammaToLinear: function () { var r = this.r, g = this.g, b = this.b; this.r = r * r; this.g = g * g; this.b = b * b; return this; }, convertLinearToGamma: function () { this.r = Math.sqrt( this.r ); this.g = Math.sqrt( this.g ); this.b = Math.sqrt( this.b ); return this; }, getHex: function () { return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; }, getHexString: function () { return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); }, getHSL: function ( optionalTarget ) { // h,s,l ranges are in 0.0 - 1.0 var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; var r = this.r, g = this.g, b = this.b; var max = Math.max( r, g, b ); var min = Math.min( r, g, b ); var hue, saturation; var lightness = ( min + max ) / 2.0; if ( min === max ) { hue = 0; saturation = 0; } else { var delta = max - min; saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); switch ( max ) { case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; case g: hue = ( b - r ) / delta + 2; break; case b: hue = ( r - g ) / delta + 4; break; } hue /= 6; } hsl.h = hue; hsl.s = saturation; hsl.l = lightness; return hsl; }, getStyle: function () { return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; }, offsetHSL: function ( h, s, l ) { var hsl = this.getHSL(); hsl.h += h; hsl.s += s; hsl.l += l; this.setHSL( hsl.h, hsl.s, hsl.l ); return this; }, add: function ( color ) { this.r += color.r; this.g += color.g; this.b += color.b; return this; }, addColors: function ( color1, color2 ) { this.r = color1.r + color2.r; this.g = color1.g + color2.g; this.b = color1.b + color2.b; return this; }, addScalar: function ( s ) { this.r += s; this.g += s; this.b += s; return this; }, multiply: function ( color ) { this.r *= color.r; this.g *= color.g; this.b *= color.b; return this; }, multiplyScalar: function ( s ) { this.r *= s; this.g *= s; this.b *= s; return this; }, lerp: function ( color, alpha ) { this.r += ( color.r - this.r ) * alpha; this.g += ( color.g - this.g ) * alpha; this.b += ( color.b - this.b ) * alpha; return this; }, equals: function ( c ) { return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); }, fromArray: function ( array, offset ) { if ( offset === undefined ) offset = 0; this.r = array[ offset ]; this.g = array[ offset + 1 ]; this.b = array[ offset + 2 ]; return this; }, toArray: function ( array, offset ) { if ( array === undefined ) array = []; if ( offset === undefined ) offset = 0; array[ offset ] = this.r; array[ offset + 1 ] = this.g; array[ offset + 2 ] = this.b; return array; } }; THREE.ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; three.js-r73/src/math/Vector3.js0000644000175500017550000003276412610076566016373 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author *kile / http://kile.stravaganza.org/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ * @author egraether / http://egraether.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.Vector3 = function ( x, y, z ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; THREE.Vector3.prototype = { constructor: THREE.Vector3, set: function ( x, y, z ) { this.x = x; this.y = y; this.z = z; return this; }, setX: function ( x ) { this.x = x; return this; }, setY: function ( y ) { this.y = y; return this; }, setZ: function ( z ) { this.z = z; return this; }, setComponent: function ( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; case 2: this.z = value; break; default: throw new Error( 'index is out of range: ' + index ); } }, getComponent: function ( index ) { switch ( index ) { case 0: return this.x; case 1: return this.y; case 2: return this.z; default: throw new Error( 'index is out of range: ' + index ); } }, clone: function () { return new this.constructor( this.x, this.y, this.z ); }, copy: function ( v ) { this.x = v.x; this.y = v.y; this.z = v.z; return this; }, add: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } this.x += v.x; this.y += v.y; this.z += v.z; return this; }, addScalar: function ( s ) { this.x += s; this.y += s; this.z += s; return this; }, addVectors: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; this.z = a.z + b.z; return this; }, addScaledVector: function ( v, s ) { this.x += v.x * s; this.y += v.y * s; this.z += v.z * s; return this; }, sub: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } this.x -= v.x; this.y -= v.y; this.z -= v.z; return this; }, subScalar: function ( s ) { this.x -= s; this.y -= s; this.z -= s; return this; }, subVectors: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; this.z = a.z - b.z; return this; }, multiply: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); return this.multiplyVectors( v, w ); } this.x *= v.x; this.y *= v.y; this.z *= v.z; return this; }, multiplyScalar: function ( scalar ) { if ( isFinite( scalar ) ) { this.x *= scalar; this.y *= scalar; this.z *= scalar; } else { this.x = 0; this.y = 0; this.z = 0; } return this; }, multiplyVectors: function ( a, b ) { this.x = a.x * b.x; this.y = a.y * b.y; this.z = a.z * b.z; return this; }, applyEuler: function () { var quaternion; return function applyEuler( euler ) { if ( euler instanceof THREE.Euler === false ) { console.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); this.applyQuaternion( quaternion.setFromEuler( euler ) ); return this; }; }(), applyAxisAngle: function () { var quaternion; return function applyAxisAngle( axis, angle ) { if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); return this; }; }(), applyMatrix3: function ( m ) { var x = this.x; var y = this.y; var z = this.z; var e = m.elements; this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; return this; }, applyMatrix4: function ( m ) { // input: THREE.Matrix4 affine matrix var x = this.x, y = this.y, z = this.z; var e = m.elements; this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ]; this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ]; this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ]; return this; }, applyProjection: function ( m ) { // input: THREE.Matrix4 projection matrix var x = this.x, y = this.y, z = this.z; var e = m.elements; var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * d; this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * d; this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d; return this; }, applyQuaternion: function ( q ) { var x = this.x; var y = this.y; var z = this.z; var qx = q.x; var qy = q.y; var qz = q.z; var qw = q.w; // calculate quat * vector var ix = qw * x + qy * z - qz * y; var iy = qw * y + qz * x - qx * z; var iz = qw * z + qx * y - qy * x; var iw = - qx * x - qy * y - qz * z; // calculate result * inverse quat this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; return this; }, project: function () { var matrix; return function project( camera ) { if ( matrix === undefined ) matrix = new THREE.Matrix4(); matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) ); return this.applyProjection( matrix ); }; }(), unproject: function () { var matrix; return function unproject( camera ) { if ( matrix === undefined ) matrix = new THREE.Matrix4(); matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) ); return this.applyProjection( matrix ); }; }(), transformDirection: function ( m ) { // input: THREE.Matrix4 affine matrix // vector interpreted as a direction var x = this.x, y = this.y, z = this.z; var e = m.elements; this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; this.normalize(); return this; }, divide: function ( v ) { this.x /= v.x; this.y /= v.y; this.z /= v.z; return this; }, divideScalar: function ( scalar ) { return this.multiplyScalar( 1 / scalar ); }, min: function ( v ) { this.x = Math.min( this.x, v.x ); this.y = Math.min( this.y, v.y ); this.z = Math.min( this.z, v.z ); return this; }, max: function ( v ) { this.x = Math.max( this.x, v.x ); this.y = Math.max( this.y, v.y ); this.z = Math.max( this.z, v.z ); return this; }, clamp: function ( min, max ) { // This function assumes min < max, if this assumption isn't true it will not operate correctly this.x = Math.max( min.x, Math.min( max.x, this.x ) ); this.y = Math.max( min.y, Math.min( max.y, this.y ) ); this.z = Math.max( min.z, Math.min( max.z, this.z ) ); return this; }, clampScalar: function () { var min, max; return function clampScalar( minVal, maxVal ) { if ( min === undefined ) { min = new THREE.Vector3(); max = new THREE.Vector3(); } min.set( minVal, minVal, minVal ); max.set( maxVal, maxVal, maxVal ); return this.clamp( min, max ); }; }(), clampLength: function ( min, max ) { var length = this.length(); this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length ); return this; }, floor: function () { this.x = Math.floor( this.x ); this.y = Math.floor( this.y ); this.z = Math.floor( this.z ); return this; }, ceil: function () { this.x = Math.ceil( this.x ); this.y = Math.ceil( this.y ); this.z = Math.ceil( this.z ); return this; }, round: function () { this.x = Math.round( this.x ); this.y = Math.round( this.y ); this.z = Math.round( this.z ); return this; }, roundToZero: function () { this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); return this; }, negate: function () { this.x = - this.x; this.y = - this.y; this.z = - this.z; return this; }, dot: function ( v ) { return this.x * v.x + this.y * v.y + this.z * v.z; }, lengthSq: function () { return this.x * this.x + this.y * this.y + this.z * this.z; }, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); }, lengthManhattan: function () { return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); }, normalize: function () { return this.divideScalar( this.length() ); }, setLength: function ( length ) { return this.multiplyScalar( length / this.length() ); }, lerp: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; this.z += ( v.z - this.z ) * alpha; return this; }, lerpVectors: function ( v1, v2, alpha ) { this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); return this; }, cross: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); return this.crossVectors( v, w ); } var x = this.x, y = this.y, z = this.z; this.x = y * v.z - z * v.y; this.y = z * v.x - x * v.z; this.z = x * v.y - y * v.x; return this; }, crossVectors: function ( a, b ) { var ax = a.x, ay = a.y, az = a.z; var bx = b.x, by = b.y, bz = b.z; this.x = ay * bz - az * by; this.y = az * bx - ax * bz; this.z = ax * by - ay * bx; return this; }, projectOnVector: function () { var v1, dot; return function projectOnVector( vector ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); v1.copy( vector ).normalize(); dot = this.dot( v1 ); return this.copy( v1 ).multiplyScalar( dot ); }; }(), projectOnPlane: function () { var v1; return function projectOnPlane( planeNormal ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); v1.copy( this ).projectOnVector( planeNormal ); return this.sub( v1 ); } }(), reflect: function () { // reflect incident vector off plane orthogonal to normal // normal is assumed to have unit length var v1; return function reflect( normal ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); } }(), angleTo: function ( v ) { var theta = this.dot( v ) / ( this.length() * v.length() ); // clamp, to handle numerical problems return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) ); }, distanceTo: function ( v ) { return Math.sqrt( this.distanceToSquared( v ) ); }, distanceToSquared: function ( v ) { var dx = this.x - v.x; var dy = this.y - v.y; var dz = this.z - v.z; return dx * dx + dy * dy + dz * dz; }, setEulerFromRotationMatrix: function ( m, order ) { console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); }, setEulerFromQuaternion: function ( q, order ) { console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); }, getPositionFromMatrix: function ( m ) { console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); return this.setFromMatrixPosition( m ); }, getScaleFromMatrix: function ( m ) { console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); return this.setFromMatrixScale( m ); }, getColumnFromMatrix: function ( index, matrix ) { console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); return this.setFromMatrixColumn( index, matrix ); }, setFromMatrixPosition: function ( m ) { this.x = m.elements[ 12 ]; this.y = m.elements[ 13 ]; this.z = m.elements[ 14 ]; return this; }, setFromMatrixScale: function ( m ) { var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); this.x = sx; this.y = sy; this.z = sz; return this; }, setFromMatrixColumn: function ( index, matrix ) { var offset = index * 4; var me = matrix.elements; this.x = me[ offset ]; this.y = me[ offset + 1 ]; this.z = me[ offset + 2 ]; return this; }, equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); }, fromArray: function ( array, offset ) { if ( offset === undefined ) offset = 0; this.x = array[ offset ]; this.y = array[ offset + 1 ]; this.z = array[ offset + 2 ]; return this; }, toArray: function ( array, offset ) { if ( array === undefined ) array = []; if ( offset === undefined ) offset = 0; array[ offset ] = this.x; array[ offset + 1 ] = this.y; array[ offset + 2 ] = this.z; return array; }, fromAttribute: function ( attribute, index, offset ) { if ( offset === undefined ) offset = 0; index = index * attribute.itemSize + offset; this.x = attribute.array[ index ]; this.y = attribute.array[ index + 1 ]; this.z = attribute.array[ index + 2 ]; return this; } }; three.js-r73/src/math/Sphere.js0000644000175500017550000000502712610076566016264 0ustar debacledebacle/** * @author bhouston / http://clara.io * @author mrdoob / http://mrdoob.com/ */ THREE.Sphere = function ( center, radius ) { this.center = ( center !== undefined ) ? center : new THREE.Vector3(); this.radius = ( radius !== undefined ) ? radius : 0; }; THREE.Sphere.prototype = { constructor: THREE.Sphere, set: function ( center, radius ) { this.center.copy( center ); this.radius = radius; return this; }, setFromPoints: function () { var box = new THREE.Box3(); return function ( points, optionalCenter ) { var center = this.center; if ( optionalCenter !== undefined ) { center.copy( optionalCenter ); } else { box.setFromPoints( points ).center( center ); } var maxRadiusSq = 0; for ( var i = 0, il = points.length; i < il; i ++ ) { maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); } this.radius = Math.sqrt( maxRadiusSq ); return this; }; }(), clone: function () { return new this.constructor().copy( this ); }, copy: function ( sphere ) { this.center.copy( sphere.center ); this.radius = sphere.radius; return this; }, empty: function () { return ( this.radius <= 0 ); }, containsPoint: function ( point ) { return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); }, distanceToPoint: function ( point ) { return ( point.distanceTo( this.center ) - this.radius ); }, intersectsSphere: function ( sphere ) { var radiusSum = this.radius + sphere.radius; return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); }, clampPoint: function ( point, optionalTarget ) { var deltaLengthSq = this.center.distanceToSquared( point ); var result = optionalTarget || new THREE.Vector3(); result.copy( point ); if ( deltaLengthSq > ( this.radius * this.radius ) ) { result.sub( this.center ).normalize(); result.multiplyScalar( this.radius ).add( this.center ); } return result; }, getBoundingBox: function ( optionalTarget ) { var box = optionalTarget || new THREE.Box3(); box.set( this.center, this.center ); box.expandByScalar( this.radius ); return box; }, applyMatrix4: function ( matrix ) { this.center.applyMatrix4( matrix ); this.radius = this.radius * matrix.getMaxScaleOnAxis(); return this; }, translate: function ( offset ) { this.center.add( offset ); return this; }, equals: function ( sphere ) { return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); } }; three.js-r73/src/math/Euler.js0000644000175500017550000001217312610076566016112 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley * @author bhouston / http://clara.io */ THREE.Euler = function ( x, y, z, order ) { this._x = x || 0; this._y = y || 0; this._z = z || 0; this._order = order || THREE.Euler.DefaultOrder; }; THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; THREE.Euler.DefaultOrder = 'XYZ'; THREE.Euler.prototype = { constructor: THREE.Euler, get x () { return this._x; }, set x ( value ) { this._x = value; this.onChangeCallback(); }, get y () { return this._y; }, set y ( value ) { this._y = value; this.onChangeCallback(); }, get z () { return this._z; }, set z ( value ) { this._z = value; this.onChangeCallback(); }, get order () { return this._order; }, set order ( value ) { this._order = value; this.onChangeCallback(); }, set: function ( x, y, z, order ) { this._x = x; this._y = y; this._z = z; this._order = order || this._order; this.onChangeCallback(); return this; }, clone: function () { return new this.constructor( this._x, this._y, this._z, this._order); }, copy: function ( euler ) { this._x = euler._x; this._y = euler._y; this._z = euler._z; this._order = euler._order; this.onChangeCallback(); return this; }, setFromRotationMatrix: function ( m, order, update ) { var clamp = THREE.Math.clamp; // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var te = m.elements; var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; order = order || this._order; if ( order === 'XYZ' ) { this._y = Math.asin( clamp( m13, - 1, 1 ) ); if ( Math.abs( m13 ) < 0.99999 ) { this._x = Math.atan2( - m23, m33 ); this._z = Math.atan2( - m12, m11 ); } else { this._x = Math.atan2( m32, m22 ); this._z = 0; } } else if ( order === 'YXZ' ) { this._x = Math.asin( - clamp( m23, - 1, 1 ) ); if ( Math.abs( m23 ) < 0.99999 ) { this._y = Math.atan2( m13, m33 ); this._z = Math.atan2( m21, m22 ); } else { this._y = Math.atan2( - m31, m11 ); this._z = 0; } } else if ( order === 'ZXY' ) { this._x = Math.asin( clamp( m32, - 1, 1 ) ); if ( Math.abs( m32 ) < 0.99999 ) { this._y = Math.atan2( - m31, m33 ); this._z = Math.atan2( - m12, m22 ); } else { this._y = 0; this._z = Math.atan2( m21, m11 ); } } else if ( order === 'ZYX' ) { this._y = Math.asin( - clamp( m31, - 1, 1 ) ); if ( Math.abs( m31 ) < 0.99999 ) { this._x = Math.atan2( m32, m33 ); this._z = Math.atan2( m21, m11 ); } else { this._x = 0; this._z = Math.atan2( - m12, m22 ); } } else if ( order === 'YZX' ) { this._z = Math.asin( clamp( m21, - 1, 1 ) ); if ( Math.abs( m21 ) < 0.99999 ) { this._x = Math.atan2( - m23, m22 ); this._y = Math.atan2( - m31, m11 ); } else { this._x = 0; this._y = Math.atan2( m13, m33 ); } } else if ( order === 'XZY' ) { this._z = Math.asin( - clamp( m12, - 1, 1 ) ); if ( Math.abs( m12 ) < 0.99999 ) { this._x = Math.atan2( m32, m22 ); this._y = Math.atan2( m13, m11 ); } else { this._x = Math.atan2( - m23, m33 ); this._y = 0; } } else { console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) } this._order = order; if ( update !== false ) this.onChangeCallback(); return this; }, setFromQuaternion: function () { var matrix; return function ( q, order, update ) { if ( matrix === undefined ) matrix = new THREE.Matrix4(); matrix.makeRotationFromQuaternion( q ); this.setFromRotationMatrix( matrix, order, update ); return this; }; }(), setFromVector3: function ( v, order ) { return this.set( v.x, v.y, v.z, order || this._order ); }, reorder: function () { // WARNING: this discards revolution information -bhouston var q = new THREE.Quaternion(); return function ( newOrder ) { q.setFromEuler( this ); this.setFromQuaternion( q, newOrder ); }; }(), equals: function ( euler ) { return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); }, fromArray: function ( array ) { this._x = array[ 0 ]; this._y = array[ 1 ]; this._z = array[ 2 ]; if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; this.onChangeCallback(); return this; }, toArray: function ( array, offset ) { if ( array === undefined ) array = []; if ( offset === undefined ) offset = 0; array[ offset ] = this._x; array[ offset + 1 ] = this._y; array[ offset + 2 ] = this._z; array[ offset + 3 ] = this._order; return array; }, toVector3: function ( optionalResult ) { if ( optionalResult ) { return optionalResult.set( this._x, this._y, this._z ); } else { return new THREE.Vector3( this._x, this._y, this._z ); } }, onChange: function ( callback ) { this.onChangeCallback = callback; return this; }, onChangeCallback: function () {} }; three.js-r73/src/math/Triangle.js0000644000175500017550000000741212610076566016603 0ustar debacledebacle/** * @author bhouston / http://clara.io * @author mrdoob / http://mrdoob.com/ */ THREE.Triangle = function ( a, b, c ) { this.a = ( a !== undefined ) ? a : new THREE.Vector3(); this.b = ( b !== undefined ) ? b : new THREE.Vector3(); this.c = ( c !== undefined ) ? c : new THREE.Vector3(); }; THREE.Triangle.normal = function () { var v0 = new THREE.Vector3(); return function ( a, b, c, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); result.subVectors( c, b ); v0.subVectors( a, b ); result.cross( v0 ); var resultLengthSq = result.lengthSq(); if ( resultLengthSq > 0 ) { return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); } return result.set( 0, 0, 0 ); }; }(); // static/instance method to calculate barycentric coordinates // based on: http://www.blackpawn.com/texts/pointinpoly/default.html THREE.Triangle.barycoordFromPoint = function () { var v0 = new THREE.Vector3(); var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); return function ( point, a, b, c, optionalTarget ) { v0.subVectors( c, a ); v1.subVectors( b, a ); v2.subVectors( point, a ); var dot00 = v0.dot( v0 ); var dot01 = v0.dot( v1 ); var dot02 = v0.dot( v2 ); var dot11 = v1.dot( v1 ); var dot12 = v1.dot( v2 ); var denom = ( dot00 * dot11 - dot01 * dot01 ); var result = optionalTarget || new THREE.Vector3(); // collinear or singular triangle if ( denom === 0 ) { // arbitrary location outside of triangle? // not sure if this is the best idea, maybe should be returning undefined return result.set( - 2, - 1, - 1 ); } var invDenom = 1 / denom; var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; // barycentric coordinates must always sum to 1 return result.set( 1 - u - v, v, u ); }; }(); THREE.Triangle.containsPoint = function () { var v1 = new THREE.Vector3(); return function ( point, a, b, c ) { var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); }; }(); THREE.Triangle.prototype = { constructor: THREE.Triangle, set: function ( a, b, c ) { this.a.copy( a ); this.b.copy( b ); this.c.copy( c ); return this; }, setFromPointsAndIndices: function ( points, i0, i1, i2 ) { this.a.copy( points[ i0 ] ); this.b.copy( points[ i1 ] ); this.c.copy( points[ i2 ] ); return this; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( triangle ) { this.a.copy( triangle.a ); this.b.copy( triangle.b ); this.c.copy( triangle.c ); return this; }, area: function () { var v0 = new THREE.Vector3(); var v1 = new THREE.Vector3(); return function () { v0.subVectors( this.c, this.b ); v1.subVectors( this.a, this.b ); return v0.cross( v1 ).length() * 0.5; }; }(), midpoint: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); }, normal: function ( optionalTarget ) { return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); }, plane: function ( optionalTarget ) { var result = optionalTarget || new THREE.Plane(); return result.setFromCoplanarPoints( this.a, this.b, this.c ); }, barycoordFromPoint: function ( point, optionalTarget ) { return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); }, containsPoint: function ( point ) { return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); }, equals: function ( triangle ) { return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); } }; three.js-r73/src/math/Vector2.js0000644000175500017550000001403312610076566016357 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author philogb / http://blog.thejit.org/ * @author egraether / http://egraether.com/ * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.Vector2 = function ( x, y ) { this.x = x || 0; this.y = y || 0; }; THREE.Vector2.prototype = { constructor: THREE.Vector2, get width() { return this.x }, set width( value ) { this.x = value }, get height() { return this.y }, set height( value ) { this.y = value }, // set: function ( x, y ) { this.x = x; this.y = y; return this; }, setX: function ( x ) { this.x = x; return this; }, setY: function ( y ) { this.y = y; return this; }, setComponent: function ( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; default: throw new Error( 'index is out of range: ' + index ); } }, getComponent: function ( index ) { switch ( index ) { case 0: return this.x; case 1: return this.y; default: throw new Error( 'index is out of range: ' + index ); } }, clone: function () { return new this.constructor( this.x, this.y ); }, copy: function ( v ) { this.x = v.x; this.y = v.y; return this; }, add: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } this.x += v.x; this.y += v.y; return this; }, addScalar: function ( s ) { this.x += s; this.y += s; return this; }, addVectors: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; return this; }, addScaledVector: function ( v, s ) { this.x += v.x * s; this.y += v.y * s; return this; }, sub: function ( v, w ) { if ( w !== undefined ) { console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } this.x -= v.x; this.y -= v.y; return this; }, subScalar: function ( s ) { this.x -= s; this.y -= s; return this; }, subVectors: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; return this; }, multiply: function ( v ) { this.x *= v.x; this.y *= v.y; return this; }, multiplyScalar: function ( scalar ) { if ( isFinite( scalar ) ) { this.x *= scalar; this.y *= scalar; } else { this.x = 0; this.y = 0; } return this; }, divide: function ( v ) { this.x /= v.x; this.y /= v.y; return this; }, divideScalar: function ( scalar ) { return this.multiplyScalar( 1 / scalar ); }, min: function ( v ) { this.x = Math.min( this.x, v.x ); this.y = Math.min( this.y, v.y ); return this; }, max: function ( v ) { this.x = Math.max( this.x, v.x ); this.y = Math.max( this.y, v.y ); return this; }, clamp: function ( min, max ) { // This function assumes min < max, if this assumption isn't true it will not operate correctly this.x = Math.max( min.x, Math.min( max.x, this.x ) ); this.y = Math.max( min.y, Math.min( max.y, this.y ) ); return this; }, clampScalar: function () { var min, max; return function clampScalar( minVal, maxVal ) { if ( min === undefined ) { min = new THREE.Vector2(); max = new THREE.Vector2(); } min.set( minVal, minVal ); max.set( maxVal, maxVal ); return this.clamp( min, max ); }; }(), clampLength: function ( min, max ) { var length = this.length(); this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length ); return this; }, floor: function () { this.x = Math.floor( this.x ); this.y = Math.floor( this.y ); return this; }, ceil: function () { this.x = Math.ceil( this.x ); this.y = Math.ceil( this.y ); return this; }, round: function () { this.x = Math.round( this.x ); this.y = Math.round( this.y ); return this; }, roundToZero: function () { this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); return this; }, negate: function () { this.x = - this.x; this.y = - this.y; return this; }, dot: function ( v ) { return this.x * v.x + this.y * v.y; }, lengthSq: function () { return this.x * this.x + this.y * this.y; }, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y ); }, lengthManhattan: function() { return Math.abs( this.x ) + Math.abs( this.y ); }, normalize: function () { return this.divideScalar( this.length() ); }, distanceTo: function ( v ) { return Math.sqrt( this.distanceToSquared( v ) ); }, distanceToSquared: function ( v ) { var dx = this.x - v.x, dy = this.y - v.y; return dx * dx + dy * dy; }, setLength: function ( length ) { return this.multiplyScalar( length / this.length() ); }, lerp: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; return this; }, lerpVectors: function ( v1, v2, alpha ) { this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); return this; }, equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) ); }, fromArray: function ( array, offset ) { if ( offset === undefined ) offset = 0; this.x = array[ offset ]; this.y = array[ offset + 1 ]; return this; }, toArray: function ( array, offset ) { if ( array === undefined ) array = []; if ( offset === undefined ) offset = 0; array[ offset ] = this.x; array[ offset + 1 ] = this.y; return array; }, fromAttribute: function ( attribute, index, offset ) { if ( offset === undefined ) offset = 0; index = index * attribute.itemSize + offset; this.x = attribute.array[ index ]; this.y = attribute.array[ index + 1 ]; return this; }, rotateAround: function ( center, angle ) { var c = Math.cos( angle ), s = Math.sin( angle ); var x = this.x - center.x; var y = this.y - center.y; this.x = x * c - y * s + center.x; this.y = x * s + y * c + center.y; return this; } }; three.js-r73/src/math/Matrix3.js0000644000175500017550000001223612610076566016365 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley * @author bhouston / http://clara.io */ THREE.Matrix3 = function () { this.elements = new Float32Array( [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ] ); if ( arguments.length > 0 ) { console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); } }; THREE.Matrix3.prototype = { constructor: THREE.Matrix3, set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { var te = this.elements; te[ 0 ] = n11; te[ 3 ] = n12; te[ 6 ] = n13; te[ 1 ] = n21; te[ 4 ] = n22; te[ 7 ] = n23; te[ 2 ] = n31; te[ 5 ] = n32; te[ 8 ] = n33; return this; }, identity: function () { this.set( 1, 0, 0, 0, 1, 0, 0, 0, 1 ); return this; }, clone: function () { return new this.constructor().fromArray( this.elements ); }, copy: function ( m ) { var me = m.elements; this.set( me[ 0 ], me[ 3 ], me[ 6 ], me[ 1 ], me[ 4 ], me[ 7 ], me[ 2 ], me[ 5 ], me[ 8 ] ); return this; }, multiplyVector3: function ( vector ) { console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); return vector.applyMatrix3( this ); }, multiplyVector3Array: function ( a ) { console.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); return this.applyToVector3Array( a ); }, applyToVector3Array: function () { var v1; return function ( array, offset, length ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); if ( offset === undefined ) offset = 0; if ( length === undefined ) length = array.length; for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { v1.fromArray( array, j ); v1.applyMatrix3( this ); v1.toArray( array, j ); } return array; }; }(), applyToBuffer: function () { var v1; return function applyToBuffer( buffer, offset, length ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); if ( offset === undefined ) offset = 0; if ( length === undefined ) length = buffer.length / buffer.itemSize; for ( var i = 0, j = offset; i < length; i ++, j ++ ) { v1.x = buffer.getX( j ); v1.y = buffer.getY( j ); v1.z = buffer.getZ( j ); v1.applyMatrix3( this ); buffer.setXYZ( v1.x, v1.y, v1.z ); } return buffer; }; }(), multiplyScalar: function ( s ) { var te = this.elements; te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; return this; }, determinant: function () { var te = this.elements; var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; }, getInverse: function ( matrix, throwOnInvertible ) { // input: THREE.Matrix4 // ( based on http://code.google.com/p/webgl-mjs/ ) var me = matrix.elements; var te = this.elements; te[ 0 ] = me[ 10 ] * me[ 5 ] - me[ 6 ] * me[ 9 ]; te[ 1 ] = - me[ 10 ] * me[ 1 ] + me[ 2 ] * me[ 9 ]; te[ 2 ] = me[ 6 ] * me[ 1 ] - me[ 2 ] * me[ 5 ]; te[ 3 ] = - me[ 10 ] * me[ 4 ] + me[ 6 ] * me[ 8 ]; te[ 4 ] = me[ 10 ] * me[ 0 ] - me[ 2 ] * me[ 8 ]; te[ 5 ] = - me[ 6 ] * me[ 0 ] + me[ 2 ] * me[ 4 ]; te[ 6 ] = me[ 9 ] * me[ 4 ] - me[ 5 ] * me[ 8 ]; te[ 7 ] = - me[ 9 ] * me[ 0 ] + me[ 1 ] * me[ 8 ]; te[ 8 ] = me[ 5 ] * me[ 0 ] - me[ 1 ] * me[ 4 ]; var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; // no inverse if ( det === 0 ) { var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; if ( throwOnInvertible || false ) { throw new Error( msg ); } else { console.warn( msg ); } this.identity(); return this; } this.multiplyScalar( 1.0 / det ); return this; }, transpose: function () { var tmp, m = this.elements; tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; return this; }, flattenToArrayOffset: function ( array, offset ) { var te = this.elements; array[ offset ] = te[ 0 ]; array[ offset + 1 ] = te[ 1 ]; array[ offset + 2 ] = te[ 2 ]; array[ offset + 3 ] = te[ 3 ]; array[ offset + 4 ] = te[ 4 ]; array[ offset + 5 ] = te[ 5 ]; array[ offset + 6 ] = te[ 6 ]; array[ offset + 7 ] = te[ 7 ]; array[ offset + 8 ] = te[ 8 ]; return array; }, getNormalMatrix: function ( m ) { // input: THREE.Matrix4 this.getInverse( m ).transpose(); return this; }, transposeIntoArray: function ( r ) { var m = this.elements; r[ 0 ] = m[ 0 ]; r[ 1 ] = m[ 3 ]; r[ 2 ] = m[ 6 ]; r[ 3 ] = m[ 1 ]; r[ 4 ] = m[ 4 ]; r[ 5 ] = m[ 7 ]; r[ 6 ] = m[ 2 ]; r[ 7 ] = m[ 5 ]; r[ 8 ] = m[ 8 ]; return this; }, fromArray: function ( array ) { this.elements.set( array ); return this; }, toArray: function () { var te = this.elements; return [ te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], te[ 8 ] ]; } }; three.js-r73/src/animation/0000755000175500017550000000000012610076566015522 5ustar debacledebaclethree.js-r73/src/animation/AnimationUtils.js0000644000175500017550000000437512610076566021031 0ustar debacledebacle/** * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.AnimationUtils = { getEqualsFunc: function( exemplarValue ) { if ( exemplarValue.equals ) { return function equals_object( a, b ) { return a.equals( b ); } } return function equals_primitive( a, b ) { return ( a === b ); }; }, clone: function( exemplarValue ) { var typeName = typeof exemplarValue; if ( typeName === "object" ) { if ( exemplarValue.clone ) { return exemplarValue.clone(); } console.error( "can not figure out how to copy exemplarValue", exemplarValue ); } return exemplarValue; }, lerp: function( a, b, alpha, interTrack ) { var lerpFunc = THREE.AnimationUtils.getLerpFunc( a, interTrack ); return lerpFunc( a, b, alpha ); }, lerp_object: function( a, b, alpha ) { return a.lerp( b, alpha ); }, slerp_object: function( a, b, alpha ) { return a.slerp( b, alpha ); }, lerp_number: function( a, b, alpha ) { return a * ( 1 - alpha ) + b * alpha; }, lerp_boolean: function( a, b, alpha ) { return ( alpha < 0.5 ) ? a : b; }, lerp_boolean_immediate: function( a, b, alpha ) { return a; }, lerp_string: function( a, b, alpha ) { return ( alpha < 0.5 ) ? a : b; }, lerp_string_immediate: function( a, b, alpha ) { return a; }, // NOTE: this is an accumulator function that modifies the first argument (e.g. a). This is to minimize memory alocations. getLerpFunc: function( exemplarValue, interTrack ) { if ( exemplarValue === undefined || exemplarValue === null ) throw new Error( "examplarValue is null" ); var typeName = typeof exemplarValue; switch( typeName ) { case "object": if ( exemplarValue.lerp ) { return THREE.AnimationUtils.lerp_object; } if ( exemplarValue.slerp ) { return THREE.AnimationUtils.slerp_object; } break; case "number": return THREE.AnimationUtils.lerp_number; case "boolean": if ( interTrack ) { return THREE.AnimationUtils.lerp_boolean; } else { return THREE.AnimationUtils.lerp_boolean_immediate; } case "string": if ( interTrack ) { return THREE.AnimationUtils.lerp_string; } else { return THREE.AnimationUtils.lerp_string_immediate; } } } }; three.js-r73/src/animation/PropertyBinding.js0000644000175500017550000002365412610076566021211 0ustar debacledebacle/** * * A track bound to a real value in the scene graph. * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.PropertyBinding = function ( rootNode, trackName ) { this.rootNode = rootNode; this.trackName = trackName; this.referenceCount = 0; this.originalValue = null; // the value of the property before it was controlled by this binding var parseResults = THREE.PropertyBinding.parseTrackName( trackName ); this.directoryName = parseResults.directoryName; this.nodeName = parseResults.nodeName; this.objectName = parseResults.objectName; this.objectIndex = parseResults.objectIndex; this.propertyName = parseResults.propertyName; this.propertyIndex = parseResults.propertyIndex; this.node = THREE.PropertyBinding.findNode( rootNode, this.nodeName ) || rootNode; this.cumulativeValue = null; this.cumulativeWeight = 0; }; THREE.PropertyBinding.prototype = { constructor: THREE.PropertyBinding, reset: function() { this.cumulativeValue = null; this.cumulativeWeight = 0; }, accumulate: function( value, weight ) { if ( ! this.isBound ) this.bind(); if ( this.cumulativeWeight === 0 ) { if ( weight > 0 ) { if ( this.cumulativeValue === null ) { this.cumulativeValue = THREE.AnimationUtils.clone( value ); } this.cumulativeWeight = weight; } } else { var lerpAlpha = weight / ( this.cumulativeWeight + weight ); this.cumulativeValue = this.lerpValue( this.cumulativeValue, value, lerpAlpha ); this.cumulativeWeight += weight; } }, unbind: function() { if ( ! this.isBound ) return; this.setValue( this.originalValue ); this.setValue = null; this.getValue = null; this.lerpValue = null; this.equalsValue = null; this.triggerDirty = null; this.isBound = false; }, // bind to the real property in the scene graph, remember original value, memorize various accessors for speed/inefficiency bind: function() { if ( this.isBound ) return; var targetObject = this.node; // ensure there is a value node if ( ! targetObject ) { console.error( " trying to update node for track: " + this.trackName + " but it wasn't found." ); return; } if ( this.objectName ) { // special case were we need to reach deeper into the hierarchy to get the face materials.... if ( this.objectName === "materials" ) { if ( ! targetObject.material ) { console.error( ' can not bind to material as node does not have a material', this ); return; } if ( ! targetObject.material.materials ) { console.error( ' can not bind to material.materials as node.material does not have a materials array', this ); return; } targetObject = targetObject.material.materials; } else if ( this.objectName === "bones" ) { if ( ! targetObject.skeleton ) { console.error( ' can not bind to bones as node does not have a skeleton', this ); return; } // potential future optimization: skip this if propertyIndex is already an integer, and convert the integer string to a true integer. targetObject = targetObject.skeleton.bones; // support resolving morphTarget names into indices. for ( var i = 0; i < targetObject.length; i ++ ) { if ( targetObject[i].name === this.objectIndex ) { this.objectIndex = i; break; } } } else { if ( targetObject[ this.objectName ] === undefined ) { console.error( ' can not bind to objectName of node, undefined', this ); return; } targetObject = targetObject[ this.objectName ]; } if ( this.objectIndex !== undefined ) { if ( targetObject[ this.objectIndex ] === undefined ) { console.error( " trying to bind to objectIndex of objectName, but is undefined:", this, targetObject ); return; } targetObject = targetObject[ this.objectIndex ]; } } // special case mappings var nodeProperty = targetObject[ this.propertyName ]; if ( ! nodeProperty ) { console.error( " trying to update property for track: " + this.nodeName + '.' + this.propertyName + " but it wasn't found.", targetObject ); return; } // access a sub element of the property array (only primitives are supported right now) if ( this.propertyIndex !== undefined ) { if ( this.propertyName === "morphTargetInfluences" ) { // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. // support resolving morphTarget names into indices. if ( ! targetObject.geometry ) { console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry', this ); } if ( ! targetObject.geometry.morphTargets ) { console.error( ' can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this ); } for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { if ( targetObject.geometry.morphTargets[i].name === this.propertyIndex ) { this.propertyIndex = i; break; } } } this.setValue = function setValue_propertyIndexed( value ) { if ( ! this.equalsValue( nodeProperty[ this.propertyIndex ], value ) ) { nodeProperty[ this.propertyIndex ] = value; return true; } return false; }; this.getValue = function getValue_propertyIndexed() { return nodeProperty[ this.propertyIndex ]; }; } // must use copy for Object3D.Euler/Quaternion else if ( nodeProperty.copy ) { this.setValue = function setValue_propertyObject( value ) { if ( ! this.equalsValue( nodeProperty, value ) ) { nodeProperty.copy( value ); return true; } return false; } this.getValue = function getValue_propertyObject() { return nodeProperty; }; } // otherwise just set the property directly on the node (do not use nodeProperty as it may not be a reference object) else { this.setValue = function setValue_property( value ) { if ( ! this.equalsValue( targetObject[ this.propertyName ], value ) ) { targetObject[ this.propertyName ] = value; return true; } return false; } this.getValue = function getValue_property() { return targetObject[ this.propertyName ]; }; } // trigger node dirty if ( targetObject.needsUpdate !== undefined ) { // material this.triggerDirty = function triggerDirty_needsUpdate() { this.node.needsUpdate = true; } } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform this.triggerDirty = function triggerDirty_matrixWorldNeedsUpdate() { targetObject.matrixWorldNeedsUpdate = true; } } this.originalValue = this.getValue(); this.equalsValue = THREE.AnimationUtils.getEqualsFunc( this.originalValue ); this.lerpValue = THREE.AnimationUtils.getLerpFunc( this.originalValue, true ); this.isBound = true; }, apply: function() { // for speed capture the setter pattern as a closure (sort of a memoization pattern: https://en.wikipedia.org/wiki/Memoization) if ( ! this.isBound ) this.bind(); // early exit if there is nothing to apply. if ( this.cumulativeWeight > 0 ) { // blend with original value if ( this.cumulativeWeight < 1 ) { var remainingWeight = 1 - this.cumulativeWeight; var lerpAlpha = remainingWeight / ( this.cumulativeWeight + remainingWeight ); this.cumulativeValue = this.lerpValue( this.cumulativeValue, this.originalValue, lerpAlpha ); } var valueChanged = this.setValue( this.cumulativeValue ); if ( valueChanged && this.triggerDirty ) { this.triggerDirty(); } // reset accumulator this.cumulativeValue = null; this.cumulativeWeight = 0; } } }; THREE.PropertyBinding.parseTrackName = function( trackName ) { // matches strings in the form of: // nodeName.property // nodeName.property[accessor] // nodeName.material.property[accessor] // uuid.property[accessor] // uuid.objectName[objectIndex].propertyName[propertyIndex] // parentName/nodeName.property // parentName/parentName/nodeName.property[index] // .bone[Armature.DEF_cog].position // created and tested via https://regex101.com/#javascript var re = /^(([\w]+\/)*)([\w-\d]+)?(\.([\w]+)(\[([\w\d\[\]\_. ]+)\])?)?(\.([\w.]+)(\[([\w\d\[\]\_. ]+)\])?)$/; var matches = re.exec(trackName); if ( ! matches ) { throw new Error( "cannot parse trackName at all: " + trackName ); } if (matches.index === re.lastIndex) { re.lastIndex++; } var results = { directoryName: matches[1], nodeName: matches[3], // allowed to be null, specified root node. objectName: matches[5], objectIndex: matches[7], propertyName: matches[9], propertyIndex: matches[11] // allowed to be null, specifies that the whole property is set. }; if ( results.propertyName === null || results.propertyName.length === 0 ) { throw new Error( "can not parse propertyName from trackName: " + trackName ); } return results; }; THREE.PropertyBinding.findNode = function( root, nodeName ) { function searchSkeleton( skeleton ) { for ( var i = 0; i < skeleton.bones.length; i ++ ) { var bone = skeleton.bones[i]; if ( bone.name === nodeName ) { return bone; } } return null; } function searchNodeSubtree( children ) { for ( var i = 0; i < children.length; i ++ ) { var childNode = children[i]; if ( childNode.name === nodeName || childNode.uuid === nodeName ) { return childNode; } var result = searchNodeSubtree( childNode.children ); if ( result ) return result; } return null; } // if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) { return root; } // search into skeleton bones. if ( root.skeleton ) { var bone = searchSkeleton( root.skeleton ); if ( bone ) { return bone; } } // search into node subtree. if ( root.children ) { var subTreeNode = searchNodeSubtree( root.children ); if ( subTreeNode ) { return subTreeNode; } } return null; } three.js-r73/src/animation/AnimationAction.js0000644000175500017550000000636712610076566021151 0ustar debacledebacle/** * * A clip that has been explicitly scheduled. * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.AnimationAction = function ( clip, startTime, timeScale, weight, loop ) { if ( clip === undefined ) throw new Error( 'clip is null' ); this.clip = clip; this.localRoot = null; this.startTime = startTime || 0; this.timeScale = timeScale || 1; this.weight = weight || 1; this.loop = loop || THREE.LoopRepeat; this.loopCount = 0; this.enabled = true; // allow for easy disabling of the action. this.actionTime = - this.startTime; this.clipTime = 0; this.propertyBindings = []; }; /* THREE.LoopOnce = 2200; THREE.LoopRepeat = 2201; THREE.LoopPingPing = 2202; */ THREE.AnimationAction.prototype = { constructor: THREE.AnimationAction, setLocalRoot: function( localRoot ) { this.localRoot = localRoot; return this; }, updateTime: function( clipDeltaTime ) { var previousClipTime = this.clipTime; var previousLoopCount = this.loopCount; var previousActionTime = this.actionTime; var duration = this.clip.duration; this.actionTime = this.actionTime + clipDeltaTime; if ( this.loop === THREE.LoopOnce ) { this.loopCount = 0; this.clipTime = Math.min( Math.max( this.actionTime, 0 ), duration ); // if time is changed since last time, see if we have hit a start/end limit if ( this.clipTime !== previousClipTime ) { if ( this.clipTime === duration ) { this.mixer.dispatchEvent( { type: 'finished', action: this, direction: 1 } ); } else if ( this.clipTime === 0 ) { this.mixer.dispatchEvent( { type: 'finished', action: this, direction: -1 } ); } } return this.clipTime; } this.loopCount = Math.floor( this.actionTime / duration ); var newClipTime = this.actionTime - this.loopCount * duration; newClipTime = newClipTime % duration; // if we are ping pong looping, ensure that we go backwards when appropriate if ( this.loop == THREE.LoopPingPong ) { if ( Math.abs( this.loopCount % 2 ) === 1 ) { newClipTime = duration - newClipTime; } } this.clipTime = newClipTime; if ( this.loopCount !== previousLoopCount ) { this.mixer.dispatchEvent( { type: 'loop', action: this, loopDelta: ( this.loopCount - this.loopCount ) } ); } return this.clipTime; }, syncWith: function( action ) { this.actionTime = action.actionTime; this.timeScale = action.timeScale; return this; }, warpToDuration: function( duration ) { this.timeScale = this.clip.duration / duration; return this; }, init: function( time ) { this.clipTime = time - this.startTime; return this; }, update: function( clipDeltaTime ) { this.updateTime( clipDeltaTime ); var clipResults = this.clip.getAt( this.clipTime ); return clipResults; }, getTimeScaleAt: function( time ) { if ( this.timeScale.getAt ) { // pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip return this.timeScale.getAt( time ); } return this.timeScale; }, getWeightAt: function( time ) { if ( this.weight.getAt ) { // pass in time, not clip time, allows for fadein/fadeout across multiple loops of the clip return this.weight.getAt( time ); } return this.weight; } }; three.js-r73/src/animation/AnimationClip.js0000644000175500017550000001642612610076566020620 0ustar debacledebacle/** * * Reusable set of Tracks that represent an animation. * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.AnimationClip = function ( name, duration, tracks ) { this.name = name; this.tracks = tracks; this.duration = ( duration !== undefined ) ? duration : -1; // this means it should figure out its duration by scanning the tracks if ( this.duration < 0 ) { for ( var i = 0; i < this.tracks.length; i ++ ) { var track = this.tracks[i]; this.duration = Math.max( track.keys[ track.keys.length - 1 ].time ); } } // maybe only do these on demand, as doing them here could potentially slow down loading // but leaving these here during development as this ensures a lot of testing of these functions this.trim(); this.optimize(); this.results = []; }; THREE.AnimationClip.prototype = { constructor: THREE.AnimationClip, getAt: function( clipTime ) { clipTime = Math.max( 0, Math.min( clipTime, this.duration ) ); for ( var i = 0; i < this.tracks.length; i ++ ) { var track = this.tracks[ i ]; this.results[ i ] = track.getAt( clipTime ); } return this.results; }, trim: function() { for ( var i = 0; i < this.tracks.length; i ++ ) { this.tracks[ i ].trim( 0, this.duration ); } return this; }, optimize: function() { for ( var i = 0; i < this.tracks.length; i ++ ) { this.tracks[ i ].optimize(); } return this; } }; THREE.AnimationClip.CreateFromMorphTargetSequence = function( name, morphTargetSequence, fps ) { var numMorphTargets = morphTargetSequence.length; var tracks = []; for ( var i = 0; i < numMorphTargets; i ++ ) { var keys = []; keys.push( { time: ( i + numMorphTargets - 1 ) % numMorphTargets, value: 0 } ); keys.push( { time: i, value: 1 } ); keys.push( { time: ( i + 1 ) % numMorphTargets, value: 0 } ); keys.sort( THREE.KeyframeTrack.keyComparer ); // if there is a key at the first frame, duplicate it as the last frame as well for perfect loop. if ( keys[0].time === 0 ) { keys.push( { time: numMorphTargets, value: keys[0].value }); } tracks.push( new THREE.NumberKeyframeTrack( '.morphTargetInfluences[' + morphTargetSequence[i].name + ']', keys ).scale( 1.0 / fps ) ); } return new THREE.AnimationClip( name, -1, tracks ); }; THREE.AnimationClip.findByName = function( clipArray, name ) { for ( var i = 0; i < clipArray.length; i ++ ) { if ( clipArray[i].name === name ) { return clipArray[i]; } } return null; }; THREE.AnimationClip.CreateClipsFromMorphTargetSequences = function( morphTargets, fps ) { var animationToMorphTargets = {}; // tested with https://regex101.com/ on trick sequences such flamingo_flyA_003, flamingo_run1_003, crdeath0059 var pattern = /^([\w-]*?)([\d]+)$/; // sort morph target names into animation groups based patterns like Walk_001, Walk_002, Run_001, Run_002 for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { var morphTarget = morphTargets[ i ]; var parts = morphTarget.name.match( pattern ); if ( parts && parts.length > 1 ) { var name = parts[ 1 ]; var animationMorphTargets = animationToMorphTargets[ name ]; if ( ! animationMorphTargets ) { animationToMorphTargets[ name ] = animationMorphTargets = []; } animationMorphTargets.push( morphTarget ); } } var clips = []; for ( var name in animationToMorphTargets ) { clips.push( THREE.AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps ) ); } return clips; }; // parse the standard JSON format for clips THREE.AnimationClip.parse = function( json ) { var tracks = []; for ( var i = 0; i < json.tracks.length; i ++ ) { tracks.push( THREE.KeyframeTrack.parse( json.tracks[i] ).scale( 1.0 / json.fps ) ); } return new THREE.AnimationClip( json.name, json.duration, tracks ); }; // parse the animation.hierarchy format THREE.AnimationClip.parseAnimation = function( animation, bones, nodeName ) { if ( ! animation ) { console.error( " no animation in JSONLoader data" ); return null; } var convertTrack = function( trackName, animationKeys, propertyName, trackType, animationKeyToValueFunc ) { var keys = []; for ( var k = 0; k < animationKeys.length; k ++ ) { var animationKey = animationKeys[k]; if ( animationKey[propertyName] !== undefined ) { keys.push( { time: animationKey.time, value: animationKeyToValueFunc( animationKey ) } ); } } // only return track if there are actually keys. if ( keys.length > 0 ) { return new trackType( trackName, keys ); } return null; }; var tracks = []; var clipName = animation.name || 'default'; var duration = animation.length || -1; // automatic length determination in AnimationClip. var fps = animation.fps || 30; var hierarchyTracks = animation.hierarchy || []; for ( var h = 0; h < hierarchyTracks.length; h ++ ) { var animationKeys = hierarchyTracks[ h ].keys; // skip empty tracks if ( ! animationKeys || animationKeys.length == 0 ) { continue; } // process morph targets in a way exactly compatible with AnimationHandler.init( animation ) if ( animationKeys[0].morphTargets ) { // figure out all morph targets used in this track var morphTargetNames = {}; for ( var k = 0; k < animationKeys.length; k ++ ) { if ( animationKeys[k].morphTargets ) { for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) { morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1; } } } // create a track for each morph target with all zero morphTargetInfluences except for the keys in which the morphTarget is named. for ( var morphTargetName in morphTargetNames ) { var keys = []; for ( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) { var animationKey = animationKeys[k]; keys.push( { time: animationKey.time, value: (( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ) }); } tracks.push( new THREE.NumberKeyframeTrack( nodeName + '.morphTargetInfluence[' + morphTargetName + ']', keys ) ); } duration = morphTargetNames.length * ( fps || 1.0 ); } else { var boneName = nodeName + '.bones[' + bones[ h ].name + ']'; // track contains positions... var positionTrack = convertTrack( boneName + '.position', animationKeys, 'pos', THREE.VectorKeyframeTrack, function( animationKey ) { return new THREE.Vector3().fromArray( animationKey.pos ) } ); if ( positionTrack ) tracks.push( positionTrack ); // track contains quaternions... var quaternionTrack = convertTrack( boneName + '.quaternion', animationKeys, 'rot', THREE.QuaternionKeyframeTrack, function( animationKey ) { if ( animationKey.rot.slerp ) { return animationKey.rot.clone(); } else { return new THREE.Quaternion().fromArray( animationKey.rot ); } } ); if ( quaternionTrack ) tracks.push( quaternionTrack ); // track contains quaternions... var scaleTrack = convertTrack( boneName + '.scale', animationKeys, 'scl', THREE.VectorKeyframeTrack, function( animationKey ) { return new THREE.Vector3().fromArray( animationKey.scl ) } ); if ( scaleTrack ) tracks.push( scaleTrack ); } } if ( tracks.length === 0 ) { return null; } var clip = new THREE.AnimationClip( clipName, duration, tracks ); return clip; }; three.js-r73/src/animation/AnimationMixer.js0000644000175500017550000001166112610076566021011 0ustar debacledebacle/** * * Mixes together the AnimationClips scheduled by AnimationActions and applies them to the root and subtree * * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.AnimationMixer = function( root ) { this.root = root; this.time = 0; this.timeScale = 1.0; this.actions = []; this.propertyBindingMap = {}; }; THREE.AnimationMixer.prototype = { constructor: THREE.AnimationMixer, addAction: function( action ) { // TODO: check for duplicate action names? Or provide each action with a UUID? this.actions.push( action ); action.init( this.time ); action.mixer = this; var tracks = action.clip.tracks; var root = action.localRoot || this.root; for ( var i = 0; i < tracks.length; i ++ ) { var track = tracks[ i ]; var propertyBindingKey = root.uuid + '-' + track.name; var propertyBinding = this.propertyBindingMap[ propertyBindingKey ]; if ( propertyBinding === undefined ) { propertyBinding = new THREE.PropertyBinding( root, track.name ); this.propertyBindingMap[ propertyBindingKey ] = propertyBinding; } // push in the same order as the tracks. action.propertyBindings.push( propertyBinding ); // track usages of shared property bindings, because if we leave too many around, the mixer can get slow propertyBinding.referenceCount += 1; } }, removeAllActions: function() { for ( var i = 0; i < this.actions.length; i ++ ) { this.actions[i].mixer = null; } // unbind all property bindings for ( var properyBindingKey in this.propertyBindingMap ) { this.propertyBindingMap[ properyBindingKey ].unbind(); } this.actions = []; this.propertyBindingMap = {}; return this; }, removeAction: function( action ) { var index = this.actions.indexOf( action ); if ( index !== - 1 ) { this.actions.splice( index, 1 ); action.mixer = null; } // remove unused property bindings because if we leave them around the mixer can get slow var root = action.localRoot || this.root; var tracks = action.clip.tracks; for ( var i = 0; i < tracks.length; i ++ ) { var track = tracks[ i ]; var propertyBindingKey = root.uuid + '-' + track.name; var propertyBinding = this.propertyBindingMap[ propertyBindingKey ]; propertyBinding.referenceCount -= 1; if ( propertyBinding.referenceCount <= 0 ) { propertyBinding.unbind(); delete this.propertyBindingMap[ propertyBindingKey ]; } } return this; }, // can be optimized if needed findActionByName: function( name ) { for ( var i = 0; i < this.actions.length; i ++ ) { if ( this.actions[i].name === name ) return this.actions[i]; } return null; }, play: function( action, optionalFadeInDuration ) { action.startTime = this.time; this.addAction( action ); return this; }, fadeOut: function( action, duration ) { var keys = []; keys.push( { time: this.time, value: 1 } ); keys.push( { time: this.time + duration, value: 0 } ); action.weight = new THREE.NumberKeyframeTrack( "weight", keys ); return this; }, fadeIn: function( action, duration ) { var keys = []; keys.push( { time: this.time, value: 0 } ); keys.push( { time: this.time + duration, value: 1 } ); action.weight = new THREE.NumberKeyframeTrack( "weight", keys ); return this; }, warp: function( action, startTimeScale, endTimeScale, duration ) { var keys = []; keys.push( { time: this.time, value: startTimeScale } ); keys.push( { time: this.time + duration, value: endTimeScale } ); action.timeScale = new THREE.NumberKeyframeTrack( "timeScale", keys ); return this; }, crossFade: function( fadeOutAction, fadeInAction, duration, warp ) { this.fadeOut( fadeOutAction, duration ); this.fadeIn( fadeInAction, duration ); if ( warp ) { var startEndRatio = fadeOutAction.clip.duration / fadeInAction.clip.duration; var endStartRatio = 1.0 / startEndRatio; this.warp( fadeOutAction, 1.0, startEndRatio, duration ); this.warp( fadeInAction, endStartRatio, 1.0, duration ); } return this; }, update: function( deltaTime ) { var mixerDeltaTime = deltaTime * this.timeScale; this.time += mixerDeltaTime; for ( var i = 0; i < this.actions.length; i ++ ) { var action = this.actions[i]; var weight = action.getWeightAt( this.time ); var actionTimeScale = action.getTimeScaleAt( this.time ); var actionDeltaTime = mixerDeltaTime * actionTimeScale; var actionResults = action.update( actionDeltaTime ); if ( action.weight <= 0 || ! action.enabled ) continue; for ( var j = 0; j < actionResults.length; j ++ ) { var name = action.clip.tracks[j].name; action.propertyBindings[ j ].accumulate( actionResults[j], weight ); } } // apply to nodes for ( var propertyBindingKey in this.propertyBindingMap ) { this.propertyBindingMap[ propertyBindingKey ].apply(); } return this; } }; THREE.EventDispatcher.prototype.apply( THREE.AnimationMixer.prototype ); three.js-r73/src/animation/tracks/0000755000175500017550000000000012610076566017011 5ustar debacledebaclethree.js-r73/src/animation/tracks/NumberKeyframeTrack.js0000644000175500017550000000265012610076566023253 0ustar debacledebacle/** * * A Track that interpolates Numbers * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.NumberKeyframeTrack = function ( name, keys ) { THREE.KeyframeTrack.call( this, name, keys ); // local cache of value type to avoid allocations during runtime. this.result = this.keys[0].value; }; THREE.NumberKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); THREE.NumberKeyframeTrack.prototype.constructor = THREE.NumberKeyframeTrack; THREE.NumberKeyframeTrack.prototype.setResult = function( value ) { this.result = value; }; // memoization of the lerp function for speed. // NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. THREE.NumberKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { return value0 * ( 1 - alpha ) + value1 * alpha; }; THREE.NumberKeyframeTrack.prototype.compareValues = function( value0, value1 ) { return ( value0 === value1 ); }; THREE.NumberKeyframeTrack.prototype.clone = function() { var clonedKeys = []; for ( var i = 0; i < this.keys.length; i ++ ) { var key = this.keys[i]; clonedKeys.push( { time: key.time, value: key.value } ); } return new THREE.NumberKeyframeTrack( this.name, clonedKeys ); }; THREE.NumberKeyframeTrack.parse = function( json ) { return new THREE.NumberKeyframeTrack( json.name, json.keys ); }; three.js-r73/src/animation/tracks/ColorKeyframeTrack.js0000644000175500017550000000315312610076566023100 0ustar debacledebacle/** * * A Track that interpolates Color * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.ColorKeyframeTrack = function ( name, keys ) { THREE.KeyframeTrack.call( this, name, keys ); // local cache of value type to avoid allocations during runtime. this.result = this.keys[0].value.clone(); }; THREE.ColorKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); THREE.ColorKeyframeTrack.prototype.constructor = THREE.ColorKeyframeTrack; THREE.ColorKeyframeTrack.prototype.setResult = function( value ) { this.result.copy( value ); }; // memoization of the lerp function for speed. // NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. THREE.ColorKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { return value0.lerp( value1, alpha ); }; THREE.ColorKeyframeTrack.prototype.compareValues = function( value0, value1 ) { return value0.equals( value1 ); }; THREE.ColorKeyframeTrack.prototype.clone = function() { var clonedKeys = []; for ( var i = 0; i < this.keys.length; i ++ ) { var key = this.keys[i]; clonedKeys.push( { time: key.time, value: key.value.clone() } ); } return new THREE.ColorKeyframeTrack( this.name, clonedKeys ); }; THREE.ColorKeyframeTrack.parse = function( json ) { var keys = []; for ( var i = 0; i < json.keys.length; i ++ ) { var jsonKey = json.keys[i]; keys.push( { value: new THREE.Color().fromArray( jsonKey.value ), time: jsonKey.time } ); } return new THREE.ColorKeyframeTrack( json.name, keys ); }; three.js-r73/src/animation/tracks/QuaternionKeyframeTrack.js0000644000175500017550000000354512610076566024154 0ustar debacledebacle/** * * A Track that interpolates Quaternion * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.QuaternionKeyframeTrack = function ( name, keys ) { THREE.KeyframeTrack.call( this, name, keys ); // local cache of value type to avoid allocations during runtime. this.result = this.keys[0].value.clone(); }; THREE.QuaternionKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); THREE.QuaternionKeyframeTrack.prototype.constructor = THREE.QuaternionKeyframeTrack; THREE.QuaternionKeyframeTrack.prototype.setResult = function( value ) { this.result.copy( value ); }; // memoization of the lerp function for speed. // NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. THREE.QuaternionKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { return value0.slerp( value1, alpha ); }; THREE.QuaternionKeyframeTrack.prototype.compareValues = function( value0, value1 ) { return value0.equals( value1 ); }; THREE.QuaternionKeyframeTrack.prototype.multiply = function( quat ) { for ( var i = 0; i < this.keys.length; i ++ ) { this.keys[i].value.multiply( quat ); } return this; }; THREE.QuaternionKeyframeTrack.prototype.clone = function() { var clonedKeys = []; for ( var i = 0; i < this.keys.length; i ++ ) { var key = this.keys[i]; clonedKeys.push( { time: key.time, value: key.value.clone() } ); } return new THREE.QuaternionKeyframeTrack( this.name, clonedKeys ); }; THREE.QuaternionKeyframeTrack.parse = function( json ) { var keys = []; for ( var i = 0; i < json.keys.length; i ++ ) { var jsonKey = json.keys[i]; keys.push( { value: new THREE.Quaternion().fromArray( jsonKey.value ), time: jsonKey.time } ); } return new THREE.QuaternionKeyframeTrack( json.name, keys ); }; three.js-r73/src/animation/tracks/StringKeyframeTrack.js0000644000175500017550000000264212610076566023272 0ustar debacledebacle/** * * A Track that interpolates Strings * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.StringKeyframeTrack = function ( name, keys ) { THREE.KeyframeTrack.call( this, name, keys ); // local cache of value type to avoid allocations during runtime. this.result = this.keys[0].value; }; THREE.StringKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); THREE.StringKeyframeTrack.prototype.constructor = THREE.StringKeyframeTrack; THREE.StringKeyframeTrack.prototype.setResult = function( value ) { this.result = value; }; // memoization of the lerp function for speed. // NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. THREE.StringKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { return ( alpha < 1.0 ) ? value0 : value1; }; THREE.StringKeyframeTrack.prototype.compareValues = function( value0, value1 ) { return ( value0 === value1 ); }; THREE.StringKeyframeTrack.prototype.clone = function() { var clonedKeys = []; for ( var i = 0; i < this.keys.length; i ++ ) { var key = this.keys[i]; clonedKeys.push( { time: key.time, value: key.value } ); } return new THREE.StringKeyframeTrack( this.name, clonedKeys ); }; THREE.StringKeyframeTrack.parse = function( json ) { return new THREE.StringKeyframeTrack( json.name, json.keys ); }; three.js-r73/src/animation/tracks/BooleanKeyframeTrack.js0000644000175500017550000000265512610076566023407 0ustar debacledebacle/** * * A Track that interpolates Boolean * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.BooleanKeyframeTrack = function ( name, keys ) { THREE.KeyframeTrack.call( this, name, keys ); // local cache of value type to avoid allocations during runtime. this.result = this.keys[0].value; }; THREE.BooleanKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); THREE.BooleanKeyframeTrack.prototype.constructor = THREE.BooleanKeyframeTrack; THREE.BooleanKeyframeTrack.prototype.setResult = function( value ) { this.result = value; }; // memoization of the lerp function for speed. // NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. THREE.BooleanKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { return ( alpha < 1.0 ) ? value0 : value1; }; THREE.BooleanKeyframeTrack.prototype.compareValues = function( value0, value1 ) { return ( value0 === value1 ); }; THREE.BooleanKeyframeTrack.prototype.clone = function() { var clonedKeys = []; for ( var i = 0; i < this.keys.length; i ++ ) { var key = this.keys[i]; clonedKeys.push( { time: key.time, value: key.value } ); } return new THREE.BooleanKeyframeTrack( this.name, clonedKeys ); }; THREE.BooleanKeyframeTrack.parse = function( json ) { return new THREE.BooleanKeyframeTrack( json.name, json.keys ); }; three.js-r73/src/animation/tracks/VectorKeyframeTrack.js0000644000175500017550000000333112610076566023262 0ustar debacledebacle/** * * A Track that interpolates Vectors * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.VectorKeyframeTrack = function ( name, keys ) { THREE.KeyframeTrack.call( this, name, keys ); // local cache of value type to avoid allocations during runtime. this.result = this.keys[0].value.clone(); }; THREE.VectorKeyframeTrack.prototype = Object.create( THREE.KeyframeTrack.prototype ); THREE.VectorKeyframeTrack.prototype.constructor = THREE.VectorKeyframeTrack; THREE.VectorKeyframeTrack.prototype.setResult = function( value ) { this.result.copy( value ); }; // memoization of the lerp function for speed. // NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis. THREE.VectorKeyframeTrack.prototype.lerpValues = function( value0, value1, alpha ) { return value0.lerp( value1, alpha ); }; THREE.VectorKeyframeTrack.prototype.compareValues = function( value0, value1 ) { return value0.equals( value1 ); }; THREE.VectorKeyframeTrack.prototype.clone = function() { var clonedKeys = []; for ( var i = 0; i < this.keys.length; i ++ ) { var key = this.keys[i]; clonedKeys.push( { time: key.time, value: key.value.clone() } ); } return new THREE.VectorKeyframeTrack( this.name, clonedKeys ); }; THREE.VectorKeyframeTrack.parse = function( json ) { var elementCount = json.keys[0].value.length; var valueType = THREE[ 'Vector' + elementCount ]; var keys = []; for ( var i = 0; i < json.keys.length; i ++ ) { var jsonKey = json.keys[i]; keys.push( { value: new valueType().fromArray( jsonKey.value ), time: jsonKey.time } ); } return new THREE.VectorKeyframeTrack( json.name, keys ); }; three.js-r73/src/animation/KeyframeTrack.js0000644000175500017550000001535512610076566020621 0ustar debacledebacle/** * * A Track that returns a keyframe interpolated value, currently linearly interpolated * * @author Ben Houston / http://clara.io/ * @author David Sarno / http://lighthaus.us/ */ THREE.KeyframeTrack = function ( name, keys ) { if ( name === undefined ) throw new Error( "track name is undefined" ); if ( keys === undefined || keys.length === 0 ) throw new Error( "no keys in track named " + name ); this.name = name; this.keys = keys; // time in seconds, value as value // the index of the last result, used as a starting point for local search. this.lastIndex = 0; this.validate(); this.optimize(); }; THREE.KeyframeTrack.prototype = { constructor: THREE.KeyframeTrack, getAt: function( time ) { // this can not go higher than this.keys.length. while( ( this.lastIndex < this.keys.length ) && ( time >= this.keys[this.lastIndex].time ) ) { this.lastIndex ++; }; // this can not go lower than 0. while( ( this.lastIndex > 0 ) && ( time < this.keys[this.lastIndex - 1].time ) ) { this.lastIndex --; } if ( this.lastIndex >= this.keys.length ) { this.setResult( this.keys[ this.keys.length - 1 ].value ); return this.result; } if ( this.lastIndex === 0 ) { this.setResult( this.keys[ 0 ].value ); return this.result; } var prevKey = this.keys[ this.lastIndex - 1 ]; this.setResult( prevKey.value ); // if true, means that prev/current keys are identical, thus no interpolation required. if ( prevKey.constantToNext ) { return this.result; } // linear interpolation to start with var currentKey = this.keys[ this.lastIndex ]; var alpha = ( time - prevKey.time ) / ( currentKey.time - prevKey.time ); this.result = this.lerpValues( this.result, currentKey.value, alpha ); return this.result; }, // move all keyframes either forwards or backwards in time shift: function( timeOffset ) { if ( timeOffset !== 0.0 ) { for ( var i = 0; i < this.keys.length; i ++ ) { this.keys[i].time += timeOffset; } } return this; }, // scale all keyframe times by a factor (useful for frame <-> seconds conversions) scale: function( timeScale ) { if ( timeScale !== 1.0 ) { for ( var i = 0; i < this.keys.length; i ++ ) { this.keys[i].time *= timeScale; } } return this; }, // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values trim: function( startTime, endTime ) { var firstKeysToRemove = 0; for ( var i = 1; i < this.keys.length; i ++ ) { if ( this.keys[i] <= startTime ) { firstKeysToRemove ++; } } var lastKeysToRemove = 0; for ( var i = this.keys.length - 2; i > 0; i ++ ) { if ( this.keys[i] >= endTime ) { lastKeysToRemove ++; } else { break; } } // remove last keys first because it doesn't affect the position of the first keys (the otherway around doesn't work as easily) if ( ( firstKeysToRemove + lastKeysToRemove ) > 0 ) { this.keys = this.keys.splice( firstKeysToRemove, this.keys.length - lastKeysToRemove - firstKeysToRemove );; } return this; }, /* NOTE: This is commented out because we really shouldn't have to handle unsorted key lists Tracks with out of order keys should be considered to be invalid. - bhouston sort: function() { this.keys.sort( THREE.KeyframeTrack.keyComparer ); return this; },*/ // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable // One could eventually ensure that all key.values in a track are all of the same type (otherwise interpolation makes no sense.) validate: function() { var prevKey = null; if ( this.keys.length === 0 ) { console.error( " track is empty, no keys", this ); return; } for ( var i = 0; i < this.keys.length; i ++ ) { var currKey = this.keys[i]; if ( ! currKey ) { console.error( " key is null in track", this, i ); return; } if ( ( typeof currKey.time ) !== 'number' || isNaN( currKey.time ) ) { console.error( " key.time is not a valid number", this, i, currKey ); return; } if ( currKey.value === undefined || currKey.value === null) { console.error( " key.value is null in track", this, i, currKey ); return; } if ( prevKey && prevKey.time > currKey.time ) { console.error( " key.time is less than previous key time, out of order keys", this, i, currKey, prevKey ); return; } prevKey = currKey; } return this; }, // currently only removes equivalent sequential keys (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0), which are common in morph target animations optimize: function() { var newKeys = []; var prevKey = this.keys[0]; newKeys.push( prevKey ); var equalsFunc = THREE.AnimationUtils.getEqualsFunc( prevKey.value ); for ( var i = 1; i < this.keys.length - 1; i ++ ) { var currKey = this.keys[i]; var nextKey = this.keys[i+1]; // if prevKey & currKey are the same time, remove currKey. If you want immediate adjacent keys, use an epsilon offset // it is not possible to have two keys at the same time as we sort them. The sort is not stable on keys with the same time. if ( ( prevKey.time === currKey.time ) ) { continue; } // remove completely unnecessary keyframes that are the same as their prev and next keys if ( this.compareValues( prevKey.value, currKey.value ) && this.compareValues( currKey.value, nextKey.value ) ) { continue; } // determine if interpolation is required prevKey.constantToNext = this.compareValues( prevKey.value, currKey.value ); newKeys.push( currKey ); prevKey = currKey; } newKeys.push( this.keys[ this.keys.length - 1 ] ); this.keys = newKeys; return this; } }; THREE.KeyframeTrack.keyComparer = function keyComparator(key0, key1) { return key0.time - key1.time; }; THREE.KeyframeTrack.parse = function( json ) { if ( json.type === undefined ) throw new Error( "track type undefined, can not parse" ); var trackType = THREE.KeyframeTrack.GetTrackTypeForTypeName( json.type ); return trackType.parse( json ); }; THREE.KeyframeTrack.GetTrackTypeForTypeName = function( typeName ) { switch( typeName.toLowerCase() ) { case "vector": case "vector2": case "vector3": case "vector4": return THREE.VectorKeyframeTrack; case "quaternion": return THREE.QuaternionKeyframeTrack; case "integer": case "scalar": case "double": case "float": case "number": return THREE.NumberKeyframeTrack; case "bool": case "boolean": return THREE.BooleanKeyframeTrack; case "string": return THREE.StringKeyframeTrack; }; throw new Error( "Unsupported typeName: " + typeName ); }; three.js-r73/src/textures/0000755000175500017550000000000012610076566015426 5ustar debacledebaclethree.js-r73/src/textures/Texture.js0000644000175500017550000001201212610076566017420 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author szimek / https://github.com/szimek/ */ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { Object.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } ); this.uuid = THREE.Math.generateUUID(); this.name = ''; this.sourceFile = ''; this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; this.mipmaps = []; this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING; this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; this.anisotropy = anisotropy !== undefined ? anisotropy : 1; this.format = format !== undefined ? format : THREE.RGBAFormat; this.type = type !== undefined ? type : THREE.UnsignedByteType; this.offset = new THREE.Vector2( 0, 0 ); this.repeat = new THREE.Vector2( 1, 1 ); this.generateMipmaps = true; this.premultiplyAlpha = false; this.flipY = true; this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) this.version = 0; this.onUpdate = null; }; THREE.Texture.DEFAULT_IMAGE = undefined; THREE.Texture.DEFAULT_MAPPING = THREE.UVMapping; THREE.Texture.prototype = { constructor: THREE.Texture, set needsUpdate ( value ) { if ( value === true ) this.version ++; }, clone: function () { return new this.constructor().copy( this ); }, copy: function ( source ) { this.image = source.image; this.mipmaps = source.mipmaps.slice( 0 ); this.mapping = source.mapping; this.wrapS = source.wrapS; this.wrapT = source.wrapT; this.magFilter = source.magFilter; this.minFilter = source.minFilter; this.anisotropy = source.anisotropy; this.format = source.format; this.type = source.type; this.offset.copy( source.offset ); this.repeat.copy( source.repeat ); this.generateMipmaps = source.generateMipmaps; this.premultiplyAlpha = source.premultiplyAlpha; this.flipY = source.flipY; this.unpackAlignment = source.unpackAlignment; return this; }, toJSON: function ( meta ) { if ( meta.textures[ this.uuid ] !== undefined ) { return meta.textures[ this.uuid ]; } function getDataURL( image ) { var canvas; if ( image.toDataURL !== undefined ) { canvas = image; } else { canvas = document.createElement( 'canvas' ); canvas.width = image.width; canvas.height = image.height; canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height ); } if ( canvas.width > 2048 || canvas.height > 2048 ) { return canvas.toDataURL( 'image/jpeg', 0.6 ); } else { return canvas.toDataURL( 'image/png' ); } } var output = { metadata: { version: 4.4, type: 'Texture', generator: 'Texture.toJSON' }, uuid: this.uuid, name: this.name, mapping: this.mapping, repeat: [ this.repeat.x, this.repeat.y ], offset: [ this.offset.x, this.offset.y ], wrap: [ this.wrapS, this.wrapT ], minFilter: this.minFilter, magFilter: this.magFilter, anisotropy: this.anisotropy }; if ( this.image !== undefined ) { // TODO: Move to THREE.Image var image = this.image; if ( image.uuid === undefined ) { image.uuid = THREE.Math.generateUUID(); // UGH } if ( meta.images[ image.uuid ] === undefined ) { meta.images[ image.uuid ] = { uuid: image.uuid, url: getDataURL( image ) }; } output.image = image.uuid; } meta.textures[ this.uuid ] = output; return output; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); }, transformUv: function ( uv ) { if ( this.mapping !== THREE.UVMapping ) return; uv.multiply( this.repeat ); uv.add( this.offset ); if ( uv.x < 0 || uv.x > 1 ) { switch ( this.wrapS ) { case THREE.RepeatWrapping: uv.x = uv.x - Math.floor( uv.x ); break; case THREE.ClampToEdgeWrapping: uv.x = uv.x < 0 ? 0 : 1; break; case THREE.MirroredRepeatWrapping: if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { uv.x = Math.ceil( uv.x ) - uv.x; } else { uv.x = uv.x - Math.floor( uv.x ); } break; } } if ( uv.y < 0 || uv.y > 1 ) { switch ( this.wrapT ) { case THREE.RepeatWrapping: uv.y = uv.y - Math.floor( uv.y ); break; case THREE.ClampToEdgeWrapping: uv.y = uv.y < 0 ? 0 : 1; break; case THREE.MirroredRepeatWrapping: if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { uv.y = Math.ceil( uv.y ) - uv.y; } else { uv.y = uv.y - Math.floor( uv.y ); } break; } } if ( this.flipY ) { uv.y = 1 - uv.y; } } }; THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); THREE.TextureIdCount = 0; three.js-r73/src/textures/DataTexture.js0000644000175500017550000000127312610076566020221 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); this.image = { data: data, width: width, height: height }; this.magFilter = magFilter !== undefined ? magFilter : THREE.NearestFilter; this.minFilter = minFilter !== undefined ? minFilter : THREE.NearestFilter; this.flipY = false; this.generateMipmaps = false; }; THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.DataTexture.prototype.constructor = THREE.DataTexture; three.js-r73/src/textures/CanvasTexture.js0000644000175500017550000000067312610076566020566 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.CanvasTexture = function ( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { THREE.Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); this.needsUpdate = true; }; THREE.CanvasTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.CanvasTexture.prototype.constructor = THREE.CanvasTexture; three.js-r73/src/textures/CubeTexture.js0000644000175500017550000000126212610076566020224 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { mapping = mapping !== undefined ? mapping : THREE.CubeReflectionMapping; THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); this.images = images; this.flipY = false; }; THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.CubeTexture.prototype.constructor = THREE.CubeTexture; THREE.CubeTexture.prototype.copy = function ( source ) { THREE.Texture.prototype.copy.call( this, source ); this.images = source.images; return this; };three.js-r73/src/textures/VideoTexture.js0000644000175500017550000000116312610076566020414 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { THREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); this.generateMipmaps = false; var scope = this; function update() { requestAnimationFrame( update ); if ( video.readyState === video.HAVE_ENOUGH_DATA ) { scope.needsUpdate = true; } } update(); }; THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.VideoTexture.prototype.constructor = THREE.VideoTexture; three.js-r73/src/textures/CompressedTexture.js0000644000175500017550000000137712610076566021461 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); this.image = { width: width, height: height }; this.mipmaps = mipmaps; // no flipping for cube textures // (also flipping doesn't work for compressed textures ) this.flipY = false; // can't generate mipmaps for compressed textures // mips must be embedded in DDS files this.generateMipmaps = false; }; THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.CompressedTexture.prototype.constructor = THREE.CompressedTexture; three.js-r73/src/objects/0000755000175500017550000000000012610076566015174 5ustar debacledebaclethree.js-r73/src/objects/Line.js0000644000175500017550000001126512610076566016426 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Line = function ( geometry, material, mode ) { if ( mode === 1 ) { console.warn( 'THREE.Line: parameter THREE.LinePieces no longer supported. Created THREE.LineSegments instead.' ); return new THREE.LineSegments( geometry, material ); } THREE.Object3D.call( this ); this.type = 'Line'; this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); }; THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); THREE.Line.prototype.constructor = THREE.Line; THREE.Line.prototype.raycast = ( function () { var inverseMatrix = new THREE.Matrix4(); var ray = new THREE.Ray(); var sphere = new THREE.Sphere(); return function raycast( raycaster, intersects ) { var precision = raycaster.linePrecision; var precisionSq = precision * precision; var geometry = this.geometry; if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); // Checking boundingSphere distance to ray sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( this.matrixWorld ); if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { return; } inverseMatrix.getInverse( this.matrixWorld ); ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); var vStart = new THREE.Vector3(); var vEnd = new THREE.Vector3(); var interSegment = new THREE.Vector3(); var interRay = new THREE.Vector3(); var step = this instanceof THREE.LineSegments ? 2 : 1; if ( geometry instanceof THREE.BufferGeometry ) { var index = geometry.index; var attributes = geometry.attributes; if ( index !== null ) { var indices = index.array; var positions = attributes.position.array; for ( var i = 0, l = indices.length - 1; i < l; i += step ) { var a = indices[ i ]; var b = indices[ i + 1 ]; vStart.fromArray( positions, a * 3 ); vEnd.fromArray( positions, b * 3 ); var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); if ( distSq > precisionSq ) continue; interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation var distance = raycaster.ray.origin.distanceTo( interRay ); if ( distance < raycaster.near || distance > raycaster.far ) continue; intersects.push( { distance: distance, // What do we want? intersection point on the ray or on the segment?? // point: raycaster.ray.at( distance ), point: interSegment.clone().applyMatrix4( this.matrixWorld ), index: i, face: null, faceIndex: null, object: this } ); } } else { var positions = attributes.position.array; for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { vStart.fromArray( positions, 3 * i ); vEnd.fromArray( positions, 3 * i + 3 ); var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); if ( distSq > precisionSq ) continue; interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation var distance = raycaster.ray.origin.distanceTo( interRay ); if ( distance < raycaster.near || distance > raycaster.far ) continue; intersects.push( { distance: distance, // What do we want? intersection point on the ray or on the segment?? // point: raycaster.ray.at( distance ), point: interSegment.clone().applyMatrix4( this.matrixWorld ), index: i, face: null, faceIndex: null, object: this } ); } } } else if ( geometry instanceof THREE.Geometry ) { var vertices = geometry.vertices; var nbVertices = vertices.length; for ( var i = 0; i < nbVertices - 1; i += step ) { var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); if ( distSq > precisionSq ) continue; interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation var distance = raycaster.ray.origin.distanceTo( interRay ); if ( distance < raycaster.near || distance > raycaster.far ) continue; intersects.push( { distance: distance, // What do we want? intersection point on the ray or on the segment?? // point: raycaster.ray.at( distance ), point: interSegment.clone().applyMatrix4( this.matrixWorld ), index: i, face: null, faceIndex: null, object: this } ); } } }; }() ); THREE.Line.prototype.clone = function () { return new this.constructor( this.geometry, this.material ).copy( this ); }; // DEPRECATED THREE.LineStrip = 0; THREE.LinePieces = 1; three.js-r73/src/objects/Bone.js0000644000175500017550000000100512610076566016411 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author ikerr / http://verold.com */ THREE.Bone = function ( skin ) { THREE.Object3D.call( this ); this.type = 'Bone'; this.skin = skin; }; THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); THREE.Bone.prototype.constructor = THREE.Bone; THREE.Bone.prototype.copy = function ( source ) { THREE.Object3D.prototype.copy.call( this, source ); this.skin = source.skin; return this; }; three.js-r73/src/objects/SkinnedMesh.js0000644000175500017550000000600012610076566017736 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author ikerr / http://verold.com */ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { THREE.Mesh.call( this, geometry, material ); this.type = 'SkinnedMesh'; this.bindMode = "attached"; this.bindMatrix = new THREE.Matrix4(); this.bindMatrixInverse = new THREE.Matrix4(); // init bones // TODO: remove bone creation as there is no reason (other than // convenience) for THREE.SkinnedMesh to do this. var bones = []; if ( this.geometry && this.geometry.bones !== undefined ) { var bone, gbone; for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { gbone = this.geometry.bones[ b ]; bone = new THREE.Bone( this ); bones.push( bone ); bone.name = gbone.name; bone.position.fromArray( gbone.pos ); bone.quaternion.fromArray( gbone.rotq ); if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); } for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { gbone = this.geometry.bones[ b ]; if ( gbone.parent !== - 1 && gbone.parent !== null) { bones[ gbone.parent ].add( bones[ b ] ); } else { this.add( bones[ b ] ); } } } this.normalizeSkinWeights(); this.updateMatrixWorld( true ); this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ), this.matrixWorld ); }; THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh; THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) { this.skeleton = skeleton; if ( bindMatrix === undefined ) { this.updateMatrixWorld( true ); this.skeleton.calculateInverses(); bindMatrix = this.matrixWorld; } this.bindMatrix.copy( bindMatrix ); this.bindMatrixInverse.getInverse( bindMatrix ); }; THREE.SkinnedMesh.prototype.pose = function () { this.skeleton.pose(); }; THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { if ( this.geometry instanceof THREE.Geometry ) { for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { var sw = this.geometry.skinWeights[ i ]; var scale = 1.0 / sw.lengthManhattan(); if ( scale !== Infinity ) { sw.multiplyScalar( scale ); } else { sw.set( 1 ); // this will be normalized by the shader anyway } } } else { // skinning weights assumed to be normalized for THREE.BufferGeometry } }; THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) { THREE.Mesh.prototype.updateMatrixWorld.call( this, true ); if ( this.bindMode === "attached" ) { this.bindMatrixInverse.getInverse( this.matrixWorld ); } else if ( this.bindMode === "detached" ) { this.bindMatrixInverse.getInverse( this.bindMatrix ); } else { console.warn( 'THREE.SkinnedMesh unrecognized bindMode: ' + this.bindMode ); } }; THREE.SkinnedMesh.prototype.clone = function() { return new this.constructor( this.geometry, this.material, this.useVertexTexture ).copy( this ); }; three.js-r73/src/objects/Skeleton.js0000644000175500017550000000732712610076566017327 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author michael guerrero / http://realitymeltdown.com * @author ikerr / http://verold.com */ THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) { this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; this.identityMatrix = new THREE.Matrix4(); // copy the bone array bones = bones || []; this.bones = bones.slice( 0 ); // create a bone texture or an array of floats if ( this.useVertexTexture ) { // layout (1 matrix = 4 pixels) // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) var size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix size = THREE.Math.nextPowerOfTwo( Math.ceil( size ) ); size = Math.max( size, 4 ); this.boneTextureWidth = size; this.boneTextureHeight = size; this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); } else { this.boneMatrices = new Float32Array( 16 * this.bones.length ); } // use the supplied bone inverses or calculate the inverses if ( boneInverses === undefined ) { this.calculateInverses(); } else { if ( this.bones.length === boneInverses.length ) { this.boneInverses = boneInverses.slice( 0 ); } else { console.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); this.boneInverses = []; for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { this.boneInverses.push( new THREE.Matrix4() ); } } } }; THREE.Skeleton.prototype.calculateInverses = function () { this.boneInverses = []; for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { var inverse = new THREE.Matrix4(); if ( this.bones[ b ] ) { inverse.getInverse( this.bones[ b ].matrixWorld ); } this.boneInverses.push( inverse ); } }; THREE.Skeleton.prototype.pose = function () { var bone; // recover the bind-time world matrices for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { bone = this.bones[ b ]; if ( bone ) { bone.matrixWorld.getInverse( this.boneInverses[ b ] ); } } // compute the local matrices, positions, rotations and scales for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { bone = this.bones[ b ]; if ( bone ) { if ( bone.parent ) { bone.matrix.getInverse( bone.parent.matrixWorld ); bone.matrix.multiply( bone.matrixWorld ); } else { bone.matrix.copy( bone.matrixWorld ); } bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); } } }; THREE.Skeleton.prototype.update = ( function () { var offsetMatrix = new THREE.Matrix4(); return function update() { // flatten bone matrices to array for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { // compute the offset between the current and the original transform var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix; offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] ); offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); } if ( this.useVertexTexture ) { this.boneTexture.needsUpdate = true; } }; } )(); THREE.Skeleton.prototype.clone = function () { return new THREE.Skeleton( this.bones, this.boneInverses, this.useVertexTexture ); }; three.js-r73/src/objects/LensFlare.js0000644000175500017550000000465212610076566017414 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.LensFlare = function ( texture, size, distance, blending, color ) { THREE.Object3D.call( this ); this.lensFlares = []; this.positionScreen = new THREE.Vector3(); this.customUpdateCallback = undefined; if ( texture !== undefined ) { this.add( texture, size, distance, blending, color ); } }; THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); THREE.LensFlare.prototype.constructor = THREE.LensFlare; /* * Add: adds another flare */ THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { if ( size === undefined ) size = - 1; if ( distance === undefined ) distance = 0; if ( opacity === undefined ) opacity = 1; if ( color === undefined ) color = new THREE.Color( 0xffffff ); if ( blending === undefined ) blending = THREE.NormalBlending; distance = Math.min( distance, Math.max( 0, distance ) ); this.lensFlares.push( { texture: texture, // THREE.Texture size: size, // size in pixels (-1 = use texture.width) distance: distance, // distance (0-1) from light source (0=at light source) x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is in front z = 1 is back scale: 1, // scale rotation: 0, // rotation opacity: opacity, // opacity color: color, // color blending: blending // blending } ); }; /* * Update lens flares update positions on all flares based on the screen position * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. */ THREE.LensFlare.prototype.updateLensFlares = function () { var f, fl = this.lensFlares.length; var flare; var vecX = - this.positionScreen.x * 2; var vecY = - this.positionScreen.y * 2; for ( f = 0; f < fl; f ++ ) { flare = this.lensFlares[ f ]; flare.x = this.positionScreen.x + vecX * flare.distance; flare.y = this.positionScreen.y + vecY * flare.distance; flare.wantedRotation = flare.x * Math.PI * 0.25; flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; } }; THREE.LensFlare.prototype.copy = function ( source ) { THREE.Object3D.prototype.copy.call( this, source ); this.positionScreen.copy( source.positionScreen ); this.customUpdateCallback = source.customUpdateCallback; for ( var i = 0, l = source.lensFlares.length; i < l; i ++ ) { this.lensFlares.push( source.lensFlares[ i ] ); } return this; }; three.js-r73/src/objects/Mesh.js0000644000175500017550000001713212610076566016432 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author jonobr1 / http://jonobr1.com/ */ THREE.Mesh = function ( geometry, material ) { THREE.Object3D.call( this ); this.type = 'Mesh'; this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); this.updateMorphTargets(); }; THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); THREE.Mesh.prototype.constructor = THREE.Mesh; THREE.Mesh.prototype.updateMorphTargets = function () { if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { this.morphTargetBase = - 1; this.morphTargetInfluences = []; this.morphTargetDictionary = {}; for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { this.morphTargetInfluences.push( 0 ); this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; } } }; THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { if ( this.morphTargetDictionary[ name ] !== undefined ) { return this.morphTargetDictionary[ name ]; } console.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); return 0; }; THREE.Mesh.prototype.raycast = ( function () { var inverseMatrix = new THREE.Matrix4(); var ray = new THREE.Ray(); var sphere = new THREE.Sphere(); var vA = new THREE.Vector3(); var vB = new THREE.Vector3(); var vC = new THREE.Vector3(); var tempA = new THREE.Vector3(); var tempB = new THREE.Vector3(); var tempC = new THREE.Vector3(); var uvA = new THREE.Vector2(); var uvB = new THREE.Vector2(); var uvC = new THREE.Vector2(); var barycoord = new THREE.Vector3(); var intersectionPoint = new THREE.Vector3(); var intersectionPointWorld = new THREE.Vector3(); function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) { THREE.Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord ); uv1.multiplyScalar( barycoord.x ); uv2.multiplyScalar( barycoord.y ); uv3.multiplyScalar( barycoord.z ); uv1.add( uv2 ).add( uv3 ); return uv1.clone(); } function checkIntersection( object, raycaster, ray, pA, pB, pC, point ){ var intersect; var material = object.material; if ( material.side === THREE.BackSide ) { intersect = ray.intersectTriangle( pC, pB, pA, true, point ); } else { intersect = ray.intersectTriangle( pA, pB, pC, material.side !== THREE.DoubleSide, point ); } if ( intersect === null ) return null; intersectionPointWorld.copy( point ); intersectionPointWorld.applyMatrix4( object.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); if ( distance < raycaster.near || distance > raycaster.far ) return null; return { distance: distance, point: intersectionPointWorld.clone(), object: object }; } function checkBufferGeometryIntersection( object, raycaster, ray, positions, uvs, a, b, c ) { vA.fromArray( positions, a * 3 ); vB.fromArray( positions, b * 3 ); vC.fromArray( positions, c * 3 ); var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint ); if ( intersection ) { if ( uvs ) { uvA.fromArray( uvs, a * 2 ); uvB.fromArray( uvs, b * 2 ); uvC.fromArray( uvs, c * 2 ); intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC ); } intersection.face = new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ); intersection.faceIndex = a; } return intersection; } return function raycast( raycaster, intersects ) { var geometry = this.geometry; var material = this.material; if ( material === undefined ) return; // Checking boundingSphere distance to ray if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); var matrixWorld = this.matrixWorld; sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( matrixWorld ); if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) return; // Check boundingBox before continuing inverseMatrix.getInverse( matrixWorld ); ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); if ( geometry.boundingBox !== null ) { if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) return; } var uvs, intersection; if ( geometry instanceof THREE.BufferGeometry ) { var a, b, c; var index = geometry.index; var attributes = geometry.attributes; var positions = attributes.position.array; if ( attributes.uv !== undefined ){ uvs = attributes.uv.array; } if ( index !== null ) { var indices = index.array; for ( var i = 0, l = indices.length; i < l; i += 3 ) { a = indices[ i ]; b = indices[ i + 1 ]; c = indices[ i + 2 ]; intersection = checkBufferGeometryIntersection( this, raycaster, ray, positions, uvs, a, b, c ); if ( intersection ) { intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics intersects.push( intersection ); } } } else { for ( var i = 0, l = positions.length; i < l; i += 9 ) { a = i / 3; b = a + 1; c = a + 2; intersection = checkBufferGeometryIntersection( this, raycaster, ray, positions, uvs, a, b, c ); if ( intersection ) { intersection.index = a; // triangle number in positions buffer semantics intersects.push( intersection ); } } } } else if ( geometry instanceof THREE.Geometry ) { var fvA, fvB, fvC; var isFaceMaterial = material instanceof THREE.MeshFaceMaterial; var materials = isFaceMaterial === true ? material.materials : null; var vertices = geometry.vertices; var faces = geometry.faces; var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; for ( var f = 0, fl = faces.length; f < fl; f ++ ) { var face = faces[ f ]; var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material; if ( faceMaterial === undefined ) continue; fvA = vertices[ face.a ]; fvB = vertices[ face.b ]; fvC = vertices[ face.c ]; if ( faceMaterial.morphTargets === true ) { var morphTargets = geometry.morphTargets; var morphInfluences = this.morphTargetInfluences; vA.set( 0, 0, 0 ); vB.set( 0, 0, 0 ); vC.set( 0, 0, 0 ); for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { var influence = morphInfluences[ t ]; if ( influence === 0 ) continue; var targets = morphTargets[ t ].vertices; vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence ); vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence ); vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence ); } vA.add( fvA ); vB.add( fvB ); vC.add( fvC ); fvA = vA; fvB = vB; fvC = vC; } intersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); if ( intersection ) { if ( uvs ) { var uvs_f = uvs[ f ]; uvA.copy( uvs_f[ 0 ] ); uvB.copy( uvs_f[ 1 ] ); uvC.copy( uvs_f[ 2 ] ); intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC ); } intersection.face = face; intersection.faceIndex = f; intersects.push( intersection ); } } } }; }() ); THREE.Mesh.prototype.clone = function () { return new this.constructor( this.geometry, this.material ).copy( this ); }; three.js-r73/src/objects/Sprite.js0000644000175500017550000000316612610076566017006 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.Sprite = ( function () { var indices = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ); var vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0, - 0.5, 0.5, 0 ] ); var uvs = new Float32Array( [ 0, 0, 1, 0, 1, 1, 0, 1 ] ); var geometry = new THREE.BufferGeometry(); geometry.setIndex( new THREE.BufferAttribute( indices, 1 ) ); geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); return function Sprite( material ) { THREE.Object3D.call( this ); this.type = 'Sprite'; this.geometry = geometry; this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); }; } )(); THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); THREE.Sprite.prototype.constructor = THREE.Sprite; THREE.Sprite.prototype.raycast = ( function () { var matrixPosition = new THREE.Vector3(); return function raycast( raycaster, intersects ) { matrixPosition.setFromMatrixPosition( this.matrixWorld ); var distanceSq = raycaster.ray.distanceSqToPoint( matrixPosition ); var guessSizeSq = this.scale.x * this.scale.y; if ( distanceSq > guessSizeSq ) { return; } intersects.push( { distance: Math.sqrt( distanceSq ), point: this.position, face: null, object: this } ); }; }() ); THREE.Sprite.prototype.clone = function () { return new this.constructor( this.material ).copy( this ); }; // Backwards compatibility THREE.Particle = THREE.Sprite; three.js-r73/src/objects/LOD.js0000644000175500017550000000556612610076566016164 0ustar debacledebacle/** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.LOD = function () { THREE.Object3D.call( this ); this.type = 'LOD'; Object.defineProperties( this, { levels: { enumerable: true, value: [] }, objects: { get: function () { console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); return this.levels; } } } ); }; THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); THREE.LOD.prototype.constructor = THREE.LOD; THREE.LOD.prototype.addLevel = function ( object, distance ) { if ( distance === undefined ) distance = 0; distance = Math.abs( distance ); var levels = this.levels; for ( var l = 0; l < levels.length; l ++ ) { if ( distance < levels[ l ].distance ) { break; } } levels.splice( l, 0, { distance: distance, object: object } ); this.add( object ); }; THREE.LOD.prototype.getObjectForDistance = function ( distance ) { var levels = this.levels; for ( var i = 1, l = levels.length; i < l; i ++ ) { if ( distance < levels[ i ].distance ) { break; } } return levels[ i - 1 ].object; }; THREE.LOD.prototype.raycast = ( function () { var matrixPosition = new THREE.Vector3(); return function raycast( raycaster, intersects ) { matrixPosition.setFromMatrixPosition( this.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( matrixPosition ); this.getObjectForDistance( distance ).raycast( raycaster, intersects ); }; }() ); THREE.LOD.prototype.update = function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); return function update( camera ) { var levels = this.levels; if ( levels.length > 1 ) { v1.setFromMatrixPosition( camera.matrixWorld ); v2.setFromMatrixPosition( this.matrixWorld ); var distance = v1.distanceTo( v2 ); levels[ 0 ].object.visible = true; for ( var i = 1, l = levels.length; i < l; i ++ ) { if ( distance >= levels[ i ].distance ) { levels[ i - 1 ].object.visible = false; levels[ i ].object.visible = true; } else { break; } } for ( ; i < l; i ++ ) { levels[ i ].object.visible = false; } } }; }(); THREE.LOD.prototype.copy = function ( source ) { THREE.Object3D.prototype.copy.call( this, source, false ); var levels = source.levels; for ( var i = 0, l = levels.length; i < l; i ++ ) { var level = levels[ i ]; this.addLevel( level.object.clone(), level.distance ); } return this; }; THREE.LOD.prototype.toJSON = function ( meta ) { var data = THREE.Object3D.prototype.toJSON.call( this, meta ); data.object.levels = []; var levels = this.levels; for ( var i = 0, l = levels.length; i < l; i ++ ) { var level = levels[ i ]; data.object.levels.push( { object: level.object.uuid, distance: level.distance } ); } return data; }; three.js-r73/src/objects/LineSegments.js0000644000175500017550000000047612610076566020136 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.LineSegments = function ( geometry, material ) { THREE.Line.call( this, geometry, material ); this.type = 'LineSegments'; }; THREE.LineSegments.prototype = Object.create( THREE.Line.prototype ); THREE.LineSegments.prototype.constructor = THREE.LineSegments; three.js-r73/src/objects/Points.js0000644000175500017550000000601012610076566017003 0ustar debacledebacle/** * @author alteredq / http://alteredqualia.com/ */ THREE.Points = function ( geometry, material ) { THREE.Object3D.call( this ); this.type = 'Points'; this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.PointsMaterial( { color: Math.random() * 0xffffff } ); }; THREE.Points.prototype = Object.create( THREE.Object3D.prototype ); THREE.Points.prototype.constructor = THREE.Points; THREE.Points.prototype.raycast = ( function () { var inverseMatrix = new THREE.Matrix4(); var ray = new THREE.Ray(); return function raycast( raycaster, intersects ) { var object = this; var geometry = object.geometry; var threshold = raycaster.params.Points.threshold; inverseMatrix.getInverse( this.matrixWorld ); ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); if ( geometry.boundingBox !== null ) { if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { return; } } var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); var localThresholdSq = localThreshold * localThreshold; var position = new THREE.Vector3(); function testPoint( point, index ) { var rayPointDistanceSq = ray.distanceSqToPoint( point ); if ( rayPointDistanceSq < localThresholdSq ) { var intersectPoint = ray.closestPointToPoint( point ); intersectPoint.applyMatrix4( object.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( intersectPoint ); if ( distance < raycaster.near || distance > raycaster.far ) return; intersects.push( { distance: distance, distanceToRay: Math.sqrt( rayPointDistanceSq ), point: intersectPoint.clone(), index: index, face: null, object: object } ); } } if ( geometry instanceof THREE.BufferGeometry ) { var index = geometry.index; var attributes = geometry.attributes; var positions = attributes.position.array; if ( index !== null ) { var indices = index.array; for ( var i = 0, il = indices.length; i < il; i ++ ) { var a = indices[ i ]; position.fromArray( positions, a * 3 ); testPoint( position, a ); } } else { for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { position.fromArray( positions, i * 3 ); testPoint( position, i ); } } } else { var vertices = geometry.vertices; for ( var i = 0, l = vertices.length; i < l; i ++ ) { testPoint( vertices[ i ], i ); } } }; }() ); THREE.Points.prototype.clone = function () { return new this.constructor( this.geometry, this.material ).copy( this ); }; // Backwards compatibility THREE.PointCloud = function ( geometry, material ) { console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); return new THREE.Points( geometry, material ); }; THREE.ParticleSystem = function ( geometry, material ) { console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); return new THREE.Points( geometry, material ); }; three.js-r73/src/objects/Group.js0000644000175500017550000000037212610076566016630 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ THREE.Group = function () { THREE.Object3D.call( this ); this.type = 'Group'; }; THREE.Group.prototype = Object.create( THREE.Object3D.prototype ); THREE.Group.prototype.constructor = THREE.Group;three.js-r73/src/Three.js0000644000175500017550000001561712610076566015162 0ustar debacledebacle/** * @author mrdoob / http://mrdoob.com/ */ var THREE = { REVISION: '73' }; // if ( typeof define === 'function' && define.amd ) { define( 'three', THREE ); } else if ( 'undefined' !== typeof exports && 'undefined' !== typeof module ) { module.exports = THREE; } // polyfills if ( self.requestAnimationFrame === undefined || self.cancelAnimationFrame === undefined ) { // Missing in Android stock browser. ( function () { var lastTime = 0; var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; for ( var x = 0; x < vendors.length && ! self.requestAnimationFrame; ++ x ) { self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; } if ( self.requestAnimationFrame === undefined && self.setTimeout !== undefined ) { self.requestAnimationFrame = function ( callback ) { var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); var id = self.setTimeout( function () { callback( currTime + timeToCall ); }, timeToCall ); lastTime = currTime + timeToCall; return id; }; } if ( self.cancelAnimationFrame === undefined && self.clearTimeout !== undefined ) { self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ); }; } } )(); } // if ( self.performance === undefined ) { self.performance = {}; } if ( self.performance.now === undefined ) { ( function () { var start = Date.now(); self.performance.now = function () { return Date.now() - start; } } )(); } // if ( Number.EPSILON === undefined ) { Number.EPSILON = Math.pow( 2, -52 ); } // if ( Math.sign === undefined ) { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign Math.sign = function ( x ) { return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x; }; } if ( Function.prototype.name === undefined && Object.defineProperty !== undefined ) { // Missing in IE9-11. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name Object.defineProperty( Function.prototype, 'name', { get: function () { return this.toString().match( /^\s*function\s*(\S*)\s*\(/ )[ 1 ]; } } ); } // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; // GL STATE CONSTANTS THREE.CullFaceNone = 0; THREE.CullFaceBack = 1; THREE.CullFaceFront = 2; THREE.CullFaceFrontBack = 3; THREE.FrontFaceDirectionCW = 0; THREE.FrontFaceDirectionCCW = 1; // SHADOWING TYPES THREE.BasicShadowMap = 0; THREE.PCFShadowMap = 1; THREE.PCFSoftShadowMap = 2; // MATERIAL CONSTANTS // side THREE.FrontSide = 0; THREE.BackSide = 1; THREE.DoubleSide = 2; // shading THREE.FlatShading = 1; THREE.SmoothShading = 2; // colors THREE.NoColors = 0; THREE.FaceColors = 1; THREE.VertexColors = 2; // blending modes THREE.NoBlending = 0; THREE.NormalBlending = 1; THREE.AdditiveBlending = 2; THREE.SubtractiveBlending = 3; THREE.MultiplyBlending = 4; THREE.CustomBlending = 5; // custom blending equations // (numbers start from 100 not to clash with other // mappings to OpenGL constants defined in Texture.js) THREE.AddEquation = 100; THREE.SubtractEquation = 101; THREE.ReverseSubtractEquation = 102; THREE.MinEquation = 103; THREE.MaxEquation = 104; // custom blending destination factors THREE.ZeroFactor = 200; THREE.OneFactor = 201; THREE.SrcColorFactor = 202; THREE.OneMinusSrcColorFactor = 203; THREE.SrcAlphaFactor = 204; THREE.OneMinusSrcAlphaFactor = 205; THREE.DstAlphaFactor = 206; THREE.OneMinusDstAlphaFactor = 207; // custom blending source factors //THREE.ZeroFactor = 200; //THREE.OneFactor = 201; //THREE.SrcAlphaFactor = 204; //THREE.OneMinusSrcAlphaFactor = 205; //THREE.DstAlphaFactor = 206; //THREE.OneMinusDstAlphaFactor = 207; THREE.DstColorFactor = 208; THREE.OneMinusDstColorFactor = 209; THREE.SrcAlphaSaturateFactor = 210; // depth modes THREE.NeverDepth = 0; THREE.AlwaysDepth = 1; THREE.LessDepth = 2; THREE.LessEqualDepth = 3; THREE.EqualDepth = 4; THREE.GreaterEqualDepth = 5; THREE.GreaterDepth = 6; THREE.NotEqualDepth = 7; // TEXTURE CONSTANTS THREE.MultiplyOperation = 0; THREE.MixOperation = 1; THREE.AddOperation = 2; // Mapping modes THREE.UVMapping = 300; THREE.CubeReflectionMapping = 301; THREE.CubeRefractionMapping = 302; THREE.EquirectangularReflectionMapping = 303; THREE.EquirectangularRefractionMapping = 304; THREE.SphericalReflectionMapping = 305; // Wrapping modes THREE.RepeatWrapping = 1000; THREE.ClampToEdgeWrapping = 1001; THREE.MirroredRepeatWrapping = 1002; // Filters THREE.NearestFilter = 1003; THREE.NearestMipMapNearestFilter = 1004; THREE.NearestMipMapLinearFilter = 1005; THREE.LinearFilter = 1006; THREE.LinearMipMapNearestFilter = 1007; THREE.LinearMipMapLinearFilter = 1008; // Data types THREE.UnsignedByteType = 1009; THREE.ByteType = 1010; THREE.ShortType = 1011; THREE.UnsignedShortType = 1012; THREE.IntType = 1013; THREE.UnsignedIntType = 1014; THREE.FloatType = 1015; THREE.HalfFloatType = 1025; // Pixel types //THREE.UnsignedByteType = 1009; THREE.UnsignedShort4444Type = 1016; THREE.UnsignedShort5551Type = 1017; THREE.UnsignedShort565Type = 1018; // Pixel formats THREE.AlphaFormat = 1019; THREE.RGBFormat = 1020; THREE.RGBAFormat = 1021; THREE.LuminanceFormat = 1022; THREE.LuminanceAlphaFormat = 1023; // THREE.RGBEFormat handled as THREE.RGBAFormat in shaders THREE.RGBEFormat = THREE.RGBAFormat; //1024; // DDS / ST3C Compressed texture formats THREE.RGB_S3TC_DXT1_Format = 2001; THREE.RGBA_S3TC_DXT1_Format = 2002; THREE.RGBA_S3TC_DXT3_Format = 2003; THREE.RGBA_S3TC_DXT5_Format = 2004; // PVRTC compressed texture formats THREE.RGB_PVRTC_4BPPV1_Format = 2100; THREE.RGB_PVRTC_2BPPV1_Format = 2101; THREE.RGBA_PVRTC_4BPPV1_Format = 2102; THREE.RGBA_PVRTC_2BPPV1_Format = 2103; // Loop styles for AnimationAction THREE.LoopOnce = 2200; THREE.LoopRepeat = 2201; THREE.LoopPingPong = 2202; // DEPRECATED THREE.Projector = function () { console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); this.projectVector = function ( vector, camera ) { console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); vector.project( camera ); }; this.unprojectVector = function ( vector, camera ) { console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); vector.unproject( camera ); }; this.pickingRay = function ( vector, camera ) { console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); }; }; THREE.CanvasRenderer = function () { console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); this.domElement = document.createElement( 'canvas' ); this.clear = function () {}; this.render = function () {}; this.setClearColor = function () {}; this.setSize = function () {}; }; three.js-r73/CONTRIBUTING.md0000644000175500017550000000240212610076566015203 0ustar debacledebacle### The issues section is for bug reports and feature requests only. If you need help, please use [stackoverflow](http://stackoverflow.com/questions/tagged/three.js). Before reporting a bug --- 1. Search issue tracker for similar issues. 2. Try the latest dev branch version of three.js. 3. Refer to the [Migration Guide](https://github.com/mrdoob/three.js/wiki/Migration) when upgrading to the dev version. How to report a bug --- 1. Specify the revision number of the three.js library where the bug occurred. 2. Specify your browser version, operating system, and graphics card. (for example, Chrome 23.0.1271.95, Windows 7, Nvidia Quadro 2000M) 3. Describe the problem in detail. Explain what happened, and what you expected would happen. 4. Provide a small test-case (http://jsfiddle.net). If a test-case is not possible, provide a link to a live version of your application. 5. If helpful, include a screenshot. Annotate the screenshot for clarity. How to contribute to three.js --- 1. Make sure you have a GitHub account. 2. Fork the repository on GitHub. 3. Check the [Contribution Guidelines](https://github.com/mrdoob/three.js/wiki/How-to-contribute-to-three.js). 4. Make changes to your clone of the repository. 5. Submit a pull request.