diff --git a/dist/xrfragment.three.js b/dist/xrfragment.three.js new file mode 100644 index 0000000..744f5ba --- /dev/null +++ b/dist/xrfragment.three.js @@ -0,0 +1,637 @@ +var $hx_exports = typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this; +(function ($global) { "use strict"; +$hx_exports["xrfragment"] = $hx_exports["xrfragment"] || {}; +var EReg = function(r,opt) { + this.r = new RegExp(r,opt.split("u").join("")); +}; +EReg.__name__ = true; +EReg.prototype = { + match: function(s) { + if(this.r.global) { + this.r.lastIndex = 0; + } + this.r.m = this.r.exec(s); + this.r.s = s; + return this.r.m != null; + } + ,split: function(s) { + var d = "#__delim__#"; + return s.replace(this.r,d).split(d); + } +}; +var HxOverrides = function() { }; +HxOverrides.__name__ = true; +HxOverrides.cca = function(s,index) { + var x = s.charCodeAt(index); + if(x != x) { + return undefined; + } + return x; +}; +HxOverrides.substr = function(s,pos,len) { + if(len == null) { + len = s.length; + } else if(len < 0) { + if(pos == 0) { + len = s.length + len; + } else { + return ""; + } + } + return s.substr(pos,len); +}; +HxOverrides.now = function() { + return Date.now(); +}; +Math.__name__ = true; +var Reflect = function() { }; +Reflect.__name__ = true; +Reflect.field = function(o,field) { + try { + return o[field]; + } catch( _g ) { + return null; + } +}; +Reflect.fields = function(o) { + var a = []; + if(o != null) { + var hasOwnProperty = Object.prototype.hasOwnProperty; + for( var f in o ) { + if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) { + a.push(f); + } + } + } + return a; +}; +Reflect.deleteField = function(o,field) { + if(!Object.prototype.hasOwnProperty.call(o,field)) { + return false; + } + delete(o[field]); + return true; +}; +var Std = function() { }; +Std.__name__ = true; +Std.string = function(s) { + return js_Boot.__string_rec(s,""); +}; +Std.parseInt = function(x) { + if(x != null) { + var _g = 0; + var _g1 = x.length; + while(_g < _g1) { + var i = _g++; + var c = x.charCodeAt(i); + if(c <= 8 || c >= 14 && c != 32 && c != 45) { + var nc = x.charCodeAt(i + 1); + var v = parseInt(x,nc == 120 || nc == 88 ? 16 : 10); + if(isNaN(v)) { + return null; + } else { + return v; + } + } + } + } + return null; +}; +var StringTools = function() { }; +StringTools.__name__ = true; +StringTools.isSpace = function(s,pos) { + var c = HxOverrides.cca(s,pos); + if(!(c > 8 && c < 14)) { + return c == 32; + } else { + return true; + } +}; +StringTools.ltrim = function(s) { + var l = s.length; + var r = 0; + while(r < l && StringTools.isSpace(s,r)) ++r; + if(r > 0) { + return HxOverrides.substr(s,r,l - r); + } else { + return s; + } +}; +StringTools.rtrim = function(s) { + var l = s.length; + var r = 0; + while(r < l && StringTools.isSpace(s,l - r - 1)) ++r; + if(r > 0) { + return HxOverrides.substr(s,0,l - r); + } else { + return s; + } +}; +StringTools.trim = function(s) { + return StringTools.ltrim(StringTools.rtrim(s)); +}; +StringTools.replace = function(s,sub,by) { + return s.split(sub).join(by); +}; +var haxe_iterators_ArrayIterator = function(array) { + this.current = 0; + this.array = array; +}; +haxe_iterators_ArrayIterator.__name__ = true; +haxe_iterators_ArrayIterator.prototype = { + hasNext: function() { + return this.current < this.array.length; + } + ,next: function() { + return this.array[this.current++]; + } +}; +var js_Boot = function() { }; +js_Boot.__name__ = true; +js_Boot.__string_rec = function(o,s) { + if(o == null) { + return "null"; + } + if(s.length >= 5) { + return "<...>"; + } + var t = typeof(o); + if(t == "function" && (o.__name__ || o.__ename__)) { + t = "object"; + } + switch(t) { + case "function": + return ""; + case "object": + if(((o) instanceof Array)) { + var str = "["; + s += "\t"; + var _g = 0; + var _g1 = o.length; + while(_g < _g1) { + var i = _g++; + str += (i > 0 ? "," : "") + js_Boot.__string_rec(o[i],s); + } + str += "]"; + return str; + } + var tostr; + try { + tostr = o.toString; + } catch( _g ) { + return "???"; + } + if(tostr != null && tostr != Object.toString && typeof(tostr) == "function") { + var s2 = o.toString(); + if(s2 != "[object Object]") { + return s2; + } + } + var str = "{\n"; + s += "\t"; + var hasp = o.hasOwnProperty != null; + var k = null; + for( k in o ) { + if(hasp && !o.hasOwnProperty(k)) { + continue; + } + if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") { + continue; + } + if(str.length != 2) { + str += ", \n"; + } + str += s + k + " : " + js_Boot.__string_rec(o[k],s); + } + s = s.substring(1); + str += "\n" + s + "}"; + return str; + case "string": + return o; + default: + return String(o); + } +}; +var xrfragment_Parser = $hx_exports["xrfragment"]["Parser"] = function() { }; +xrfragment_Parser.__name__ = true; +xrfragment_Parser.parse = function(key,value,resultMap) { + var Frag_h = Object.create(null); + Frag_h["prio"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_INT; + Frag_h["#"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW; + Frag_h["class"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING; + Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL; + Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW; + Frag_h["q"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["scale"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["rot"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["translate"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["visible"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_INT | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["env"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["t"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.BROWSER_OVERRIDE | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["gravity"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["physics"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["fov"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_INT | xrfragment_XRF.BROWSER_OVERRIDE | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["clip"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.BROWSER_OVERRIDE | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["fog"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.BROWSER_OVERRIDE | xrfragment_XRF.EMBED_OVERRIDE; + Frag_h["namespace"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING; + Frag_h["SPDX"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING; + Frag_h["unit"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING; + Frag_h["description"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING; + Frag_h["session"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.BROWSER_OVERRIDE | xrfragment_XRF.EMBED_OVERRIDE | xrfragment_XRF.PROMPT; + if(value.length == 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key)) { + resultMap[key] = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.BROWSER_OVERRIDE); + return true; + } + if(key.split(".").length > 1 && value.split(".").length > 1) { + resultMap[key] = new xrfragment_XRF(key,xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.PROP_BIND); + return true; + } + if(Object.prototype.hasOwnProperty.call(Frag_h,key)) { + var v = new xrfragment_XRF(key,Frag_h[key]); + if(!v.validate(value)) { + console.log("src/xrfragment/Parser.hx:75:","⚠ fragment '" + key + "' has incompatible value (" + value + ")"); + return false; + } + if(xrfragment_Parser.debug) { + console.log("src/xrfragment/Parser.hx:78:","✔ XR Fragment '" + key + "': '" + v.string + "'"); + } + resultMap[key] = v; + } + return true; +}; +var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { + this.isNumber = new EReg("^[0-9\\.]+$",""); + this.isClass = new EReg("^[-]?class$",""); + this.isExclude = new EReg("^-",""); + this.isProp = new EReg("^.*:[><=!]?",""); + this.q = { }; + this.str = ""; + if(str != null) { + this.parse(str); + } +}; +xrfragment_Query.__name__ = true; +xrfragment_Query.prototype = { + toObject: function() { + return this.q; + } + ,expandAliases: function(token) { + var classAlias = new EReg("^(-)?\\.",""); + if(classAlias.match(token)) { + return StringTools.replace(token,".","class:"); + } else { + return token; + } + } + ,get: function() { + return this.q; + } + ,parse: function(str,recurse) { + if(recurse == null) { + recurse = false; + } + var _gthis = this; + var token = str.split(" "); + var q = { }; + var process = function(str,prefix) { + if(prefix == null) { + prefix = ""; + } + str = StringTools.trim(str); + var k = str.split(":")[0]; + var v = str.split(":")[1]; + var filter = { }; + if(q[prefix + k]) { + filter = q[prefix + k]; + } + filter["rules"] = filter["rules"] != null ? filter["rules"] : []; + if(_gthis.isProp.match(str)) { + var oper = ""; + if(str.indexOf("*") != -1) { + oper = "*"; + } + if(str.indexOf(">") != -1) { + oper = ">"; + } + if(str.indexOf("<") != -1) { + oper = "<"; + } + if(str.indexOf(">=") != -1) { + oper = ">="; + } + if(str.indexOf("<=") != -1) { + oper = "<="; + } + if(_gthis.isExclude.match(k)) { + oper = "!="; + k = HxOverrides.substr(k,1,null); + } else { + v = HxOverrides.substr(v,oper.length,null); + } + if(oper.length == 0) { + oper = "="; + } + if(_gthis.isClass.match(k)) { + filter[prefix + k] = oper != "!="; + q[v] = filter; + } else { + var rule = { }; + if(_gthis.isNumber.match(v)) { + rule[oper] = parseFloat(v); + } else { + rule[oper] = v; + } + filter["rules"].push(rule); + q[k] = filter; + } + return; + } else { + filter["id"] = _gthis.isExclude.match(str) ? false : true; + var key = _gthis.isExclude.match(str) ? HxOverrides.substr(str,1,null) : str; + q[key] = filter; + } + }; + var _g = 0; + var _g1 = token.length; + while(_g < _g1) { + var i = _g++; + process(this.expandAliases(token[i])); + } + return this.q = q; + } + ,test: function(obj) { + var qualify = false; + var _g = 0; + var _g1 = Reflect.fields(obj); + while(_g < _g1.length) { + var k = _g1[_g]; + ++_g; + var v = Std.string(Reflect.field(obj,k)); + if(this.testProperty(k,v)) { + qualify = true; + } + } + var _g = 0; + var _g1 = Reflect.fields(obj); + while(_g < _g1.length) { + var k = _g1[_g]; + ++_g; + var v = Std.string(Reflect.field(obj,k)); + if(this.testProperty(k,v,true)) { + qualify = false; + } + } + return qualify; + } + ,testProperty: function(property,value,exclude) { + var conds = 0; + var fails = 0; + var qualify = 0; + var testprop = function(expr) { + conds += 1; + fails += expr ? 0 : 1; + return expr; + }; + if(this.q[value] != null) { + var v = this.q[value]; + if(v[property] != null) { + return v[property]; + } + } + var _g = 0; + var _g1 = Reflect.fields(this.q); + while(_g < _g1.length) { + var k = _g1[_g]; + ++_g; + var filter = Reflect.field(this.q,k); + if(filter.rules == null) { + continue; + } + var rules = filter.rules; + var _g2 = 0; + while(_g2 < rules.length) { + var rule = rules[_g2]; + ++_g2; + if(exclude) { + if(Reflect.field(rule,"!=") != null && testprop((value == null ? "null" : "" + value) == Std.string(Reflect.field(rule,"!="))) && exclude) { + ++qualify; + } + } else { + if(Reflect.field(rule,"*") != null && testprop(parseFloat(value) != null)) { + ++qualify; + } + if(Reflect.field(rule,">") != null && testprop(parseFloat(value) > parseFloat(Reflect.field(rule,">")))) { + ++qualify; + } + if(Reflect.field(rule,"<") != null && testprop(parseFloat(value) < parseFloat(Reflect.field(rule,"<")))) { + ++qualify; + } + if(Reflect.field(rule,">=") != null && testprop(parseFloat(value) >= parseFloat(Reflect.field(rule,">=")))) { + ++qualify; + } + if(Reflect.field(rule,"<=") != null && testprop(parseFloat(value) <= parseFloat(Reflect.field(rule,"<=")))) { + ++qualify; + } + if(Reflect.field(rule,"=") != null && (testprop(value == Reflect.field(rule,"=")) || testprop(parseFloat(value) == parseFloat(Reflect.field(rule,"="))))) { + ++qualify; + } + } + } + } + return qualify > 0; + } +}; +var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { }; +xrfragment_URI.__name__ = true; +xrfragment_URI.parse = function(url,filter) { + var store = { }; + if(url.indexOf("#") == -1) { + return store; + } + var fragment = url.split("#"); + var splitArray = fragment[1].split("&"); + var _g = 0; + var _g1 = splitArray.length; + while(_g < _g1) { + var i = _g++; + var splitByEqual = splitArray[i].split("="); + var regexPlus = new EReg("\\+","g"); + var key = splitByEqual[0]; + var value = ""; + if(splitByEqual.length > 1) { + var s = regexPlus.split(splitByEqual[1]).join(" "); + value = decodeURIComponent(s.split("+").join(" ")); + } + var ok = xrfragment_Parser.parse(key,value,store); + } + if(filter != null && filter != 0) { + var _g = 0; + var _g1 = Reflect.fields(store); + while(_g < _g1.length) { + var key = _g1[_g]; + ++_g; + var xrf = store[key]; + if(!xrf.is(filter)) { + Reflect.deleteField(store,key); + } + } + } + return store; +}; +var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags) { + this.fragment = _fragment; + this.flags = _flags; +}; +xrfragment_XRF.__name__ = true; +xrfragment_XRF.set = function(flag,flags) { + return flags | flag; +}; +xrfragment_XRF.unset = function(flag,flags) { + return flags & ~flag; +}; +xrfragment_XRF.prototype = { + is: function(flag) { + return (this.flags & flag) != 0; + } + ,validate: function(value) { + this.guessType(this,value); + if(value.split("|").length > 1) { + this.args = []; + var args = value.split("|"); + var _g = 0; + var _g1 = args.length; + while(_g < _g1) { + var i = _g++; + var x = new xrfragment_XRF(this.fragment,this.flags); + this.guessType(x,args[i]); + this.args.push(x); + } + } + if(this.fragment == "q") { + this.query = new xrfragment_Query(value).get(); + } + var ok = true; + if(!((this.args) instanceof Array)) { + if(this.is(xrfragment_XRF.T_VECTOR3) && !(typeof(this.x) == "number" && typeof(this.y) == "number" && typeof(this.z) == "number")) { + ok = false; + } + if(this.is(xrfragment_XRF.T_VECTOR2) && !(typeof(this.x) == "number" && typeof(this.y) == "number")) { + ok = false; + } + var tmp; + if(this.is(xrfragment_XRF.T_INT)) { + var v = this.int; + tmp = !(typeof(v) == "number" && ((v | 0) === v)); + } else { + tmp = false; + } + if(tmp) { + ok = false; + } + } + return ok; + } + ,guessType: function(v,str) { + v.string = str; + if(str.split(",").length > 1) { + var xyz = str.split(","); + if(xyz.length > 0) { + v.x = parseFloat(xyz[0]); + } + if(xyz.length > 1) { + v.y = parseFloat(xyz[1]); + } + if(xyz.length > 2) { + v.z = parseFloat(xyz[2]); + } + } + if(xrfragment_XRF.isColor.match(str)) { + v.color = str; + } + if(xrfragment_XRF.isFloat.match(str)) { + v.float = parseFloat(str); + } + if(xrfragment_XRF.isInt.match(str)) { + v.int = Std.parseInt(str); + } + } +}; +if(typeof(performance) != "undefined" ? typeof(performance.now) == "function" : false) { + HxOverrides.now = performance.now.bind(performance); +} +String.__name__ = true; +Array.__name__ = true; +js_Boot.__toStr = ({ }).toString; +xrfragment_Parser.error = ""; +xrfragment_Parser.debug = false; +xrfragment_XRF.ASSET = 1; +xrfragment_XRF.PROP_BIND = 2; +xrfragment_XRF.QUERY_OPERATOR = 4; +xrfragment_XRF.PROMPT = 8; +xrfragment_XRF.ROUNDROBIN = 16; +xrfragment_XRF.BROWSER_OVERRIDE = 32; +xrfragment_XRF.EMBED_OVERRIDE = 64; +xrfragment_XRF.PV_OVERRIDE = 128; +xrfragment_XRF.PV_EXECUTE = 256; +xrfragment_XRF.T_COLOR = 8192; +xrfragment_XRF.T_INT = 16384; +xrfragment_XRF.T_FLOAT = 32768; +xrfragment_XRF.T_VECTOR2 = 65536; +xrfragment_XRF.T_VECTOR3 = 131072; +xrfragment_XRF.T_URL = 262144; +xrfragment_XRF.T_PREDEFINED_VIEW = 524288; +xrfragment_XRF.T_STRING = 1048576; +xrfragment_XRF.T_STRING_OBJ = 2097152; +xrfragment_XRF.T_STRING_OBJ_PROP = 4194304; +xrfragment_XRF.isColor = new EReg("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$",""); +xrfragment_XRF.isInt = new EReg("^[0-9]+$",""); +xrfragment_XRF.isFloat = new EReg("^[0-9]+\\.[0-9]+$",""); +xrfragment_XRF.isVector = new EReg("([,]+|\\w)",""); +xrfragment_XRF.isUrl = new EReg("(://)?\\..*",""); +xrfragment_XRF.isUrlOrPretypedView = new EReg("(^#|://)?\\..*",""); +xrfragment_XRF.isString = new EReg(".*",""); +})({}); +var xrfragment = $hx_exports["xrfragment"]; +xrfragment.three = {} + +xrfragment.init = function(opts){ + opts = opts || {} + for ( let i in opts ) xrfragment[i] = opts[i] + xrfragment.Parser.debug = xrfragment.debug + if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader ) +} + +xrfragment.patchLoader = function(loader){ + loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){ + load.call( this, + url, + (model) => { onLoad(model); xrfragment.parseModel(model) }, + onProgress, + onError) + })(loader.prototype.load) +} + +xrfragment.parseModel = function(model){ + model.scene.traverse( (mesh) => { + if( mesh.userData ){ + let frag = {} + for( let k in mesh.userData ){ + xrfragment.Parser.parse( k, mesh.userData[k], frag ) + // call native function (xrf/env.js e.g.), or pass it to user decorator + let func = xrfragment.three[k] || function(){} + if( xrfragment[k] ) xrfragment[k]( func, frag[k], mesh, model, xrfragment.scene, xrfragment.renderer, xrfragment.THREE ) + else func( frag[k], mesh, model, xrfragment.scene, xrfragment.renderer, xrfragment.THREE ) + } + } + }) +} +xrfragment.three.env = function(v, mesh, model, scene, renderer, THREE){ + let env = mesh.getObjectByName(v.string) + env.material.map.mapping = THREE.EquirectangularReflectionMapping; + scene.environment = env.material.map + scene.texture = env.material.map + renderer.toneMapping = THREE.ACESFilmicToneMapping; + renderer.toneMappingExposure = 1; +} +export default xrfragment; diff --git a/example/assets/style.css b/example/assets/style.css index 6ee8348..fa7d9b2 100644 --- a/example/assets/style.css +++ b/example/assets/style.css @@ -70,3 +70,13 @@ input[type="submit"] { background: #f0f0f0; border-color: #Ccc; } + +a#source{ + position: absolute; + bottom: 20px; + right: 20px; + color: #888; + font-weight: bold; + font-family: sans-serif; + text-decoration: underline; +} diff --git a/example/threejs/basic/index.html b/example/threejs/parser_only/index.html similarity index 99% rename from example/threejs/basic/index.html rename to example/threejs/parser_only/index.html index 2773108..f899ab1 100644 --- a/example/threejs/basic/index.html +++ b/example/threejs/parser_only/index.html @@ -93,6 +93,8 @@ } let XRF = xrfragment; + XRF.Parser.debug= true; + gltf.scene.traverse( (mesh) => { if( mesh.userData ){ let frag = {} diff --git a/example/threejs/basic/main.css b/example/threejs/parser_only/main.css similarity index 100% rename from example/threejs/basic/main.css rename to example/threejs/parser_only/main.css diff --git a/example/threejs/sandbox/index.html b/example/threejs/sandbox/index.html new file mode 100644 index 0000000..c0715a2 --- /dev/null +++ b/example/threejs/sandbox/index.html @@ -0,0 +1,252 @@ + + + + three.js vr - sandbox + + + + + + + +
+ + + + + + +
+ source + + + + + + + + + + + diff --git a/example/threejs/sandbox/main.css b/example/threejs/sandbox/main.css new file mode 100644 index 0000000..d496122 --- /dev/null +++ b/example/threejs/sandbox/main.css @@ -0,0 +1,91 @@ +body { + margin: 0; + background-color: #000; + color: #fff; + font-family: Monospace; + font-size: 13px; + line-height: 24px; + overscroll-behavior: none; +} + +a { + color: #ff0; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +button { + cursor: pointer; + text-transform: uppercase; +} + +#info { + position: absolute; + top: 0px; + width: 100%; + padding: 10px; + box-sizing: border-box; + text-align: center; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + z-index: 1; /* TODO Solve this in HTML */ +} + +a, button, input, select { + pointer-events: auto; +} + +.lil-gui { + z-index: 2 !important; /* TODO Solve this in HTML */ +} + +@media all and ( max-width: 640px ) { + .lil-gui.root { + right: auto; + top: auto; + max-height: 50%; + max-width: 80%; + bottom: 0; + left: 0; + } +} + +#overlay { + position: absolute; + font-size: 16px; + z-index: 2; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + background: rgba(0,0,0,0.7); +} + + #overlay button { + background: transparent; + border: 0; + border: 1px solid rgb(255, 255, 255); + border-radius: 4px; + color: #ffffff; + padding: 12px 18px; + text-transform: uppercase; + cursor: pointer; + } + +#notSupported { + width: 50%; + margin: auto; + background-color: #f00; + margin-top: 20px; + padding: 10px; +} diff --git a/src/three/index.js b/src/three/index.js new file mode 100644 index 0000000..ab159d4 --- /dev/null +++ b/src/three/index.js @@ -0,0 +1,33 @@ +xrfragment.three = {} + +xrfragment.init = function(opts){ + opts = opts || {} + for ( let i in opts ) xrfragment[i] = opts[i] + xrfragment.Parser.debug = xrfragment.debug + if( opts.loaders ) opts.loaders.map( xrfragment.patchLoader ) +} + +xrfragment.patchLoader = function(loader){ + loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){ + load.call( this, + url, + (model) => { onLoad(model); xrfragment.parseModel(model) }, + onProgress, + onError) + })(loader.prototype.load) +} + +xrfragment.parseModel = function(model){ + model.scene.traverse( (mesh) => { + if( mesh.userData ){ + let frag = {} + for( let k in mesh.userData ){ + xrfragment.Parser.parse( k, mesh.userData[k], frag ) + // call native function (xrf/env.js e.g.), or pass it to user decorator + let func = xrfragment.three[k] || function(){} + if( xrfragment[k] ) xrfragment[k]( func, frag[k], mesh, model, xrfragment.scene, xrfragment.renderer, xrfragment.THREE ) + else func( frag[k], mesh, model, xrfragment.scene, xrfragment.renderer, xrfragment.THREE ) + } + } + }) +} diff --git a/src/three/xrf/env.js b/src/three/xrf/env.js new file mode 100644 index 0000000..123a6de --- /dev/null +++ b/src/three/xrf/env.js @@ -0,0 +1,8 @@ +xrfragment.three.env = function(v, mesh, model, scene, renderer, THREE){ + let env = mesh.getObjectByName(v.string) + env.material.map.mapping = THREE.EquirectangularReflectionMapping; + scene.environment = env.material.map + scene.texture = env.material.map + renderer.toneMapping = THREE.ACESFilmicToneMapping; + renderer.toneMappingExposure = 1; +}