Merge branch 'feat/non-euclidian'

This commit is contained in:
Leon van Kammen 2023-12-06 12:56:27 +01:00
commit 12937d5b88
117 changed files with 371997 additions and 16470 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
dist/*.pyc
src/spec/tmp.json
tags
example/assets/*.blend

4
.vimrc
View file

@ -1,4 +1,4 @@
noremap <silent> <F8> :!haxe --no-output %<CR>
noremap <silent> <F9> :!./make build_js<CR>
noremap <silent> <F10> :!./make && echo OK && ./make tests<CR>
noremap <silent> <F9> :!./make build js<CR>
noremap <silent> <F10> :!./make build && ./make tests<CR>
noremap <silent> <F11> :!./make tests \| less<CR>

View file

@ -37,6 +37,10 @@ Pre-build libraries can be found in [/dist folder](dist)<br>
If you really want to build from source:
```
$ ./make install
$ ./make build && ./make runtest
$ nix-shell # nix-users: drops you into a dev-ready shell
$ ./make install # debian-users: install deps via apt-get
$ ./make build && ./make tests
```
> NOTE #1: to rebundle the THREE/AFRAME javascripts during dev run `./make build js`
> NOTE #2: to regenerate the parser in various languages (via haxe), run `./make build parser`

21
dist/utils.js vendored
View file

@ -267,7 +267,7 @@ function notify(scope){
if( str.match(/error/g) ) opts.status = "danger"
if( str.match(/warning/g) ) opts.status = "warning"
}
opts = Object.assign({ message: str , status, timeout:2000 },opts)
opts = Object.assign({ message: str , status, timeout:4000 },opts)
SnackBar( opts )
}
}
@ -285,12 +285,25 @@ function download(){
}
function embed(){
// *TODO* this should be part of the XRF framework
let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs
// *TODO* this should be part of the XRF Threejs framework
if( typeof THREE == 'undefined' ) THREE = xrf.THREE
let radToDeg = THREE.MathUtils.radToDeg
let toDeg = (x) => x / (Math.PI / 180)
let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs
// *TODO* add camera direction
let direction = new xrf.THREE.Vector3()
camera.getWorldDirection(direction)
const pitch = Math.asin(direction.y);
const yaw = Math.atan2(direction.x, direction.z);
const pitchInDegrees = pitch * 180 / Math.PI;
const yawInDegrees = yaw * 180 / Math.PI;
let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}`
let newHash = document.location.hash.replace(/[&]?pos=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'')
let newHash = document.location.hash.replace(/[&]?(pos|rot)=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'')
newHash += `&${lastPos}`
document.location.hash = newHash.replace(/&&/,'&')
.replace(/#&/,'')
// copy url to clipboard
var dummy = document.createElement('input'),
text = window.location.href;

File diff suppressed because one or more lines are too long

339
dist/xrfragment.js vendored
View file

@ -72,6 +72,20 @@ Reflect.deleteField = function(o,field) {
delete(o[field]);
return true;
};
Reflect.copy = function(o) {
if(o == null) {
return null;
}
var o2 = { };
var _g = 0;
var _g1 = Reflect.fields(o);
while(_g < _g1.length) {
var f = _g1[_g];
++_g;
o2[f] = Reflect.field(o,f);
}
return o2;
};
var Std = function() { };
Std.__name__ = true;
Std.string = function(s) {
@ -209,86 +223,22 @@ js_Boot.__string_rec = function(o,s) {
return String(o);
}
};
var xrfragment_Parser = $hx_exports["xrfragment"]["Parser"] = function() { };
xrfragment_Parser.__name__ = true;
xrfragment_Parser.parse = function(key,value,store) {
var Frag_h = Object.create(null);
Frag_h["#"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW | xrfragment_XRF.PV_EXECUTE;
Frag_h["prio"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_INT;
Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL;
Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW;
Frag_h["tag"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
Frag_h["q"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.METADATA;
Frag_h["scale"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
Frag_h["rot"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
Frag_h["mov"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
Frag_h["show"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_INT | xrfragment_XRF.METADATA;
Frag_h["env"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.METADATA;
Frag_h["t"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
Frag_h["gravity"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
Frag_h["physics"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA;
Frag_h["fov"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_INT | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
Frag_h["clip"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
Frag_h["fog"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
Frag_h["bg"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
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.NAVIGATOR | xrfragment_XRF.METADATA | xrfragment_XRF.PROMPT;
var isPVDynamic = value.length == 0 && key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key);
var isPVDefault = value.length == 0 && key.length > 0 && key == "#";
if(isPVDynamic) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR);
v.validate(key);
store[key] = v;
return true;
}
if(key.split(".").length > 1 && value.split(".").length > 1) {
store[key] = new xrfragment_XRF(key,xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING | xrfragment_XRF.PROP_BIND);
return true;
}
var v = new xrfragment_XRF(key,Frag_h[key]);
if(Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(!v.validate(value)) {
console.log("src/xrfragment/Parser.hx:83:","⚠ fragment '" + key + "' has incompatible value (" + value + ")");
return false;
}
store[key] = v;
if(xrfragment_Parser.debug) {
console.log("src/xrfragment/Parser.hx:87:","✔ " + key + ": " + v.string);
}
} else {
if(typeof(value) == "string") {
v.guessType(v,value);
}
v.noXRF = true;
store[key] = v;
}
return true;
};
var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) {
this.isNumber = new EReg("^[0-9\\.]+$","");
this.isRoot = new EReg("^[-]?/","");
this.isExclude = new EReg("^-","");
this.isProp = new EReg("^.*:[><=!]?","");
var xrfragment_Filter = $hx_exports["xrfragment"]["Filter"] = function(str) {
this.q = { };
this.str = "";
if(str != null) {
this.parse(str);
}
};
xrfragment_Query.__name__ = true;
xrfragment_Query.prototype = {
xrfragment_Filter.__name__ = true;
xrfragment_Filter.prototype = {
toObject: function() {
return this.q;
return Reflect.copy(this.q);
}
,get: function() {
return this.q;
return Reflect.copy(this.q);
}
,parse: function(str) {
var _gthis = this;
var token = str.split(" ");
var q = { };
var process = function(str,prefix) {
@ -296,59 +246,42 @@ xrfragment_Query.prototype = {
prefix = "";
}
str = StringTools.trim(str);
var k = str.split(":")[0];
var v = str.split(":")[1];
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)) {
if(xrfragment_XRF.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 = "!=";
if(xrfragment_XRF.isExclude.match(k)) {
k = HxOverrides.substr(k,1,null);
} else {
v = HxOverrides.substr(v,oper.length,null);
}
v = HxOverrides.substr(v,oper.length,null);
if(oper.length == 0) {
oper = "=";
}
var rule = { };
if(_gthis.isNumber.match(v)) {
if(xrfragment_XRF.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;
filter["root"] = _gthis.isRoot.match(str);
if(_gthis.isExclude.match(str)) {
str = HxOverrides.substr(str,1,null);
}
if(_gthis.isRoot.match(str)) {
str = HxOverrides.substr(str,1,null);
}
q[str] = filter;
q["expr"] = rule;
}
var value = xrfragment_XRF.isDeep.match(str) ? k.split("*").length - 1 : 0;
q["deep"] = value;
var value = xrfragment_XRF.isExclude.match(str) ? false : true;
q["show"] = value;
var value = k.replace(xrfragment_XRF.operators.r,"");
q["key"] = value;
q["value"] = v;
};
var _g = 0;
var _g1 = token.length;
@ -397,49 +330,75 @@ xrfragment_Query.prototype = {
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;
}
if(Reflect.field(this.q,"expr")) {
var f = Reflect.field(this.q,"expr");
if(!Reflect.field(this.q,"show")) {
if(Reflect.field(f,"!=") != null && testprop((value == null ? "null" : "" + value) == Std.string(Reflect.field(f,"!="))) && exclude) {
++qualify;
}
} else {
if(Reflect.field(f,"*") != null && testprop(parseFloat(value) != null)) {
++qualify;
}
if(Reflect.field(f,">") != null && testprop(parseFloat(value) >= parseFloat(Reflect.field(f,">")))) {
++qualify;
}
if(Reflect.field(f,"<") != null && testprop(parseFloat(value) <= parseFloat(Reflect.field(f,"<")))) {
++qualify;
}
if(Reflect.field(f,"=") != null && (testprop(value == Reflect.field(f,"=")) || testprop(parseFloat(value) == parseFloat(Reflect.field(f,"="))))) {
++qualify;
}
}
}
return qualify > 0;
}
};
var xrfragment_Parser = $hx_exports["xrfragment"]["Parser"] = function() { };
xrfragment_Parser.__name__ = true;
xrfragment_Parser.parse = function(key,value,store,index) {
var Frag_h = Object.create(null);
Frag_h["#"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW | xrfragment_XRF.PV_EXECUTE;
Frag_h["src"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL;
Frag_h["href"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_URL | xrfragment_XRF.T_PREDEFINED_VIEW;
Frag_h["tag"] = xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING;
Frag_h["pos"] = xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.T_STRING | xrfragment_XRF.T_STRING_OBJ | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
Frag_h["rot"] = xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.METADATA | xrfragment_XRF.NAVIGATOR;
Frag_h["t"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_FLOAT | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.T_STRING | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
Frag_h["tv"] = xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_FLOAT | xrfragment_XRF.T_VECTOR2 | xrfragment_XRF.T_VECTOR3 | xrfragment_XRF.NAVIGATOR | xrfragment_XRF.METADATA;
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.NAVIGATOR | xrfragment_XRF.METADATA | xrfragment_XRF.PROMPT;
var keyStripped = key.replace(xrfragment_XRF.operators.r,"");
var isPVDynamic = key.length > 0 && !Object.prototype.hasOwnProperty.call(Frag_h,key);
var isPVDefault = value.length == 0 && key.length > 0 && key == "#";
if(isPVDynamic) {
var v = new xrfragment_XRF(key,xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR,index);
v.validate(value);
store[keyStripped] = v;
return true;
}
var v = new xrfragment_XRF(key,Frag_h[key],index);
if(Object.prototype.hasOwnProperty.call(Frag_h,key)) {
if(!v.validate(value)) {
console.log("src/xrfragment/Parser.hx:66:","⚠ fragment '" + key + "' has incompatible value (" + value + ")");
return false;
}
store[keyStripped] = v;
if(xrfragment_Parser.debug) {
console.log("src/xrfragment/Parser.hx:70:","✔ " + key + ": " + v.string);
}
} else {
if(typeof(value) == "string") {
v.guessType(v,value);
}
v.noXRF = true;
store[keyStripped] = v;
}
return true;
};
var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { };
xrfragment_URI.__name__ = true;
xrfragment_URI.parse = function(url,filter) {
@ -461,7 +420,7 @@ xrfragment_URI.parse = function(url,filter) {
var s = regexPlus.split(splitByEqual[1]).join(" ");
value = decodeURIComponent(s.split("+").join(" "));
}
var ok = xrfragment_Parser.parse(key,value,store);
var ok = xrfragment_Parser.parse(key,value,store,i);
}
if(filter != null && filter != 0) {
var _g = 0;
@ -477,9 +436,10 @@ xrfragment_URI.parse = function(url,filter) {
}
return store;
};
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags) {
var xrfragment_XRF = $hx_exports["xrfragment"]["XRF"] = function(_fragment,_flags,_index) {
this.fragment = _fragment;
this.flags = _flags;
this.index = _index;
};
xrfragment_XRF.__name__ = true;
xrfragment_XRF.set = function(flag,flags) {
@ -490,68 +450,58 @@ xrfragment_XRF.unset = function(flag,flags) {
};
xrfragment_XRF.prototype = {
is: function(flag) {
var v = this.flags;
if(!(typeof(v) == "number" && ((v | 0) === v))) {
this.flags = 0;
}
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;
}
if(!this.is(xrfragment_XRF.T_FLOAT) && this.is(xrfragment_XRF.T_VECTOR2) && !(typeof(this.x) == "number" && typeof(this.y) == "number")) {
ok = false;
}
if(!(this.is(xrfragment_XRF.T_VECTOR2) || this.is(xrfragment_XRF.T_STRING)) && this.is(xrfragment_XRF.T_VECTOR3) && !(typeof(this.x) == "number" && typeof(this.y) == "number" && typeof(this.z) == "number")) {
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(typeof(str) != "string") {
return;
}
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(str.length > 0) {
if(str.split(",").length > 1) {
var xyzw = str.split(",");
if(xyzw.length > 0) {
v.x = parseFloat(xyzw[0]);
}
if(xyzw.length > 1) {
v.y = parseFloat(xyzw[1]);
}
if(xyzw.length > 2) {
v.z = parseFloat(xyzw[2]);
}
if(xyzw.length > 3) {
v.w = parseFloat(xyzw[3]);
}
}
if(xrfragment_XRF.isColor.match(str)) {
v.color = str;
}
if(xrfragment_XRF.isFloat.match(str)) {
v.x = parseFloat(str);
v.float = v.x;
}
if(xrfragment_XRF.isInt.match(str)) {
v.int = Std.parseInt(str);
v.x = v.int;
}
v.filter = new xrfragment_Filter(v.fragment + "=" + v.string);
} else {
v.filter = new xrfragment_Filter(v.fragment);
}
}
};
@ -583,11 +533,16 @@ 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.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(".*","");
xrfragment_XRF.operators = new EReg("(^-|[\\*]+)","");
xrfragment_XRF.isProp = new EReg("^.*=[><=]?","");
xrfragment_XRF.isExclude = new EReg("^-","");
xrfragment_XRF.isDeep = new EReg("\\*","");
xrfragment_XRF.isNumber = new EReg("^[0-9\\.]+$","");
})({});
var xrfragment = $hx_exports["xrfragment"];

870
dist/xrfragment.lua vendored

File diff suppressed because it is too large Load diff

158788
dist/xrfragment.module.js vendored

File diff suppressed because it is too large Load diff

View file

@ -1,706 +0,0 @@
<?php
/**
*/
use \haxe\iterators\ArrayIterator as IteratorsArrayIterator;
use \php\Boot;
use \php\_Boot\HxClosure;
use \haxe\iterators\ArrayKeyValueIterator;
final class Array_hx implements \JsonSerializable, \Countable, \IteratorAggregate, \ArrayAccess {
/**
* @var mixed[]
*/
public $arr;
/**
* @var int
* The length of `this` Array.
*/
public $length;
/**
* @param mixed[] $arr
*
* @return mixed[]|Array_hx
*/
public static function wrap ($arr) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:267: characters 3-23
$a = new Array_hx();
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:268: characters 3-14
$a->arr = $arr;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:269: characters 3-31
$a->length = count($arr);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:270: characters 3-11
return $a;
}
/**
* Creates a new Array.
*
* @return void
*/
public function __construct () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:37: characters 9-36
$this1 = [];
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:37: characters 3-36
$this->arr = $this1;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:38: characters 3-13
$this->length = 0;
}
/**
* Returns a new Array by appending the elements of `a` to the elements of
* `this` Array.
* This operation does not modify `this` Array.
* If `a` is the empty Array `[]`, a copy of `this` Array is returned.
* The length of the returned Array is equal to the sum of `this.length`
* and `a.length`.
* If `a` is `null`, the result is unspecified.
*
* @param mixed[]|Array_hx $a
*
* @return mixed[]|Array_hx
*/
public function concat ($a) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:42: characters 3-46
return Array_hx::wrap(array_merge($this->arr, $a->arr));
}
/**
* Returns whether `this` Array contains `x`.
* If `x` is found by checking standard equality, the function returns `true`, otherwise
* the function returns `false`.
*
* @param mixed $x
*
* @return bool
*/
public function contains ($x) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:60: characters 3-26
return $this->indexOf($x) !== -1;
}
/**
* Returns a shallow copy of `this` Array.
* The elements are not copied and retain their identity, so
* `a[i] == a.copy()[i]` is true for any valid `i`. However,
* `a == a.copy()` is always false.
*
* @return mixed[]|Array_hx
*/
public function copy () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:46: characters 3-28
return (clone $this);
}
/**
* @return int
*/
#[\ReturnTypeWillChange]
public function count () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:257: characters 3-16
return $this->length;
}
/**
* Returns an Array containing those elements of `this` for which `f`
* returned true.
* The individual elements are not duplicated and retain their identity.
* If `f` is null, the result is unspecified.
*
* @param \Closure $f
*
* @return mixed[]|Array_hx
*/
public function filter ($f) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:50: characters 3-35
$result = [];
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:51: characters 15-18
$data = $this->arr;
$_g_current = 0;
$_g_length = count($data);
$_g_data = $data;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:51: lines 51-55
while ($_g_current < $_g_length) {
$item = $_g_data[$_g_current++];
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:52: lines 52-54
if ($f($item)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:53: characters 5-22
$result[] = $item;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:56: characters 3-22
return Array_hx::wrap($result);
}
/**
* @return \Traversable
*/
#[\ReturnTypeWillChange]
public function getIterator () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:250: characters 3-38
return new \ArrayIterator($this->arr);
}
/**
* Returns position of the first occurrence of `x` in `this` Array, searching front to back.
* If `x` is found by checking standard equality, the function returns its index.
* If `x` is not found, the function returns -1.
* If `fromIndex` is specified, it will be used as the starting index to search from,
* otherwise search starts with zero index. If it is negative, it will be taken as the
* offset from the end of `this` Array to compute the starting index. If given or computed
* starting index is less than 0, the whole array will be searched, if it is greater than
* or equal to the length of `this` Array, the function returns -1.
*
* @param mixed $x
* @param int $fromIndex
*
* @return int
*/
public function indexOf ($x, $fromIndex = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:64: characters 7-69
$tmp = null;
if (($fromIndex === null) && !($x instanceof HxClosure)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:64: characters 53-69
$value = $x;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:64: characters 7-69
$tmp = !(is_int($value) || is_float($value));
} else {
$tmp = false;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:64: lines 64-71
if ($tmp) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:65: characters 4-50
$index = array_search($x, $this->arr, true);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:66: lines 66-70
if ($index === false) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:67: characters 5-14
return -1;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:69: characters 5-17
return $index;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:72: lines 72-79
if ($fromIndex === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:73: characters 4-17
$fromIndex = 0;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:75: lines 75-76
if ($fromIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:76: characters 5-24
$fromIndex += $this->length;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:77: lines 77-78
if ($fromIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:78: characters 5-18
$fromIndex = 0;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:80: lines 80-84
while ($fromIndex < $this->length) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:81: lines 81-82
if (Boot::equal($this->arr[$fromIndex], $x)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:82: characters 5-21
return $fromIndex;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:83: characters 4-15
++$fromIndex;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:85: characters 3-12
return -1;
}
/**
* Inserts the element `x` at the position `pos`.
* This operation modifies `this` Array in place.
* The offset is calculated like so:
* - If `pos` exceeds `this.length`, the offset is `this.length`.
* - If `pos` is negative, the offset is calculated from the end of `this`
* Array, i.e. `this.length + pos`. If this yields a negative value, the
* offset is 0.
* - Otherwise, the offset is `pos`.
* If the resulting offset does not exceed `this.length`, all elements from
* and including that offset to the end of `this` Array are moved one index
* ahead.
*
* @param int $pos
* @param mixed $x
*
* @return void
*/
public function insert ($pos, $x) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:89: characters 3-11
$this->length++;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:90: characters 3-56
array_splice($this->arr, $pos, 0, [$x]);
}
/**
* Returns an iterator of the Array values.
*
* @return IteratorsArrayIterator
*/
public function iterator () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:95: characters 3-48
return new IteratorsArrayIterator($this);
}
/**
* Returns a string representation of `this` Array, with `sep` separating
* each element.
* The result of this operation is equal to `Std.string(this[0]) + sep +
* Std.string(this[1]) + sep + ... + sep + Std.string(this[this.length-1])`
* If `this` is the empty Array `[]`, the result is the empty String `""`.
* If `this` has exactly one element, the result is equal to a call to
* `Std.string(this[0])`.
* If `sep` is null, the result is unspecified.
*
* @param string $sep
*
* @return string
*/
public function join ($sep) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:104: characters 3-98
return implode($sep, array_map((Boot::class??'null') . "::stringify", $this->arr));
}
/**
* @return mixed[]
*/
#[\ReturnTypeWillChange]
public function jsonSerialize () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:263: characters 3-13
return $this->arr;
}
/**
* Returns an iterator of the Array indices and values.
*
* @return ArrayKeyValueIterator
*/
public function keyValueIterator () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:100: characters 3-41
return new ArrayKeyValueIterator($this);
}
/**
* Returns position of the last occurrence of `x` in `this` Array, searching back to front.
* If `x` is found by checking standard equality, the function returns its index.
* If `x` is not found, the function returns -1.
* If `fromIndex` is specified, it will be used as the starting index to search from,
* otherwise search starts with the last element index. If it is negative, it will be
* taken as the offset from the end of `this` Array to compute the starting index. If
* given or computed starting index is greater than or equal to the length of `this` Array,
* the whole array will be searched, if it is less than 0, the function returns -1.
*
* @param mixed $x
* @param int $fromIndex
*
* @return int
*/
public function lastIndexOf ($x, $fromIndex = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:108: lines 108-109
if (($fromIndex === null) || ($fromIndex >= $this->length)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:109: characters 4-26
$fromIndex = $this->length - 1;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:110: lines 110-111
if ($fromIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:111: characters 4-23
$fromIndex += $this->length;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:112: lines 112-116
while ($fromIndex >= 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:113: lines 113-114
if (Boot::equal($this->arr[$fromIndex], $x)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:114: characters 5-21
return $fromIndex;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:115: characters 4-15
--$fromIndex;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:117: characters 3-12
return -1;
}
/**
* Creates a new Array by applying function `f` to all elements of `this`.
* The order of elements is preserved.
* If `f` is null, the result is unspecified.
*
* @param \Closure $f
*
* @return mixed[]|Array_hx
*/
public function map ($f) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:121: characters 3-35
$result = [];
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:122: characters 15-18
$data = $this->arr;
$_g_current = 0;
$_g_length = count($data);
$_g_data = $data;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:122: lines 122-124
while ($_g_current < $_g_length) {
$item = $_g_data[$_g_current++];
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:123: characters 4-24
$result[] = $f($item);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:125: characters 3-22
return Array_hx::wrap($result);
}
/**
* @param int $offset
*
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists ($offset) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:212: characters 3-25
return $offset < $this->length;
}
/**
* @param int $offset
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function &offsetGet ($offset) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:218: lines 218-222
try {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:219: characters 4-22
return $this->arr[$offset];
} catch(\Throwable $_g) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:221: characters 4-15
return null;
}
}
/**
* @param int $offset
* @param mixed $value
*
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet ($offset, $value) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:228: lines 228-233
if ($this->length <= $offset) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:229: characters 13-19
$_g = $this->length;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:229: characters 22-32
$_g1 = $offset + 1;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:229: lines 229-231
while ($_g < $_g1) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:229: characters 13-32
$i = $_g++;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:230: characters 5-18
$this->arr[$i] = null;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:232: characters 4-23
$this->length = $offset + 1;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:234: characters 3-22
$this->arr[$offset] = $value;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:235: characters 3-35
return $value;
}
/**
* @param int $offset
*
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset ($offset) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:241: lines 241-244
if (($offset >= 0) && ($offset < $this->length)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:242: characters 4-39
array_splice($this->arr, $offset, 1);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:243: characters 4-12
--$this->length;
}
}
/**
* Removes the last element of `this` Array and returns it.
* This operation modifies `this` Array in place.
* If `this` has at least one element, `this.length` will decrease by 1.
* If `this` is the empty Array `[]`, null is returned and the length
* remains 0.
*
* @return mixed
*/
public function pop () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:129: lines 129-130
if ($this->length > 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:130: characters 4-12
$this->length--;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:131: characters 3-31
return array_pop($this->arr);
}
/**
* Adds the element `x` at the end of `this` Array and returns the new
* length of `this` Array.
* This operation modifies `this` Array in place.
* `this.length` increases by 1.
*
* @param mixed $x
*
* @return int
*/
public function push ($x) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:135: characters 3-20
$this->arr[$this->length++] = $x;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:136: characters 3-16
return $this->length;
}
/**
* Removes the first occurrence of `x` in `this` Array.
* This operation modifies `this` Array in place.
* If `x` is found by checking standard equality, it is removed from `this`
* Array and all following elements are reindexed accordingly. The function
* then returns true.
* If `x` is not found, `this` Array is not changed and the function
* returns false.
*
* @param mixed $x
*
* @return bool
*/
public function remove ($x) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:140: characters 3-22
$result = false;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:141: characters 16-20
$_g = 0;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:141: characters 20-26
$_g1 = $this->length;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:141: lines 141-148
while ($_g < $_g1) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:141: characters 16-26
$index = $_g++;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:142: lines 142-147
if (Boot::equal($this->arr[$index], $x)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:143: characters 5-39
array_splice($this->arr, $index, 1);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:144: characters 5-13
$this->length--;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:145: characters 5-18
$result = true;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:146: characters 5-10
break;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:149: characters 3-16
return $result;
}
/**
* Set the length of the Array.
* If `len` is shorter than the array's current size, the last
* `length - len` elements will be removed. If `len` is longer, the Array
* will be extended, with new elements set to a target-specific default
* value:
* - always null on dynamic targets
* - 0, 0.0 or false for Int, Float and Bool respectively on static targets
* - null for other types on static targets
*
* @param int $len
*
* @return void
*/
public function resize ($len) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:201: lines 201-205
if ($this->length < $len) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:202: characters 4-42
$this->arr = array_pad($this->arr, $len, null);
} else if ($this->length > $len) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:204: characters 4-47
array_splice($this->arr, $len, $this->length - $len);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:206: characters 3-15
$this->length = $len;
}
/**
* Reverse the order of elements of `this` Array.
* This operation modifies `this` Array in place.
* If `this.length < 2`, `this` remains unchanged.
*
* @return void
*/
public function reverse () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:153: characters 3-34
$this->arr = array_reverse($this->arr);
}
/**
* Removes the first element of `this` Array and returns it.
* This operation modifies `this` Array in place.
* If `this` has at least one element, `this`.length and the index of each
* remaining element is decreased by 1.
* If `this` is the empty Array `[]`, `null` is returned and the length
* remains 0.
*
* @return mixed
*/
public function shift () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:157: lines 157-158
if ($this->length > 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:158: characters 4-12
$this->length--;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:159: characters 3-33
return array_shift($this->arr);
}
/**
* Creates a shallow copy of the range of `this` Array, starting at and
* including `pos`, up to but not including `end`.
* This operation does not modify `this` Array.
* The elements are not copied and retain their identity.
* If `end` is omitted or exceeds `this.length`, it defaults to the end of
* `this` Array.
* If `pos` or `end` are negative, their offsets are calculated from the
* end of `this` Array by `this.length + pos` and `this.length + end`
* respectively. If this yields a negative value, 0 is used instead.
* If `pos` exceeds `this.length` or if `end` is less than or equals
* `pos`, the result is `[]`.
*
* @param int $pos
* @param int $end
*
* @return mixed[]|Array_hx
*/
public function slice ($pos, $end = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:163: lines 163-164
if ($pos < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:164: characters 4-17
$pos += $this->length;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:165: lines 165-166
if ($pos < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:166: characters 4-11
$pos = 0;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:167: lines 167-177
if ($end === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:168: characters 4-45
return Array_hx::wrap(array_slice($this->arr, $pos));
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:170: lines 170-171
if ($end < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:171: characters 5-18
$end += $this->length;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:172: lines 172-176
if ($end <= $pos) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:173: characters 5-14
return new Array_hx();
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:175: characters 5-57
return Array_hx::wrap(array_slice($this->arr, $pos, $end - $pos));
}
}
}
/**
* Sorts `this` Array according to the comparison function `f`, where
* `f(x,y)` returns 0 if x == y, a positive Int if x > y and a
* negative Int if x < y.
* This operation modifies `this` Array in place.
* The sort operation is not guaranteed to be stable, which means that the
* order of equal elements may not be retained. For a stable Array sorting
* algorithm, `haxe.ds.ArraySort.sort()` can be used instead.
* If `f` is null, the result is unspecified.
*
* @param \Closure $f
*
* @return void
*/
public function sort ($f) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:181: characters 3-15
usort($this->arr, $f);
}
/**
* Removes `len` elements from `this` Array, starting at and including
* `pos`, an returns them.
* This operation modifies `this` Array in place.
* If `len` is < 0 or `pos` exceeds `this`.length, an empty Array [] is
* returned and `this` Array is unchanged.
* If `pos` is negative, its value is calculated from the end of `this`
* Array by `this.length + pos`. If this yields a negative value, 0 is
* used instead.
* If the sum of the resulting values for `len` and `pos` exceed
* `this.length`, this operation will affect the elements from `pos` to the
* end of `this` Array.
* The length of the returned Array is equal to the new length of `this`
* Array subtracted from the original length of `this` Array. In other
* words, each element of the original `this` Array either remains in
* `this` Array or becomes an element of the returned Array.
*
* @param int $pos
* @param int $len
*
* @return mixed[]|Array_hx
*/
public function splice ($pos, $len) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:185: lines 185-186
if ($len < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:186: characters 4-13
return new Array_hx();
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:187: characters 3-57
$result = Array_hx::wrap(array_splice($this->arr, $pos, $len));
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:188: characters 3-26
$this->length -= $result->length;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:189: characters 3-16
return $result;
}
/**
* Returns a string representation of `this` Array.
* The result will include the individual elements' String representations
* separated by comma. The enclosing [ ] may be missing on some platforms,
* use `Std.string()` to get a String representation that is consistent
* across platforms.
*
* @return string
*/
public function toString () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:197: characters 10-54
$arr = $this->arr;
$strings = [];
foreach ($arr as $key => $value) {
$strings[$key] = Boot::stringify($value, 9);
}
return "[" . (implode(",", $strings)??'null') . "]";
}
/**
* Adds the element `x` at the start of `this` Array.
* This operation modifies `this` Array in place.
* `this.length` and the index of each Array element increases by 1.
*
* @param mixed $x
*
* @return void
*/
public function unshift ($x) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Array.hx:193: characters 3-40
$this->length = array_unshift($this->arr, $x);
}
public function __toString() {
return $this->toString();
}
}
Boot::registerClass(Array_hx::class, 'Array');

View file

@ -1,147 +0,0 @@
<?php
/**
*/
use \php\Boot;
use \haxe\Exception as HaxeException;
/**
* The EReg class represents regular expressions.
* While basic usage and patterns consistently work across platforms, some more
* complex operations may yield different results. This is a necessary trade-
* off to retain a certain level of performance.
* EReg instances can be created by calling the constructor, or with the
* special syntax `~/pattern/modifier`
* EReg instances maintain an internal state, which is affected by several of
* its methods.
* A detailed explanation of the supported operations is available at
* <https://haxe.org/manual/std-regex.html>
*/
final class EReg {
/**
* @var bool
*/
public $global;
/**
* @var string
*/
public $last;
/**
* @var array[]
*/
public $matches;
/**
* @var string
*/
public $options;
/**
* @var string
*/
public $pattern;
/**
* @var string
*/
public $re;
/**
* Creates a new regular expression with pattern `r` and modifiers `opt`.
* This is equivalent to the shorthand syntax `~/r/opt`
* If `r` or `opt` are null, the result is unspecified.
*
* @param string $r
* @param string $opt
*
* @return void
*/
public function __construct ($r, $opt) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:37: characters 3-19
$this->pattern = $r;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:38: characters 3-45
$this->options = str_replace("g", "", $opt);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:39: characters 3-26
$this->global = $this->options !== $opt;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:40: characters 3-49
$this->options = str_replace("u", "", $this->options);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:41: characters 3-68
$this->re = "\"" . (str_replace("\"", "\\\"", $r)??'null') . "\"" . ($this->options??'null');
}
/**
* @return void
*/
public function handlePregError () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:63: characters 3-36
$e = preg_last_error();
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:64: lines 64-72
if ($e === PREG_INTERNAL_ERROR) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:65: characters 4-9
throw HaxeException::thrown("EReg: internal PCRE error");
} else if ($e === PREG_BACKTRACK_LIMIT_ERROR) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:67: characters 4-9
throw HaxeException::thrown("EReg: backtrack limit");
} else if ($e === PREG_RECURSION_LIMIT_ERROR) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:69: characters 4-9
throw HaxeException::thrown("EReg: recursion limit");
} else if ($e === PREG_JIT_STACKLIMIT_ERROR) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:71: characters 4-9
throw HaxeException::thrown("failed due to limited JIT stack space");
}
}
/**
* Tells if `this` regular expression matches String `s`.
* This method modifies the internal state.
* If `s` is `null`, the result is unspecified.
*
* @param string $s
*
* @return bool
*/
public function match ($s) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:45: characters 10-29
$p = preg_match(($this->re . "u"), $s, $this->matches, PREG_OFFSET_CAPTURE, 0);
if ($p === false) {
$this->handlePregError();
$p = preg_match($this->re, $s, $this->matches, PREG_OFFSET_CAPTURE);
}
if ($p > 0) {
$this->last = $s;
} else {
$this->last = null;
}
return $p > 0;
}
/**
* Splits String `s` at all substrings `this` EReg matches.
* If a match is found at the start of `s`, the result contains a leading
* empty String "" entry.
* If a match is found at the end of `s`, the result contains a trailing
* empty String "" entry.
* If two matching substrings appear next to each other, the result
* contains the empty String `""` between them.
* By default, this method splits `s` into two parts at the first matched
* substring. If the global g modifier is in place, `s` is split at each
* matched substring.
* If `s` is null, the result is unspecified.
*
* @param string $s
*
* @return string[]|\Array_hx
*/
public function split ($s) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:128: characters 3-96
$parts = preg_split(($this->re . "u"), $s, ($this->global ? -1 : 2));
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:129: lines 129-132
if ($parts === false) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:130: characters 4-21
$this->handlePregError();
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:131: characters 4-55
$parts = preg_split($this->re, $s, ($this->global ? -1 : 2));
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/EReg.hx:133: characters 3-48
return \Array_hx::wrap($parts);
}
}
Boot::registerClass(EReg::class, 'EReg');

View file

@ -1,179 +0,0 @@
<?php
/**
*/
use \php\Boot;
use \php\_Boot\HxClass;
/**
* The Reflect API is a way to manipulate values dynamically through an
* abstract interface in an untyped manner. Use with care.
* @see https://haxe.org/manual/std-reflection.html
*/
class Reflect {
/**
* Removes the field named `field` from structure `o`.
* This method is only guaranteed to work on anonymous structures.
* If `o` or `field` are null, the result is unspecified.
*
* @param mixed $o
* @param string $field
*
* @return bool
*/
public static function deleteField ($o, $field) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:158: lines 158-163
if (Reflect::hasField($o, $field)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:159: characters 4-40
unset($o->{$field});
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:160: characters 4-15
return true;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:162: characters 4-16
return false;
}
}
/**
* Returns the value of the field named `field` on object `o`.
* If `o` is not an object or has no field named `field`, the result is
* null.
* If the field is defined as a property, its accessors are ignored. Refer
* to `Reflect.getProperty` for a function supporting property accessors.
* If `field` is null, the result is unspecified.
*
* @param mixed $o
* @param string $field
*
* @return mixed
*/
public static function field ($o, $field) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:50: lines 50-52
if (is_string($o)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:51: characters 24-45
$tmp = Boot::dynamicString($o);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:51: characters 4-53
return $tmp->{$field};
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:53: lines 53-54
if (!is_object($o)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:54: characters 4-15
return null;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:56: lines 56-58
if (($field === "") && (PHP_VERSION_ID < 70100)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:57: characters 4-56
return (((array)($o))[$field] ?? null);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:60: lines 60-62
if (property_exists($o, $field)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:61: characters 4-33
return $o->{$field};
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:63: lines 63-65
if (method_exists($o, $field)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:64: characters 4-44
return Boot::getInstanceClosure($o, $field);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:67: lines 67-78
if (($o instanceof HxClass)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:68: characters 4-54
$phpClassName = $o->phpClassName;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:69: lines 69-71
if (defined("" . ($phpClassName??'null') . "::" . ($field??'null'))) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:70: characters 5-52
return constant("" . ($phpClassName??'null') . "::" . ($field??'null'));
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:72: lines 72-74
if (property_exists($phpClassName, $field)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:73: characters 5-34
return $o->{$field};
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:75: lines 75-77
if (method_exists($phpClassName, $field)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:76: characters 5-54
return Boot::getStaticClosure($phpClassName, $field);
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:80: characters 3-14
return null;
}
/**
* Returns the fields of structure `o`.
* This method is only guaranteed to work on anonymous structures. Refer to
* `Type.getInstanceFields` for a function supporting class instances.
* If `o` is null, the result is unspecified.
*
* @param mixed $o
*
* @return string[]|\Array_hx
*/
public static function fields ($o) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:117: lines 117-119
if (is_object($o)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:118: characters 4-77
return \Array_hx::wrap(array_keys(get_object_vars($o)));
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:120: characters 3-12
return new \Array_hx();
}
/**
* Tells if structure `o` has a field named `field`.
* This is only guaranteed to work for anonymous structures. Refer to
* `Type.getInstanceFields` for a function supporting class instances.
* If `o` or `field` are null, the result is unspecified.
*
* @param mixed $o
* @param string $field
*
* @return bool
*/
public static function hasField ($o, $field) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:34: lines 34-35
if (!is_object($o)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:35: characters 4-16
return false;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:36: lines 36-37
if (property_exists($o, $field)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:37: characters 4-15
return true;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:39: lines 39-44
if (($o instanceof HxClass)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:40: characters 4-54
$phpClassName = $o->phpClassName;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:41: lines 41-43
if (!(property_exists($phpClassName, $field) || method_exists($phpClassName, $field))) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:43: characters 8-47
return defined("" . ($phpClassName??'null') . "::" . ($field??'null'));
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:41: lines 41-43
return true;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:46: characters 3-15
return false;
}
/**
* Sets the field named `field` of object `o` to value `value`.
* If `o` has no field named `field`, this function is only guaranteed to
* work for anonymous structures.
* If `o` or `field` are null, the result is unspecified.
*
* @param mixed $o
* @param string $field
* @param mixed $value
*
* @return void
*/
public static function setField ($o, $field, $value) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Reflect.hx:84: characters 3-35
$o->{$field} = $value;
}
}
Boot::registerClass(Reflect::class, 'Reflect');

View file

@ -1,125 +0,0 @@
<?php
/**
*/
use \php\Boot;
use \php\_Boot\HxString;
/**
* The Std class provides standard methods for manipulating basic types.
*/
class Std {
/**
* Converts a `String` to a `Float`.
* The parsing rules for `parseInt` apply here as well, with the exception of invalid input
* resulting in a `NaN` value instead of null.
* Additionally, decimal notation may contain a single `.` to denote the start of the fractions.
*
* @param string $x
*
* @return float
*/
public static function parseFloat ($x) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:74: characters 3-35
$result = floatval($x);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:75: lines 75-76
if (!Boot::equal($result, 0)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:76: characters 4-17
return $result;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:78: characters 3-22
$x = ltrim($x);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:79: characters 3-53
$firstCharIndex = (mb_substr($x, 0, 1) === "-" ? 1 : 0);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:80: characters 3-47
$charCode = HxString::charCodeAt($x, $firstCharIndex);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:82: lines 82-84
if ($charCode === 46) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:83: characters 4-47
$charCode = HxString::charCodeAt($x, $firstCharIndex + 1);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:86: lines 86-90
if (($charCode !== null) && ($charCode >= 48) && ($charCode <= 57)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:87: characters 4-14
return 0.0;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:89: characters 4-20
return NAN;
}
}
/**
* Converts a `String` to an `Int`.
* Leading whitespaces are ignored.
* If `x` starts with 0x or 0X, hexadecimal notation is recognized where the following digits may
* contain 0-9 and A-F.
* Otherwise `x` is read as decimal number with 0-9 being allowed characters. `x` may also start with
* a - to denote a negative value.
* In decimal mode, parsing continues until an invalid character is detected, in which case the
* result up to that point is returned. For hexadecimal notation, the effect of invalid characters
* is unspecified.
* Leading 0s that are not part of the 0x/0X hexadecimal notation are ignored, which means octal
* notation is not supported.
* If `x` is null, the result is unspecified.
* If `x` cannot be parsed as integer, the result is `null`.
*
* @param string $x
*
* @return int
*/
public static function parseInt ($x) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:55: lines 55-70
if (is_numeric($x)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:56: characters 4-31
return intval($x, 10);
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:58: characters 4-23
$x = ltrim($x);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:59: characters 4-54
$firstCharIndex = (mb_substr($x, 0, 1) === "-" ? 1 : 0);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:60: characters 4-53
$firstCharCode = HxString::charCodeAt($x, $firstCharIndex);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:61: lines 61-63
if (!(($firstCharCode !== null) && ($firstCharCode >= 48) && ($firstCharCode <= 57))) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:62: characters 5-16
return null;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:64: characters 21-49
$index = $firstCharIndex + 1;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:64: characters 4-50
$secondChar = ($index < 0 ? "" : mb_substr($x, $index, 1));
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:65: lines 65-69
if (($secondChar === "x") || ($secondChar === "X")) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:66: characters 5-31
return intval($x, 0);
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:68: characters 5-32
return intval($x, 10);
}
}
}
/**
* Converts any value to a String.
* If `s` is of `String`, `Int`, `Float` or `Bool`, its value is returned.
* If `s` is an instance of a class and that class or one of its parent classes has
* a `toString` method, that method is called. If no such method is present, the result
* is unspecified.
* If `s` is an enum constructor without argument, the constructor's name is returned. If
* arguments exists, the constructor's name followed by the String representations of
* the arguments is returned.
* If `s` is a structure, the field names along with their values are returned. The field order
* and the operator separating field names and values are unspecified.
* If s is null, "null" is returned.
*
* @param mixed $s
*
* @return string
*/
public static function string ($s) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/Std.hx:47: characters 3-27
return Boot::stringify($s);
}
}
Boot::registerClass(Std::class, 'Std');

View file

@ -1,40 +0,0 @@
<?php
/**
*/
use \php\Boot;
/**
* This class provides advanced methods on Strings. It is ideally used with
* `using StringTools` and then acts as an [extension](https://haxe.org/manual/lf-static-extension.html)
* to the `String` class.
* If the first argument to any of the methods is null, the result is
* unspecified.
*/
class StringTools {
/**
* Replace all occurrences of the String `sub` in the String `s` by the
* String `by`.
* If `sub` is the empty String `""`, `by` is inserted after each character
* of `s` except the last one. If `by` is also the empty String `""`, `s`
* remains unchanged.
* If `sub` or `by` are null, the result is unspecified.
*
* @param string $s
* @param string $sub
* @param string $by
*
* @return string
*/
public static function replace ($s, $sub, $by) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/StringTools.hx:104: lines 104-106
if ($sub === "") {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/StringTools.hx:105: characters 4-89
return implode($by, preg_split("//u", $s, -1, PREG_SPLIT_NO_EMPTY));
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/StringTools.hx:107: characters 3-40
return str_replace($sub, $by, $s);
}
}
Boot::registerClass(StringTools::class, 'StringTools');

View file

@ -1,125 +0,0 @@
<?php
/**
*/
namespace haxe;
use \php\Boot;
/**
* Base class for exceptions.
* If this class (or derivatives) is used to catch an exception, then
* `haxe.CallStack.exceptionStack()` will not return a stack for the exception
* caught. Use `haxe.Exception.stack` property instead:
* ```haxe
* try {
* throwSomething();
* } catch(e:Exception) {
* trace(e.stack);
* }
* ```
* Custom exceptions should extend this class:
* ```haxe
* class MyException extends haxe.Exception {}
* //...
* throw new MyException('terrible exception');
* ```
* `haxe.Exception` is also a wildcard type to catch any exception:
* ```haxe
* try {
* throw 'Catch me!';
* } catch(e:haxe.Exception) {
* trace(e.message); // Output: Catch me!
* }
* ```
* To rethrow an exception just throw it again.
* Haxe will try to rethrow an original native exception whenever possible.
* ```haxe
* try {
* var a:Array<Int> = null;
* a.push(1); // generates target-specific null-pointer exception
* } catch(e:haxe.Exception) {
* throw e; // rethrows native exception instead of haxe.Exception
* }
* ```
*/
class Exception extends \Exception {
/**
* @var \Throwable
*/
public $__nativeException;
/**
* @var Exception
*/
public $__previousException;
/**
* @var int
*/
public $__skipStack;
/**
* @param mixed $value
*
* @return mixed
*/
public static function thrown ($value) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:30: lines 30-38
if (($value instanceof Exception)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:31: characters 4-35
return $value->get_native();
} else if (($value instanceof \Throwable)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:33: characters 4-16
return $value;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:35: characters 4-38
$e = new ValueException($value);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:36: characters 4-21
$e->__skipStack = 1;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:37: characters 4-12
return $e;
}
}
/**
* Create a new Exception instance.
* The `previous` argument could be used for exception chaining.
* The `native` argument is for internal usage only.
* There is no need to provide `native` argument manually and no need to keep it
* upon extending `haxe.Exception` unless you know what you're doing.
*
* @param string $message
* @param Exception $previous
* @param mixed $native
*
* @return void
*/
public function __construct ($message, $previous = null, $native = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:16: characters 39-40
$this->__skipStack = 0;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:42: characters 3-30
parent::__construct($message, 0, $previous);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:43: characters 3-38
$this->__previousException = $previous;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:44: lines 44-48
if (($native !== null) && ($native instanceof \Throwable)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:45: characters 4-30
$this->__nativeException = $native;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:47: characters 4-33
$this->__nativeException = $this;
}
}
/**
* @return mixed
*/
final public function get_native () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/_std/haxe/Exception.hx:72: characters 3-27
return $this->__nativeException;
}
}
Boot::registerClass(Exception::class, 'haxe.Exception');
Boot::registerGetters('haxe\\Exception', [
'native' => true
]);

View file

@ -1,88 +0,0 @@
<?php
/**
*/
namespace haxe;
use \php\Boot;
/**
* Log primarily provides the `trace()` method, which is invoked upon a call to
* `trace()` in Haxe code.
*/
class Log {
/**
* @var \Closure
* Outputs `v` in a platform-dependent way.
* The second parameter `infos` is injected by the compiler and contains
* information about the position where the `trace()` call was made.
* This method can be rebound to a custom function:
* var oldTrace = haxe.Log.trace; // store old function
* haxe.Log.trace = function(v, ?infos) {
* // handle trace
* }
* ...
* haxe.Log.trace = oldTrace;
* If it is bound to null, subsequent calls to `trace()` will cause an
* exception.
*/
static public $trace;
/**
* Format the output of `trace` before printing it.
*
* @param mixed $v
* @param object $infos
*
* @return string
*/
public static function formatOutput ($v, $infos) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:34: characters 3-27
$str = \Std::string($v);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:35: lines 35-36
if ($infos === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:36: characters 4-14
return $str;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:37: characters 3-54
$pstr = ($infos->fileName??'null') . ":" . ($infos->lineNumber??'null');
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:38: lines 38-40
if ($infos->customParams !== null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:39: lines 39-40
$_g = 0;
$_g1 = $infos->customParams;
while ($_g < $_g1->length) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:39: characters 9-10
$v = ($_g1->arr[$_g] ?? null);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:39: lines 39-40
++$_g;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:40: characters 5-32
$str = ($str??'null') . ", " . \Std::string($v);
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:41: characters 3-27
return ($pstr??'null') . ": " . ($str??'null');
}
/**
* @internal
* @access private
*/
static public function __hx__init ()
{
static $called = false;
if ($called) return;
$called = true;
self::$trace = function ($v, $infos = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:63: characters 3-36
$str = Log::formatOutput($v, $infos);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/Log.hx:70: characters 3-19
echo(\Std::string($str) . \PHP_EOL);
};
}
}
Boot::registerClass(Log::class, 'haxe.Log');
Log::__hx__init();

View file

@ -1,44 +0,0 @@
<?php
/**
*/
namespace haxe;
use \php\Boot;
/**
* An exception containing arbitrary value.
* This class is automatically used for throwing values, which don't extend `haxe.Exception`
* or native exception type.
* For example:
* ```haxe
* throw "Terrible error";
* ```
* will be compiled to
* ```haxe
* throw new ValueException("Terrible error");
* ```
*/
class ValueException extends Exception {
/**
* @var mixed
* Thrown value.
*/
public $value;
/**
* @param mixed $value
* @param Exception $previous
* @param mixed $native
*
* @return void
*/
public function __construct ($value, $previous = null, $native = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/ValueException.hx:24: characters 3-100
parent::__construct(\Std::string($value), $previous, $native);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/ValueException.hx:25: characters 3-21
$this->value = $value;
}
}
Boot::registerClass(ValueException::class, 'haxe.ValueException');

View file

@ -1,57 +0,0 @@
<?php
/**
*/
namespace haxe\iterators;
use \php\Boot;
/**
* This iterator is used only when `Array<T>` is passed to `Iterable<T>`
*/
class ArrayIterator {
/**
* @var mixed[]|\Array_hx
*/
public $array;
/**
* @var int
*/
public $current;
/**
* Create a new `ArrayIterator`.
*
* @param mixed[]|\Array_hx $array
*
* @return void
*/
public function __construct ($array) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/iterators/ArrayIterator.hx:30: characters 20-21
$this->current = 0;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/iterators/ArrayIterator.hx:37: characters 3-21
$this->array = $array;
}
/**
* See `Iterator.hasNext`
*
* @return bool
*/
public function hasNext () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/iterators/ArrayIterator.hx:45: characters 3-32
return $this->current < $this->array->length;
}
/**
* See `Iterator.next`
*
* @return mixed
*/
public function next () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/iterators/ArrayIterator.hx:53: characters 3-26
return ($this->array->arr[$this->current++] ?? null);
}
}
Boot::registerClass(ArrayIterator::class, 'haxe.iterators.ArrayIterator');

View file

@ -1,26 +0,0 @@
<?php
/**
*/
namespace haxe\iterators;
use \php\Boot;
class ArrayKeyValueIterator {
/**
* @var mixed[]|\Array_hx
*/
public $array;
/**
* @param mixed[]|\Array_hx $array
*
* @return void
*/
public function __construct ($array) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/haxe/iterators/ArrayKeyValueIterator.hx:32: characters 3-21
$this->array = $array;
}
}
Boot::registerClass(ArrayKeyValueIterator::class, 'haxe.iterators.ArrayKeyValueIterator');

File diff suppressed because it is too large Load diff

View file

@ -1,43 +0,0 @@
<?php
/**
*/
namespace php\_Boot;
use \php\Boot;
/**
* Anonymous objects implementation
*/
class HxAnon extends \StdClass {
/**
* @return void
*/
public function __construct () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:950: lines 950-960
;
}
/**
* @param string $name
* @param array $args
*
* @return mixed
*/
public function __call ($name, $args) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:958: characters 3-57
return ($this->$name)(...$args);
}
/**
* @param string $name
*
* @return mixed
*/
public function __get ($name) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:953: characters 3-14
return null;
}
}
Boot::registerClass(HxAnon::class, 'php._Boot.HxAnon');

View file

@ -1,95 +0,0 @@
<?php
/**
*/
namespace php\_Boot;
use \php\Boot;
/**
* Class<T> implementation for Haxe->PHP internals.
*/
class HxClass {
/**
* @var string
*/
public $phpClassName;
/**
* @param string $phpClassName
*
* @return void
*/
public function __construct ($phpClassName) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:667: characters 3-35
$this->phpClassName = $phpClassName;
}
/**
* Magic method to call static methods of this class, when `HxClass` instance is in a `Dynamic` variable.
*
* @param string $method
* @param array $args
*
* @return mixed
*/
public function __call ($method, $args) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:675: characters 3-111
$callback = ((($this->phpClassName === "String" ? HxString::class : $this->phpClassName))??'null') . "::" . ($method??'null');
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:676: characters 3-53
return \call_user_func_array($callback, $args);
}
/**
* Magic method to get static vars of this class, when `HxClass` instance is in a `Dynamic` variable.
*
* @param string $property
*
* @return mixed
*/
public function __get ($property) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:684: lines 684-692
if (\defined("" . ($this->phpClassName??'null') . "::" . ($property??'null'))) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:685: characters 4-54
return \constant("" . ($this->phpClassName??'null') . "::" . ($property??'null'));
} else if (Boot::hasGetter($this->phpClassName, $property)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:687: characters 29-41
$tmp = $this->phpClassName;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:687: characters 4-59
return $tmp::{"get_" . ($property??'null')}();
} else if (\method_exists($this->phpClassName, $property)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:689: characters 4-56
return Boot::getStaticClosure($this->phpClassName, $property);
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:691: characters 33-45
$tmp = $this->phpClassName;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:691: characters 4-56
return $tmp::${$property};
}
}
/**
* Magic method to set static vars of this class, when `HxClass` instance is in a `Dynamic` variable.
*
* @param string $property
* @param mixed $value
*
* @return void
*/
public function __set ($property, $value) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:700: lines 700-704
if (Boot::hasSetter($this->phpClassName, $property)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:701: characters 22-34
$tmp = $this->phpClassName;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:701: characters 4-59
$tmp::{"set_" . ($property??'null')}($value);
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:703: characters 26-38
$tmp = $this->phpClassName;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:703: characters 4-56
$tmp::${$property} = $value;
}
}
}
Boot::registerClass(HxClass::class, 'php._Boot.HxClass');

View file

@ -1,114 +0,0 @@
<?php
/**
*/
namespace php\_Boot;
use \php\Boot;
use \haxe\Exception;
/**
* Closures implementation
*/
class HxClosure {
/**
* @var mixed
* A callable value, which can be invoked by PHP
*/
public $callable;
/**
* @var string
* Method name for methods
*/
public $func;
/**
* @var mixed
* `this` for instance methods; php class name for static methods
*/
public $target;
/**
* @param mixed $target
* @param string $func
*
* @return void
*/
public function __construct ($target, $func) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:978: characters 3-23
$this->target = $target;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:979: characters 3-19
$this->func = $func;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:981: lines 981-983
if (\is_null($target)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:982: characters 4-9
throw Exception::thrown("Unable to create closure on `null`");
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:984: characters 3-104
$this->callable = (($target instanceof HxAnon) ? $target->{$func} : [$target, $func]);
}
/**
* @see http://php.net/manual/en/language.oop5.magic.php#object.invoke
*
* @return mixed
*/
public function __invoke () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:992: characters 3-71
return \call_user_func_array($this->callable, \func_get_args());
}
/**
* Invoke this closure with `newThis` instead of `this`
*
* @param mixed $newThis
* @param array $args
*
* @return mixed
*/
public function callWith ($newThis, $args) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1019: characters 3-65
return \call_user_func_array($this->getCallback($newThis), $args);
}
/**
* Check if this is the same closure
*
* @param HxClosure $closure
*
* @return bool
*/
public function equals ($closure) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1012: characters 10-60
if (Boot::equal($this->target, $closure->target)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1012: characters 39-59
return $this->func === $closure->func;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1012: characters 10-60
return false;
}
}
/**
* Generates callable value for PHP
*
* @param mixed $eThis
*
* @return mixed[]
*/
public function getCallback ($eThis = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:999: lines 999-1001
if ($eThis === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1000: characters 4-18
$eThis = $this->target;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1002: lines 1002-1004
if (($eThis instanceof HxAnon)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1003: characters 4-36
return $eThis->{$this->func};
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:1005: characters 3-39
return [$eThis, $this->func];
}
}
Boot::registerClass(HxClosure::class, 'php._Boot.HxClosure');

View file

@ -1,160 +0,0 @@
<?php
/**
*/
namespace php\_Boot;
use \php\Boot;
/**
* For Dynamic access which looks like String.
* Instances of this class should not be saved anywhere.
* Instead it should be used to immediately invoke a String field right after instance creation one time only.
*/
class HxDynamicStr extends HxClosure {
/**
* @var string
*/
static public $hxString;
/**
* @param string $str
* @param string $method
* @param array $args
*
* @return mixed
*/
public static function invoke ($str, $method, $args) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:892: characters 3-34
\array_unshift($args, $str);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:893: characters 3-69
return \call_user_func_array((HxDynamicStr::$hxString??'null') . "::" . ($method??'null'), $args);
}
/**
* Returns HxDynamicStr instance if `value` is a string.
* Otherwise returns `value` as-is.
*
* @param mixed $value
*
* @return mixed
*/
public static function wrap ($value) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:884: lines 884-888
if (\is_string($value)) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:885: characters 4-34
return new HxDynamicStr($value);
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:887: characters 4-16
return $value;
}
}
/**
* @param string $str
*
* @return void
*/
public function __construct ($str) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:897: characters 3-19
parent::__construct($str, null);
}
/**
* @param string $method
* @param array $args
*
* @return mixed
*/
public function __call ($method, $args) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:913: characters 10-38
\array_unshift($args, $this->target);
return \call_user_func_array((HxDynamicStr::$hxString??'null') . "::" . ($method??'null'), $args);
}
/**
* @param string $field
*
* @return mixed
*/
public function __get ($field) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:902: lines 902-908
if ($field === "length") {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:904: characters 5-36
return mb_strlen($this->target);
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:906: characters 5-17
$this->func = $field;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:907: characters 5-16
return $this;
}
}
/**
* @see http://php.net/manual/en/language.oop5.magic.php#object.invoke
*
* @return mixed
*/
public function __invoke () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:921: characters 10-54
$str = $this->target;
$method = $this->func;
$args = \func_get_args();
\array_unshift($args, $str);
return \call_user_func_array((HxDynamicStr::$hxString??'null') . "::" . ($method??'null'), $args);
}
/**
* Invoke this closure with `newThis` instead of `this`
*
* @param mixed $newThis
* @param array $args
*
* @return mixed
*/
public function callWith ($newThis, $args) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:938: lines 938-940
if ($newThis === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:939: characters 4-20
$newThis = $this->target;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:941: characters 10-37
$method = $this->func;
\array_unshift($args, $newThis);
return \call_user_func_array((HxDynamicStr::$hxString??'null') . "::" . ($method??'null'), $args);
}
/**
* Generates callable value for PHP
*
* @param mixed $eThis
*
* @return mixed[]
*/
public function getCallback ($eThis = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:928: lines 928-930
if ($eThis === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:929: characters 4-51
return [$this, $this->func];
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:931: characters 3-69
return [new HxDynamicStr($eThis), $this->func];
}
/**
* @internal
* @access private
*/
static public function __hx__init ()
{
static $called = false;
if ($called) return;
$called = true;
self::$hxString = Boot::getClass(HxString::class)->phpClassName;
}
}
Boot::registerClass(HxDynamicStr::class, 'php._Boot.HxDynamicStr');
HxDynamicStr::__hx__init();

View file

@ -1,73 +0,0 @@
<?php
/**
*/
namespace php\_Boot;
use \php\Boot;
/**
* Base class for enum types
*/
class HxEnum {
/**
* @var int
*/
public $index;
/**
* @var array
*/
public $params;
/**
* @var string
*/
public $tag;
/**
* @param string $tag
* @param int $index
* @param array $arguments
*
* @return void
*/
public function __construct ($tag, $index, $arguments = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:721: characters 3-17
$this->tag = $tag;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:722: characters 3-21
$this->index = $index;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:723: characters 12-63
$tmp = null;
if ($arguments === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:723: characters 33-50
$this1 = [];
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:723: characters 12-63
$tmp = $this1;
} else {
$tmp = $arguments;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:723: characters 3-63
$this->params = $tmp;
}
/**
* PHP magic method to get string representation of this `Class`
*
* @return string
*/
public function __toString () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:738: characters 3-30
return Boot::stringify($this);
}
/**
* Get string representation of this `Class`
*
* @return string
*/
public function toString () {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:730: characters 3-22
return $this->__toString();
}
}
Boot::registerClass(HxEnum::class, 'php._Boot.HxEnum');

View file

@ -1,294 +0,0 @@
<?php
/**
*/
namespace php\_Boot;
use \php\Boot;
/**
* `String` implementation
*/
class HxString {
/**
* @param string $str
* @param int $index
*
* @return string
*/
public static function charAt ($str, $index) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:759: characters 10-58
if ($index < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:759: characters 22-24
return "";
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:759: characters 27-58
return \mb_substr($str, $index, 1);
}
}
/**
* @param string $str
* @param int $index
*
* @return int
*/
public static function charCodeAt ($str, $index) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:763: lines 763-765
if (($index < 0) || ($str === "")) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:764: characters 4-15
return null;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:766: lines 766-768
if ($index === 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:767: characters 11-30
$code = \ord($str[0]);
if ($code < 192) {
return $code;
} else if ($code < 224) {
return (($code - 192) << 6) + \ord($str[1]) - 128;
} else if ($code < 240) {
return (($code - 224) << 12) + ((\ord($str[1]) - 128) << 6) + \ord($str[2]) - 128;
} else {
return (($code - 240) << 18) + ((\ord($str[1]) - 128) << 12) + ((\ord($str[2]) - 128) << 6) + \ord($str[3]) - 128;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:769: characters 3-46
$char = \mb_substr($str, $index, 1);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:770: characters 10-50
if ($char === "") {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:770: characters 23-27
return null;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:770: characters 30-50
$code = \ord($char[0]);
if ($code < 192) {
return $code;
} else if ($code < 224) {
return (($code - 192) << 6) + \ord($char[1]) - 128;
} else if ($code < 240) {
return (($code - 224) << 12) + ((\ord($char[1]) - 128) << 6) + \ord($char[2]) - 128;
} else {
return (($code - 240) << 18) + ((\ord($char[1]) - 128) << 12) + ((\ord($char[2]) - 128) << 6) + \ord($char[3]) - 128;
}
}
}
/**
* @param int $code
*
* @return string
*/
public static function fromCharCode ($code) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:865: characters 3-29
return \mb_chr($code);
}
/**
* @param string $str
* @param string $search
* @param int $startIndex
*
* @return int
*/
public static function indexOf ($str, $search, $startIndex = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:774: lines 774-787
if ($startIndex === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:775: characters 4-18
$startIndex = 0;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:777: characters 4-28
$length = mb_strlen($str);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:778: lines 778-783
if ($startIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:779: characters 5-25
$startIndex += $length;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:780: lines 780-782
if ($startIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:781: characters 6-20
$startIndex = 0;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:784: lines 784-786
if (($startIndex >= $length) && ($search !== "")) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:785: characters 5-14
return -1;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:788: lines 788-793
$index = null;
if ($search === "") {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:789: characters 4-28
$length = mb_strlen($str);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:788: lines 788-793
$index = ($startIndex > $length ? $length : $startIndex);
} else {
$index = \mb_strpos($str, $search, $startIndex);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:794: characters 10-39
if ($index === false) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:794: characters 28-30
return -1;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:794: characters 33-38
return $index;
}
}
/**
* @param string $str
* @param string $search
* @param int $startIndex
*
* @return int
*/
public static function lastIndexOf ($str, $search, $startIndex = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:798: characters 3-26
$start = $startIndex;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:799: lines 799-811
if ($start === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:800: characters 4-13
$start = 0;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:802: characters 4-28
$length = mb_strlen($str);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:803: lines 803-810
if ($start >= 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:804: characters 5-27
$start -= $length;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:805: lines 805-807
if ($start > 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:806: characters 6-15
$start = 0;
}
} else if ($start < -$length) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:809: characters 5-20
$start = -$length;
}
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:812: lines 812-817
$index = null;
if ($search === "") {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:813: characters 4-28
$length = mb_strlen($str);
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:812: lines 812-817
$index = (($startIndex === null) || ($startIndex > $length) ? $length : $startIndex);
} else {
$index = \mb_strrpos($str, $search, $start);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:818: lines 818-822
if ($index === false) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:819: characters 4-13
return -1;
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:821: characters 4-16
return $index;
}
}
/**
* @param string $str
* @param string $delimiter
*
* @return string[]|\Array_hx
*/
public static function split ($str, $delimiter) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:826: lines 826-831
$arr = null;
if ($delimiter === "") {
$arr = \preg_split("//u", $str, -1, \PREG_SPLIT_NO_EMPTY);
} else {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:829: characters 4-49
$delimiter = \preg_quote($delimiter, "/");
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:826: lines 826-831
$arr = \preg_split("/" . ($delimiter??'null') . "/", $str);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:832: characters 3-41
return \Array_hx::wrap($arr);
}
/**
* @param string $str
* @param int $pos
* @param int $len
*
* @return string
*/
public static function substr ($str, $pos, $len = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:836: characters 3-41
return \mb_substr($str, $pos, $len);
}
/**
* @param string $str
* @param int $startIndex
* @param int $endIndex
*
* @return string
*/
public static function substring ($str, $startIndex, $endIndex = null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:840: lines 840-845
if ($endIndex === null) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:841: lines 841-843
if ($startIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:842: characters 5-19
$startIndex = 0;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:844: characters 4-44
return \mb_substr($str, $startIndex);
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:846: lines 846-848
if ($endIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:847: characters 4-16
$endIndex = 0;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:849: lines 849-851
if ($startIndex < 0) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:850: characters 4-18
$startIndex = 0;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:852: lines 852-856
if ($startIndex > $endIndex) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:853: characters 4-23
$tmp = $endIndex;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:854: characters 4-25
$endIndex = $startIndex;
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:855: characters 4-20
$startIndex = $tmp;
}
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:857: characters 3-66
return \mb_substr($str, $startIndex, $endIndex - $startIndex);
}
/**
* @param string $str
*
* @return string
*/
public static function toLowerCase ($str) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:755: characters 3-35
return \mb_strtolower($str);
}
/**
* @param string $str
*
* @return string
*/
public static function toString ($str) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:861: characters 3-13
return $str;
}
/**
* @param string $str
*
* @return string
*/
public static function toUpperCase ($str) {
#/nix/store/ljakxdz94hcvn9b4k9y292dn5lhh20iy-haxe-4.2.5/lib/haxe/std/php/Boot.hx:751: characters 3-35
return \mb_strtoupper($str);
}
}
Boot::registerClass(HxString::class, 'php._Boot.HxString');

View file

@ -1,63 +0,0 @@
<?php
/**
* Polyfills for some functions, which are required by Haxe-generated code, but not available in PHP 7.0.
* No Haxe-generated code is available at this point.
* No code should be executed from this file.
* Symbols declarations are the only code allowed here.
*/
namespace { //Namespace declaration is required because this file is included under non-root namespace.
/**
* @see http://php.net/manual/en/function.mb-chr.php
*/
if(!function_exists('mb_chr')) {
function mb_chr($code, $encoding = null) {
if($encoding && $encoding !== 'UTF-8') {
throw new Exception("$encoding is not supported in mb_chr() polyfill.");
}
if (0x80 > $code %= 0x200000) {
$s = chr($code);
} elseif (0x800 > $code) {
$s = chr(0xC0 | $code >> 6) . chr(0x80 | $code & 0x3F);
} elseif (0x10000 > $code) {
$s = chr(0xE0 | $code >> 12) . chr(0x80 | $code >> 6 & 0x3F) . chr(0x80 | $code & 0x3F);
} else {
$s = chr(0xF0 | $code >> 18) . chr(0x80 | $code >> 12 & 0x3F) . chr(0x80 | $code >> 6 & 0x3F) . chr(0x80 | $code & 0x3F);
}
return $s;
}
}
/**
* @see http://php.net/manual/en/function.mb-ord.php
*/
if(!function_exists('mb_ord')) {
function mb_ord($s, $encoding = null) {
if($encoding && $encoding !== 'UTF-8') {
throw new Exception("$encoding is not supported in mb_ord() polyfill.");
}
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $s[2] - 0x80;
}
return $code;
}
}
/**
* @see http://php.net/manual/en/function.mb-scrub.php
*/
if(!function_exists('mb_scrub')) {
function mb_scrub($s, $encoding = null) {
$encoding = null === $encoding ? mb_internal_encoding() : $encoding;
return mb_convert_encoding($s, $encoding, $encoding);
}
}
}

View file

@ -1,139 +0,0 @@
<?php
/**
*/
namespace xrfragment;
use \php\_Boot\HxAnon;
use \php\Boot;
use \haxe\Log;
use \php\_Boot\HxString;
class Parser {
/**
* @var bool
*/
static public $debug = false;
/**
* @var string
*/
static public $error = "";
/**
* @param string $key
* @param string $value
* @param mixed $store
*
* @return bool
*/
public static function parse ($key, $value, $store) {
#src/xrfragment/Parser.hx:17: characters 35-57
$this1 = [];
$Frag_data = $this1;
#src/xrfragment/Parser.hx:20: characters 7-68
$Frag_data["prio"] = XRF::$ASSET | XRF::$T_INT;
#src/xrfragment/Parser.hx:21: characters 7-68
$Frag_data["#"] = XRF::$ASSET | XRF::$T_PREDEFINED_VIEW;
#src/xrfragment/Parser.hx:22: characters 7-68
$Frag_data["class"] = XRF::$ASSET | XRF::$T_STRING;
#src/xrfragment/Parser.hx:23: characters 7-68
$Frag_data["src"] = XRF::$ASSET | XRF::$T_URL;
#src/xrfragment/Parser.hx:26: characters 7-133
$Frag_data["pos"] = XRF::$PV_OVERRIDE | XRF::$ROUNDROBIN | XRF::$T_VECTOR3 | XRF::$T_STRING_OBJ | XRF::$EMBEDDED | XRF::$NAVIGATOR;
#src/xrfragment/Parser.hx:27: characters 7-97
$Frag_data["href"] = XRF::$ASSET | XRF::$T_URL | XRF::$T_PREDEFINED_VIEW;
#src/xrfragment/Parser.hx:30: characters 7-98
$Frag_data["q"] = XRF::$PV_OVERRIDE | XRF::$T_STRING | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:31: characters 7-119
$Frag_data["scale"] = XRF::$QUERY_OPERATOR | XRF::$PV_OVERRIDE | XRF::$ROUNDROBIN | XRF::$T_VECTOR3 | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:32: characters 7-135
$Frag_data["rot"] = XRF::$QUERY_OPERATOR | XRF::$PV_OVERRIDE | XRF::$ROUNDROBIN | XRF::$T_VECTOR3 | XRF::$EMBEDDED | XRF::$NAVIGATOR;
#src/xrfragment/Parser.hx:33: characters 7-119
$Frag_data["translate"] = XRF::$QUERY_OPERATOR | XRF::$PV_OVERRIDE | XRF::$ROUNDROBIN | XRF::$T_VECTOR3 | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:34: characters 7-119
$Frag_data["visible"] = XRF::$QUERY_OPERATOR | XRF::$PV_OVERRIDE | XRF::$ROUNDROBIN | XRF::$T_INT | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:35: characters 7-92
$Frag_data["env"] = XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$T_STRING | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:38: characters 7-125
$Frag_data["t"] = XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$ROUNDROBIN | XRF::$T_VECTOR2 | XRF::$NAVIGATOR | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:39: characters 7-93
$Frag_data["gravity"] = XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$T_VECTOR3 | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:40: characters 7-93
$Frag_data["physics"] = XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$T_VECTOR3 | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:43: characters 7-109
$Frag_data["fov"] = XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$T_INT | XRF::$NAVIGATOR | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:44: characters 7-109
$Frag_data["clip"] = XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$T_VECTOR2 | XRF::$NAVIGATOR | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:45: characters 7-109
$Frag_data["fog"] = XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$T_STRING | XRF::$NAVIGATOR | XRF::$EMBEDDED;
#src/xrfragment/Parser.hx:48: characters 7-92
$Frag_data["namespace"] = XRF::$ASSET | XRF::$T_STRING;
#src/xrfragment/Parser.hx:49: characters 7-92
$Frag_data["SPDX"] = XRF::$ASSET | XRF::$T_STRING;
#src/xrfragment/Parser.hx:50: characters 7-92
$Frag_data["unit"] = XRF::$ASSET | XRF::$T_STRING;
#src/xrfragment/Parser.hx:51: characters 7-92
$Frag_data["description"] = XRF::$ASSET | XRF::$T_STRING;
#src/xrfragment/Parser.hx:54: characters 7-114
$Frag_data["session"] = XRF::$ASSET | XRF::$T_URL | XRF::$PV_OVERRIDE | XRF::$NAVIGATOR | XRF::$EMBEDDED | XRF::$PROMPT;
#src/xrfragment/Parser.hx:67: lines 67-72
if ((mb_strlen($value) === 0) && (mb_strlen($key) > 0) && !\array_key_exists($key, $Frag_data)) {
#src/xrfragment/Parser.hx:68: characters 5-64
$v = new XRF($key, XRF::$PV_EXECUTE | XRF::$NAVIGATOR);
#src/xrfragment/Parser.hx:69: characters 9-24
$v->validate($key);
#src/xrfragment/Parser.hx:70: characters 5-23
\Reflect::setField($store, $key, $v);
#src/xrfragment/Parser.hx:71: characters 5-16
return true;
}
#src/xrfragment/Parser.hx:73: lines 73-76
if ((HxString::split($key, ".")->length > 1) && (HxString::split($value, ".")->length > 1)) {
#src/xrfragment/Parser.hx:74: characters 5-95
$value1 = new XRF($key, XRF::$ASSET | XRF::$PV_OVERRIDE | XRF::$T_STRING | XRF::$PROP_BIND);
\Reflect::setField($store, $key, $value1);
#src/xrfragment/Parser.hx:75: characters 5-16
return true;
}
#src/xrfragment/Parser.hx:79: characters 7-47
$v = new XRF($key, ($Frag_data[$key] ?? null));
#src/xrfragment/Parser.hx:80: lines 80-90
if (\array_key_exists($key, $Frag_data)) {
#src/xrfragment/Parser.hx:81: lines 81-84
if (!$v->validate($value)) {
#src/xrfragment/Parser.hx:82: characters 11-16
(Log::$trace)("⚠ fragment '" . ($key??'null') . "' has incompatible value (" . ($value??'null') . ")", new _HxAnon_Parser0("src/xrfragment/Parser.hx", 82, "xrfragment.Parser", "parse"));
#src/xrfragment/Parser.hx:83: characters 11-23
return false;
}
#src/xrfragment/Parser.hx:85: characters 9-27
\Reflect::setField($store, $key, $v);
#src/xrfragment/Parser.hx:86: characters 9-50
if (Parser::$debug) {
#src/xrfragment/Parser.hx:86: characters 21-26
(Log::$trace)("" . ($key??'null') . ": " . ($v->string??'null'), new _HxAnon_Parser0("src/xrfragment/Parser.hx", 86, "xrfragment.Parser", "parse"));
}
} else {
#src/xrfragment/Parser.hx:88: characters 9-63
if (is_string($value)) {
#src/xrfragment/Parser.hx:88: characters 43-63
$v->guessType($v, $value);
}
#src/xrfragment/Parser.hx:89: characters 9-29
\Reflect::setField($store, "_" . ($key??'null'), $v);
}
#src/xrfragment/Parser.hx:92: characters 7-18
return true;
}
}
class _HxAnon_Parser0 extends HxAnon {
function __construct($fileName, $lineNumber, $className, $methodName) {
$this->fileName = $fileName;
$this->lineNumber = $lineNumber;
$this->className = $className;
$this->methodName = $methodName;
}
}
Boot::registerClass(Parser::class, 'xrfragment.Parser');

View file

@ -1,393 +0,0 @@
<?php
/**
*/
namespace xrfragment;
use \php\_Boot\HxAnon;
use \php\Boot;
use \php\_Boot\HxString;
class Query {
/**
* @var \EReg
*/
public $isClass;
/**
* @var \EReg
*/
public $isExclude;
/**
* @var \EReg
*/
public $isNumber;
/**
* @var \EReg
*/
public $isProp;
/**
* @var \EReg
*/
public $isRoot;
/**
* @var mixed
*/
public $q;
/**
* @var string
* # Spec
*
* > version 1.0.0 [![Actions Status](https://github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions) generated by `make doc` @ $(date +"%Y-%m-%dT%H:%M:%S%z")
*
* In case your programming language has no parser ([check here](https://github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Query.parse(str)` using the spec:
*/
public $str;
/**
* @param string $str
*
* @return void
*/
public function __construct ($str) {
#src/xrfragment/Query.hx:59: characters 36-49
$this->isNumber = new \EReg("^[0-9\\.]+\$", "");
#src/xrfragment/Query.hx:58: characters 36-50
$this->isClass = new \EReg("^[-]?class\$", "");
#src/xrfragment/Query.hx:57: characters 36-46
$this->isRoot = new \EReg("^[-]?/", "");
#src/xrfragment/Query.hx:56: characters 36-41
$this->isExclude = new \EReg("^-", "");
#src/xrfragment/Query.hx:55: characters 36-50
$this->isProp = new \EReg("^.*:[><=!]?", "");
#src/xrfragment/Query.hx:54: characters 47-49
$this->q = new HxAnon();
#src/xrfragment/Query.hx:53: characters 28-30
$this->str = "";
#src/xrfragment/Query.hx:62: characters 5-39
if ($str !== null) {
#src/xrfragment/Query.hx:62: characters 24-39
$this->parse($str);
}
}
/**
* @param string $token
*
* @return string
*/
public function expandAliases ($token) {
#src/xrfragment/Query.hx:71: characters 5-33
$classAlias = new \EReg("^(-)?\\.", "");
#src/xrfragment/Query.hx:72: characters 12-85
if ($classAlias->match($token)) {
#src/xrfragment/Query.hx:72: characters 38-77
return \StringTools::replace($token, ".", "class:");
} else {
#src/xrfragment/Query.hx:72: characters 80-85
return $token;
}
}
/**
* @return mixed
*/
public function get () {
#src/xrfragment/Query.hx:76: characters 5-18
return $this->q;
}
/**
* @param string $str
*
* @return mixed
*/
public function parse ($str) {
#src/xrfragment/Query.hx:79: lines 79-126
$_gthis = $this;
#src/xrfragment/Query.hx:81: characters 5-32
$token = HxString::split($str, " ");
#src/xrfragment/Query.hx:82: characters 5-44
$q = new HxAnon();
#src/xrfragment/Query.hx:84: lines 84-123
$process = function ($str, $prefix = "") use (&$_gthis, &$q) {
if ($prefix === null) {
$prefix = "";
}
#src/xrfragment/Query.hx:85: characters 7-34
$str = \trim($str);
#src/xrfragment/Query.hx:86: characters 7-40
$k = (HxString::split($str, ":")->arr[0] ?? null);
#src/xrfragment/Query.hx:87: characters 7-40
$v = (HxString::split($str, ":")->arr[1] ?? null);
#src/xrfragment/Query.hx:89: characters 7-51
$filter = new HxAnon();
#src/xrfragment/Query.hx:90: characters 7-53
if (\Reflect::field($q, ($prefix??'null') . ($k??'null'))) {
#src/xrfragment/Query.hx:90: characters 29-53
$filter = \Reflect::field($q, ($prefix??'null') . ($k??'null'));
}
#src/xrfragment/Query.hx:91: characters 7-89
$value = (\Reflect::field($filter, "rules") !== null ? \Reflect::field($filter, "rules") : new \Array_hx());
\Reflect::setField($filter, "rules", $value);
#src/xrfragment/Query.hx:93: lines 93-122
if ($_gthis->isProp->match($str)) {
#src/xrfragment/Query.hx:94: characters 9-30
$oper = "";
#src/xrfragment/Query.hx:95: characters 9-49
if (HxString::indexOf($str, "*") !== -1) {
#src/xrfragment/Query.hx:95: characters 39-49
$oper = "*";
}
#src/xrfragment/Query.hx:96: characters 9-49
if (HxString::indexOf($str, ">") !== -1) {
#src/xrfragment/Query.hx:96: characters 39-49
$oper = ">";
}
#src/xrfragment/Query.hx:97: characters 9-49
if (HxString::indexOf($str, "<") !== -1) {
#src/xrfragment/Query.hx:97: characters 39-49
$oper = "<";
}
#src/xrfragment/Query.hx:98: characters 9-50
if (HxString::indexOf($str, ">=") !== -1) {
#src/xrfragment/Query.hx:98: characters 39-50
$oper = ">=";
}
#src/xrfragment/Query.hx:99: characters 9-50
if (HxString::indexOf($str, "<=") !== -1) {
#src/xrfragment/Query.hx:99: characters 39-50
$oper = "<=";
}
#src/xrfragment/Query.hx:100: lines 100-103
if ($_gthis->isExclude->match($k)) {
#src/xrfragment/Query.hx:101: characters 11-22
$oper = "!=";
#src/xrfragment/Query.hx:102: characters 15-26
$k = \mb_substr($k, 1, null);
} else {
#src/xrfragment/Query.hx:103: characters 19-40
$v = \mb_substr($v, mb_strlen($oper), null);
}
#src/xrfragment/Query.hx:104: characters 9-42
if (mb_strlen($oper) === 0) {
#src/xrfragment/Query.hx:104: characters 32-42
$oper = "=";
}
#src/xrfragment/Query.hx:105: lines 105-114
if ($_gthis->isClass->match($k)) {
#src/xrfragment/Query.hx:106: characters 11-45
$value = $oper !== "!=";
\Reflect::setField($filter, ($prefix??'null') . ($k??'null'), $value);
#src/xrfragment/Query.hx:107: characters 11-26
\Reflect::setField($q, $v, $filter);
} else {
#src/xrfragment/Query.hx:109: characters 11-53
$rule = new HxAnon();
#src/xrfragment/Query.hx:110: lines 110-111
if ($_gthis->isNumber->match($v)) {
#src/xrfragment/Query.hx:110: characters 35-67
$value = \Std::parseFloat($v);
\Reflect::setField($rule, $oper, $value);
} else {
#src/xrfragment/Query.hx:111: characters 16-30
\Reflect::setField($rule, $oper, $v);
}
#src/xrfragment/Query.hx:112: characters 11-39
\Reflect::field($filter, "rules")->push($rule);
#src/xrfragment/Query.hx:113: characters 11-29
\Reflect::setField($q, $k, $filter);
}
#src/xrfragment/Query.hx:115: characters 9-15
return;
} else {
#src/xrfragment/Query.hx:117: characters 9-62
$value = ($_gthis->isExclude->match($str) ? false : true);
\Reflect::setField($filter, "id", $value);
#src/xrfragment/Query.hx:118: characters 9-63
$value = $_gthis->isRoot->match($str);
\Reflect::setField($filter, "root", $value);
#src/xrfragment/Query.hx:119: characters 9-55
if ($_gthis->isExclude->match($str)) {
#src/xrfragment/Query.hx:119: characters 42-55
$str = \mb_substr($str, 1, null);
}
#src/xrfragment/Query.hx:120: characters 9-55
if ($_gthis->isRoot->match($str)) {
#src/xrfragment/Query.hx:120: characters 42-55
$str = \mb_substr($str, 1, null);
}
#src/xrfragment/Query.hx:121: characters 9-29
\Reflect::setField($q, $str, $filter);
}
};
#src/xrfragment/Query.hx:124: characters 15-19
$_g = 0;
#src/xrfragment/Query.hx:124: characters 19-31
$_g1 = $token->length;
#src/xrfragment/Query.hx:124: characters 5-68
while ($_g < $_g1) {
#src/xrfragment/Query.hx:124: characters 15-31
$i = $_g++;
#src/xrfragment/Query.hx:124: characters 34-68
$process($this->expandAliases(($token->arr[$i] ?? null)));
}
#src/xrfragment/Query.hx:125: characters 5-22
return $this->q = $q;
}
/**
* @param mixed $obj
*
* @return bool
*/
public function test ($obj = null) {
#src/xrfragment/Query.hx:130: characters 5-30
$qualify = false;
#src/xrfragment/Query.hx:132: lines 132-135
$_g = 0;
$_g1 = \Reflect::fields($obj);
while ($_g < $_g1->length) {
#src/xrfragment/Query.hx:132: characters 11-12
$k = ($_g1->arr[$_g] ?? null);
#src/xrfragment/Query.hx:132: lines 132-135
++$_g;
#src/xrfragment/Query.hx:133: characters 7-57
$v = \Std::string(\Reflect::field($obj, $k));
#src/xrfragment/Query.hx:134: characters 7-47
if ($this->testProperty($k, $v)) {
#src/xrfragment/Query.hx:134: characters 33-47
$qualify = true;
}
}
#src/xrfragment/Query.hx:136: lines 136-139
$_g = 0;
$_g1 = \Reflect::fields($obj);
while ($_g < $_g1->length) {
#src/xrfragment/Query.hx:136: characters 11-12
$k = ($_g1->arr[$_g] ?? null);
#src/xrfragment/Query.hx:136: lines 136-139
++$_g;
#src/xrfragment/Query.hx:137: characters 7-57
$v = \Std::string(\Reflect::field($obj, $k));
#src/xrfragment/Query.hx:138: characters 7-54
if ($this->testProperty($k, $v, true)) {
#src/xrfragment/Query.hx:138: characters 39-54
$qualify = false;
}
}
#src/xrfragment/Query.hx:140: characters 5-19
return $qualify;
}
/**
* @param string $property
* @param string $value
* @param bool $exclude
*
* @return bool
*/
public function testProperty ($property, $value, $exclude = null) {
#src/xrfragment/Query.hx:145: characters 5-23
$conds = 0;
#src/xrfragment/Query.hx:146: characters 5-23
$fails = 0;
#src/xrfragment/Query.hx:147: characters 5-26
$qualify = 0;
#src/xrfragment/Query.hx:149: lines 149-153
$testprop = function ($expr) use (&$conds, &$fails) {
#src/xrfragment/Query.hx:150: characters 7-15
$conds += 1;
#src/xrfragment/Query.hx:151: characters 7-27
$fails += ($expr ? 0 : 1);
#src/xrfragment/Query.hx:152: characters 7-18
return $expr;
};
#src/xrfragment/Query.hx:156: lines 156-159
if (\Reflect::field($this->q, $value) !== null) {
#src/xrfragment/Query.hx:157: characters 7-52
$v = \Reflect::field($this->q, $value);
#src/xrfragment/Query.hx:158: characters 7-59
if (\Reflect::field($v, $property) !== null) {
#src/xrfragment/Query.hx:158: characters 37-59
return \Reflect::field($v, $property);
}
}
#src/xrfragment/Query.hx:162: lines 162-183
$_g = 0;
$_g1 = \Reflect::fields($this->q);
while ($_g < $_g1->length) {
#src/xrfragment/Query.hx:162: characters 11-12
$k = ($_g1->arr[$_g] ?? null);
#src/xrfragment/Query.hx:162: lines 162-183
++$_g;
#src/xrfragment/Query.hx:163: characters 7-47
$filter = \Reflect::field($this->q, $k);
#src/xrfragment/Query.hx:164: characters 7-43
if (Boot::dynamicField($filter, 'rules') === null) {
#src/xrfragment/Query.hx:164: characters 35-43
continue;
}
#src/xrfragment/Query.hx:165: characters 7-47
$rules = Boot::dynamicField($filter, 'rules');
#src/xrfragment/Query.hx:167: lines 167-182
$_g2 = 0;
while ($_g2 < $rules->length) {
#src/xrfragment/Query.hx:167: characters 12-16
$rule = ($rules->arr[$_g2] ?? null);
#src/xrfragment/Query.hx:167: lines 167-182
++$_g2;
#src/xrfragment/Query.hx:169: lines 169-181
if ($exclude) {
#src/xrfragment/Query.hx:170: characters 11-145
if ((\Reflect::field($rule, "!=") !== null) && $testprop(\Std::string($value) === \Std::string(\Reflect::field($rule, "!="))) && $exclude) {
#src/xrfragment/Query.hx:170: characters 133-145
++$qualify;
}
} else {
#src/xrfragment/Query.hx:172: characters 11-141
if ((\Reflect::field($rule, "*") !== null) && $testprop(\Std::parseFloat($value) !== null)) {
#src/xrfragment/Query.hx:172: characters 129-141
++$qualify;
}
#src/xrfragment/Query.hx:173: characters 11-143
if ((\Reflect::field($rule, ">") !== null) && $testprop(\Std::parseFloat($value) > \Std::parseFloat(\Reflect::field($rule, ">")))) {
#src/xrfragment/Query.hx:173: characters 131-143
++$qualify;
}
#src/xrfragment/Query.hx:174: characters 11-143
if ((\Reflect::field($rule, "<") !== null) && $testprop(\Std::parseFloat($value) < \Std::parseFloat(\Reflect::field($rule, "<")))) {
#src/xrfragment/Query.hx:174: characters 131-143
++$qualify;
}
#src/xrfragment/Query.hx:175: characters 11-143
if ((\Reflect::field($rule, ">=") !== null) && $testprop(\Std::parseFloat($value) >= \Std::parseFloat(\Reflect::field($rule, ">=")))) {
#src/xrfragment/Query.hx:175: characters 131-143
++$qualify;
}
#src/xrfragment/Query.hx:176: characters 11-143
if ((\Reflect::field($rule, "<=") !== null) && $testprop(\Std::parseFloat($value) <= \Std::parseFloat(\Reflect::field($rule, "<=")))) {
#src/xrfragment/Query.hx:176: characters 131-143
++$qualify;
}
#src/xrfragment/Query.hx:177: lines 177-180
if ((\Reflect::field($rule, "=") !== null) && ($testprop($value === \Reflect::field($rule, "=")) || $testprop(Boot::equal(\Std::parseFloat($value), \Std::parseFloat(\Reflect::field($rule, "=")))))) {
#src/xrfragment/Query.hx:180: characters 14-26
++$qualify;
}
}
}
}
#src/xrfragment/Query.hx:184: characters 5-23
return $qualify > 0;
}
/**
* @return mixed
*/
public function toObject () {
#src/xrfragment/Query.hx:66: characters 5-18
return $this->q;
}
}
Boot::registerClass(Query::class, 'xrfragment.Query');

View file

@ -1,101 +0,0 @@
<?php
/**
*/
namespace xrfragment;
use \php\_Boot\HxAnon;
use \php\Boot;
use \php\_Boot\HxString;
/**
* # Spec
*
* > version 1.0.0 [![Actions Status](https://github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions) generated by `make doc` @ $(date +"%Y-%m-%dT%H:%M:%S%z")
*
* ### XR Fragment URI Grammar
*
* ```
* reserved = gen-delims / sub-delims
* gen-delims = "#" / "&"
* sub-delims = "," / "="
* ```
*
* > Example: `://foo.com/my3d.asset#pos=1,0,0&prio=-5&t=0,100|100,200`
*
* | Explanation | |
* |-|-|
* | `pos=1,2,3` | vector/coordinate argument e.g. |
* | `pos=1,2,3&rot=0,90,0&q=.foo` | combinators |
*
* In case your programming language has no parser ([check here](https://github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Parser.parse(k,v,store)` using the spec:
*
*/
class URI {
/**
* @param string $url
* @param int $filter
*
* @return mixed
*/
public static function parse ($url, $filter) {
#src/xrfragment/URI.hx:37: characters 7-50
$store = new HxAnon();
#src/xrfragment/URI.hx:38: characters 7-63
if (($url === null) || (HxString::indexOf($url, "#") === -1)) {
#src/xrfragment/URI.hx:38: characters 51-63
return $store;
}
#src/xrfragment/URI.hx:39: characters 7-54
$fragment = HxString::split($url, "#");
#src/xrfragment/URI.hx:40: characters 7-62
$splitArray = HxString::split(($fragment->arr[1] ?? null), "&");
#src/xrfragment/URI.hx:41: characters 19-23
$_g = 0;
#src/xrfragment/URI.hx:41: characters 23-40
$_g1 = $splitArray->length;
#src/xrfragment/URI.hx:41: lines 41-51
while ($_g < $_g1) {
#src/xrfragment/URI.hx:41: characters 19-40
$i = $_g++;
#src/xrfragment/URI.hx:43: characters 9-53
$splitByEqual = HxString::split(($splitArray->arr[$i] ?? null), "=");
#src/xrfragment/URI.hx:44: characters 9-33
$regexPlus = new \EReg("\\+", "g");
#src/xrfragment/URI.hx:45: characters 9-42
$key = ($splitByEqual->arr[0] ?? null);
#src/xrfragment/URI.hx:46: characters 5-27
$value = "";
#src/xrfragment/URI.hx:47: lines 47-49
if ($splitByEqual->length > 1) {
#src/xrfragment/URI.hx:48: characters 19-84
$value = \urldecode($regexPlus->split(($splitByEqual->arr[1] ?? null))->join(" "));
}
#src/xrfragment/URI.hx:50: characters 5-49
$ok = Parser::parse($key, $value, $store);
}
#src/xrfragment/URI.hx:52: lines 52-59
if (($filter !== null) && ($filter !== 0)) {
#src/xrfragment/URI.hx:53: lines 53-58
$_g = 0;
$_g1 = \Reflect::fields($store);
while ($_g < $_g1->length) {
#src/xrfragment/URI.hx:53: characters 14-17
$key = ($_g1->arr[$_g] ?? null);
#src/xrfragment/URI.hx:53: lines 53-58
++$_g;
#src/xrfragment/URI.hx:54: characters 13-42
$xrf = \Reflect::field($store, $key);
#src/xrfragment/URI.hx:55: lines 55-57
if (!$xrf->is($filter)) {
#src/xrfragment/URI.hx:56: characters 8-25
\Reflect::deleteField($store, $key);
}
}
}
#src/xrfragment/URI.hx:60: characters 7-19
return $store;
}
}
Boot::registerClass(URI::class, 'xrfragment.URI');

View file

@ -1,334 +0,0 @@
<?php
/**
*/
namespace xrfragment;
use \php\Boot;
use \php\_Boot\HxString;
class XRF {
/**
* @var int
*/
static public $ASSET = 1;
/**
* @var int
*/
static public $EMBEDDED = 64;
/**
* @var int
*/
static public $NAVIGATOR = 32;
/**
* @var int
*/
static public $PROMPT = 8;
/**
* @var int
*/
static public $PROP_BIND = 2;
/**
* @var int
*/
static public $PV_EXECUTE = 256;
/**
* @var int
*/
static public $PV_OVERRIDE = 128;
/**
* @var int
*/
static public $QUERY_OPERATOR = 4;
/**
* @var int
*/
static public $ROUNDROBIN = 16;
/**
* @var int
*/
static public $T_COLOR = 8192;
/**
* @var int
*/
static public $T_FLOAT = 32768;
/**
* @var int
*/
static public $T_INT = 16384;
/**
* @var int
*/
static public $T_PREDEFINED_VIEW = 524288;
/**
* @var int
*/
static public $T_STRING = 1048576;
/**
* @var int
*/
static public $T_STRING_OBJ = 2097152;
/**
* @var int
*/
static public $T_STRING_OBJ_PROP = 4194304;
/**
* @var int
*/
static public $T_URL = 262144;
/**
* @var int
*/
static public $T_VECTOR2 = 65536;
/**
* @var int
*/
static public $T_VECTOR3 = 131072;
/**
* @var \EReg
*/
static public $isColor;
/**
* @var \EReg
*/
static public $isFloat;
/**
* @var \EReg
*/
static public $isInt;
/**
* @var \EReg
*/
static public $isString;
/**
* @var \EReg
*/
static public $isUrl;
/**
* @var \EReg
*/
static public $isUrlOrPretypedView;
/**
* @var \EReg
*/
static public $isVector;
/**
* @var XRF[]|\Array_hx
*/
public $args;
/**
* @var string
*/
public $color;
/**
* @var int
*/
public $flags;
/**
* @var float
*/
public $float;
/**
* @var string
*/
public $fragment;
/**
* @var int
*/
public $int;
/**
* @var Query
*/
public $query;
/**
* @var string
*/
public $string;
/**
* @var float
*/
public $x;
/**
* @var float
*/
public $y;
/**
* @var float
*/
public $z;
/**
* @param int $flag
* @param int $flags
*
* @return int
*/
public static function set ($flag, $flags) {
#src/xrfragment/XRF.hx:70: characters 5-24
return $flags | $flag;
}
/**
* @param int $flag
* @param int $flags
*
* @return int
*/
public static function unset ($flag, $flags) {
#src/xrfragment/XRF.hx:74: characters 5-25
return $flags & ~$flag;
}
/**
* @param string $_fragment
* @param int $_flags
*
* @return void
*/
public function __construct ($_fragment, $_flags) {
#src/xrfragment/XRF.hx:61: characters 5-25
$this->fragment = $_fragment;
#src/xrfragment/XRF.hx:62: characters 5-22
$this->flags = $_flags;
}
/**
* @param XRF $v
* @param string $str
*
* @return void
*/
public function guessType ($v, $str) {
#src/xrfragment/XRF.hx:103: characters 5-19
$v->string = $str;
#src/xrfragment/XRF.hx:104: lines 104-109
if (HxString::split($str, ",")->length > 1) {
#src/xrfragment/XRF.hx:105: characters 7-46
$xyz = HxString::split($str, ",");
#src/xrfragment/XRF.hx:106: characters 7-56
if ($xyz->length > 0) {
#src/xrfragment/XRF.hx:106: characters 28-56
$v->x = \Std::parseFloat(($xyz->arr[0] ?? null));
}
#src/xrfragment/XRF.hx:107: characters 7-56
if ($xyz->length > 1) {
#src/xrfragment/XRF.hx:107: characters 28-56
$v->y = \Std::parseFloat(($xyz->arr[1] ?? null));
}
#src/xrfragment/XRF.hx:108: characters 7-56
if ($xyz->length > 2) {
#src/xrfragment/XRF.hx:108: characters 28-56
$v->z = \Std::parseFloat(($xyz->arr[2] ?? null));
}
}
#src/xrfragment/XRF.hx:111: characters 5-43
if (XRF::$isColor->match($str)) {
#src/xrfragment/XRF.hx:111: characters 30-43
$v->color = $str;
}
#src/xrfragment/XRF.hx:112: characters 5-59
if (XRF::$isFloat->match($str)) {
#src/xrfragment/XRF.hx:112: characters 30-59
$v->float = \Std::parseFloat($str);
}
#src/xrfragment/XRF.hx:113: characters 5-57
if (XRF::$isInt->match($str)) {
#src/xrfragment/XRF.hx:113: characters 30-57
$v->int = \Std::parseInt($str);
}
}
/**
* @param int $flag
*
* @return bool
*/
public function is ($flag) {
#src/xrfragment/XRF.hx:66: characters 5-31
return ($this->flags & $flag) !== 0;
}
/**
* @param string $value
*
* @return bool
*/
public function validate ($value) {
#src/xrfragment/XRF.hx:78: characters 5-27
$this->guessType($this, $value);
#src/xrfragment/XRF.hx:80: lines 80-88
if (HxString::split($value, "|")->length > 1) {
#src/xrfragment/XRF.hx:81: characters 7-35
$this->args = new \Array_hx();
#src/xrfragment/XRF.hx:82: characters 7-49
$args = HxString::split($value, "|");
#src/xrfragment/XRF.hx:83: characters 17-21
$_g = 0;
#src/xrfragment/XRF.hx:83: characters 21-32
$_g1 = $args->length;
#src/xrfragment/XRF.hx:83: lines 83-87
while ($_g < $_g1) {
#src/xrfragment/XRF.hx:83: characters 17-32
$i = $_g++;
#src/xrfragment/XRF.hx:84: characters 9-45
$x = new XRF($this->fragment, $this->flags);
#src/xrfragment/XRF.hx:85: characters 9-30
$this->guessType($x, ($args->arr[$i] ?? null));
#src/xrfragment/XRF.hx:86: characters 9-28
$_this = $this->args;
$_this->arr[$_this->length++] = $x;
}
}
#src/xrfragment/XRF.hx:90: characters 5-59
if ($this->fragment === "q") {
#src/xrfragment/XRF.hx:90: characters 27-59
$this->query = (new Query($value))->get();
}
#src/xrfragment/XRF.hx:92: characters 5-24
$ok = true;
#src/xrfragment/XRF.hx:93: lines 93-97
if (!($this->args instanceof \Array_hx)) {
#src/xrfragment/XRF.hx:94: characters 7-115
if ($this->is(XRF::$T_VECTOR3) && !((is_float($this->x) || is_int($this->x)) && (is_float($this->y) || is_int($this->y)) && (is_float($this->z) || is_int($this->z)))) {
#src/xrfragment/XRF.hx:94: characters 105-115
$ok = false;
}
#src/xrfragment/XRF.hx:95: characters 7-115
if ($this->is(XRF::$T_VECTOR2) && !((is_float($this->x) || is_int($this->x)) && (is_float($this->y) || is_int($this->y)))) {
#src/xrfragment/XRF.hx:95: characters 105-115
$ok = false;
}
#src/xrfragment/XRF.hx:96: characters 7-63
if ($this->is(XRF::$T_INT) && !Boot::isOfType($this->int, Boot::getClass('Int'))) {
#src/xrfragment/XRF.hx:96: characters 53-63
$ok = false;
}
}
#src/xrfragment/XRF.hx:98: characters 5-14
return $ok;
}
/**
* @internal
* @access private
*/
static public function __hx__init ()
{
static $called = false;
if ($called) return;
$called = true;
self::$isColor = new \EReg("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})\$", "");
self::$isInt = new \EReg("^[0-9]+\$", "");
self::$isFloat = new \EReg("^[0-9]+\\.[0-9]+\$", "");
self::$isVector = new \EReg("([,]+|\\w)", "");
self::$isUrl = new \EReg("(://)?\\..*", "");
self::$isUrlOrPretypedView = new \EReg("(^#|://)?\\..*", "");
self::$isString = new \EReg(".*", "");
}
}
Boot::registerClass(XRF::class, 'xrfragment.XRF');
XRF::__hx__init();

392
dist/xrfragment.py vendored
View file

@ -63,7 +63,7 @@ class EReg:
_hx_class_name = "EReg"
__slots__ = ("pattern", "matchObj", "_hx_global")
_hx_fields = ["pattern", "matchObj", "global"]
_hx_methods = ["split"]
_hx_methods = ["split", "replace"]
def __init__(self,r,opt):
self.matchObj = None
@ -107,12 +107,35 @@ class EReg:
else:
return [HxString.substring(s,0,self.matchObj.start()), HxString.substr(s,self.matchObj.end(),None)]
def replace(self,s,by):
_this = by.split("$$")
by = "_hx_#repl#__".join([python_Boot.toString1(x1,'') for x1 in _this])
def _hx_local_0(x):
res = by
g = x.groups()
_g = 0
_g1 = len(g)
while (_g < _g1):
i = _g
_g = (_g + 1)
gs = g[i]
if (gs is None):
continue
delimiter = ("$" + HxOverrides.stringOrNull(str((i + 1))))
_this = (list(res) if ((delimiter == "")) else res.split(delimiter))
res = gs.join([python_Boot.toString1(x1,'') for x1 in _this])
_this = res.split("_hx_#repl#__")
res = "$".join([python_Boot.toString1(x1,'') for x1 in _this])
return res
replace = _hx_local_0
return python_lib_Re.sub(self.pattern,replace,s,(0 if (self._hx_global) else 1))
class Reflect:
_hx_class_name = "Reflect"
__slots__ = ()
_hx_statics = ["field", "deleteField"]
_hx_statics = ["field", "deleteField", "copy"]
@staticmethod
def field(o,field):
@ -129,6 +152,20 @@ class Reflect:
o.__delattr__(field)
return True
@staticmethod
def copy(o):
if (o is None):
return None
o2 = _hx_AnonObject({})
_g = 0
_g1 = python_Boot.fields(o)
while (_g < len(_g1)):
f = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
_g = (_g + 1)
value = Reflect.field(o,f)
setattr(o2,(("_hx_" + f) if ((f in python_Boot.keywords)) else (("_hx_" + f) if (((((len(f) > 2) and ((ord(f[0]) == 95))) and ((ord(f[1]) == 95))) and ((ord(f[(len(f) - 1)]) != 95)))) else f)),value)
return o2
class Std:
_hx_class_name = "Std"
@ -984,7 +1021,11 @@ class python_HaxeIterator:
class python_internal_ArrayImpl:
_hx_class_name = "python.internal.ArrayImpl"
__slots__ = ()
_hx_statics = ["concat", "copy", "iterator", "keyValueIterator", "indexOf", "lastIndexOf", "join", "toString", "pop", "push", "unshift", "remove", "contains", "shift", "slice", "sort", "splice", "map", "filter", "insert", "reverse", "_get"]
_hx_statics = ["get_length", "concat", "copy", "iterator", "keyValueIterator", "indexOf", "lastIndexOf", "join", "toString", "pop", "push", "unshift", "remove", "contains", "shift", "slice", "sort", "splice", "map", "filter", "insert", "reverse", "_get"]
@staticmethod
def get_length(x):
return len(x)
@staticmethod
def concat(a1,a2):
@ -1120,7 +1161,7 @@ class python_internal_ArrayImpl:
class HxOverrides:
_hx_class_name = "HxOverrides"
__slots__ = ()
_hx_statics = ["eq", "stringOrNull", "push", "arrayGet"]
_hx_statics = ["eq", "stringOrNull", "length", "arrayGet"]
@staticmethod
def eq(a,b):
@ -1136,12 +1177,12 @@ class HxOverrides:
return s
@staticmethod
def push(x,e):
if isinstance(x,list):
_this = x
_this.append(e)
return len(_this)
return x.push(e)
def length(x):
if isinstance(x,str):
return len(x)
elif isinstance(x,list):
return len(x)
return x.length
@staticmethod
def arrayGet(a,i):
@ -1173,7 +1214,7 @@ class python_internal_MethodClosure:
class HxString:
_hx_class_name = "HxString"
__slots__ = ()
_hx_statics = ["split", "charCodeAt", "charAt", "lastIndexOf", "toUpperCase", "toLowerCase", "indexOf", "indexOfImpl", "toString", "substring", "substr"]
_hx_statics = ["split", "charCodeAt", "charAt", "lastIndexOf", "toUpperCase", "toLowerCase", "indexOf", "indexOfImpl", "toString", "get_length", "substring", "substr"]
@staticmethod
def split(s,d):
@ -1252,6 +1293,10 @@ class HxString:
def toString(s):
return s
@staticmethod
def get_length(s):
return len(s)
@staticmethod
def substring(s,startIndex,endIndex = None):
if (startIndex < 0):
@ -1280,159 +1325,73 @@ class HxString:
return s[startIndex:(startIndex + _hx_len)]
class xrfragment_Parser:
_hx_class_name = "xrfragment.Parser"
__slots__ = ()
_hx_statics = ["error", "debug", "parse"]
@staticmethod
def parse(key,value,store):
Frag = haxe_ds_StringMap()
Frag.h["#"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW) | xrfragment_XRF.PV_EXECUTE)
Frag.h["prio"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_INT)
Frag.h["src"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_URL)
Frag.h["href"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.T_PREDEFINED_VIEW)
Frag.h["tag"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["pos"] = (((((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.T_STRING_OBJ) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
Frag.h["q"] = ((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_STRING) | xrfragment_XRF.METADATA)
Frag.h["scale"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
Frag.h["rot"] = (((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
Frag.h["mov"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
Frag.h["show"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_INT) | xrfragment_XRF.METADATA)
Frag.h["env"] = (((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_STRING) | xrfragment_XRF.METADATA)
Frag.h["t"] = (((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.ROUNDROBIN) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
Frag.h["gravity"] = (((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
Frag.h["physics"] = (((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA)
Frag.h["fov"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_INT) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
Frag.h["clip"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
Frag.h["fog"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
Frag.h["bg"] = ((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
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.NAVIGATOR) | xrfragment_XRF.METADATA) | xrfragment_XRF.PROMPT)
isPVDynamic = (((len(value) == 0) and ((len(key) > 0))) and (not (key in Frag.h)))
isPVDefault = (((len(value) == 0) and ((len(key) > 0))) and ((key == "#")))
if isPVDynamic:
v = xrfragment_XRF(key,(xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR))
v.validate(key)
setattr(store,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
return True
if ((len(key.split(".")) > 1) and ((len(value.split(".")) > 1))):
value1 = xrfragment_XRF(key,(((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_STRING) | xrfragment_XRF.PROP_BIND))
setattr(store,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),value1)
return True
v = xrfragment_XRF(key,Frag.h.get(key,None))
if (key in Frag.h):
if (not v.validate(value)):
print(str((((("⚠ fragment '" + ("null" if key is None else key)) + "' has incompatible value (") + ("null" if value is None else value)) + ")")))
return False
setattr(store,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
if xrfragment_Parser.debug:
print(str(((("" + ("null" if key is None else key)) + ": ") + HxOverrides.stringOrNull(v.string))))
else:
if Std.isOfType(value,str):
v.guessType(v,value)
v.noXRF = True
setattr(store,(("_hx_" + key) if ((key in python_Boot.keywords)) else (("_hx_" + key) if (((((len(key) > 2) and ((ord(key[0]) == 95))) and ((ord(key[1]) == 95))) and ((ord(key[(len(key) - 1)]) != 95)))) else key)),v)
return True
class xrfragment_Query:
_hx_class_name = "xrfragment.Query"
__slots__ = ("str", "q", "isProp", "isExclude", "isRoot", "isNumber")
_hx_fields = ["str", "q", "isProp", "isExclude", "isRoot", "isNumber"]
class xrfragment_Filter:
_hx_class_name = "xrfragment.Filter"
__slots__ = ("str", "q")
_hx_fields = ["str", "q"]
_hx_methods = ["toObject", "get", "parse", "test", "testProperty"]
def __init__(self,_hx_str):
self.isNumber = EReg("^[0-9\\.]+$","")
self.isRoot = EReg("^[-]?/","")
self.isExclude = EReg("^-","")
self.isProp = EReg("^.*:[><=!]?","")
self.q = _hx_AnonObject({})
self.str = ""
if (_hx_str is not None):
self.parse(_hx_str)
def toObject(self):
return self.q
return Reflect.copy(self.q)
def get(self):
return self.q
return Reflect.copy(self.q)
def parse(self,_hx_str):
_gthis = self
token = _hx_str.split(" ")
q = _hx_AnonObject({})
def _hx_local_0(_hx_str,prefix = None):
if (prefix is None):
prefix = ""
_hx_str = StringTools.trim(_hx_str)
k = HxOverrides.arrayGet(_hx_str.split(":"), 0)
v = HxOverrides.arrayGet(_hx_str.split(":"), 1)
k = HxOverrides.arrayGet(_hx_str.split("="), 0)
v = HxOverrides.arrayGet(_hx_str.split("="), 1)
_hx_filter = _hx_AnonObject({})
if Reflect.field(q,(("null" if prefix is None else prefix) + ("null" if k is None else k))):
_hx_filter = Reflect.field(q,(("null" if prefix is None else prefix) + ("null" if k is None else k)))
value = (Reflect.field(_hx_filter,"rules") if ((Reflect.field(_hx_filter,"rules") is not None)) else list())
setattr(_hx_filter,(("_hx_" + "rules") if (("rules" in python_Boot.keywords)) else (("_hx_" + "rules") if (((((len("rules") > 2) and ((ord("rules"[0]) == 95))) and ((ord("rules"[1]) == 95))) and ((ord("rules"[(len("rules") - 1)]) != 95)))) else "rules")),value)
_this = _gthis.isProp
_this = xrfragment_XRF.isProp
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
oper = ""
startIndex = None
if (((_hx_str.find("*") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"*",startIndex))) != -1):
oper = "*"
startIndex = None
if (((_hx_str.find(">") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,">",startIndex))) != -1):
oper = ">"
startIndex = None
if (((_hx_str.find("<") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"<",startIndex))) != -1):
oper = "<"
startIndex = None
if (((_hx_str.find(">=") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,">=",startIndex))) != -1):
oper = ">="
startIndex = None
if (((_hx_str.find("<=") if ((startIndex is None)) else HxString.indexOfImpl(_hx_str,"<=",startIndex))) != -1):
oper = "<="
_this = _gthis.isExclude
_this = xrfragment_XRF.isExclude
_this.matchObj = python_lib_Re.search(_this.pattern,k)
if (_this.matchObj is not None):
oper = "!="
k = HxString.substr(k,1,None)
else:
v = HxString.substr(v,len(oper),None)
v = HxString.substr(v,len(oper),None)
if (len(oper) == 0):
oper = "="
rule = _hx_AnonObject({})
_this = _gthis.isNumber
_this = xrfragment_XRF.isNumber
_this.matchObj = python_lib_Re.search(_this.pattern,v)
if (_this.matchObj is not None):
value = Std.parseFloat(v)
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),value)
else:
setattr(rule,(("_hx_" + oper) if ((oper in python_Boot.keywords)) else (("_hx_" + oper) if (((((len(oper) > 2) and ((ord(oper[0]) == 95))) and ((ord(oper[1]) == 95))) and ((ord(oper[(len(oper) - 1)]) != 95)))) else oper)),v)
Reflect.field(Reflect.field(_hx_filter,"rules"),"push")(rule)
setattr(q,(("_hx_" + k) if ((k in python_Boot.keywords)) else (("_hx_" + k) if (((((len(k) > 2) and ((ord(k[0]) == 95))) and ((ord(k[1]) == 95))) and ((ord(k[(len(k) - 1)]) != 95)))) else k)),_hx_filter)
return
else:
_this = _gthis.isExclude
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = (False if ((_this.matchObj is not None)) else True)
setattr(_hx_filter,(("_hx_" + "id") if (("id" in python_Boot.keywords)) else (("_hx_" + "id") if (((((len("id") > 2) and ((ord("id"[0]) == 95))) and ((ord("id"[1]) == 95))) and ((ord("id"[(len("id") - 1)]) != 95)))) else "id")),value)
_this = _gthis.isRoot
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = (_this.matchObj is not None)
setattr(_hx_filter,(("_hx_" + "root") if (("root" in python_Boot.keywords)) else (("_hx_" + "root") if (((((len("root") > 2) and ((ord("root"[0]) == 95))) and ((ord("root"[1]) == 95))) and ((ord("root"[(len("root") - 1)]) != 95)))) else "root")),value)
_this = _gthis.isExclude
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
_hx_str = HxString.substr(_hx_str,1,None)
_this = _gthis.isRoot
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
_hx_str = HxString.substr(_hx_str,1,None)
setattr(q,(("_hx_" + _hx_str) if ((_hx_str in python_Boot.keywords)) else (("_hx_" + _hx_str) if (((((len(_hx_str) > 2) and ((ord(_hx_str[0]) == 95))) and ((ord(_hx_str[1]) == 95))) and ((ord(_hx_str[(len(_hx_str) - 1)]) != 95)))) else _hx_str)),_hx_filter)
setattr(q,(("_hx_" + "expr") if (("expr" in python_Boot.keywords)) else (("_hx_" + "expr") if (((((len("expr") > 2) and ((ord("expr"[0]) == 95))) and ((ord("expr"[1]) == 95))) and ((ord("expr"[(len("expr") - 1)]) != 95)))) else "expr")),rule)
_this = xrfragment_XRF.isDeep
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = ((Reflect.field(k.split("*"),"length") - 1) if ((_this.matchObj is not None)) else 0)
setattr(q,(("_hx_" + "deep") if (("deep" in python_Boot.keywords)) else (("_hx_" + "deep") if (((((len("deep") > 2) and ((ord("deep"[0]) == 95))) and ((ord("deep"[1]) == 95))) and ((ord("deep"[(len("deep") - 1)]) != 95)))) else "deep")),value)
_this = xrfragment_XRF.isExclude
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
value = (False if ((_this.matchObj is not None)) else True)
setattr(q,(("_hx_" + "show") if (("show" in python_Boot.keywords)) else (("_hx_" + "show") if (((((len("show") > 2) and ((ord("show"[0]) == 95))) and ((ord("show"[1]) == 95))) and ((ord("show"[(len("show") - 1)]) != 95)))) else "show")),value)
value = xrfragment_XRF.operators.replace(k,"")
setattr(q,(("_hx_" + "key") if (("key" in python_Boot.keywords)) else (("_hx_" + "key") if (((((len("key") > 2) and ((ord("key"[0]) == 95))) and ((ord("key"[1]) == 95))) and ((ord("key"[(len("key") - 1)]) != 95)))) else "key")),value)
setattr(q,(("_hx_" + "value") if (("value" in python_Boot.keywords)) else (("_hx_" + "value") if (((((len("value") > 2) and ((ord("value"[0]) == 95))) and ((ord("value"[1]) == 95))) and ((ord("value"[(len("value") - 1)]) != 95)))) else "value")),v)
process = _hx_local_0
_g = 0
_g1 = len(token)
@ -1482,39 +1441,69 @@ class xrfragment_Query:
v = Reflect.field(self.q,value)
if (Reflect.field(v,property) is not None):
return Reflect.field(v,property)
_g = 0
_g1 = python_Boot.fields(self.q)
while (_g < len(_g1)):
k = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
_g = (_g + 1)
_hx_filter = Reflect.field(self.q,k)
if (Reflect.field(_hx_filter,"rules") is None):
continue
rules = Reflect.field(_hx_filter,"rules")
_g2 = 0
while (_g2 < len(rules)):
rule = (rules[_g2] if _g2 >= 0 and _g2 < len(rules) else None)
_g2 = (_g2 + 1)
if exclude:
if (((Reflect.field(rule,"!=") is not None) and testprop((Std.string(value) == Std.string(Reflect.field(rule,"!="))))) and exclude):
qualify = (qualify + 1)
else:
if ((Reflect.field(rule,"*") is not None) and testprop((Std.parseFloat(value) is not None))):
qualify = (qualify + 1)
if ((Reflect.field(rule,">") is not None) and testprop((Std.parseFloat(value) > Std.parseFloat(Reflect.field(rule,">"))))):
qualify = (qualify + 1)
if ((Reflect.field(rule,"<") is not None) and testprop((Std.parseFloat(value) < Std.parseFloat(Reflect.field(rule,"<"))))):
qualify = (qualify + 1)
if ((Reflect.field(rule,">=") is not None) and testprop((Std.parseFloat(value) >= Std.parseFloat(Reflect.field(rule,">="))))):
qualify = (qualify + 1)
if ((Reflect.field(rule,"<=") is not None) and testprop((Std.parseFloat(value) <= Std.parseFloat(Reflect.field(rule,"<="))))):
qualify = (qualify + 1)
if ((Reflect.field(rule,"=") is not None) and ((testprop((value == Reflect.field(rule,"="))) or testprop((Std.parseFloat(value) == Std.parseFloat(Reflect.field(rule,"="))))))):
qualify = (qualify + 1)
if Reflect.field(self.q,"expr"):
f = Reflect.field(self.q,"expr")
if (not Reflect.field(self.q,"show")):
if (((Reflect.field(f,"!=") is not None) and testprop((Std.string(value) == Std.string(Reflect.field(f,"!="))))) and exclude):
qualify = (qualify + 1)
else:
if ((Reflect.field(f,"*") is not None) and testprop((Std.parseFloat(value) is not None))):
qualify = (qualify + 1)
if ((Reflect.field(f,">") is not None) and testprop((Std.parseFloat(value) >= Std.parseFloat(Reflect.field(f,">"))))):
qualify = (qualify + 1)
if ((Reflect.field(f,"<") is not None) and testprop((Std.parseFloat(value) <= Std.parseFloat(Reflect.field(f,"<"))))):
qualify = (qualify + 1)
if ((Reflect.field(f,"=") is not None) and ((testprop((value == Reflect.field(f,"="))) or testprop((Std.parseFloat(value) == Std.parseFloat(Reflect.field(f,"="))))))):
qualify = (qualify + 1)
return (qualify > 0)
class xrfragment_Parser:
_hx_class_name = "xrfragment.Parser"
__slots__ = ()
_hx_statics = ["error", "debug", "parse"]
@staticmethod
def parse(key,value,store,index = None):
Frag = haxe_ds_StringMap()
Frag.h["#"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_PREDEFINED_VIEW) | xrfragment_XRF.PV_EXECUTE)
Frag.h["src"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_URL)
Frag.h["href"] = ((xrfragment_XRF.ASSET | xrfragment_XRF.T_URL) | xrfragment_XRF.T_PREDEFINED_VIEW)
Frag.h["tag"] = (xrfragment_XRF.ASSET | xrfragment_XRF.T_STRING)
Frag.h["pos"] = (((((xrfragment_XRF.PV_OVERRIDE | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.T_STRING) | xrfragment_XRF.T_STRING_OBJ) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
Frag.h["rot"] = ((((xrfragment_XRF.QUERY_OPERATOR | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.METADATA) | xrfragment_XRF.NAVIGATOR)
Frag.h["t"] = ((((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_FLOAT) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.T_STRING) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
Frag.h["tv"] = ((((((xrfragment_XRF.ASSET | xrfragment_XRF.PV_OVERRIDE) | xrfragment_XRF.T_FLOAT) | xrfragment_XRF.T_VECTOR2) | xrfragment_XRF.T_VECTOR3) | xrfragment_XRF.NAVIGATOR) | xrfragment_XRF.METADATA)
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.NAVIGATOR) | xrfragment_XRF.METADATA) | xrfragment_XRF.PROMPT)
keyStripped = xrfragment_XRF.operators.replace(key,"")
isPVDynamic = ((len(key) > 0) and (not (key in Frag.h)))
isPVDefault = (((len(value) == 0) and ((len(key) > 0))) and ((key == "#")))
if isPVDynamic:
v = xrfragment_XRF(key,(xrfragment_XRF.PV_EXECUTE | xrfragment_XRF.NAVIGATOR),index)
v.validate(value)
setattr(store,(("_hx_" + keyStripped) if ((keyStripped in python_Boot.keywords)) else (("_hx_" + keyStripped) if (((((len(keyStripped) > 2) and ((ord(keyStripped[0]) == 95))) and ((ord(keyStripped[1]) == 95))) and ((ord(keyStripped[(len(keyStripped) - 1)]) != 95)))) else keyStripped)),v)
return True
v = xrfragment_XRF(key,Frag.h.get(key,None),index)
if (key in Frag.h):
if (not v.validate(value)):
print(str((((("⚠ fragment '" + ("null" if key is None else key)) + "' has incompatible value (") + ("null" if value is None else value)) + ")")))
return False
setattr(store,(("_hx_" + keyStripped) if ((keyStripped in python_Boot.keywords)) else (("_hx_" + keyStripped) if (((((len(keyStripped) > 2) and ((ord(keyStripped[0]) == 95))) and ((ord(keyStripped[1]) == 95))) and ((ord(keyStripped[(len(keyStripped) - 1)]) != 95)))) else keyStripped)),v)
if xrfragment_Parser.debug:
print(str(((("" + ("null" if key is None else key)) + ": ") + HxOverrides.stringOrNull(v.string))))
else:
if Std.isOfType(value,str):
v.guessType(v,value)
v.noXRF = True
setattr(store,(("_hx_" + keyStripped) if ((keyStripped in python_Boot.keywords)) else (("_hx_" + keyStripped) if (((((len(keyStripped) > 2) and ((ord(keyStripped[0]) == 95))) and ((ord(keyStripped[1]) == 95))) and ((ord(keyStripped[(len(keyStripped) - 1)]) != 95)))) else keyStripped)),v)
return True
class xrfragment_URI:
_hx_class_name = "xrfragment.URI"
__slots__ = ()
@ -1547,7 +1536,7 @@ class xrfragment_URI:
if (len(splitByEqual) > 1):
_this1 = regexPlus.split((splitByEqual[1] if 1 < len(splitByEqual) else None))
value = python_lib_urllib_Parse.unquote(" ".join([python_Boot.toString1(x1,'') for x1 in _this1]))
ok = xrfragment_Parser.parse(key,value,store)
ok = xrfragment_Parser.parse(key,value,store,i)
if ((_hx_filter is not None) and ((_hx_filter != 0))):
_g = 0
_g1 = python_Boot.fields(store)
@ -1562,76 +1551,72 @@ class xrfragment_URI:
class xrfragment_XRF:
_hx_class_name = "xrfragment.XRF"
__slots__ = ("fragment", "flags", "x", "y", "z", "color", "string", "int", "float", "args", "query", "noXRF")
_hx_fields = ["fragment", "flags", "x", "y", "z", "color", "string", "int", "float", "args", "query", "noXRF"]
__slots__ = ("fragment", "flags", "index", "x", "y", "z", "w", "color", "string", "int", "float", "filter", "noXRF")
_hx_fields = ["fragment", "flags", "index", "x", "y", "z", "w", "color", "string", "int", "float", "filter", "noXRF"]
_hx_methods = ["is", "validate", "guessType"]
_hx_statics = ["ASSET", "PROP_BIND", "QUERY_OPERATOR", "PROMPT", "ROUNDROBIN", "NAVIGATOR", "METADATA", "PV_OVERRIDE", "PV_EXECUTE", "T_COLOR", "T_INT", "T_FLOAT", "T_VECTOR2", "T_VECTOR3", "T_URL", "T_PREDEFINED_VIEW", "T_STRING", "T_STRING_OBJ", "T_STRING_OBJ_PROP", "isColor", "isInt", "isFloat", "isVector", "isUrl", "isUrlOrPretypedView", "isString", "set", "unset"]
_hx_statics = ["ASSET", "PROP_BIND", "QUERY_OPERATOR", "PROMPT", "ROUNDROBIN", "NAVIGATOR", "METADATA", "PV_OVERRIDE", "PV_EXECUTE", "T_COLOR", "T_INT", "T_FLOAT", "T_VECTOR2", "T_VECTOR3", "T_URL", "T_PREDEFINED_VIEW", "T_STRING", "T_STRING_OBJ", "T_STRING_OBJ_PROP", "isColor", "isInt", "isFloat", "isVector", "isUrl", "isUrlOrPretypedView", "isString", "operators", "isProp", "isExclude", "isDeep", "isNumber", "set", "unset"]
def __init__(self,_fragment,_flags):
def __init__(self,_fragment,_flags,_index = None):
self.noXRF = None
self.query = None
self.args = None
self.filter = None
self.float = None
self.int = None
self.string = None
self.color = None
self.w = None
self.z = None
self.y = None
self.x = None
self.fragment = _fragment
self.flags = _flags
self.index = _index
def _hx_is(self,flag):
if (not Std.isOfType(self.flags,Int)):
self.flags = 0
return (((self.flags & flag)) != 0)
def validate(self,value):
self.guessType(self,value)
if (len(value.split("|")) > 1):
self.args = list()
args = value.split("|")
_g = 0
_g1 = len(args)
while (_g < _g1):
i = _g
_g = (_g + 1)
x = xrfragment_XRF(self.fragment,self.flags)
self.guessType(x,(args[i] if i >= 0 and i < len(args) else None))
_this = self.args
_this.append(x)
if (self.fragment == "q"):
self.query = xrfragment_Query(value).get()
ok = True
if (not Std.isOfType(self.args,list)):
if (self._hx_is(xrfragment_XRF.T_VECTOR3) and (not (((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float)) and Std.isOfType(self.z,Float))))):
ok = False
if (self._hx_is(xrfragment_XRF.T_VECTOR2) and (not ((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float))))):
ok = False
if (self._hx_is(xrfragment_XRF.T_INT) and (not Std.isOfType(self.int,Int))):
ok = False
if (((not self._hx_is(xrfragment_XRF.T_FLOAT)) and self._hx_is(xrfragment_XRF.T_VECTOR2)) and (not ((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float))))):
ok = False
if (((not ((self._hx_is(xrfragment_XRF.T_VECTOR2) or self._hx_is(xrfragment_XRF.T_STRING)))) and self._hx_is(xrfragment_XRF.T_VECTOR3)) and (not (((Std.isOfType(self.x,Float) and Std.isOfType(self.y,Float)) and Std.isOfType(self.z,Float))))):
ok = False
return ok
def guessType(self,v,_hx_str):
v.string = _hx_str
if (len(_hx_str.split(",")) > 1):
xyz = _hx_str.split(",")
if (len(xyz) > 0):
v.x = Std.parseFloat((xyz[0] if 0 < len(xyz) else None))
if (len(xyz) > 1):
v.y = Std.parseFloat((xyz[1] if 1 < len(xyz) else None))
if (len(xyz) > 2):
v.z = Std.parseFloat((xyz[2] if 2 < len(xyz) else None))
_this = xrfragment_XRF.isColor
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
v.color = _hx_str
_this = xrfragment_XRF.isFloat
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
v.float = Std.parseFloat(_hx_str)
_this = xrfragment_XRF.isInt
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
v.int = Std.parseInt(_hx_str)
if (not Std.isOfType(_hx_str,str)):
return
if (len(_hx_str) > 0):
if (len(_hx_str.split(",")) > 1):
xyzw = _hx_str.split(",")
if (len(xyzw) > 0):
v.x = Std.parseFloat((xyzw[0] if 0 < len(xyzw) else None))
if (len(xyzw) > 1):
v.y = Std.parseFloat((xyzw[1] if 1 < len(xyzw) else None))
if (len(xyzw) > 2):
v.z = Std.parseFloat((xyzw[2] if 2 < len(xyzw) else None))
if (len(xyzw) > 3):
v.w = Std.parseFloat((xyzw[3] if 3 < len(xyzw) else None))
_this = xrfragment_XRF.isColor
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
v.color = _hx_str
_this = xrfragment_XRF.isFloat
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
v.x = Std.parseFloat(_hx_str)
v.float = v.x
_this = xrfragment_XRF.isInt
_this.matchObj = python_lib_Re.search(_this.pattern,_hx_str)
if (_this.matchObj is not None):
v.int = Std.parseInt(_hx_str)
v.x = v.int
v.filter = xrfragment_Filter(((HxOverrides.stringOrNull(v.fragment) + "=") + HxOverrides.stringOrNull(v.string)))
else:
v.filter = xrfragment_Filter(v.fragment)
@staticmethod
def set(flag,flags):
@ -1671,9 +1656,14 @@ xrfragment_XRF.T_STRING = 1048576
xrfragment_XRF.T_STRING_OBJ = 2097152
xrfragment_XRF.T_STRING_OBJ_PROP = 4194304
xrfragment_XRF.isColor = EReg("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$","")
xrfragment_XRF.isInt = EReg("^[0-9]+$","")
xrfragment_XRF.isFloat = EReg("^[0-9]+\\.[0-9]+$","")
xrfragment_XRF.isInt = EReg("^[-0-9]+$","")
xrfragment_XRF.isFloat = EReg("^[-0-9]+\\.[0-9]+$","")
xrfragment_XRF.isVector = EReg("([,]+|\\w)","")
xrfragment_XRF.isUrl = EReg("(://)?\\..*","")
xrfragment_XRF.isUrlOrPretypedView = EReg("(^#|://)?\\..*","")
xrfragment_XRF.isString = EReg(".*","")
xrfragment_XRF.isString = EReg(".*","")
xrfragment_XRF.operators = EReg("(^-|[\\*]+)","")
xrfragment_XRF.isProp = EReg("^.*=[><=]?","")
xrfragment_XRF.isExclude = EReg("^-","")
xrfragment_XRF.isDeep = EReg("\\*","")
xrfragment_XRF.isNumber = EReg("^[0-9\\.]+$","")

2471
dist/xrfragment.three.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -94,8 +94,8 @@ value: draft-XRFRAGMENTS-leonvankammen-00
.# Abstract
This draft is a specification for 4D URLs & [hypermediatic](https://github.com/coderofsalvation/hypermediatic) navigation, which links together space, time & text together, for hypermedia browsers with- or without a network-connection.<br>
The specification promotes spatial addressibility, sharing, navigation, query-ing and annotating interactive (text)objects across for (XR) Browsers.<br>
XR Fragments allows us to enrich existing dataformats, by recursive use of existing proven technologies like [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment) and BibTags notation.<br>
The specification promotes spatial addressibility, sharing, navigation, filtering and databinding objects for (XR) Browsers.<br>
XR Fragments allows us to better use existing metadata inside 3D scene(files), by connecting it to proven technologies like [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment).
> Almost every idea in this document is demonstrated at [https://xrfragment.org](https://xrfragment.org)
@ -103,34 +103,38 @@ XR Fragments allows us to enrich existing dataformats, by recursive use of exist
# Introduction
How can we add more features to existing text & 3D scenes, without introducing new dataformats?<br>
How can we add more control to existing text & 3D scenes, without introducing new dataformats?<br>
Historically, there's many attempts to create the ultimate markuplanguage or 3D fileformat.<br>
The lowest common denominator is: describing/tagging/naming nodes using **plain text**.<br>
XR Fragments allows us to enrich/connect existing dataformats, by introducing existing technologies/ideas:<br>
The lowest common denominator is: designers describing/tagging/naming things using **plain text**.<br>
XR Fragments exploits the fact that all 3D models already contain such metadata:
**XR Fragments allows controlling of metadata in 3D scene(files) using URLs**
Or more detailed:
1. addressibility and [hypermediatic](https://github.com/coderofsalvation/hypermediatic) navigation of 3D scenes/objects: [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment) + src/href spatial metadata
1. Interlinking text/& 3D by collapsing space into a Word Graph (XRWG) to show [visible links](#visible-links) (and augmenting text with [bibs](https://github.com/coderofsalvation/tagbibs) / [BibTags](https://en.wikipedia.org/wiki/BibTeX) appendices (see [visual-meta](https://visual-meta.info) e.g.)
1. Interlinking (text)objects by collapsing space into a Word Graph (XRWG) to show [visible links](#visible-links)
1. unlocking spatial potential of the (originally 2D) hashtag (which jumps to a chapter) for navigating XR documents
> NOTE: The chapters in this document are ordered from highlevel to lowlevel (technical) as much as possible
# Core principle
XR Fragments strives to serve (nontechnical/fuzzy) humans first, and machine(implementations) later, by ensuring hasslefree text-vs-thought feedback loops.<br>
This also means that the repair-ability of machine-matters should be human friendly too (not too complex).<br>
**XR Fragments allows controlling of metadata in 3D scene(files) using URLs**
XR Fragments tries to seek to connect the world of text (semantical web / RDF), and the world of pixels.<br>
Instead of combining them (in a game-editor e.g.), XR Fragments is opting for a more integrated path **towards** them, by describing how to make browsers **4D URL-ready**:
Instead of combining them (in a game-editor e.g.), XR Fragments **integrates all**, by collecting metadata into an XRWG and control it via URL:
| principle | XR 4D URL | HTML 2D URL |
|----------------------|-------------------------------------------------|---------------------------------------|
| the XRWG | wordgraph (collapses 3D scene to tags) | Ctrl-F (find) |
| the hashbus | hashtags map to camera/scene-projections | hashtags map to document positions |
| spacetime hashtags | positions camera, triggers scene-preset/time | jumps/scrolls to chapter |
| the hashbus | hashtags alter camera/scene/object-projections | hashtags alter document positions |
| src metadata | renders content and offers sourceportation | renders content |
| href metadata | teleports to other XR document | jumps to other HTML document |
| href metadata | repositions camera or animation-range | jumps to camera |
| href metadata | draws visible connection(s) for XRWG 'tag' | |
| href metadata | triggers predefined view | Media fragments |
| href metadata | triggers camera/scene/object/projections | n/a |
| href metadata | draws visible connection(s) for XRWG 'tag' | n/a |
| href metadata | filters certain (in)visible objects | n/a |
> XR Fragments does not look at XR (or the web) thru the lens of HTML.<br>But approaches things from a higherlevel feedbackloop/hypermedia browser-perspective:
@ -142,13 +146,16 @@ Instead of combining them (in a game-editor e.g.), XR Fragments is opting for a
│ 2D URL: ://library.com /document ?search #chapter
│ │
│ 4D URL: ://park.com /4Dscene.fbx ──> ?misc ──> #view ───> hashbus │
│ │ #query │ │
│ │ #filter │ │
│ │ #tag │ │
│ │ #material │ │
│ │ #animation │ │
│ │ #texture │ │
│ │ #variable │ │
│ │ │ │
│ XRWG <─────────────────────<────────────+ │
│ │ │ │
│ ├─ objects ───────────────>────────────│ │
│ └─ text ───────────────>────────────+ │
│ └─ objects ──────────────>────────────+ │
│ │
│ │
+──────────────────────────────────────────────────────────────────────────────────────────────+
@ -180,36 +187,63 @@ sub-delims = "," / "="
| Demo | Explanation |
|-------------------------------|---------------------------------|
| `pos=1,2,3` | vector/coordinate argument e.g. |
| `pos=1,2,3&rot=0,90,0&q=.foo` | combinators |
| `pos=1,2,3&rot=0,90,0&foo` | combinators |
> this is already implemented in all browsers
# List of URI Fragments
| fragment | type | example | info |
|--------------|----------|-------------------|----------------------------------------------------------------------|
| `#pos` | vector3 | `#pos=0.5,0,0` | positions camera (or XR floor) to xyz-coord 0.5,0,0, |
| `#rot` | vector3 | `#rot=0,90,0` | rotates camera to xyz-coord 0.5,0,0 |
| `#t` | vector3 | `#t=1,500,1000` | play animation-loop range between frame 500 and 1000, at normal speed|
| `#......` | string | `#.cubes` `#cube` | predefined views, XRWG fragments and ID fragments |
| fragment | type | example | info |
|-------------------|------------|--------------------|----------------------------------------------------------------------|
| `#pos` | vector3 | `#pos=0.5,0,0` | positions camera (or XR floor) to xyz-coord 0.5,0,0, |
| `#rot` | vector3 | `#rot=0,90,0` | rotates camera to xyz-coord 0.5,0,0 |
| `#t` | timevector | `#t=2,2000,1` | play animation-loop range between frame 2 and 2000 at (normal) speed 1 |
> xyz coordinates are similar to ones found in SVG Media Fragments
# List of metadata for 3D nodes
## List of metadata for 3D nodes
| key | type | example (JSON) | function | existing compatibility |
|--------------|----------|------------------------|---------------------|----------------------------------------|
| `href` | string | `"href": "b.gltf"` | XR teleport | custom property in 3D fileformats |
| `src` | string | `"src": "#cube"` | XR embed / teleport | custom property in 3D fileformats |
| `tag` | string | `"tag": "cubes geo"` | tag object (for query-use / XRWG highlighting) | custom property in 3D fileformats |
| `tag` | string | `"tag": "cubes geo"` | tag object (for filter-use / XRWG highlighting) | custom property in 3D fileformats |
Supported popular compatible 3D fileformats: `.gltf`, `.obj`, `.fbx`, `.usdz`, `.json` (THREE.js), `.dae` and so on.
> Supported popular compatible 3D fileformats: `.gltf`, `.obj`, `.fbx`, `.usdz`, `.json` (THREE.js), `.dae` and so on.
## vector datatypes
| type | syntax | example | info |
|------
| vector2 | x,y | 2,3.0 | 2-dimensional vector |
| vector3 | x,y,z | 2,3.0,4 | 3-dimensional vector |
| timevector | speed | 1 | 1D timeline: play |
| | | 0 | 1D timeline: stop |
| | x,speed | 1,2 | 1D timeline: play at offset `1` at (normal) speed `2` |
| | | 0,0 | 1D timeline: stop (stopoffset-startoffset == 0) |
| | | 0,1 | 1D timeline: unpause with (normal) speed `1` |
| | | 1..100,1 | 1D timeline: play (loop) between offset `1` and `100` at normal speed (`1`) |
| | x,y,xspeed,yspeed | 0,0.5,0,0 | 2D timeline: stop uv-coordinate at `0,0.5` |
| | | 0,0.5,0.2,0 | 2D timeline: play uv-coordinate at offset `0,0.5` and scroll `x` (=u) `0.2` within each second |
| | | 0,0..0.5,0.2,0 | 2D timeline: play uv-coordinate between offset `0,0` and `0,0.5` (loop) and scroll `x` (=u) `0.2` within each second |
| | x,y,z,xspeed,yspeed,zspeed | 0,0.5,1,0.2,0,2 | XD timeline: play uv-coordinate at `0,0.5` and scroll `x` (=u) `0.2` within each second and pass `1` and `2` as custom data to shader uniforms `za` and `zb` |
> NOTE: XR Fragments are optional but also file- and protocol-agnostic, which means that programmatic 3D scene(nodes) can also use the mechanism/metadata.
## Dynamic XR Fragments (+databindings)
These are automatic fragment-to-metadata mappings, which only trigger if the 3D scene metadata matches a specific identifier (`aliasname` e.g.)
| fragment | type | example | info |
|------------------------|----------|-------------------|-------------------------------------------------------------------------------|
| `#<aliasname>` | string | `#cubes` | evaluate predefined views (`#cubes: #foo&bar` e.g.) |
| `#<tag_or_objectname>` | string | `#person` | focus object(s) with `tag: person` or name `person` by looking up XRWG |
| `#<cameraname>` | string | `#cam01` | set camera as active camera |
| `#<objectname>=<material>` | string=string | `#car=metallic`| set material of car to material with name `metallic` |
| | string=string | `#product=metallic`| set material of objects tagged with `product` to material with name `metallic` |
| `#<objectname>=<mediafrag>` | string=[media frag](https://www.w3.org/TR/media-frags/#valid-uri) | `#foo=0,1`| play media `src` using [media fragment URI](https://www.w3.org/TR/media-frags/#valid-uri) |
| `#<objectname>=<timevector>` | string=timevector | `#sky=0,0.5,0.1,0`| sets 1D/2D/3D time(line) vectors (uv-position e.g.) to `0,0.5` (and autoscroll x with max `0.1` every second)|
| | | `#music=1,2`| play media of object (`src: podcast.mp3` e.g.) from beginning (`1`) at double speed (`2`) |
# Spatial Referencing 3D
XR Fragments assume the following objectname-to-URIFragment mapping:
```
@ -245,7 +279,7 @@ For example, to render a portal with a preview-version of the scene, create an 3
| fragment | type | functionality |
|----------|--------|------------------------------|
| <b>#pos</b>=0,0,0 | vector3 | (re)position camera |
| <b>#pos</b>=0,0,0 | vector3 or string| (re)position camera based on coordinates directly, or indirectly using objectname (its worldposition) |
| <b>#t</b>=0,100 | vector3 | set playback speed, and (re)position looprange of scene-animation or `src`-mediacontent |
| <b>#rot</b>=0,90,0 | vector3 | rotate camera |
@ -256,7 +290,7 @@ For example, to render a portal with a preview-version of the scene, create an 3
1. set the position of the camera accordingly to the vector3 values of `#pos`
1. `rot` sets the rotation of the camera (only for non-VR/AR headsets)
1. `t` sets the playbackspeed and animation-range of the current scene animation(s) or `src`-mediacontent (video/audioframes e.g., use `t=0,7,7` to 'STOP' at frame 7 e.g.)
1. in case an `href` does not mention any `pos`-coordinate, `pos=0,0,0` will be assumed
1. after scene load: in case an `href` does not mention any `pos`-coordinate, `pos=0,0,0` will be assumed
Here's an ascii representation of a 3D scene-graph which contains 3D objects `◻` and their metadata:
@ -291,27 +325,27 @@ The URL-processing-flow for hypermedia browsers goes like this:
5. IF a `#cube` matches anything else in the XR Word Graph (XRWG) draw wires to them (text or related objects).
# Embedding XR content (src-instancing)
# Embedding XR content using src
`src` is the 3D version of the <a target="_blank" href="https://www.w3.org/html/wiki/Elements/iframe">iframe</a>.<br>
It instances content (in objects) in the current scene/asset.
| fragment | type | example value |
|----------|------|---------------|
|`src`| string (uri, hashtag/query) | `#cube`<br>`#sometag`<br>#q=-ball_inside_cube`<br>`#q=-/sky -rain`<br>`#q=-.language .english`<br>`#q=price:>2 price:<5`<br>`https://linux.org/penguin.png`<br>`https://linux.world/distrowatch.gltf#t=1,100`<br>`linuxapp://conference/nixworkshop/apply.gltf#q=flyer`<br>`androidapp://page1?tutorial#pos=0,0,1&t1,100`|
|`src`| string (uri, hashtag/filter) | `#cube`<br>`#sometag`<br>#cube&-ball_inside_cube`<br>`#-sky&-rain`<br>`#-language&english`<br>`#price=>5`<br>`https://linux.org/penguin.png`<br>`https://linux.world/distrowatch.gltf#t=1,100`<br>`linuxapp://conference/nixworkshop/apply.gltf#-cta&cta_apply`<br>`androidapp://page1?tutorial#pos=0,0,1&t1,100`<br>`foo.mp3#0,0,0`|
Here's an ascii representation of a 3D scene-graph with 3D objects `◻` which embeds remote & local 3D objects `◻` with/out using queries:
Here's an ascii representation of a 3D scene-graph with 3D objects `◻` which embeds remote & local 3D objects `◻` with/out using filters:
```
+────────────────────────────────────────────────────────+ +─────────────────────────+
│ │ │ │
│ index.gltf │ │ ocean.com/aquarium.fbx │
│ │ │ │
│ │ │ │ ├ room
│ ├── ◻ canvas │ │ └── ◻ fishbowl │
│ │ └ src: painting.png │ │ ├─ ◻ bass │
│ │ │ │ └─ ◻ tuna │
│ ├── ◻ aquariumcube │ │ │
│ │ └ src: ://rescue.com/fish.gltf#bass%20tuna │ +─────────────────────────+
│ │ └ src: ://rescue.com/fish.gltf#fishbowl │ +─────────────────────────+
│ │ │
│ ├── ◻ bedroom │
│ │ └ src: #canvas
@ -323,35 +357,39 @@ Here's an ascii representation of a 3D scene-graph with 3D objects `◻` which e
```
An XR Fragment-compatible browser viewing this scene, lazy-loads and projects `painting.png` onto the (plane) object called `canvas` (which is copy-instanced in the bed and livingroom).<br>
Also, after lazy-loading `ocean.com/aquarium.gltf`, only the queried objects `bass` and `tuna` will be instanced inside `aquariumcube`.<br>
Also, after lazy-loading `ocean.com/aquarium.gltf`, only the queried objects `fishbowl` (and `bass` and `tuna`) will be instanced inside `aquariumcube`.<br>
Resizing will be happen accordingly to its placeholder object `aquariumcube`, see chapter Scaling.<br>
> Instead of cherrypicking objects with `#bass&tuna` thru `src`, queries can be used to import the whole scene (and filter out certain objects). See next chapter below.
> Instead of cherrypicking a rootobject `#fishbowl` with `src`, additional filters can be used to include/exclude certain objects. See next chapter on filtering below.
**Specification**:
1. local/remote content is instanced by the `src` (query) value (and attaches it to the placeholder mesh containing the `src` property)
1. <b>local</b> `src` values (URL **starting** with `#`, like `#cube&foo`) means **only** the mentioned objectnames will be copied to the instanced scene (from the current scene) while preserving their names (to support recursive selectors). [(example code)](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/src.js)
1. <b>local</b> `src` values indicating a query (`#q=`), means that all included objects (from the current scene) will be copied to the instanced scene (before applying the query) while preserving their names (to support recursive selectors). [(example code)](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/src.js)
1. the instanced scene (from a `src` value) should be <b>scaled accordingly</b> to its placeholder object or <b>scaled relatively</b> based on the scale-property (of a geometry-less placeholder, an 'empty'-object in blender e.g.). For more info see Chapter Scaling.
1. <b>external</b> `src` values should be served with appropriate mimetype (so the XR Fragment-compatible browser will now how to render it). The bare minimum supported mimetypes are:
1. `src` values should make its placeholder object invisible, and only flush its children when the resolved content can succesfully be retrieved (see [broken links](#links))
1. <b>external</b> `src` values should respect the fallback link mechanism (see [broken links](#broken-links)
1. when the placeholder object is a 2D plane, but the mimetype is 3D, then render the spatial content on that plane via a stencil buffer.
1. src-values are non-recursive: when linking to an external object (`src: foo.fbx#bar`), then `src`-metadata on object `bar` should be ignored.
1. clicking on external `src`-values always allow sourceportation: teleporting to the origin URI to which the object belongs.
1. when only one object was cherrypicked (`#cube` e.g.), set its position to `0,0,0`
1. local/remote content is instanced by the `src` (filter) value (and attaches it to the placeholder mesh containing the `src` property)
2. by default all objects are loaded into the instanced src (scene) object (but not shown yet)
2. <b>local</b> `src` values (`#...` e.g.) starting with a non-negating filter (`#cube` e.g.) will (deep)reparent that object (with name `cube`) as the new root of the scene at position 0,0,0
3. <b>local</b> `src` values should respect (negative) filters (`#-foo&price=>3`)
4. the instanced scene (from a `src` value) should be <b>scaled accordingly</b> to its placeholder object or <b>scaled relatively</b> based on the scale-property (of a geometry-less placeholder, an 'empty'-object in blender e.g.). For more info see Chapter Scaling.
5. <b>external</b> `src` values should be served with appropriate mimetype (so the XR Fragment-compatible browser will now how to render it). The bare minimum supported mimetypes are:
6. `src` values should make its placeholder object invisible, and only flush its children when the resolved content can succesfully be retrieved (see [broken links](#links))
7. <b>external</b> `src` values should respect the fallback link mechanism (see [broken links](#broken-links)
8. when the placeholder object is a 2D plane, but the mimetype is 3D, then render the spatial content on that plane via a stencil buffer.
9. src-values are non-recursive: when linking to an external object (`src: foo.fbx#bar`), then `src`-metadata on object `bar` should be ignored.
10. an external `src`-value should always allow a sourceportation icon within 3 meter: teleporting to the origin URI to which the object belongs.
11. when only one object was cherrypicked (`#cube` e.g.), set its position to `0,0,0`
12. when the enduser clicks an href with `#t=1,0,0` (play) will be applied to all src mediacontent with a timeline (mp4/mp3 e.g.)
13. a non-euclidian portal can be rendered for flat 3D objects (using stencil buffer e.g.) in case ofspatial `src`-values (an object `#world3` or URL `world3.fbx` e.g.).
* `model/gltf-binary`
* `model/gltf+json`
* `image/png`
* `image/jpg`
* `text/plain;charset=utf-8;bib=^@`
* `text/plain;charset=utf-8`
[» example implementation](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/src.js)<br>
[» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/src.gltf#L192)<br>
[» discussion](https://github.com/coderofsalvation/xrfragment/issues/4)<br>
# Navigating content (internal/outbound href portals)
# Navigating content href portals
navigation, portals & mutations
@ -367,16 +405,24 @@ navigation, portals & mutations
4. URL navigation should always be reflected in the client (in case of javascript: see [[here](https://github.com/coderofsalvation/xrfragment/blob/dev/src/3rd/js/three/navigator.js) for an example navigator).
5. In XR mode, the navigator back/forward-buttons should be always visible (using a wearable e.g., see [[here](https://github.com/coderofsalvation/xrfragment/blob/dev/example/aframe/sandbox/index.html#L26-L29) for an example wearable)
7. In XR mode, the navigator back/forward-buttons should be always visible (using a wearable e.g., see [[here](https://github.com/coderofsalvation/xrfragment/blob/dev/example/aframe/sandbox/index.html#L26-L29) for an example wearable)
6. in case of navigating to a new [[pos)ition, ''first'' navigate to the ''current position'' so that the ''back-button'' of the ''browser-history'' always refers to the previous position (see [[here](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/href.js#L97))
8. in case of navigating to a new [[pos)ition, ''first'' navigate to the ''current position'' so that the ''back-button'' of the ''browser-history'' always refers to the previous position (see [[here](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/href.js#L97))
7. portal-rendering: a 2:1 ratio texture-material indicates an equirectangular projection
9. ignore previous rule in special cases, like clicking an `href` using camera-portal collision (the back-button would cause a teleport-loop)
[» example implementation](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/href.js)<br>
[» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/href.gltf#L192)<br>
[» discussion](https://github.com/coderofsalvation/xrfragment/issues/1)<br>
## Walking surfaces
XR Fragment-compatible viewers can infer this data based scanning the scene for:
1. materialless (nameless & textureless) mesh-objects (without `src` and `href`)
> optionally the viewer can offer thumbstick, mouse or joystick teleport-tools for non-roomscale VR/AR setups.
## UX spec
End-users should always have read/write access to:
@ -407,58 +453,98 @@ How does the scale of the object (with the embedded properties) impact the scale
> TODO: needs intermediate visuals to make things more obvious
# XR Fragment queries
# XR Fragment: pos
# XR Fragment: rot
# XR Fragment: t
controls the animation(s) of the scene (or `src` resource which contains a timeline)
| fragment | type | functionality |
| <b>#t</b>=1,1,100 | [[vector3|vector]] (default:`#t=1,0,0`) | speed,framestart,framestop |
* playposition is reset to framestart, when framestart or framestop is greater than 0 |
| Example Value | Explanation |
|-|-|
| `1,1,100` | play loop between frame 1 and 100 |
| `1,1,0` | play once from frame 1 (oneshot) |
| `1,0,0` | play (previously set looprange if any) |
| `0,0,0` | pause |
| `1,1,1` | play and auto-loop between begin and end of duration |
| `-1,0,0` | reverse playback speed |
| `2.3,0,0` | set (forward) playback speed to 2.3 (no restart) |
| `-2.3,0,0` | set (reverse) playback speed to -2.3 ( no restart)|
| `-2.3,100,0` | set (reverse) playback speed to -2.3 restarting from frame 100 |
[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/t.js]]<br>
[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/10]]<br>
# XR audio/video integration
To play global audio/video items:
1. add a `src: foo.mp3` or `src: bar.mp4` metadata to a 3D object (`cube` e.g.)
1. to disable auto-play and global timeline ([[#t=|t]]) control: hardcode a [[#t=|t]] XR Fragment: (`src: bar.mp3#t=0,0,0` e.g.)
1. to play it, add `href: #cube` somewhere else
1. when the enduser clicks the `href`, `#t=1,0,0` (play) will be applied to the `src` value
1. to play a single animation, add href: #animationname=1,0,0 somewhere else
> NOTE: hardcoded framestart/framestop uses sampleRate/fps of embedded audio/video, otherwise the global fps applies. For more info see [[#t|t]].
# XR Fragment filters
Include, exclude, hide/shows objects using space-separated strings:
| example | outcome |
|----------------------------------|------------------------------------------------------------------------------------|
| `#q=-sky` | show everything except object named `sky` |
| `#q=-tag:language tag:english` | hide everything with tag `language`, but show all tag `english` objects |
| `#q=price:>2 price:<5` | of all objects with property `price`, show only objects with value between 2 and 5 |
| `#-sky` | show everything except object named `sky` |
| `#-language&english` | hide everything with tag `language`, but show all tag `english` objects |
| `#-price&price=>10` | hide all objects with property `price`, then only show object with price above 10 |
It's simple but powerful syntax which allows filtering the scene using searchengine prompt-style feeling:
1. queries are a way to traverse a scene, and filter objects based on their tag- or property-values.
1. words like `german` match tag-metadata of 3D objects like `"tag":"german"`
1. words like `german` match (XR Text) objects with (Bib(s)TeX) tags like `#KarlHeinz@german` or `@german{KarlHeinz, ...` e.g.
1. filters are a way to traverse a scene, and filter objects based on their name, tag- or property-values.
* see [an (outdated) example video here](https://coderofsalvation.github.io/xrfragment.media/queries.mp4)
* see [an (outdated) example video here](https://coderofsalvation.github.io/xrfragment.media/queries.mp4) which used a dedicated `q=` variable (now deprecated and usable directly)
## including/excluding
By default, selectors work like photoshop-layers: they scan for matching layer(name/properties) within the scene-graph.
Each matched object (not their children) will be toggled (in)visible when selecting.
| operator | info |
|----------|-------------------------------------------------------------------------------------------------------------------------------|
| `-` | removes/hides object(s) |
| `:` | indicates an object-embedded custom property key/value |
| `>` `<` | compare float or int number |
| `/` | reference to root-scene.<br>Useful in case of (preventing) showing/hiding objects in nested scenes (instanced by `src`) (*) |
| `-` | hides object(s) (`#-myobject&-objects` e.g. |
| `=` | indicates an object-embedded custom property key/value (`#price=4&category=foo` e.g.) |
| `=>` `=<`| compare float or int number (`#price=>4` e.g.) |
| `*` | deepselect: automatically select children of selected object, including local (nonremote) embedded objects (starting with `#`)|
> \* = `#q=-/cube` hides object `cube` only in the root-scene (not nested `cube` objects)<br> `#q=-cube` hides both object `cube` in the root-scene <b>AND</b> nested `skybox` objects |
> NOTE 1: after an external embedded object has been instanced (`src: https://y.com/bar.fbx#room` e.g.), filters do not affect them anymore (reason: local tag/name collisions can be mitigated easily, but not in case of remote content).
> NOTE 2: depending on the used 3D framework, toggling objects (in)visible should happen by enabling/disableing writing to the colorbuffer (to allow children being still visible while their parents are invisible).
[» example implementation](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/q.js)
[» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/query.gltf#L192)
[» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/filter.gltf#L192)
[» discussion](https://github.com/coderofsalvation/xrfragment/issues/3)
## Query Parser
## Filter Parser
Here's how to write a query parser:
Here's how to write a filter parser:
1. create an associative array/object to store query-arguments as objects
1. detect object id's & properties `foo:1` and `foo` (reference regex: `/^.*:[><=!]?/` )
1. detect excluders like `-foo`,`-foo:1`,`-.foo`,`-/foo` (reference regex: `/^-/` )
1. detect root selectors like `/foo` (reference regex: `/^[-]?\//` )
1. detect number values like `foo:1` (reference regex: `/^[0-9\.]+$/` )
1. for every query token split string on `:`
1. create an empty array `rules`
1. then strip key-operator: convert "-foo" into "foo"
1. add operator and value to rule-array
1. therefore we we set `id` to `true` or `false` (false=excluder `-`)
1. create an associative array/object to store filter-arguments as objects
1. detect object id's & properties `foo=1` and `foo` (reference regex= `~/^.*=[><=]?/` )
1. detect excluders like `-foo`,`-foo=1`,`-.foo`,`-/foo` (reference regex= `/^-/` )
1. detect root selectors like `/foo` (reference regex= `/^[-]?\//` )
1. detect number values like `foo=1` (reference regex= `/^[0-9\.]+$/` )
1. detect operators so you can easily strip keys (reference regex= `/(^-|\*$)/` )
1. detect exclude keys like `-foo` (reference regex= `/^-/` )
1. for every filter token split string on `=`
1. and we set `root` to `true` or `false` (true=`/` root selector is present)
1. we convert key '/foo' into 'foo'
1. finally we add the key/value to the store like `store.foo = {id:false,root:true}` e.g.
1. therefore we we set `show` to `true` or `false` (false=excluder `-`)
> An example query-parser (which compiles to many languages) can be [found here](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Query.hx)
> An example filter-parser (which compiles to many languages) can be [found here](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Filter.hx)
# Visible links
@ -789,12 +875,12 @@ For example:
│ │
│ index.gltf │
│ │ │
│ │ #: #q=-offlinetext │
│ │ #: #-offlinetext │
│ │ │
│ ├── ◻ buttonA │
│ │ └ href: http://foo.io/campagne.fbx │
│ │ └ href@404: ipfs://foo.io/campagne.fbx │
│ │ └ href@400: #q=clienterrortext │
│ │ └ href@400: #clienterrortext
│ │ └ ◻ offlinetext │
│ │ │
│ └── ◻ embeddedObject <--------- the meshdata inside embeddedObject will (not)
@ -816,11 +902,11 @@ Consider 3D scenes linking to eachother using these `href` values:
* `href: university.edu/projects.gltf#math`
These links would all show visible links to math-tagged objects in the scene.<br>
To filter out non-related objects one could take it a step further using queries:
To filter out non-related objects one could take it a step further using filters:
* `href: schoolA.edu/projects.gltf#math&q=-topics math`
* `href: schoolB.edu/projects.gltf#math&q=-courses math`
* `href: university.edu/projects.gltf#math&q=-theme math`
* `href: schoolA.edu/projects.gltf#math&-topics math`
* `href: schoolB.edu/projects.gltf#math&-courses math`
* `href: university.edu/projects.gltf#math&-theme math`
> This would hide all object tagged with `topic`, `courses` or `theme` (including math) so that later only objects tagged with `math` will be visible
@ -854,6 +940,15 @@ This document has no IANA actions.
* [NLNET](https://nlnet.nl)
* [Future of Text](https://futureoftext.org)
* [visual-meta.info](https://visual-meta.info)
* Michiel Leenaars
* Gerben van der Broeke
* Mauve
* Jens Finkhäuser
* Marc Belmont
* Tim Gerritsen
* Frode Hegland
* Brandel Zackernuk
* Mark Anderson
# Appendix: Definitions
@ -872,7 +967,7 @@ This document has no IANA actions.
|placeholder object | a 3D object which with src-metadata (which will be replaced by the src-data.) |
|src | (HTML-piggybacked) metadata of a 3D object which instances content |
|href | (HTML-piggybacked) metadata of a 3D object which links to content |
|query | an URI Fragment-operator which queries object(s) from a scene like `#q=cube` |
|filter | URI Fragment(s) which show/hide object(s) in a scene based on name/tag/property (`#cube&-price=>3`) |
|visual-meta | [visual-meta](https://visual.meta.info) data appended to text/books/papers which is indirectly visible/editable in XR. |
|requestless metadata | metadata which never spawns new requests (unlike RDF/HTML, which can cause framerate-dropping, hence not used a lot in games) |
|FPS | frames per second in spatial experiences (games,VR,AR e.g.), should be as high as possible |
@ -880,6 +975,7 @@ This document has no IANA actions.
|extrospective | outward sensemaking ("I'm fairly sure John is a person who lives in oklahoma") |
|`◻` | ascii representation of an 3D object/mesh |
|(un)obtrusive | obtrusive: wrapping human text/thought in XML/HTML/JSON obfuscates human text into a salad of machine-symbols and words |
|flat 3D object | a 3D object of which all verticies share a plane |
|BibTeX | simple tagging/citing/referencing standard for plaintext |
|BibTag | a BibTeX tag |
|(hashtag)bibs | an easy to speak/type/scan tagging SDL ([see here](https://github.com/coderofsalvation/hashtagbibs) which expands to BibTex/JSON/XML |

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View file

@ -1 +0,0 @@
assets/example.gltf

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1 @@
assets/index.glb

View file

@ -7,7 +7,7 @@
<link rel="stylesheet" href="./../../assets/css/axist.min.css" />
<link type="text/css" rel="stylesheet" href="./../../assets/css/style.css"/>
<script async src="./../../assets/js/alpine.min.js" defer></script>
<script src="https://aframe.io/releases/1.4.2/aframe.min.js"></script>
<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/aframe-blink-controls/dist/aframe-blink-controls.min.js"></script>
<script src="./../../../dist/xrfragment.aframe.js"></script>
<script src="./../../assets/js/qr.js"></script>
@ -30,58 +30,55 @@
<textarea style="display:none"></textarea>
<canvas id="qrcode" style="display:none" width="300" height="300"></canvas>
<a-scene light="defaultLightsEnabled: false">
<a-entity id="player" wasd-controls look-controls>
<a-entity id="left-hand" laser-controls="hand: left" raycaster="objects:.ray" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor">
<a-entity rotation="-90 0 0" position="0 0.1 0" id="navigator">
<a-scene renderer="colorManagement: true; highRefreshRate:true" light="defaultLightsEnabled: false">
<a-entity id="player">
<a-entity camera="fov:90" position="0 1.6 0" wasd-controls look-controls id="camera"></a-entity>
<a-entity id="left-hand" laser-controls="hand: left" raycaster="objects:.ray" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: .floor">
<a-entity rotation="-35 0 0" position="0 0.1 0" id="navigator">
<a-entity id="back" xrf-button="label: <; width:0.05; action: history.back()" position="-0.025 0 0" class="ray"></a-entity>
<a-entity id="next" xrf-button="label: >; width:0.05; action: history.forward()" position=" 0.025 0 0" class="ray"></a-entity>
</a-entity>
</a-entity>
<a-entity id="right-hand" laser-controls="hand: right" raycaster="objects:.ray" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor"></a-entity>
<a-entity camera="fov:90" position="0 1.6 0" id="camera"></a-entity>
<a-entity id="right-hand" laser-controls="hand: right" raycaster="objects:.ray" blink-controls="cameraRig:#player; teleportOrigin: #player; collisionEntities: .floor"></a-entity>
</a-entity>
<a-entity id="home" xrf="index.gltf#pos=0,0,0"></a-entity>
<a-plane id="floor" position="0 0 0" rotation="-90 0 0" width="100" height="100" material="visible:false"></a-plane>
<a-entity id="home" xrf="index.glb"></a-entity>
</a-scene>
<script>
window.$ = (s) => document.querySelector(s)
window.notify = notify(window)
window.embed = embed
console.log = ( (log) => function(str){
if( String(str).match(/:.*#/) ) window.notify(str)
log(str)
})(console.log)
if( document.location.search.length > 2 )
$('#home').setAttribute('xrf', document.location.search.substr(1)+document.location.hash )
// allow iframe to open url
window.addEventListener('message', (event) => {
if (event.data && event.data.url) {
window.open(event.data.url, '_blank');
}
});
$('a-scene').addEventListener('XRF', () => {
window.notify = notify(window)
window.embed = embed
window.notify('loading '+document.location.search.substr(1))
// reroute console messages to snackbar notifications
console.log = ( (log) => function(str){
if( String(str).match(/(:.*#|note:)/) ) window.notify(str)
log(str)
})(console.log)
let XRF = window.AFRAME.XRF
setupConsole( $('textarea') )
setupUrlBar( $('input#uri'), XRF )
// example listener, to prompt surfing to external asset
XRF.addEventListener('href',(e) => {
if( e.click ){
const { mesh, model, camera, scene, renderer, THREE} = e.XRF
const url = e.xrf.string
const isExtern = url[0] != '#'
const notIsHome = url != $('#home').getAttribute("xrf")
const promise = e.promise() // promisify event
document.querySelector('#model').setAttribute('href',url.replace(/.*\?/,'') )
if( !renderer.xr.isPresenting ){
if( isExtern && notIsHome ){
if( !confirm("teleport to "+url+" ?") ) return promise.reject('teleport rejected')
}
}
promise.resolve()
}
})
// on localhost enable debugging mode for developer convenience
let loc = document.location
if( loc.host.match(/^localhost/) ){
$('a-scene').setAttribute('stats')
XRF.debug = 1
}
// add screenshot component with camera to capture bigger size equirects
// document.querySelector('a-scene').components.screenshot.capture('perspective')

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

View file

@ -0,0 +1,262 @@
{
"accessors" : [
{
"bufferView" : 0,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"max" : [
2.000000
],
"min" : [
0.000000
],
"type" : "SCALAR"
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"max" : [
0.000000,
1.000000,
0.000000,
1.000000
],
"min" : [
0.000000,
-8.742278e-008,
0.000000,
-1.000000
],
"type" : "VEC4"
},
{
"bufferView" : 2,
"byteOffset" : 0,
"componentType" : 5123,
"count" : 36,
"max" : [
35
],
"min" : [
0
],
"type" : "SCALAR"
},
{
"bufferView" : 3,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000,
1.000001
],
"min" : [
-1.000000,
-1.000000,
-1.000000
],
"type" : "VEC3"
},
{
"bufferView" : 4,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000,
1.000000
],
"min" : [
-1.000000,
-1.000000,
-1.000000
],
"type" : "VEC3"
},
{
"bufferView" : 5,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
-0.000000,
-0.000000,
1.000000
],
"min" : [
0.000000,
-0.000000,
-1.000000,
-1.000000
],
"type" : "VEC4"
},
{
"bufferView" : 6,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000
],
"min" : [
-1.000000,
-1.000000
],
"type" : "VEC2"
}
],
"animations" : [
{
"channels" : [
{
"sampler" : 0,
"target" : {
"node" : 0,
"path" : "rotation"
}
}
],
"name" : "animation_AnimatedCube",
"samplers" : [
{
"input" : 0,
"interpolation" : "LINEAR",
"output" : 1
}
]
}
],
"asset" : {
"generator" : "VKTS glTF 2.0 exporter",
"version" : "2.0"
},
"bufferViews" : [
{
"buffer" : 0,
"byteLength" : 12,
"byteOffset" : 0
},
{
"buffer" : 0,
"byteLength" : 48,
"byteOffset" : 12
},
{
"buffer" : 0,
"byteLength" : 72,
"byteOffset" : 60,
"target" : 34963
},
{
"buffer" : 0,
"byteLength" : 432,
"byteOffset" : 132,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 432,
"byteOffset" : 564,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 576,
"byteOffset" : 996,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 288,
"byteOffset" : 1572,
"target" : 34962
}
],
"buffers" : [
{
"byteLength" : 1860,
"uri" : "AnimatedCube.bin"
}
],
"images" : [
{
"uri" : "AnimatedCube_BaseColor.png"
},
{
"uri" : "AnimatedCube_MetallicRoughness.png"
}
],
"materials" : [
{
"name" : "AnimatedCube",
"pbrMetallicRoughness" : {
"baseColorTexture" : {
"index" : 0
},
"metallicRoughnessTexture" : {
"index" : 1
}
}
}
],
"meshes" : [
{
"name" : "AnimatedCube",
"primitives" : [
{
"attributes" : {
"NORMAL" : 4,
"POSITION" : 3,
"TANGENT" : 5,
"TEXCOORD_0" : 6
},
"indices" : 2,
"material" : 0,
"mode" : 4
}
]
}
],
"nodes" : [
{
"mesh" : 0,
"name" : "AnimatedCube",
"rotation" : [
0.000000,
-1.000000,
0.000000,
0.000000
]
}
],
"samplers" : [
{}
],
"scene" : 0,
"scenes" : [
{
"nodes" : [
0
]
}
],
"textures" : [
{
"sampler" : 0,
"source" : 0
},
{
"sampler" : 0,
"source" : 1
}
]
}

View file

@ -0,0 +1,160 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v3.5.30",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0
]
}
],
"nodes":[
{
"mesh":0,
"name":"AnimatedCube"
}
],
"animations":[
{
"channels":[
{
"sampler":0,
"target":{
"node":0,
"path":"rotation"
}
}
],
"name":"walk",
"samplers":[
{
"input":4,
"interpolation":"LINEAR",
"output":5
}
]
}
],
"materials":[
{
"name":"AnimatedCube",
"pbrMetallicRoughness":{}
}
],
"meshes":[
{
"name":"AnimatedCube",
"primitives":[
{
"attributes":{
"POSITION":0,
"TEXCOORD_0":1,
"NORMAL":2
},
"indices":3,
"material":0
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":36,
"max":[
1,
1,
1.0000009536743164
],
"min":[
-1,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":36,
"type":"VEC2"
},
{
"bufferView":2,
"componentType":5126,
"count":36,
"type":"VEC3"
},
{
"bufferView":3,
"componentType":5123,
"count":36,
"type":"SCALAR"
},
{
"bufferView":4,
"componentType":5126,
"count":3,
"max":[
2
],
"min":[
0
],
"type":"SCALAR"
},
{
"bufferView":5,
"componentType":5126,
"count":3,
"type":"VEC4"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":432,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":288,
"byteOffset":432,
"target":34962
},
{
"buffer":0,
"byteLength":432,
"byteOffset":720,
"target":34962
},
{
"buffer":0,
"byteLength":72,
"byteOffset":1152,
"target":34963
},
{
"buffer":0,
"byteLength":12,
"byteOffset":1224
},
{
"buffer":0,
"byteLength":48,
"byteOffset":1236
}
],
"buffers":[
{
"byteLength":1284,
"uri":"data:application/octet-stream;base64,AACAPwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/7/9/PwAAgD8IAIA/AACAPwAAgD/v/3+/AACAPwAAgD/v/3+/AACAPwAAgL8AAIA/AACAPwAAgL8AAIC/7/9/PwAAgD8IAIA/AACAvwAAgL8AAIA/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/AACAPwAAgD/v/3+/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/7/9/PwAAgD8IAIA/AACAPwAAgD/v/3+/7/9/PwAAgD8IAIA/AACAPwAAgL8AAIA/7/9/PwAAgD8IAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAPwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAIA/AAAAAAAAAAAAAIA/AACAvwAAgD8AAAAAAACAPwAAAAAAAAAAAACAvwAAgD8AAIC/AACAPwAAAAAAAACAAACAvwAAgD8AAIC/AAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAIC/AACAPwAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAIA/AAAAAAAAAAAAAACAAACAvwAAgD8AAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAIAAAIC/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAIA/AAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAACAPwAAAAAAAACAAACAPwAAAAAAAACAAACAPwAAAAAAAACAAAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AACAvwAAAAAAAACAAACAvwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AACAvwAAAAAAAACAAACAvwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAAAAAAAAAgD8AAABAAAAAAAAAAAAAAACAAACAPwAAAIAAAIC/AAAAAC69OzMAAAAALr27MwAAAIAAAIA/"
}
]
}

View file

@ -33,7 +33,7 @@ input[type="submit"] {
}
#overlay{
background: #FFF;
background: #FFFb;
position: fixed;
top: 0;
left: 0;
@ -130,6 +130,7 @@ a#model{
}
html.a-fullscreen a.btn-foot {
line-height:36px;
margin-right:10px;
}

BIN
example/assets/index.fbx Normal file

Binary file not shown.

BIN
example/assets/index.glb Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

164
example/assets/index.mtl Normal file
View file

@ -0,0 +1,164 @@
# Blender MTL File: 'None'
# Material Count: 16
newmtl None
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2
newmtl environmentMap.002
Ns 359.999993
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
newmtl environmentMap.004
Ns 359.999993
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
newmtl floorstone.003
Ns 349.173522
Ka 1.000000 1.000000 1.000000
Kd 0.370787 0.337474 0.425554
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 3
map_Ke .
newmtl floorstone.004
Ns 349.173522
Ka 1.000000 1.000000 1.000000
Kd 0.370787 0.337474 0.425554
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 3
map_Ke .
newmtl glass.002
Ns 1000.000000
Ka 0.963543 0.963543 0.963543
Kd 1.000000 1.000000 1.000000
Ks 0.234677 0.234677 0.234677
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 0.143627
illum 6
newmtl hotspot
Ns 359.999993
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
newmtl placeholder.003
Ns 854.195174
Ka 0.886364 0.886364 0.886364
Kd 1.000000 1.000000 1.000000
Ks 0.327273 0.327273 0.327273
Ke 0.113646 0.000000 35.199997
Ni 1.450000
d 0.159091
illum 6
newmtl placeholder.004
Ns 854.195174
Ka 0.886364 0.886364 0.886364
Kd 1.000000 1.000000 1.000000
Ks 0.327273 0.327273 0.327273
Ke 0.000000 0.330810 35.199997
Ni 1.450000
d 0.159091
illum 6
newmtl portal_bg.004
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 0.000000
Ks 0.068182 0.068182 0.068182
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.222727
illum 6
newmtl portal_bg.005
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 0.000000
Ks 0.068182 0.068182 0.068182
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.222727
illum 6
newmtl portal_bg.006
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 0.000000
Ks 0.068182 0.068182 0.068182
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.222727
illum 6
newmtl text.004
Ns 854.195174
Ka 0.886364 0.886364 0.886364
Kd 1.000000 1.000000 1.000000
Ks 0.327273 0.327273 0.327273
Ke 1.000000 1.000000 1.000000
Ni 1.450000
d 1.000000
illum 3
newmtl text.005
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Kd 0.080782 0.080782 0.080782
Ks 0.068182 0.068182 0.068182
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 3
newmtl text.006
Ns 854.195174
Ka 0.886364 0.886364 0.886364
Kd 0.518619 0.518619 0.518619
Ks 0.327273 0.327273 0.327273
Ke 1.000000 1.000000 1.000000
Ni 1.450000
d 1.000000
illum 3
newmtl vaporgradient.002
Ns 951.107117
Ka 0.827273 0.827273 0.827273
Kd 0.800000 0.800000 0.800000
Ks 0.327273 0.327273 0.327273
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 3
map_Kd .
map_Ke .

194201
example/assets/index.obj Normal file

File diff suppressed because it is too large Load diff

70
example/assets/index.py Normal file
View file

@ -0,0 +1,70 @@
#
# This is a convenient way to convert the scene to lowpoly
# (by adding decimate-modifiers)
# and then exporting a gltf to to <blenderdocument>.glb
#
# All this is done automatically when saving the blender file
#
import bpy
import os
from bpy_extras.io_utils import ImportHelper
# uncomment below in case you want to hardcode the exported filename
data = {
#gltf_file="/some/path/foo.index.glb"
}
def notify(message = "", title = "Message Box", icon = 'INFO'):
def draw(self, context):
self.layout.label(text=message)
bpy.context.window_manager.popup_menu(draw, title = title, icon = icon)
# redirect print to all consoles
def print(data):
for window in bpy.context.window_manager.windows:
screen = window.screen
for area in screen.areas:
if area.type == 'CONSOLE':
override = {'window': window, 'screen': screen, 'area': area}
bpy.ops.console.scrollback_append(override, text=str(data), type="OUTPUT")
# Function to add Decimate Modifier to objects without one (except those in the exclusion list)
def add_decimate_modifier_to_objects():
for obj in bpy.data.objects:
print(obj.type)
if obj is not None and (obj.type == 'FONT' or (obj.type == 'MESH' and len(obj.data.polygons) > 8)):
if not obj.modifiers.get("Decimate"):
#if obj.name not in exclusion_list and "Decimate" not in obj.modifiers:
print("adding decimate-modifier to:"+obj.name)
bpy.context.view_layer.objects.active = obj
bpy.data.objects[obj.name].select_set(True)
# Add Decimate Modifier with ratio 0.5
bpy.ops.object.modifier_add(type='DECIMATE')
bpy.context.object.modifiers["Decimate"].ratio = 0.5
# Function to be called on file save
def on_save_handler(blenderdoc):
if 'gltf_file' not in data:
gltf_file = bpy.data.filepath.replace('.blend','.glb')
else:
gltf_file = data['gltf_file']
add_decimate_modifier_to_objects()
# Export to glTF with specified settings and apply modifiers
bpy.ops.export_scene.gltf(
filepath=gltf_file,
export_format='GLB',
export_extras=True,
export_lights=True,
export_apply=True,
export_force_sampling=False,
)
notify(os.path.basename(gltf_file),"OK export")
# Register the handler
bpy.app.handlers.save_post.clear()
bpy.app.handlers.save_post.append(on_save_handler)
print("sourced gltf_export_on_save")

View file

@ -267,7 +267,7 @@ export function notify(scope){
if( str.match(/error/g) ) opts.status = "danger"
if( str.match(/warning/g) ) opts.status = "warning"
}
opts = Object.assign({ message: str , status, timeout:2000 },opts)
opts = Object.assign({ message: str , status, timeout:4000 },opts)
SnackBar( opts )
}
}
@ -285,12 +285,25 @@ export function download(){
}
export function embed(){
// *TODO* this should be part of the XRF framework
let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs
// *TODO* this should be part of the XRF Threejs framework
if( typeof THREE == 'undefined' ) THREE = xrf.THREE
let radToDeg = THREE.MathUtils.radToDeg
let toDeg = (x) => x / (Math.PI / 180)
let camera = document.querySelector('[camera]').object3D.parent // *TODO* fix for threejs
// *TODO* add camera direction
let direction = new xrf.THREE.Vector3()
camera.getWorldDirection(direction)
const pitch = Math.asin(direction.y);
const yaw = Math.atan2(direction.x, direction.z);
const pitchInDegrees = pitch * 180 / Math.PI;
const yawInDegrees = yaw * 180 / Math.PI;
let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}`
let newHash = document.location.hash.replace(/[&]?pos=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'')
let newHash = document.location.hash.replace(/[&]?(pos|rot)=[0-9\.-]+,[0-9\.-]+,[0-9\.-]+/,'')
newHash += `&${lastPos}`
document.location.hash = newHash.replace(/&&/,'&')
.replace(/#&/,'')
// copy url to clipboard
var dummy = document.createElement('input'),
text = window.location.href;

BIN
example/assets/podcast.mp3 Normal file

Binary file not shown.

BIN
example/assets/test.mp3 Normal file

Binary file not shown.

BIN
example/assets/test.ogg Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

80
make
View file

@ -2,6 +2,7 @@
set -e
try(){ set +e; "$@" 2>/dev/null; set -e; }
trace(){ set -x; "$@"; set +x; }
install(){
which haxe || {
@ -26,8 +27,8 @@ install(){
tests(){
{
which python3 && python3 test/generated/test.py src/spec/*.json | awk '{ print "py: "$0 } END{ print "\n"}'
which node && node test/generated/test.js src/spec/*.json | awk '{ print "js: "$0 } END{ print "\n"}'
which python3 && python3 test/generated/test.py src/spec/*.json | awk '{ print "py: "$0 } END{ print "\n"}'
} | awk '$2 ~ /src/ { $2=sprintf("%-30s",$2); print $0; next; } 1' | tee /tmp/log.txt
grep error /tmp/log.txt && exit 1 || exit 0
}
@ -51,36 +52,55 @@ server(){
}
build(){
try rm dist/*
haxe build.hxml
ok=$?
sed -i 's|.*nonlocal .*||g' dist/xrfragment.py
echo build OK
build_js
}
build_js(){
# prepend license to vanilla lib
#echo "// https://xrfragment.org\n// SPDX-License-Identifier: MPL-2.0\n$(cat dist/xrfragment.js)" > dist/xrfragment.js
# add js module
cat dist/xrfragment.js > dist/xrfragment.module.js
echo "export default xrfragment;" >> dist/xrfragment.module.js
# add THREE
cat dist/xrfragment.js \
src/3rd/js/*.js \
src/3rd/js/three/*.js \
src/3rd/js/three/xrmacro/*.js \
src/3rd/js/three/xrf/*.js > dist/xrfragment.three.js
# add THREE module
cat dist/xrfragment.three.js > dist/xrfragment.three.module.js
echo "export default xrf;" >> dist/xrfragment.three.module.js
# add AFRAME
cat dist/xrfragment.three.js \
src/3rd/js/aframe/*.js > dist/xrfragment.aframe.js
# convert ESM to normal browser js
sed 's/export //g' example/assets/js/utils.js > dist/utils.js
ls -la dist | grep js
exit $ok
parser(){
try rm dist/*
haxe build.hxml || exit 1
sed -i 's|.*nonlocal .*||g' dist/xrfragment.py
ls -lah dist/*
echo -e "[OK] parser build\n"
return $ok
}
js(){
# add js module
cat dist/xrfragment.js >> dist/xrfragment.module.js
echo "export default xrfragment;" >> dist/xrfragment.module.js
# add THREE
cat dist/xrfragment.js \
src/3rd/js/*.js \
src/3rd/js/three/*.js \
src/3rd/js/three/xrmacro/env.js \
src/3rd/js/three/xrf/*.js \
src/3rd/js/three/util/*.js \
src/3rd/js/three/xrf/dynamic/*.js \
src/3rd/js/three/xrf/src/*.js > dist/xrfragment.three.js
# add THREE module
cat dist/xrfragment.three.js > dist/xrfragment.three.module.js
echo "export default xrf;" >> dist/xrfragment.three.module.js
# add AFRAME
cat dist/xrfragment.three.js \
src/3rd/js/aframe/*.js > dist/xrfragment.aframe.js
# convert ESM to normal browser js
sed 's/export //g' example/assets/js/utils.js > dist/utils.js
# add license headers
for file in dist/xrfragment.{aframe,module,three,three.module}.js; do
awk 'BEGIN{
print "/*"
print " * generated at $(date)"
print " * https://xrfragment.org"
print " * SPDX-License-Identifier: MPL-2.0"
print " */"
system("cat '$file'")
}' > /tmp/tmp.js
mv /tmp/tmp.js $file
done
ls -la dist | grep js
return $ok
}
test -z $1 && { parser && js; }
test -z $1 || "$@"
}
test -z $1 && build

View file

@ -4,6 +4,8 @@
# nativeBuildInputs is usually what you want -- tools you need to run
nativeBuildInputs = with pkgs.buildPackages; [
nodejs
haxe
mmark
xml2rfc

View file

@ -12,18 +12,19 @@ XRWG.cleankey = (word) => String(word).replace(/[^0-9\.a-zA-Z_]/g,'')
XRWG.get = (v,k) => XRWG.find( (x) => x[ k || 'word'] == v )
XRWG.match = (str,types,level) => {
level = level || 1000
if( XRWG.length == 0 ) XRWG.generate(xrf)
level = level == undefined ? 1000 : level
types = types || []
let res = XRWG.filter( (n) => {
types.map( (type) => n[type] ? n = false : false )
return n
})
str = str.toLowerCase()
if( level <10 ) res = res.filter( (n) => n.key == str )
if( level <20 ) res = res.filter( (n) => n.word == str || n.key == str )
if( level <30 ) res = res.filter( (n) => n.word.match(str) || n.key == str )
if( level <40 ) res = res.filter( (n) => n.word.match(str) || n.key == str || String(n.value||'').match(str) )
if( level <1001 ) res = res.filter( (n) => n.word.match(str) != null || n.key.match(str) != null || String(n.value||'').match(str) != null)
if( level <10 ) res = res.filter( (n) => n.key == str )
if( level >=10 ) res = res.filter( (n) => n.word == str || n.key == str )
if( level >30 ) res = res.filter( (n) => n.word.match(str) || n.key == str )
if( level >40 ) res = res.filter( (n) => n.word.match(str) || n.key == str || String(n.value||'').match(str) )
if( level >999 ) res = res.filter( (n) => n.word.match(str) != null || n.key.match(str) != null || String(n.value||'').match(str) != null)
return res
}
@ -42,7 +43,7 @@ XRWG.generate = (opts) => {
node = { word: XRWG.cleankey(key), key, nodes:[spatialNode] }
if( spatialNode.userData[key] ) node.value = spatialNode.userData[key]
node[type] = true
xrf.emit('XRWG',node)
xrf.emit('XRWGnode',node)
XRWG.push( node )
}
}
@ -64,5 +65,5 @@ XRWG.generate = (opts) => {
// sort by n
XRWG.sort( (a,b) => a.nodes.length - b.nodes.length )
XRWG = XRWG.reverse() // the cleankey/get functions e.g. will persist
console.dir(XRWG)
xrf.emit('XRWG',XRWG)
}

View file

@ -3,10 +3,15 @@ window.AFRAME.registerComponent('xrf', {
},
init: function () {
if( !AFRAME.XRF ){
document.querySelector('a-scene').addEventListener('loaded', () => {
//window.addEventListener('popstate', clear )
//window.addEventListener('pushstate', clear )
let camera = document.querySelector('[camera]')
// start with black
camera.setAttribute('xrf-fade','')
AFRAME.fade = camera.components['xrf-fade']
if( document.location.host.match(/localhost/) ) document.querySelector('a-scene').setAttribute("stats",'')
document.querySelector('a-scene').addEventListener('loaded', () => {
// enable XR fragments
let aScene = document.querySelector('a-scene')
@ -15,7 +20,6 @@ window.AFRAME.registerComponent('xrf', {
camera: aScene.camera,
scene: aScene.object3D,
renderer: aScene.renderer,
debug: true,
loaders: {
gltf: THREE.GLTFLoader, // which 3D assets (exts) to check for XR fragments?
glb: THREE.GLTFLoader
@ -23,26 +27,83 @@ window.AFRAME.registerComponent('xrf', {
})
if( !XRF.camera ) throw 'xrfragment: no camera detected, please declare <a-entity camera..> ABOVE entities with xrf-attributes'
// override the camera-related XR Fragments so the camera-rig is affected
let camOverride = (xrf,v,opts) => {
opts.camera = document.querySelector('[camera]').object3D.parent
xrf(v,opts)
}
xrf.addEventListener('navigateLoaded', () => {
setTimeout( () => AFRAME.fade.out(),500)
xrf.pos = camOverride
xrf.href = camOverride
// *TODO* this does not really belong here perhaps
let blinkControls = document.querySelector('[blink-controls]')
if( blinkControls ){
let els = xrf.getCollisionMeshes()
let invisible = false
els.map( (mesh) => {
if( !invisible ){
invisible = mesh.material.clone()
invisible.visible = false
}
mesh.material = invisible
let el = document.createElement("a-entity")
el.setAttribute("xrf-get", mesh.name )
el.setAttribute("class","floor")
$('a-scene').appendChild(el)
})
blinkControls.components['blink-controls'].update({collisionEntities:true})
}
})
// in order to set the rotation programmatically
// we need to disable look-controls
xrf.rot = (xrf,v,opts) => {
let {frag,renderer} = opts;
if( frag.q ) return // camera was not targeted for rotation
let look = document.querySelector('[look-controls]')
if( look ) look.removeAttribute("look-controls")
// camOverride(xrf,v,opts)
// *TODO* make look-controls compatible, because simply
// adding the look-controls will revert to the old rotation (cached somehow?)
//setTimeout( () => look.setAttribute("look-controls",""), 100 )
xrf.addEventListener('href', (opts) => {
if( opts.click){
let p = opts.promise()
let url = opts.xrf.string
let isLocal = url.match(/^#/)
let hasPos = url.match(/pos=/)
if( isLocal && hasPos ){
// local teleports only
let fastFadeMs = 200
AFRAME.fade.in(fastFadeMs)
setTimeout( () => {
p.resolve()
AFRAME.fade.out(fastFadeMs)
}, fastFadeMs)
}else if( !isLocal ){
AFRAME.fade.in()
setTimeout( () => {
p.resolve()
setTimeout( () => AFRAME.fade.out(), 1000 ) // allow one second to load textures e.g.
}, AFRAME.fade.data.fadetime )
}else p.resolve()
}
})
// patch wasd-controls to affect camera-rig
if( camera.components['wasd-controls'] ){
camera.components['wasd-controls'].tick = function(time,delta){
var data = this.data;
var el = this.el;
var velocity = this.velocity;
function isEmptyObject(keys) {
var key;
for (key in keys) { return false; }
return true;
}
if (!velocity[data.adAxis] && !velocity[data.wsAxis] &&
isEmptyObject(this.keys)) { return; }
// Update velocity.
delta = delta / 1000;
this.updateVelocity(delta);
if (!velocity[data.adAxis] && !velocity[data.wsAxis]) { return; }
// Transform direction relative to heading.
let directionVector = this.getMovementVector(delta)
var rotationEuler = new THREE.Euler(0, 0, 0, 'YXZ');
rotationEuler.set(THREE.MathUtils.degToRad(0), THREE.MathUtils.degToRad(xrf.camera.rotation.y + 45), 0);
directionVector.applyEuler(rotationEuler);
// Get movement vector and translate position to camera-rig (not camera)
xrf.camera.position.add(directionVector);
}.bind( camera.components['wasd-controls'] )
}
// convert href's to a-entity's so AFRAME
@ -53,30 +114,20 @@ window.AFRAME.registerComponent('xrf', {
el.setAttribute("xrf-get",mesh.name ) // turn into AFRAME entity
el.setAttribute("class","ray") // expose to raycaster
el.setAttribute("pressable", '') // detect hand-controller click
// add click
// respond to cursor via laser-controls (https://aframe.io/docs/1.4.0/components/laser-controls.html)
el.addEventListener("click", clickHandler )
el.addEventListener("mouseenter", mesh.userData.XRF.href.selected(true) )
el.addEventListener("mouseleave", mesh.userData.XRF.href.selected(false) )
el.addEventListener("pressedstarted", clickHandler )
// this.el.addEventListener("buttondown", console.dir )
// this.el.addEventListener("touchstart", console.dir )
// this.el.addEventListener("triggerdown", console.dir )
// this.el.addEventListener("gripdown", console.dir )
// this.el.addEventListener("abuttondown", console.dir )
// this.el.addEventListener("pinchended", console.dir )
$('a-scene').appendChild(el)
}
xrf.addEventListener('interactionReady', AFRAME.XRF.clickableMeshToEntity )
// cleanup xrf-get objects when resetting scene
xrf.reset = ((reset) => () => {
reset()
console.log("aframe reset")
xrf.addEventListener('reset', (opts) => {
let els = [...document.querySelectorAll('[xrf-get]')]
els.map( (el) => document.querySelector('a-scene').removeChild(el) )
})(XRF.reset)
// undo lookup-control shenanigans (which blocks updating camerarig position in VR)
aScene.addEventListener('enter-vr', () => document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = true )
})
AFRAME.XRF.navigator.to(this.data)
.then( (model) => {

View file

@ -0,0 +1,27 @@
AFRAME.registerComponent('xrf-fade', {
schema:{
fadetime:{type:"number", default: 1000},
color:{type:"color", default:"black"},
opacity:{type:"float",default:1.0}
},
init: function(){
let fb = this.fb = document.createElement("a-box")
fb.setAttribute("scale", "1 1 1")
fb.setAttribute("material", `color: ${this.data.color}; transparent: true; side: back; shader: flat; opacity:1`)
this.el.appendChild(fb)
},
out: function(fadetime){
if( fadetime != undefined ) this.data.fadetime = fadetime
if( this.data.opacity == 0 ) return
this.data.opacity = 0.0
this.fb.setAttribute("animation", `property: components.material.material.opacity; dur: ${this.data.fadetime}; from: 1; to: ${this.data.opacity}`)
setTimeout( () => this.fb.object3D.visible = false, this.data.fadetime )
},
"in": function(fadetime){
if( fadetime != undefined ) this.data.fadetime = fadetime
if( this.data.opacity == 1 ) return
this.data.opacity = 1.0
this.fb.object3D.visible = true
this.fb.setAttribute("animation", `property: components.material.material.opacity; dur: ${this.data.fadetime}; from: 0; to: ${this.data.opacity}`)
}
});

View file

@ -26,25 +26,29 @@ AFRAME.registerComponent('xrf-gaze',{
init:function(data){
this.immersive = false;
let enabled = () => AFRAME.utils.device.isMobile()
let setVisible = () => document.querySelector('[cursor]').setAttribute('visible', enabled() )
let setVisible = () => {
let cursor = document.querySelector('[cursor]')
if( cursor ) cursor.setAttribute('visible', enabled() )
}
this.setGazer(enabled())
if( enabled() ) setVisible();
setVisible();
document.querySelector("a-scene").addEventListener('exit-vr', () => {
this.immersive = false;
setVisible()
})
document.querySelector("a-scene").addEventListener('enter-vr', () => {
this.immersive = true;
setVisible()
if( !document.querySelector("#cursor") ) return
})
let highlightMesh = (state) => (e) => {
if( !e.target.object3D ) return
let obj = e.target.object3D.children[0]
if( obj.userData && obj.userData.XRF && obj.userData.XRF.href )
if( obj && obj.userData && obj.userData.XRF && obj.userData.XRF.href )
obj.userData.XRF.href.selected( state )()
}
this.el.addEventListener("mouseenter", highlightMesh(true) )

View file

@ -1,7 +1,8 @@
window.AFRAME.registerComponent('xrf-get', {
schema: {
name: {type: 'string'},
clone: {type: 'boolean', default:false}
clone: {type: 'boolean', default:false},
reparent: {type: 'boolean', default:false}
},
init: function () {
@ -13,30 +14,40 @@ window.AFRAME.registerComponent('xrf-get', {
setTimeout( () => {
if( !this.mesh && this.el.className == "ray" ){
if( !this.mesh ){
let scene = AFRAME.XRF.scene
let mesh = this.mesh = scene.getObjectByName(meshname);
if( !this.el.className.match(/ray/) ) this.el.className += " ray"
if (!mesh){
console.error("mesh with name '"+meshname+"' not found in model")
return;
}
// convert to worldcoordinates
mesh.getWorldPosition(mesh.position)
mesh.getWorldScale(mesh.scale)
mesh.getWorldQuaternion(mesh.quaternion)
// we don't want to re-parent gltf-meshes
mesh.isXRF = true // mark for deletion by xrf
if( this.data.reparent ){
const world = {
pos: new THREE.Vector3(),
scale: new THREE.Vector3(),
quat: new THREE.Quaternion()
}
mesh.getWorldPosition(world.pos)
mesh.getWorldScale(world.scale)
mesh.getWorldQuaternion(world.quat);
mesh.position.copy(world.pos)
mesh.scale.copy(world.scale)
mesh.setRotationFromQuaternion(world.quat);
}else{
// add() will reparent the mesh so lets create a dummy
this.el.object3D.add = (a) => a
}
this.el.setObject3D('mesh',mesh)
// normalize position
//this.el.object3D.position.copy( mesh.position )
//mesh.position.fromArray([0,0,0])
if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`)
}
},500)
}else console.warn("xrf-get ignore: "+JSON.stringify(this.data))
}, evt && evt.timeout ? evt.timeout: 500)
})
this.el.emit("update")
this.el.emit("update",{timeout:0})
}

View file

@ -4,8 +4,10 @@
var xrf = {}
xrf.init = function(opts){
opts = opts || {}
opts = opts || {}
xrf.debug = parseInt( ( document.location.hash.match(/debug=([0-9])/) || [0,'0'] )[1] )
xrf.Parser.debug = xrf.debug
xrf.detectCameraRig(opts)
for ( let i in opts ) xrf[i] = opts[i]
xrf.emit('init',opts)
return xrf
@ -16,6 +18,20 @@ xrf.query = function(){
alert("queries are not implemented (yet) for this particular framework")
}
xrf.detectCameraRig = function(opts){
if( opts.camera ){ // detect rig (if any)
let getCam = ((cam) => () => cam)(opts.camera)
let offsetY = 0
while( opts.camera.parent.type != "Scene" ){
offsetY += opts.camera.position.y
opts.camera = opts.camera.parent
opts.camera.getCam = getCam
opts.camera.updateProjectionMatrix = () => opts.camera.getCam().updateProjectionMatrix()
}
opts.camera.offsetY = offsetY
}
}
xrf.roundrobin = (frag, store) => {
if( !frag.args || frag.args.length == 0 ) return 0
if( !store.rr ) store.rr = {}

View file

@ -1,5 +1,5 @@
/*
* (promise-able) EVENTS
* (promise-able) EVENTS (optionally continue after listeners are finished using .then)
*
* example:
*
@ -14,18 +14,33 @@
* xrf.emit('foo',123).then(...).catch(...).finally(...)
*/
xrf.addEventListener = function(eventName, callback) {
if( !this._listeners ) this._listeners = []
if (!this._listeners[eventName]) {
// create a new array for this event name if it doesn't exist yet
this._listeners[eventName] = [];
}
// add the callback to the listeners array for this event name
this._listeners[eventName].push(callback);
xrf.addEventListener = function(eventName, callback, scene) {
if( !this._listeners ) this._listeners = []
if (!this._listeners[eventName]) {
// create a new array for this event name if it doesn't exist yet
this._listeners[eventName] = [];
}
if( scene ) callback.scene = scene
// add the callback to the listeners array for this event name
this._listeners[eventName].push(callback);
return () => {
this._listeners[eventName] = this._listeners[eventName].filter( (c) => c != callback )
}
};
xrf.emit = function(eventName, data){
if( typeof data != 'object' ) throw 'emit() requires passing objects'
if( xrf.debug && ( eventName != "render" || xrf.debug == eventName ) ){
let label = String(`xrf.emit('${eventName}')`).padEnd(35," ");
label += data.mesh && data.mesh.name ? '#'+data.mesh.name : ''
console.groupCollapsed(label)
console.info(data)
console.groupEnd(label)
if( xrf.debug > 1 ) debugger
}
// forward to THREEjs eventbus if any
if( data.scene ) data.scene.dispatchEvent( eventName, data )
if( data.mesh ) data.mesh.dispatchEvent( eventName, data )
return xrf.emit.promise(eventName,data)
}
@ -40,15 +55,27 @@ xrf.emit.normal = function(eventName, data) {
};
xrf.emit.promise = function(e, opts){
opts.XRF = xrf // always pass root XRF obj
return new Promise( (resolve, reject) => {
opts.promise = () => {
opts.promise.halted = true
return { resolve, reject }
opts.promises = opts.promises || []
opts.promises.push(0)
return {
resolve: ((index) => () => {
opts.promises[index] = 1
let succesful = opts.promises.reduce( (a,b) => a+b )
if( succesful == opts.promises.length ) resolve(opts)
})(opts.promises.length-1),
reject: console.error
}
}
xrf.emit.normal(e, opts)
delete opts.XRF
if( !opts.promise.halted ) resolve()
if( !opts.promises ) resolve(opts)
delete opts.promise
})
}
xrf.addEventListener('reset', () => {
// *TODO* do this nicely
// xrf._listeners['renderPost'] = []
// xrf._listeners['render'] = []
})

File diff suppressed because one or more lines are too long

View file

@ -8,7 +8,7 @@ let pub = function( url, model, flags ){ // evaluate fragments in url
if( !url.match(/#/) ) url = `#${url}`
model = model || xrf.model
let { THREE, camera } = xrf
let frag = xrf.URI.parse( url, flags != undefined ? flags : xrf.XRF.NAVIGATOR )
let frag = xrf.URI.parse( url, flags )
let opts = {frag, mesh:xrf.camera, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE, hashbus: xrf.hashbus }
xrf.emit('hashbus',opts)
.then( () => {
@ -26,7 +26,7 @@ pub.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) insid
for( let k in frag ){
let opts = {frag, mesh, model, camera: xrf.camera, scene: model.scene, renderer: xrf.renderer, THREE: xrf.THREE, hashbus: xrf.hashbus }
mesh.userData.XRF = frag // allow fragment impl to access XRF obj already
xrf.emit('mesh',opts)
xrf.emit('frag2mesh',opts)
.then( () => pub.fragment(k,opts) )
}
}
@ -35,13 +35,47 @@ pub.mesh = (mesh,model) => { // evaluate embedded fragments (metadata) insid
pub.fragment = (k, opts ) => { // evaluate one fragment
let frag = opts.frag[k];
if( frag.is( xrf.XRF.PV_EXECUTE ) ) pub.XRWG({...opts,frag})
// call native function (xrf/env.js e.g.), or pass it to user decorator
xrf.emit(k,opts)
.then( () => {
let func = xrf.frag[k] || function(){}
if( xrf[k] ) xrf[k]( func, frag, opts)
else func( frag, opts)
if( typeof xrf[k] == 'function' ) xrf[k]( func, frag, opts)
else func( frag, opts)
})
}
pub.XRWG = (opts) => {
let {frag,scene,model,renderer} = opts
// if this query was triggered by an src-value, lets filter it
const isSRC = opts.embedded && opts.embedded.fragment == 'src'
if( !isSRC ){ // spec : https://xrfragment.org/#src
for ( let i in frag ) {
let v = frag[i]
let id = v.string || v.fragment
if( id == '#' || !id ) return
let match = xrf.XRWG.match(id)
if( v.is( xrf.XRF.PV_EXECUTE ) ){
scene.XRF_PV_ORIGIN = v.string
// evaluate aliases
match.map( (w) => {
if( w.key == `#${id}` ){
if( w.value && w.value[0] == '#' ){
// if value is alias, execute fragment value
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
}
}
})
xrf.emit('dynamicKey',{ ...opts,v,frag,id,match,scene })
}else{
xrf.emit('dynamicKeyValue',{ ...opts,v,frag,id,match,scene })
}
}
}
}
xrf.hashbus = { pub }

View file

@ -1,5 +1,6 @@
xrf.frag = {}
xrf.model = {}
xrf.mixers = []
xrf.init = ((init) => function(opts){
let scene = new opts.THREE.Group()
@ -8,21 +9,26 @@ xrf.init = ((init) => function(opts){
init(opts)
if( opts.loaders ) Object.values(opts.loaders).map( xrf.patchLoader )
xrf.patchRenderer(opts.renderer)
xrf.patchRenderer(opts)
xrf.navigator.init()
// return xrfragment lib as 'xrf' query functor (like jquery)
for ( let i in xrf ) xrf.query[i] = xrf[i]
return xrf.query
})(xrf.init)
xrf.patchRenderer = function(renderer){
xrf.patchRenderer = function(opts){
let {renderer,camera} = opts
renderer.xr.addEventListener( 'sessionstart', () => xrf.baseReferenceSpace = renderer.xr.getReferenceSpace() );
renderer.xr.enabled = true;
xrf.clock = new xrf.THREE.Clock()
renderer.render = ((render) => function(scene,camera){
if( xrf.model && xrf.model.render )
xrf.model.render(scene,camera)
// update clock
let time = xrf.clock.getDelta()
xrf.emit('render',{scene,camera,time,render}) // allow fragments to do something at renderframe
render(scene,camera)
xrf.emit('renderPost',{scene,camera,time,render,renderer}) // allow fragments to do something after renderframe
})(renderer.render.bind(renderer))
}
xrf.patchLoader = function(loader){
@ -46,30 +52,11 @@ xrf.parseModel = function(model,url){
let file = xrf.getFile(url)
model.file = file
// eval embedded XR fragments
model.scene.traverse( (mesh) => xrf.hashbus.pub.mesh(mesh,model) )
// add animations
model.clock = new xrf.THREE.Clock();
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
model.animations.map( (anim) => {
anim.action = model.mixer.clipAction( anim )
//anim.action.setLoop(0)
anim.action.play()
model.scene.traverse( (mesh) => {
xrf.hashbus.pub.mesh(mesh,model)
})
let tmp = new xrf.THREE.Vector3()
model.render = function(){
let time = model.clock.getDelta()
model.mixer.update( time )
// update focusline
xrf.focusLine.material.color.r = (1.0 + Math.sin( model.clock.getElapsedTime()*10 ))/2
xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( model.clock.getElapsedTime() )
xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( model.clock.getElapsedTime() *3 )
xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( model.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity;
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
}
model.animations.map( (a) => console.log("anim: "+a.name) )
xrf.emit('parseModel',{model,url,file})
}
xrf.getLastModel = () => xrf.model.last
@ -87,11 +74,18 @@ xrf.reset = () => {
return true
};
let nodes = []
xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false )
xrf.scene.traverse( (n) => n.audio && (n.audio.remove()) )
xrf.scene.traverse( (child) => child.isXRF && (nodes.push(child)) )
nodes.map( disposeObject ) // leave non-XRF objects intact
xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
xrf.add( xrf.interactive )
xrf.layers = 0
// reset certain events
xrf.emit('reset',{})
// remove mixers
xrf.mixers.map( (m) => m.stop())
xrf.mixers = []
}
xrf.parseUrl = (url) => {
@ -108,3 +102,8 @@ xrf.add = (object) => {
xrf.scene.add(object)
}
xrf.hasNoMaterial = (mesh) => {
const hasTexture = mesh.material && mesh.material.map
const hasMaterialName = mesh.material && mesh.material.name.length > 0
return mesh.geometry && !hasMaterialName && !hasTexture
}

View file

@ -4,6 +4,7 @@ xrf.navigator.to = (url,flags,loader,data) => {
if( !url ) throw 'xrf.navigator.to(..) no url given'
let hashbus = xrf.hashbus
xrf.emit('navigate', {url,loader,data})
return new Promise( (resolve,reject) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
@ -33,15 +34,15 @@ xrf.navigator.to = (url,flags,loader,data) => {
// spec: 1. generate the XRWG
xrf.XRWG.generate({model,scene:model.scene})
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
xrf.frag.defaultPredefinedView({model,scene:model.scene})
xrf.frag.defaultPredefinedViews({model,scene:model.scene})
// spec: 2. init metadata
let frag = hashbus.pub( url, model ) // and eval URI XR fragments
// spec: predefined view(s) from URL (https://xrfragment.org/#predefined_view)
setTimeout( () => { // give external objects some slack
xrf.frag.updatePredefinedView({model,scene:model.scene,frag})
},2000)
let frag = hashbus.pub( url, model) // and eval URI XR fragments
hashbus.pub.XRWG({model,scene:model.scene,frag})
xrf.add( model.scene )
xrf.navigator.updateHash(hash)
xrf.emit('navigateLoaded',{url,model})
resolve(model)
}

View file

@ -0,0 +1,9 @@
xrf.getCollisionMeshes = () => {
let meshes = []
xrf.scene.traverse( (n) => {
if( !n.userData.href && !n.userData.src && xrf.hasNoMaterial(n) ){
meshes.push(n)
}
})
return meshes
}

View file

@ -1,6 +1,6 @@
// wrapper to survive in/outside modules
xrf.InteractiveGroup = function(THREE,renderer,camera){
xrf.interactiveGroup = function(THREE,renderer,camera){
let {
Group,
@ -13,7 +13,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const _event = { type: '', data: _pointer };
let object = {selected:false}
class InteractiveGroup extends Group {
class interactive extends Group {
constructor( renderer, camera ) {
@ -71,9 +71,9 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
element.addEventListener( 'pointerup', onPointerEvent );
element.addEventListener( 'pointermove', onPointerEvent );
element.addEventListener( 'mousedown', onPointerEvent );
element.addEventListener( 'mouseup', onPointerEvent );
element.addEventListener( 'mousemove', onPointerEvent );
element.addEventListener( 'click', onPointerEvent );
element.addEventListener( 'mouseup', onPointerEvent );
// WebXR Controller Events
// TODO: Dispatch pointerevents too
@ -131,12 +131,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
}
add(obj){
Group.prototype.add.call( this, obj )
this.objects = ([]).concat( this.children )
add(obj, unparent){
if( unparent ) Group.prototype.add.call( this, obj )
this.objects.push(obj)
}
}
return new InteractiveGroup(renderer,camera)
return new interactive(renderer,camera)
}

View file

@ -0,0 +1,64 @@
xrf.addEventListener('dynamicKey', (opts) => {
let {scene,id,match,v} = opts
if( !scene ) return
let remove = []
// erase previous lines
xrf.focusLine.lines.map( (line) => line.parent && (line.parent.remove(line)) )
xrf.focusLine.points = []
xrf.focusLine.lines = []
// drawlines
match.map( (w) => {
w.nodes.map( (mesh) => xrf.drawLineToMesh({ ...opts, mesh}) )
})
})
xrf.drawLineToMesh = (opts) => {
let {scene,mesh,frag,id} = opts
const THREE = xrf.THREE
let oldSelection
// Selection of Interest if predefined_view matches object name
if( mesh.visible && mesh.material){
xrf.emit('focus',{...opts,frag})
.then( () => {
const color = new THREE.Color();
const colors = []
let from = new THREE.Vector3()
let getCenterPoint = (mesh) => {
var geometry = mesh.geometry;
geometry.computeBoundingBox();
var center = new THREE.Vector3();
geometry.boundingBox.getCenter( center );
mesh.localToWorld( center );
return center;
}
let cam = xrf.camera.getCam ? xrf.camera.getCam() : xrf.camera // *FIXME* camerarig/rig are conflicting
cam.updateMatrixWorld(true); // always keeps me diving into the docs :]
cam.getWorldPosition(from)
from.y = 0.5 // originate from the heart chakra! :p
const points = [from, getCenterPoint(mesh) ]
const geometry = new THREE.BufferGeometry().setFromPoints( points );
let line = new THREE.Line( geometry, xrf.focusLine.material );
line.isXRF = true
line.computeLineDistances();
xrf.focusLine.lines.push(line)
xrf.focusLine.points.push(from)
xrf.focusLine.opacity = 1
scene.add(line)
})
}
}
xrf.addEventListener('render', (opts) => {
// update focusline
let {time,model} = opts
if( !xrf.clock ) return
xrf.focusLine.material.color.r = (1.0 + Math.sin( xrf.clock.getElapsedTime()*10 ))/2
xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( xrf.clock.getElapsedTime() )
xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( xrf.clock.getElapsedTime() *3 )
xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( xrf.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity;
if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2
if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0
})

View file

@ -0,0 +1,123 @@
/*
* TODO: refactor/fix this (queries are being refactored to filters)
*/
xrf.addEventListener('dynamicKey', (opts) => {
let {scene,id,match,v} = opts
if( v.filter ){
let frags = {}
frags[ v.filter.key ] = v
xrf.filter.scene({frag:frags,scene})
}
})
// spec: https://xrfragment.org/#filters
xrf.filter = function(query, cb){
let result = []
if( !query ) return result
if( query[0] != '#' ) query = '#'+query
// *TODO* jquery like utility func
return result
}
xrf.filter.scene = function(opts){
let {scene,frag} = opts
scene = xrf.filter
.sort(frag) // get (sorted) filters from XR Fragments
.process(frag,scene,opts) // show/hide things
scene.visible = true // always enable scene
return scene
}
xrf.filter.sort = function(frag){
// get all filters from XR Fragments
frag.filters = Object.values(frag)
.filter( (v) => v.filter ? v : null )
.sort( (a,b) => a.index > b.index )
return xrf.filter
}
// opts = {copyScene:true} in case you want a copy of the scene (not filter the current scene inplace)
xrf.filter.process = function(frag,scene,opts){
const cleanupKey = (k) => k.replace(/[-\*\/]/g,'')
let firstFilter = frag.filters.length ? frag.filters[0].filter.get() : false
const hasName = (m,name,filter) => m.name == name
const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) ||
String(m.userData['tag']).match( new RegExp("(^| )"+name_or_tag) )
// utility functions
const getOrCloneMaterial = (o) => {
if( o.material ){
if( o.material.isXRF ) return o.material
o.material = o.material.clone()
o.material.isXRF = true
return o.material
}
return {}
}
const setVisible = (n,visible,filter,processed) => {
if( processed && processed[n.uuid] ) return
getOrCloneMaterial(n).visible = visible
if( filter.deep ) n.traverse( (m) => getOrCloneMaterial(m).visible = visible )
if( processed ) processed[n.uuid] == true
}
// spec 2: https://xrfragment.org/doc/RFC_XR_Macros.html#embedding-xr-content-using-src
// reparent scene based on objectname in case it matches a (non-negating) selector
if( opts.reparent && firstFilter && !firstFilter.value && firstFilter.show === true ){
let obj
frag.target = firstFilter
scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) )
console.log("reparent "+firstFilter.key+" "+((opts.copyScene)?"copy":"inplace"))
if(obj ){
obj.position.set(0,0,0)
if( opts.copyScene ){
opts.copyScene = new xrf.THREE.Scene()
opts.copyScene.children[0] = obj
scene = opts.copyScene
}else{
// empty current scene and add obj
while( scene.children.length > 0 ) scene.children[0].removeFromParent()
scene.add( obj )
}
}
}
// then show/hide things based on secondary selectors
// we don't use the XRWG (everything) because we process only the given (sub)scene
frag.filters.map( (v) => {
const filter = v.filter.get()
const name_or_tag = cleanupKey(v.fragment)
let processed = {}
let extembeds = {}
// hide external objects temporarely
scene.traverse( (m) => {
if( m.isSRCExternal ){
m.traverse( (n) => (extembeds[ n.uuid ] = m) && (m.visible = false) )
}
})
scene.traverseVisible( (m) => {
// filter on value(expression) #foo=>3 e.g. *TODO* do this in XRWG
if( filter.value && m.userData[filter.key] ){
const visible = v.filter.testProperty(filter.key, m.userData[filter.key], filter.show === false )
setVisible(m,visible,filter,processed)
return
}
if( hasNameOrTag(m,name_or_tag,filter ) ){
setVisible(m,filter.show,filter)
}
})
// show external objects again
for ( let i in extembeds ) extembeds[i].visible = true
})
return scene
}

View file

@ -0,0 +1,23 @@
xrf.frag.defaultPredefinedViews = (opts) => {
let {scene,model} = opts;
scene.traverse( (n) => {
if( n.userData && n.userData['#'] ){
let frag = xrf.URI.parse( n.userData['#'] )
xrf.hashbus.pub( n.userData['#'] ) // evaluate static XR fragments
xrf.hashbus.pub.XRWG({frag,model,scene}) // evaluate dynamic XR fragment using XRWG (see spec)
}
})
}
// react to enduser typing url
xrf.addEventListener('hash', (opts) => {
let frag = xrf.URI.parse( opts.hash )
xrf.hashbus.pub.XRWG({frag,scene:xrf.scene})
})
// clicking href url with predefined view
xrf.addEventListener('href', (opts) => {
if( !opts.click || opts.xrf.string[0] != '#' ) return
let frag = xrf.URI.parse( opts.xrf.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
xrf.hashbus.pub.XRWG({frag,scene:xrf.scene,href:opts.xrf})
})

View file

@ -0,0 +1,30 @@
xrf.addEventListener('dynamicKeyValue', (opts) => {
let {scene,match,v} = opts
let objname = v.fragment
let autoscroll = v.z > 0 || v.w > 0
scene.traverse( (mesh) => {
if( mesh.name == objname ){
if( !mesh.geometry ) return console.warn(`mesh '${objname}' has no uvcoordinates to offset`)
let uv = mesh.geometry.getAttribute("uv")
if( !uv.old ) uv.old = uv.clone()
for( let i = 0; i < uv.count; i++ ){
uv.setXY(i, uv.old.getX(i) + v.x, uv.old.getY(i) + v.y )
}
if( autoscroll ){
if( mesh.removeUVListener ) mesh.removeUVListener()
mesh.removeUVListener = xrf.addEventListener('render', (opts) => {
let {time} = opts
for( let i = 0; i < uv.count; i++ ){
uv.setXY(i, uv.getX(i) + v.z * time, uv.getY(i) + v.w * time)
}
uv.needsUpdate = true
})
}
uv.needsUpdate = true
}
})
})

View file

@ -29,78 +29,27 @@
*/
xrf.frag.href = function(v, opts){
opts.embedded = v // indicate embedded XR fragment
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
if( mesh.userData.XRF.href.exec ) return // mesh already initialized
const world = {
pos: new THREE.Vector3(),
scale: new THREE.Vector3(),
quat: new THREE.Quaternion()
}
// detect equirectangular image
let texture = mesh.material && mesh.material.map ? mesh.material.map : null
if( texture && texture.source.data.height == texture.source.data.width/2 ){
texture.mapping = THREE.ClampToEdgeWrapping
texture.needsUpdate = true
// poor man's equi-portal
mesh.material = new THREE.ShaderMaterial( {
side: THREE.DoubleSide,
uniforms: {
pano: { value: texture },
selected: { value: false },
},
vertexShader: `
vec3 portalPosition;
varying vec3 vWorldPosition;
varying float vDistanceToCenter;
varying float vDistance;
void main() {
vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);
portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
vDistance = length(portalPosition - cameraPosition);
vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
#define RECIPROCAL_PI2 0.15915494
uniform sampler2D pano;
uniform bool selected;
varying float vDistanceToCenter;
varying float vDistance;
varying vec3 vWorldPosition;
void main() {
vec3 direction = normalize(vWorldPosition - cameraPosition );
vec2 sampleUV;
sampleUV.y = -clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);
sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2;
sampleUV.x += 0.33; // adjust focus to AFRAME's a-scene.components.screenshot.capture()
vec4 color = texture2D(pano, sampleUV);
// Convert color to grayscale (lazy lite approach to not having to match tonemapping/shaderstacking of THREE.js)
float luminance = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
vec4 grayscale_color = selected ? color : vec4(vec3(luminance) + vec3(0.33), color.a);
gl_FragColor = grayscale_color;
}
`,
});
mesh.material.needsUpdate = true
}else if( mesh.material){ mesh.material = mesh.material.clone() }
let click = mesh.userData.XRF.href.exec = (e) => {
let isLocal = v.string[0] == '#'
let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}`
let lastPos = `pos=${camera.position.x.toFixed(2)},${camera.position.y.toFixed(2)},${camera.position.z.toFixed(2)}`
xrf
.emit('href',{click:true,mesh,xrf:v}) // let all listeners agree
.then( () => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(v.string)
//if( !file.match(/\./) || file.match(/\.html/) ){
// debugger
// let inIframe
// try { inIframe = window.self !== window.top; } catch (e) { inIframe = true; }
// return inIframe ? window.parent.postMessage({ url: v.string }, '*') : window.open( v.string, '_blank')
//}
const flags = v.string[0] == '#' ? xrf.XRF.PV_OVERRIDE : undefined
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
// always keep a trail of last positions before we navigate
if( !document.location.hash.match(lastPos) ) xrf.navigator.to(`#${lastPos}`)
// always commit current location (keep a trail of last positions before we navigate)
if( !e.nocommit && !document.location.hash.match(lastPos) ) xrf.navigator.to(`#${lastPos}`)
xrf.navigator.to(v.string) // let's surf to HREF!
})
.catch( console.error )
@ -112,7 +61,12 @@ xrf.frag.href = function(v, opts){
let newState = o.name == mesh.name ? state : false
if( o.material ){
if( o.material.uniforms ) o.material.uniforms.selected.value = newState
if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
//if( o.material.emissive ) o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = newState ? 2.0 : 1.0
if( o.material.emissive ){
if( !o.material.emissive.original ) o.material.emissive.original = o.material.emissive.clone()
o.material.emissive.r = o.material.emissive.g = o.material.emissive.b =
newState ? o.material.emissive.original.r + 0.5 : o.material.emissive.original.r
}
}
})
// update mouse cursor
@ -127,16 +81,13 @@ xrf.frag.href = function(v, opts){
mesh.addEventListener('click', click )
mesh.addEventListener('mousemove', selected(true) )
mesh.addEventListener('mouseenter', selected(true) )
mesh.addEventListener('mouseleave', selected(false) )
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
// lazy add mesh (because we're inside a recursive traverse)
setTimeout( (mesh) => {
mesh.getWorldPosition(world.pos)
mesh.getWorldScale(world.scale)
mesh.getWorldQuaternion(world.quat);
mesh.position.copy(world.pos)
mesh.scale.copy(world.scale)
mesh.setRotationFromQuaternion(world.quat);
xrf.interactive.add(mesh)
xrf.emit('interactionReady', {mesh,xrf:v,clickHandler: mesh.userData.XRF.href.exec })
}, 0, mesh )

View file

@ -1,6 +1,18 @@
xrf.frag.pos = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
camera.position.x = v.x
camera.position.y = v.y
camera.position.z = v.z
// spec: indirect coordinate using objectname: https://xrfragment.org/#navigating%203D
if( v.x == undefined ){
let obj = scene.getObjectByName(v.string)
if( !obj ) return
let pos = obj.position.clone()
obj.getWorldPosition(pos)
camera.position.copy(pos)
}else{
// spec: direct coordinate: https://xrfragment.org/#navigating%203D
camera.position.x = v.x
camera.position.y = v.y
camera.position.z = v.z
}
}

View file

@ -1,125 +0,0 @@
xrf.frag.defaultPredefinedView = (opts) => {
let {scene,model} = opts;
let frag = {}
xrf.Parser.parse("#","",frag)
xrf.frag.updatePredefinedView({frag,model,scene})
}
xrf.frag.updatePredefinedView = (opts) => {
let {frag,scene,model,renderer} = opts
// spec: https://xrfragment.org/#Selection%20of%20interest
const selectionOfInterest = (frag,scene,mesh) => {
let id = frag.string
let oldSelection
if(!id) return id // important: ignore empty strings
// Selection of Interest if predefined_view matches object name
if( mesh.visible && mesh.material){
xrf.emit('focus',{...opts,frag})
.then( () => {
const color = new THREE.Color();
const colors = []
let from = new THREE.Vector3()
let getCenterPoint = (mesh) => {
var geometry = mesh.geometry;
geometry.computeBoundingBox();
var center = new THREE.Vector3();
geometry.boundingBox.getCenter( center );
mesh.localToWorld( center );
return center;
}
xrf.camera.updateMatrixWorld(true); // always keeps me diving into the docs :]
xrf.camera.getWorldPosition(from)
from.y -= 0.5 // originate from the heart chakra! :p
const points = [from, getCenterPoint(mesh) ]
const geometry = new THREE.BufferGeometry().setFromPoints( points );
let line = new THREE.Line( geometry, xrf.focusLine.material );
line.isXRF = true
line.computeLineDistances();
xrf.focusLine.lines.push(line)
xrf.focusLine.points.push(from)
xrf.focusLine.opacity = 1
scene.add(line)
})
}
}
//// spec: https://xrfragment.org/#predefined_view
//const predefinedView = (frag,scene,mesh) => {
// let id = frag.string || frag.fragment
// id = `#${id}`
// if( id == '##' ) id = '#'; // default predefined view
// if( !id ) return // prevent empty matches
// if( mesh.userData[id] ){ // get alias
// frag = xrf.URI.parse( mesh.userData[id], xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
// xrf.emit('predefinedView',{...opts,frag})
// .then( () => {
// for ( let k in frag ){
// let opts = {frag, model, camera: xrf.camera, scene: xrf.scene, renderer: xrf.renderer, THREE: xrf.THREE }
// if( frag[k].is( xrf.XRF.PV_EXECUTE ) && scene.XRF_PV_ORIGIN != k ){ // cyclic detection
// highlightInScene(frag[k],scene) // recurse predefined views
// }
// }
// })
// }
//}
const highlightInScene = (v,scene) => {
if( !scene ) return
let remove = []
let id = v.string || v.fragment
if( id == '#' ) return
let match = xrf.XRWG.match(id)
console.dir({id,match,XRWG:xrf.XRWG})
// erase previous lines
xrf.focusLine.lines.map( (line) => scene.remove(line) )
xrf.focusLine.points = []
xrf.focusLine.lines = []
scene.traverse( (n) => n.selection ? remove.push(n) : false )
remove.map( (n) => scene.remove(n.selection) )
// create new selections
match.map( (w) => {
if( w.key == `#${id}` ){
if( w.value && w.value[0] == '#' ){
// if value is alias, execute fragment value
xrf.hashbus.pub( w.value, xrf.model, xrf.XRF.METADATA | xrf.XRF.PV_OVERRIDE | xrf.XRF.NAVIGATOR )
}
}
w.nodes.map( (mesh) => selectionOfInterest( v, scene, mesh ) )
})
}
// if this query was triggered by an src-value, lets filter it
const isSRC = opts.embedded && opts.embedded.fragment == 'src'
if( isSRC ){ // spec : https://xrfragment.org/#src
console.log("filtering predefined view of src")
console.dir(frag)
}else{
console.log("updatePredefinedView")
console.dir(frag)
for ( let i in frag ) {
let v = frag[i]
if( v.is( xrf.XRF.PV_EXECUTE ) ){
scene.XRF_PV_ORIGIN = v.string
// wait for nested instances to arrive at the scene ?
highlightInScene(v,scene)
}
}
}
}
// react to enduser typing url
xrf.addEventListener('hash', (opts) => {
let frag = xrf.URI.parse( opts.hash, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
xrf.frag.updatePredefinedView({frag,scene:xrf.scene})
})
// clicking href url with predefined view
xrf.addEventListener('href', (opts) => {
if( !opts.click || opts.xrf.string[0] != '#' ) return
let frag = xrf.URI.parse( opts.xrf.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
xrf.frag.updatePredefinedView({frag,scene:xrf.scene,href:opts.xrf})
})

View file

@ -1,40 +0,0 @@
// spec: https://xrfragment.org/#queries
xrf.frag.q = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ running query ")
let qobjs = Object.keys(v.query)
// convience function for other fragments (which apply to the query)
frag.q.getObjects = () => {
let objs = []
scene.traverse( (o) => {
for ( let name in v.query ) {
let qobj = v.query[name];
if( qobj.tag && o.userData.tag && xrf.hasTag(name,o.userData.tag) ) objs.push(o)
else if( qobj.id && o.name == name ) objs.push(o)
}
})
return objs.filter( (o) => o ) // return and filter out empty
.map( (o) => {
if( !o.positionOriginal ) o.positionOriginal = o.position.clone()
return o
})
}
xrf.frag.q.filter(scene,frag) // spec : https://xrfragment.org/#queries
}
xrf.frag.q.filter = function(scene,frag){
// spec: https://xrfragment.org/#queries
let q = frag.q.query
scene.traverse( (mesh) => {
for ( let i in q ) {
let isMeshId = q[i].id != undefined
let isMeshProperty = q[i].rules != undefined && q[i].rules.length && !isMeshId
if( q[i].root && mesh.isSRC ) continue; // ignore nested object for root-items (queryseletor '/foo' e.g.)
if( isMeshId &&
(i == mesh.name || xrf.hasTag(i,mesh.userData.tag))) mesh.visible = q[i].id
if( isMeshProperty && mesh.userData[i] ) mesh.visible = (new xrf.Query(frag.q.string)).testProperty(i,mesh.userData[i])
}
})
}

View file

@ -1,84 +1,106 @@
// *TODO* use webgl instancing
xrf.frag.src = function(v, opts){
opts.embedded = v // indicate embedded XR fragment
let { mesh, model, camera, scene, renderer, THREE, hashbus, frag} = opts
console.log(" └ instancing src")
let src;
let url = v.string
let vfrag = xrfragment.URI.parse(url)
opts.isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
let srcFrag = opts.srcFrag = xrfragment.URI.parse(url)
opts.isLocal = v.string[0] == '#'
opts.isPortal = xrf.frag.src.renderAsPortal(mesh)
const addScene = (scene,url,frag) => {
src = xrf.frag.src.filterScene(scene,{...opts,frag})
xrf.frag.src.scale( src, opts, url )
xrf.frag.src.eval( src, opts, url )
enableSourcePortation(src)
mesh.add(src)
mesh.traverse( (n) => n.isSRC = n.isXRF = true )
if( mesh.material ) mesh.material.visible = false
}
const enableSourcePortation = (src) => {
if( vfrag.href || v.string[0] == '#' ) return
let scale = new THREE.Vector3()
let size = new THREE.Vector3()
mesh.getWorldScale(scale)
new THREE.Box3().setFromObject(src).getSize(size)
const geo = new THREE.SphereGeometry( Math.max(size.x, size.y, size.z) / scale.x, 10, 10 )
const mat = new THREE.MeshBasicMaterial()
mat.transparent = true
mat.roughness = 0.05
mat.metalness = 1
mat.opacity = 0
const cube = new THREE.Mesh( geo, mat )
console.log("todo: sourceportate")
//mesh.add(cube)
}
const externalSRC = (url,frag,src) => {
fetch(url, { method: 'HEAD' })
.then( (res) => {
console.log(`loading src ${url}`)
let mimetype = res.headers.get('Content-type')
if( url.replace(/#.*/,'').match(/\.(gltf|glb)$/) ) mimetype = 'gltf'
//if( url.match(/\.(fbx|stl|obj)$/) ) mimetype =
console.log("src mimetype: "+mimetype)
opts = { ...opts, src, frag }
return xrf.frag.src.type[ mimetype ] ? xrf.frag.src.type[ mimetype ](url,opts) : xrf.frag.src.type.unknown(url,opts)
})
.then( (model) => {
if( model && model.scene ) addScene(model.scene, url, frag )
})
.finally( () => { })
.catch( console.error )
}
if( url[0] == "#" ) addScene(scene,url,vfrag) // current file
else externalSRC(url,vfrag) // external file
if( opts.isLocal ){
xrf.frag.src.localSRC(url,srcFrag,opts) // local
}else xrf.frag.src.externalSRC(url,srcFrag,opts) // external file
}
xrf.frag.src.eval = function(scene, opts, url){
let { mesh, model, camera, renderer, THREE, hashbus} = opts
if( url ){
console.log(mesh.name+" url="+url)
//let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
//let frag = xrfragment.URI.parse(url)
//// scale URI XR Fragments (queries) inside src-value
//for( var i in frag ){
// hashbus.pub.fragment(i, Object.assign(opts,{frag, model:{scene},scene}))
//}
//hashbus.pub( '#', {scene} ) // execute the default projection '#' (if exist)
//hashbus.pub( url, {scene} ) // and eval URI XR fragments
xrf.frag.src.addModel = (model,url,frag,opts) => {
let {mesh} = opts
let scene = model.scene
scene = xrf.frag.src.filterScene(scene,{...opts,frag}) // get filtered scene
if( mesh.material && !mesh.userData.src ) mesh.material.visible = false // hide placeholder object
//enableSourcePortation(scene)
if( xrf.frag.src.renderAsPortal(mesh) ){
// only add remote objects, because
// local scene-objects are already added to scene
xrf.portalNonEuclidian({...opts,model,scene:model.scene})
if( !opts.isLocal ) xrf.scene.add(scene)
}else{
xrf.frag.src.scale( scene, opts, url ) // scale scene
mesh.add(scene)
xrf.emit('parseModel', {...opts, scene, model})
}
// flag everything isSRC & isXRF
mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true })
}
xrf.frag.src.renderAsPortal = (mesh) => {
// *TODO* should support better isFlat(mesh) check
const isPlane = mesh.geometry && mesh.geometry.attributes.uv && mesh.geometry.attributes.uv.count == 4
return xrf.hasNoMaterial(mesh) && isPlane
}
xrf.frag.src.enableSourcePortation = (src) => {
// show sourceportation clickable plane
if( srcFrag.href || v.string[0] == '#' ) return
let scale = new THREE.Vector3()
let size = new THREE.Vector3()
mesh.getWorldScale(scale)
new THREE.Box3().setFromObject(src).getSize(size)
const geo = new THREE.SphereGeometry( Math.max(size.x, size.y, size.z) / scale.x, 10, 10 )
const mat = new THREE.MeshBasicMaterial()
mat.transparent = true
mat.roughness = 0.05
mat.metalness = 1
mat.opacity = 0
const cube = new THREE.Mesh( geo, mat )
console.log("todo: sourceportate")
return xrf.frag.src
}
xrf.frag.src.externalSRC = (url,frag,opts) => {
fetch(url, { method: 'HEAD' })
.then( (res) => {
console.log(`loading src ${url}`)
let mimetype = res.headers.get('Content-type')
if( url.replace(/#.*/,'').match(/\.(gltf|glb)$/) ) mimetype = 'gltf'
//if( url.match(/\.(fbx|stl|obj)$/) ) mimetype =
opts = { ...opts, frag, mimetype }
return xrf.frag.src.type[ mimetype ] ? xrf.frag.src.type[ mimetype ](url,opts) : xrf.frag.src.type.unknown(url,opts)
})
.then( (model) => {
if( model && model.scene ) xrf.frag.src.addModel(model, url, frag, opts )
})
.finally( () => { })
.catch( console.error )
return xrf.frag.src
}
xrf.frag.src.localSRC = (url,frag,opts) => {
let {model,mesh,scene} = opts
setTimeout( () => {
if( mesh.material ) mesh.material = mesh.material.clone() // clone, so we can individually highlight meshes
let _model = {
animations: model.animations,
scene: scene.clone() // *TODO* opts.isPortal ? scene : scene.clone()
}
_model.scenes = [_model.scene]
xrf.frag.src.addModel(_model,url,frag, opts) // current file
},500 )
}
// scale embedded XR fragments https://xrfragment.org/#scaling%20of%20instanced%20objects
xrf.frag.src.scale = function(scene, opts, url){
let { mesh, model, camera, renderer, THREE} = opts
// remove invisible objects (hidden by selectors) which might corrupt boundingbox size-detection
let cleanScene = scene.clone()
if( !cleanScene ) debugger
let remove = []
const notVisible = (n) => !n.visible || (n.material && !n.material.visible)
cleanScene.traverse( (n) => notVisible(n) && n.children.length == 0 && (remove.push(n)) )
remove.map( (n) => n.removeFromParent() )
let restrictTo3DBoundingBox = mesh.geometry
if( restrictTo3DBoundingBox ){
// spec 3 of https://xrfragment.org/#src
@ -86,27 +108,14 @@ xrf.frag.src.scale = function(scene, opts, url){
// normalize instanced objectsize to boundingbox
let sizeFrom = new THREE.Vector3()
let sizeTo = new THREE.Vector3()
let empty = new THREE.Object3D()
// *TODO* exclude invisible objects from boundingbox size-detection
//
// THREE.Box3.prototype.expandByObject = (function(expandByObject){
// return function(object,precise){
// return expandByObject.call(this, object.visible ? object : empty, precise)
// }
// })(THREE.Box3.prototype.expandByObject)
new THREE.Box3().setFromObject(mesh).getSize(sizeTo)
new THREE.Box3().setFromObject(scene).getSize(sizeFrom)
new THREE.Box3().setFromObject(cleanScene).getSize(sizeFrom)
let ratio = sizeFrom.divide(sizeTo)
scene.scale.multiplyScalar( 1.0 / Math.max(ratio.x, ratio.y, ratio.z));
// let factor = getMax(sizeTo) < getMax(sizeFrom) ? getMax(sizeTo) / getMax(sizeFrom) : getMax(sizeFrom) / getMax(sizeTo)
// scene.scale.multiplyScalar( factor )
}else{
// spec 4 of https://xrfragment.org/#src
// spec 2 of https://xrfragment.org/#scaling%20of%20instanced%20objects
console.log("normal scale: "+url)
scene.scale.multiply( mesh.scale )
}
scene.isXRF = model.scene.isSRC = true
@ -114,31 +123,16 @@ xrf.frag.src.scale = function(scene, opts, url){
xrf.frag.src.filterScene = (scene,opts) => {
let { mesh, model, camera, renderer, THREE, hashbus, frag} = opts
let obj, src
// cherrypicking of object(s)
if( !frag.q ){
src = new THREE.Group()
if( Object.keys(frag).length > 0 ){
for( var i in frag ){
if( scene.getObjectByName(i) ){
src.add( obj = scene.getObjectByName(i).clone(true) )
}
hashbus.pub.fragment(i, Object.assign(opts,{frag, model,scene}))
}
}else src = scene.clone(true)
if( src.children.length == 1 ) obj.position.set(0,0,0);
}
// filtering of objects using query
if( frag.q ){
src = scene.clone(true);
xrf.frag.q.filter(src,frag)
scene = xrf.filter.scene({scene,frag,reparent:true}) // *TODO* ,copyScene: opts.isPortal})
if( !opts.isLocal ){
scene.traverse( (m) => {
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
})
}
src.traverse( (m) => {
if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion
hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src
})
return src
return scene
}
/*
@ -153,72 +147,6 @@ xrf.frag.src.type = {}
xrf.frag.src.type['unknown'] = function( url, opts ){
return new Promise( (resolve,reject) => {
reject(`${url} mimetype not supported (yet)`)
reject(`${url} mimetype '${opts.mimetype}' not found or supported (yet)`)
})
}
/*
* mimetype: model/gltf+json
*/
xrf.frag.src.type['gltf'] = function( url, opts ){
return new Promise( (resolve,reject) => {
let {mesh,src} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
let loader
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
if( !dir.match("://") ){ // force relative path
dir = dir[0] == './' ? dir : `./${dir}`
loader = new Loader().setPath( dir )
}else loader = new Loader()
loader.load(url, (model) => {
resolve(model)
})
})
}
/*
* mimetype: image/png
* mimetype: image/jpg
* mimetype: image/gif
*/
xrf.frag.src.type['image/png'] = function(url,opts){
let {mesh} = opts
let restrictTo3DBoundingBox = mesh.geometry
const texture = new THREE.TextureLoader().load( url );
texture.colorSpace = THREE.SRGBColorSpace;
//const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: url.match(/(png|gif)/) ? true : false,
side: THREE.DoubleSide,
color: 0xFFFFFF,
opacity:1
});
// stretch image by pinning uv-coordinates to corners
if( mesh.geometry ){
if( mesh.geometry.attributes.uv ){ // buffergeometries
let uv = mesh.geometry.attributes.uv;
// i u v
uv.setXY(0, 0, 0 )
uv.setXY(1, 1, 0 )
uv.setXY(2, 0, 1 )
uv.setXY(3, 1, 1 )
}else {
console.warn("xrfragment: uv's of ${url} might be off for non-buffer-geometries *TODO*")
//if( geometry.faceVertexUvs ){
// *TODO* force uv's of dynamically created geometries (in threejs)
//}
}
}
mesh.material = material
}
xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png']
xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png']

View file

@ -0,0 +1,83 @@
/*
* mimetype: audio/aac
* mimetype: audio/mpeg
* mimetype: audio/ogg
* mimetype: audio/weba
* mimetype: audio/wav
*/
let loadAudio = (mimetype) => function(url,opts){
let {mesh,src,camera,THREE} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
let frag = xrf.URI.parse( url )
/* WebAudio: setup context via THREEjs */
if( !camera.listener ){
camera.listener = new THREE.AudioListener();
// *FIXME* camera vs camerarig conflict
(camera.getCam ? camera.getCam() : camera).add( camera.listener );
}
let isPositionalAudio = !(mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0)
const audioLoader = new THREE.AudioLoader();
let sound = isPositionalAudio ? new THREE.PositionalAudio( camera.listener)
: new THREE.Audio( camera.listener )
audioLoader.load( url.replace(/#.*/,''), function( buffer ) {
sound.setBuffer( buffer );
sound.setLoop(false);
sound.setVolume(1.0);
if( isPositionalAudio ){
sound.setRefDistance( mesh.scale.x);
sound.setRolloffFactor(20.0)
//sound.setDirectionalCone( 360, 360, 0.01 );
}
sound.playXRF = (t) => {
mesh.add(sound)
try{
if( sound.isPlaying && t.y != undefined ) sound.stop()
if( sound.isPlaying && t.y == undefined ) sound.pause()
let hardcodedLoop = frag.t != undefined
t = hardcodedLoop ? { ...frag.t, x: t.x} : t // override with hardcoded metadata except playstate (x)
if( t && t.x != 0 ){
// *TODO* https://stackoverflow.com/questions/12484052/how-can-i-reverse-playback-in-web-audio-api-but-keep-a-forward-version-as-well
t.x = Math.abs(t.x)
sound.setPlaybackRate( t.x ) // WebAudio does not support negative playback
// setting loop
if( t.z ) sound.setLoop( true )
// apply embedded audio/video samplerate/fps or global mixer fps
let loopStart = hardcodedLoop ? t.y : t.y * buffer.sampleRate;
let loopEnd = hardcodedLoop ? t.z : t.z * buffer.sampleRate;
let timeStart = loopStart > 0 ? loopStart : (t.y == undefined ? xrf.model.mixer.time : t.y)
if( t.z > 0 ) sound.setLoopEnd( loopEnd )
if( t.y != undefined ){
sound.setLoopStart( loopStart )
sound.offset = loopStart
}
sound.play()
}
}catch(e){ console.warn(e) }
}
mesh.audio = sound
});
}
let audioMimeTypes = [
'audio/wav',
'audio/mpeg',
'audio/mp3',
'audio/weba',
'audio/aac',
'application/ogg'
]
audioMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadAudio(mimetype) )
// listen to t XR fragment changes
xrf.addEventListener('t', (opts) => {
let t = opts.frag.t
xrf.scene.traverse( (n) => n.audio && n.audio.playXRF && (n.audio.playXRF(t)) )
})

View file

@ -0,0 +1,23 @@
/*
* mimetype: model/gltf+json
*/
xrf.frag.src.type['gltf'] = function( url, opts ){
return new Promise( (resolve,reject) => {
let {mesh,src} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
let loader
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
if( !dir.match("://") ){ // force relative path
dir = dir[0] == './' ? dir : `./${dir}`
loader = new Loader().setPath( dir )
}else loader = new Loader()
loader.load(url, (model) => {
resolve(model)
})
})
}

View file

@ -0,0 +1,12 @@
let loadHTML = (mimetype) => function(url,opts){
let {mesh,src,camera} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
let frag = xrf.URI.parse( url )
console.warn("todo: html viewer for src not implemented")
}
let htmlMimeTypes = [
'text/html'
]
htmlMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadHTML(mimetype) )

View file

@ -0,0 +1,50 @@
/*
* mimetype: image/png
* mimetype: image/jpg
* mimetype: image/gif
*/
xrf.frag.src.type['image/png'] = function(url,opts){
let {mesh,THREE} = opts
let restrictTo3DBoundingBox = mesh.geometry
mesh.material = new xrf.THREE.MeshBasicMaterial({
map: null,
transparent: url.match(/(png|gif)/) ? true : false,
side: THREE.DoubleSide,
color: 0xFFFFFF,
opacity:1
});
let renderImage = (texture) => {
let img = {w: texture.source.data.width, h: texture.source.data.height}
// stretch image by pinning uv-coordinates to corners
if( mesh.geometry ){
if( mesh.geometry.attributes.uv ){ // buffergeometries
let uv = mesh.geometry.attributes.uv;
}else {
console.warn("xrfragment: uv's of ${url} might be off for non-buffer-geometries *TODO*")
//if( geometry.faceVertexUvs ){
// *TODO* force uv's of dynamically created geometries (in threejs)
//}
}
}
mesh.material.map = texture
mesh.needsUpdate = true
}
let onLoad = (texture) => {
texture.colorSpace = THREE.SRGBColorSpace;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
renderImage(texture)
}
new THREE.TextureLoader().load( url, onLoad, null, console.error );
}
xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png']
xrf.frag.src.type['image/jpeg'] = xrf.frag.src.type['image/png']

View file

@ -0,0 +1,197 @@
// spec 8: https://xrfragment.org/doc/RFC_XR_Macros.html#embedding-xr-content-using-src
xrf.portalNonEuclidian = function(opts){
let { frag, mesh, model, camera, scene, renderer} = opts
mesh.portal = {
pos: mesh.position.clone(),
posWorld: new xrf.THREE.Vector3(),
posWorldCamera: new xrf.THREE.Vector3(),
stencilRef: xrf.portalNonEuclidian.stencilRef,
needUpdate: false,
stencilObject: false,
cameraDirection: new THREE.Vector3(),
cameraPosition: new THREE.Vector3(),
raycaster: new THREE.Raycaster(),
isLocal: opts.isLocal,
isLens: false,
isInside: false,
setStencil: (stencilRef) => mesh.portal.stencilObjects.traverse( (n) => showPortal(n, stencilRef == 0) && n.stencil && n.stencil(stencilRef) ),
positionObjectsIfNeeded: (pos,scale) => !mesh.portal.isLens && mesh.portal.stencilObjects.traverse( (n) => n.positionAtStencil && (n.positionAtStencil(pos,scale)) )
}
// allow objects to flip between original and stencil position (which puts them behind stencilplane)
const addStencilFeature = (n) => {
if( n.stencil ) return n // run once
n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef )
n.positionAtStencil = (pos,scale) => (newPos,newScale) => {
n.position.copy( newPos || pos )
n.scale.copy( scale )
n.updateMatrixWorld(true)
}
// curry function
n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() )
return n
}
this.setupStencilObjects = (scene,opts) => {
// collect related objects to render inside stencilplane
let stencilObject = scene
if( opts.srcFrag.target ){
stencilObject = scene.getObjectByName( opts.srcFrag.target.key )
// spec: if src-object is child of portal (then portal is lens, and should include all children )
mesh.traverse( (n) => n.name == opts.srcFrag.target.key && (stencilObject = n) && (mesh.portal.isLens = true) )
}
if( !stencilObject ) return console.warn(`no objects were found (src:${mesh.userData.src}) for (portal)object name '${mesh.name}'`)
mesh.portal.stencilObject = stencilObject
// spec: if src points to child, act as lens
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
let stencilObjects = [stencilObject]
stencilObjects = stencilObjects
.filter( (n) => !n.portal ) // filter out (self)references to portals (prevent recursion)
.map(addStencilFeature)
// put it into a scene (without .add() because it reparents objects) so we can render it separately
mesh.portal.stencilObjects = new xrf.THREE.Scene()
mesh.portal.stencilObjects.children = stencilObjects
xrf.portalNonEuclidian.stencilRef += 1 // each portal has unique stencil id
console.log(`enabling portal for object '${mesh.name}' (stencilRef:${mesh.portal.stencilRef})`)
return this
}
// enable the stencil-material of the stencil objects to prevent stackoverflow (portal in portal rendering)
const showPortal = (n,show) => {
if( n.portal ) n.visible = show
return true
}
this.setupListeners = () => {
mesh.onAfterRender = function(renderer, scene, camera, geometry, material, group ){
mesh.portal.needUpdate = true
}
xrf.addEventListener('renderPost', (opts) => {
let {scene,camera,time,render,renderer} = opts
if( mesh.portal.needUpdate && mesh.portal && mesh.portal.stencilObjects ){
let cameraDirection = mesh.portal.cameraDirection
let cameraPosition = mesh.portal.cameraPosition
let stencilRef = mesh.portal.stencilRef
let newPos = mesh.portal.posWorld
let stencilObject = mesh.portal.stencilObject
let newScale = mesh.scale
let raycaster = mesh.portal.raycaster
let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera
cam.getWorldPosition(cameraPosition)
cam.getWorldDirection(cameraDirection)
if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals
// init
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true
mesh.portal.setStencil(stencilRef)
renderer.autoClear = false
renderer.autoClearDepth = false
renderer.autoClearColor = false
renderer.autoClearStencil = false
// render
render( mesh.portal.stencilObjects, camera )
// de-init
renderer.autoClear = true
renderer.autoClearDepth = true
renderer.autoClearColor = true
renderer.autoClearStencil = true
mesh.portal.setStencil(0)
if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false
// trigger href upon camera collide
if( mesh.userData.XRF.href ){
raycaster.far = 0.35
raycaster.set(cameraPosition, cameraDirection )
intersects = raycaster.intersectObjects([mesh], false)
if (intersects.length > 0 && !mesh.portal.teleporting ){
mesh.portal.teleporting = true
mesh.userData.XRF.href.exec({nocommit:true})
setTimeout( () => mesh.portal.teleporting = false, 500) // dont flip back and forth
}
}
}
mesh.portal.needUpdate = false
})
return this
}
// turn mesh into stencilplane
xrf
.portalNonEuclidian
.setMaterial(mesh)
.getWorldPosition(mesh.portal.posWorld)
this
.setupListeners()
.setupStencilObjects(scene,opts)
// move portal objects to portalposition
if( mesh.portal.stencilObjects ) mesh.portal.positionObjectsIfNeeded(mesh.portal.posWorld, mesh.scale)
}
xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => {
if( n.material ){
n.material.stencilRef = stencilRef
n.material.stencilWrite = stencilRef > 0
n.material.stencilFunc = xrf.THREE.EqualStencilFunc;
}
if( n.children && !nested ) n.traverse( (m) => !m.portal && (xrf.portalNonEuclidian.selectStencil(m,stencilRef,true)) )
}
xrf.portalNonEuclidian.setMaterial = function(mesh){
mesh.material = new xrf.THREE.MeshBasicMaterial({ color: 'orange' });
mesh.material.depthWrite = false;
mesh.material.colorWrite = false;
mesh.material.stencilWrite = true;
mesh.material.stencilRef = xrf.portalNonEuclidian.stencilRef;
// mesh.renderOrder = 0;//xrf.portalNonEuclidian.stencilRef;
mesh.material.stencilFunc = xrf.THREE.AlwaysStencilFunc;
mesh.material.stencilZPass = xrf.THREE.ReplaceStencilOp;
mesh.material.stencilZFail = xrf.THREE.ReplaceStencilOp;
//n.material.depthFunc = stencilRef > 0 ? xrf.THREE.AlwaysDepth : xrf.THREE.LessEqualDepth
//mesh.material.depthTest = false;
return mesh
}
xrf.addEventListener('parseModel',(opts) => {
const scene = opts.model.scene
//for( let i in scene.children ) scene.children[i].renderOrder = 10 // render outer layers last (worldspheres e.g.)
})
// (re)set portalObjects when entering/leaving a portal
let updatePortals = (opts) => {
xrf.scene.traverse( (n) => {
if( !n.portal ) return
// move objects back to the portal
if( n.portal.isInside ) n.portal.positionObjectsIfNeeded( n.portal.posWorld, n.scale )
n.portal.isInside = false
})
if( opts.mesh && opts.mesh.portal && opts.click ){
opts.mesh.portal.isInside = true
opts.mesh.portal.positionObjectsIfNeeded() // move objects back to original pos (since we are teleporting there)
}
}
xrf.addEventListener('href', (opts) => opts.click && updatePortals(opts) )
xrf.addEventListener('navigate', updatePortals )
xrf.portalNonEuclidian.stencilRef = 1

View file

@ -0,0 +1,47 @@
let loadVideo = (mimetype) => function(url,opts){
let {mesh,src,camera} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
const THREE = xrf.THREE
let frag = xrf.URI.parse( url )
let video = mesh.video = document.createElement('video')
video.setAttribute("crossOrigin","anonymous")
video.setAttribute("playsinline",'')
video.addEventListener('loadedmetadata', function(){
let texture = new THREE.VideoTexture( video );
texture.colorSpace = THREE.SRGBColorSpace;
let mat = new xrf.THREE.MeshBasicMaterial()
mat.map = texture
mesh.material = mat
// set range
//video.addEventListener('timeupdate', function timeupdate() {
// if (frag.t && video.currentTime < frag.t.y || video.currentTime >= frag.t.z ) {
// video.currentTime = frag.t.y
// }
//},false)
})
video.src = url
video.playXRF = (t) => {
video.t = t
if( t.x == 0 ) video.pause()
else{
video.playbackRate = Math.abs( t.x ) // html5 video does not support reverseplay :/
video.play()
}
if( t.y != undefined ) video.time = t.y
}
}
let videoMimeTypes = [
'video/ogg',
'video/mp4'
]
videoMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadVideo(mimetype) )
// listen to t XR fragment changes
xrf.addEventListener('t', (opts) => {
let t = opts.frag.t
xrf.scene.traverse( (n) => n.video && (n.video.playXRF(t)) )
})

View file

@ -1,46 +1,163 @@
xrf.frag.t = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(` └ setting animation loop to ${v.x} ${v.y} ${v.z}` )
if( !model.mixer ) return
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
model.mixer.t = v
let duration = model.animations[0].duration
let frames = model.animations[0].tracks[0].times.length
let mixer = model.mixer
mixer.loop = mixer.loop || {frameStart:0,frameStop:99999999,speed: 1}
let fps = frames / duration
xrf.mixers.map ( (mixer) => {
mixer.t = v
// update speed
mixer.timeScale = mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.frameStart = v.y || mixer.loop.frameStart
mixer.loop.frameStop = v.z || mixer.loop.frameStop
// always recalculate time using frameStart/Stop
mixer.loop.timeStart = mixer.loop.frameStart / (fps * mixer.loop.speedAbs)
mixer.loop.timeStop = mixer.loop.frameStop / (fps * mixer.loop.speedAbs)
// update speed
mixer.timeScale = mixer.loop.speed
if( v.y != undefined || v.z != undefined ) mixer.updateLoop( v )
let updateTime = (time) => {
mixer.setTime(time)
mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
// play animations
mixer.play( v )
})
}
xrf.frag.t.default = {
x:0, // (play from) offset (in seconds)
y:0 // optional: (stop at) offset (in seconds)
}
// setup animation mixer for global scene & src scenes
xrf.addEventListener('parseModel', (opts) => {
let {model} = opts
let mixer = model.mixer = new xrf.THREE.AnimationMixer(model.scene)
mixer.model = model
mixer.loop = {timeStart:0,timeStop:0}
mixer.i = xrf.mixers.length
mixer.actions = []
model.animations.map( (anim) => {
anim.optimize()
console.log("action: "+anim.name)
mixer.actions.push( mixer.clipAction( anim, model.scene ) )
})
mixer.checkZombies = (animations) => {
if( mixer.zombieCheck ) return // fire only once
animations.map( (anim) => {
// collect zombie animations and warn user
let zombies = anim.tracks.map( (t) => {
let name = t.name.replace(/\..*/,'')
let obj = model.scene.getObjectByName(name)
return !model.scene.getObjectByName(name) ? {anim:anim.name,obj:name} : undefined
})
if( zombies.length > 0 && mixer.i == 0 ){ // only warn for zombies in main scene (because src-scenes might be filtered anyways)
zombies
.filter( (z) => z ) // filter out undefined
.map( (z) => console.warn(`gltf: object '${z.obj}' not found (anim: '${z.anim}'`) )
console.warn(`TIP: remove dots in objectnames in blender (which adds dots when duplicating)`)
}
})
mixer.zombieCheck = true
}
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )
mixer.play = (t) => {
mixer.isPlaying = t.x != 0
mixer.updateLoop(t)
xrf.emit( mixer.isPlaying === false ? 'stop' : 'play',{isPlaying: mixer.isPlaying})
}
mixer.stop = () => {
mixer.play(false)
}
mixer.updateLoop = (t) => {
mixer.loop.timeStart = t.y != undefined ? t.y : mixer.loop.timeStart
mixer.loop.timeStop = t.z != undefined ? t.z : mixer.loop.timeStop
mixer.actions.map( (action) => {
if( mixer.loop.timeStart != undefined ){
action.time = mixer.loop.timeStart
action.setLoop( THREE.LoopOnce, )
action.timeScale = mixer.timeScale
action.enabled = true
if( t.x != 0 ){
action.play()
}
}
})
mixer.setTime(mixer.loop.timeStart)
mixer.time = Math.abs( mixer.loop.timeStart )
mixer.update(0)
mixer.checkZombies( model.animations)
}
// update loop when needed
if( !mixer.update.patched ){
let update = mixer.update
mixer.update = function(time){
mixer.time = Math.abs(mixer.time)
if( time == 0 ) return update.call(mixer,time)
if( time == 0 ) return update.call(this,time)
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
setTimeout( (time) => updateTime(time),0,mixer.loop.timeStart) // prevent recursion
// loop jump
if( mixer.loop.speed > 0.0 && (mixer.loop.timeStop > 0 && mixer.time > mixer.loop.timeStop) ){
setTimeout( (time,anims) => mixer.updateLoop(time), 0, mixer.loop.timeStart ) // prevent recursion
}
return update.call( mixer, time )
return update.call( this, time )
}
mixer.update.patched = true
}
// calculate total duration/frame based on longest animation
mixer.duration = 0
if( model.animations.length ){
model.animations.map( (a) => mixer.duration = ( a.duration > mixer.duration ) ? a.duration : mixer.duration )
}
xrf.mixers.push(mixer)
})
if( document.location.hash.match(/t=/) ){
let url = document.location.href
let playAfterUserGesture = () => {
xrf.hashbus.pub(url) // re-post t fragment on the hashbus again
window.removeEventListener('click',playAfterUserGesture)
window.removeEventListener('touchstart',playAfterUserGesture)
}
window.addEventListener('click', playAfterUserGesture )
window.addEventListener('touchstart', playAfterUserGesture )
}
xrf.addEventListener('render', (opts) => {
let model = xrf.model
let {time} = opts
if( !model ) return
if( xrf.mixers.length ){
xrf.mixers.map( (m) => m.isPlaying && (m.update( time )) )
// update active camera in case selected by dynamicKey in URI
if( xrf.model.camera && model.mixer.isPlaying ){
let cam = xrf.camera.getCam()
// cam.fov = model.cameras[0].fov (why is blender not exporting radians?)
cam.far = model.cameras[0].far
cam.near = model.cameras[0].near
let rig = xrf.camera
rig.position.copy( model.cameras[0].position )
rig.position.y -= rig.offsetY // VR/AR compensate camera rig
//rig.rotation.copy( model.cameras[0].rotation )
rig.updateProjectionMatrix()
}
}
})
xrf.addEventListener('dynamicKey', (opts) => {
// select active camera if any
let {id,match,v} = opts
match.map( (w) => {
w.nodes.map( (node) => {
if( node.isCamera ){
console.log("setting camera to "+node.name)
xrf.model.camera = node
}
})
})
})

View file

@ -1,14 +1,14 @@
xrf.addEventListener('env', (opts) => {
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
if( frag.env && !scene.environment ){
let env = scene.getObjectByName(frag.env.string)
if( !env ) env = xrf.scene.getObjectByName(frag.env.string) // repurpose from parent scene
if( !env ) return console.warn("xrf.env "+frag.env.string+" not found")
env.material.map.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = env.material.map
//let env = scene.getObjectByName(frag.env.string)
//if( !env ) env = xrf.scene.getObjectByName(frag.env.string) // repurpose from parent scene
//if( !env ) return console.warn("xrf.env "+frag.env.string+" not found")
//env.material.map.mapping = THREE.EquirectangularReflectionMapping;
//scene.environment = env.material.map
//scene.texture = env.material.map
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 2;
// renderer.toneMapping = THREE.ACESFilmicToneMapping;
// renderer.toneMappingExposure = 2;
console.log(` └ applied image '${frag.env.string}' as environment map`)
}

View file

@ -1,6 +1,6 @@
xrf.macros = {}
xrf.addEventListener('mesh', (opts) => {
xrf.addEventListener('frag2mesh', (opts) => {
let { frag, mesh, model, camera, scene, renderer, THREE, hashbus} = opts
for( let k in frag ){

View file

@ -1,14 +1,14 @@
xrf.addEventListener('pos', (opts) => {
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
if( frag.pos && frag.q ){
// apply roundrobin (if any)
if( v.args ) v = v.args[ xrf.roundrobin(v,model) ]
//if( frag.pos && frag.q ){
// // apply roundrobin (if any)
// if( v.args ) v = v.args[ xrf.roundrobin(v,model) ]
frag.q.getObjects().map( (o) => {
// if object has no parent (name == 'Scene') use absolute positioning, otherwise relative to parent
o.position.x = o.parent.name == 'Scene' ? v.x : o.positionOriginal.x + v.x
o.position.y = o.parent.name == 'Scene' ? v.z : o.positionOriginal.y + v.z
o.position.z = o.parent.name == 'Scene' ? v.y : o.positionOriginal.z + v.y
})
}
// frag.q.getObjects().map( (o) => {
// // if object has no parent (name == 'Scene') use absolute positioning, otherwise relative to parent
// o.position.x = o.parent.name == 'Scene' ? v.x : o.positionOriginal.x + v.x
// o.position.y = o.parent.name == 'Scene' ? v.z : o.positionOriginal.y + v.z
// o.position.z = o.parent.name == 'Scene' ? v.y : o.positionOriginal.z + v.y
// })
//}
})

View file

@ -1,4 +1,4 @@
import xrfragment.Query;
import xrfragment.Filter;
import xrfragment.URI;
import xrfragment.XRF;
@ -15,42 +15,50 @@ class Test {
static var errors:Int = 0;
static public function main():Void {
test( Spec.load("src/spec/url.json") );
test( Spec.load("src/spec/query.selectors.json") );
test( Spec.load("src/spec/query.root.json") );
test( Spec.load("src/spec/query.rules.json") );
test( "url.json", Spec.load("src/spec/url.json") );
test( "pos.json", Spec.load("src/spec/pos.json") );
test( "t.json", Spec.load("src/spec/t.json") );
test( "filter.selectors.json", Spec.load("src/spec/filter.selectors.json") );
//test( Spec.load("src/spec/tmp.json") );
if( errors > 1 ) trace("\n-----\n[ ] "+errors+" errors :/");
}
static public function test(spec:Array<Dynamic>):Void {
var Query = xrfragment.Query;
static public function test( topic:String, spec:Array<Dynamic>):Void {
trace("\n[.] running "+topic);
var Filter = xrfragment.Filter;
for( i in 0...spec.length ){
var q:Query = null;
var f:Filter = null;
var res:haxe.DynamicAccess<Dynamic> = null;
var valid:Bool = false;
var item:Dynamic = spec[i];
if( item.fn == "query" ) q = new Query(item.data);
if( item.fn == "url" ) res = URI.parse(item.data,0);
if( item.expect.fn == "test" ) valid = item.expect.out == q.test( item.expect.input[0] );
if( item.expect.fn == "testProperty" ) valid = item.expect.out == q.testProperty( item.expect.input[0], item.expect.input[1] );
if( item.expect.fn == "testPropertyExclude" ) valid = item.expect.out == q.testProperty( item.expect.input[0], item.expect.input[1], true );
f = new Filter(item.data);
res = URI.parse(item.data,null);
if( item.expect.fn == "test" ) valid = item.expect.out == f.test( item.expect.input[0] );
if( item.expect.fn == "testProperty" ) valid = item.expect.out == f.testProperty( item.expect.input[0], item.expect.input[1] );
if( item.expect.fn == "testPropertyInt" ) valid = item.expect.out == f.testProperty( item.expect.input[0], item.expect.input[1] );
if( item.expect.fn == "testPropertyExclude" ) valid = item.expect.out == f.testProperty( item.expect.input[0], item.expect.input[1], true );
if( item.expect.fn == "testParsed" ) valid = item.expect.out == res.exists(item.expect.input);
if( item.expect.fn == "testPredefinedView" ) valid = res.exists(item.expect.input) && item.expect.out == res.get(item.expect.input).is( XRF.PV_EXECUTE) ;
if( item.expect.fn == "testPropertyAssign" ) valid = res.exists(item.expect.input) && item.expect.out == res.get(item.expect.input).is( XRF.PROP_BIND) ;
if( item.expect.fn == "testBrowserOverride" ) valid = item.expect.out == (URI.parse(item.data,XRF.NAVIGATOR)).exists(item.expect.input);
if( item.expect.fn == "testEmbedOverride" ) valid = item.expect.out == (URI.parse(item.data,XRF.METADATA)).exists(item.expect.input);
if( item.expect.fn == "equal.string" ) valid = res.get(item.expect.input) && item.expect.out == res.get(item.expect.input).string;
if( item.expect.fn == "equal.x" ) valid = equalX(res,item);
if( item.expect.fn == "equal.xy" ) valid = equalXY(res,item);
if( item.expect.fn == "equal.xyz" ) valid = equalXYZ(res,item);
if( item.expect.fn == "equal.multi" ) valid = equalMulti(res, item);
if( item.expect.fn == "testQueryRoot" ) valid = item.expect.out == q.get()[ item.expect.input[0] ].root;
if( item.expect.fn == "testFilterRoot" ) valid = res.exists(item.expect.input[0]) && res.get(item.expect.input[0]).filter.get().root == item.expect.out;
if( item.expect.fn == "testFilterDeep" ) valid = res.exists(item.expect.input[0]) && res.get(item.expect.input[0]).filter.get().deep == item.expect.out;
var ok:String = valid ? "[ ] " : "[ ] ";
trace( ok + item.fn + ": '" + item.data + "'" + (item.label ? " (" + (item.label?item.label:item.expect.fn) +")" : ""));
if( !valid ) errors += 1;
}
}
static public function equalX(res:haxe.DynamicAccess<Dynamic>, item:Dynamic):Bool {
if( !item.expect.out && !res.get(item.expect.input) ) return true;
else return res.get(item.expect.input) && item.expect.out == (Std.string(res.get(item.expect.input).x) );
}
static public function equalXY(res:haxe.DynamicAccess<Dynamic>, item:Dynamic):Bool {
if( !item.expect.out && !res.get(item.expect.input) ) return true;
else return res.get(item.expect.input) && item.expect.out == (Std.string(res.get(item.expect.input).x) +","+ Std.string(res.get(item.expect.input).y) );
@ -61,17 +69,6 @@ class Test {
else return res.get(item.expect.input) && item.expect.out == (Std.string(res.get(item.expect.input).x) +","+ Std.string(res.get(item.expect.input).y)+","+ Std.string(res.get(item.expect.input).z));
}
static public function equalMulti(res:haxe.DynamicAccess<Dynamic>, item:Dynamic):Bool {
var target:Dynamic = res.get(item.expect.input);
var str:String = "";
if( !target ) return false;
for( i in 0...target.args.length ){
str = str + "|" + target.args[i].string;
}
str = str.substr(1);
return item.expect.out ? str == item.expect.out : false;
}
static public function testUrl():Void {
var Uri = xrfragment.URI;
var url:String = "http://foo.com?foo=1#bar=flop&a=1,2&b=c|d|1,2,3";
@ -79,114 +76,18 @@ class Test {
trace( Uri.parse(url,0) );
}
static public function testQuery():Void {
var Query = xrfragment.Query;
static public function testFilter():Void {
var Filter = xrfragment.Filter;
trace( (new Query("foo or bar")).toObject() );
trace( (new Query("class:fopoer or bar foo:bar")).toObject().or[0] );
trace( (new Query("-skybox class:foo")).toObject().or[0] );
trace( (new Query("foo/flop moo or bar")).toObject().or[0] );
trace( (new Query("-foo/flop moo or bar")).toObject().or[0] );
trace( (new Query("price:>4 moo or bar")).toObject().or[0] );
trace( (new Query("price:>=4 moo or bar")).toObject().or[0] );
trace( (new Query("price:<=4 moo or bar")).toObject().or[0] );
trace( (new Query("price:!=4 moo or bar")).toObject().or[0] );
var q:Dynamic = new Query("price:!=4 moo or bar");
var obj:Dynamic = q.toObject();
q.test( "price", 4);
var ok = !q.selected("slkklskdf");
if( !ok ) throw 'node should not be allowed';
q = new Query("price:!=3 moo or bar");
var obj:Dynamic = q.toObject();
q.test( "price", 4);
var ok = q.selected("slkklskdf");
if( !ok ) throw 'non-mentioned node should be allowed';
q = new Query("moo or bar");
var obj:Dynamic = q.toObject();
var ok = !q.selected("slkklskdf");
if( !ok ) throw 'node should not be allowed';
obj = q.toObject();
var ok = q.selected("moo");
if( !ok ) throw 'moo should be allowed';
var ok = q.selected("bar");
if( !ok ) throw 'bar should be allowed';
q = new Query("price:>3 moo or bar");
var obj:Dynamic = q.toObject();
q.test( "price", 4);
var ok = q.selected("foo");
if( !ok ) throw 'node should be allowed';
var ok = q.selected("bar");
if( !ok ) throw 'node should be allowed';
var ok = q.selected("moo");
if( !ok ) throw 'node should be allowed';
q = new Query("price:>3 price:<10 -bar");
var obj:Dynamic = q.toObject();
q.test( "price", 4);
var ok = q.selected("foo");
if( !ok ) throw 'node should be allowed';
var ok = !q.selected("bar");
if( !ok ) throw 'bar should not be allowed';
q.test("price", 20);
var ok = !q.selected("foo");
if( !ok ) throw 'price 20 should not be allowed';
q = new Query("-bar");
var obj:Dynamic = q.toObject();
var ok = q.selected("foo");
if( !ok ) throw 'node should be allowed';
var ok = !q.selected("bar");
if( !ok ) throw 'bar should not be allowed';
q = new Query("title:*");
var obj:Dynamic = q.toObject();
var ok = !q.selected("foo");
if( !ok ) throw 'node should not be allowed';
q.test("foo","bar");
var ok = !q.selected("foo");
if( !ok ) throw 'node should not be allowed';
q.test("title","bar");
var ok = q.selected("foo");
if( !ok ) throw 'node should be allowed';
q = new Query("-bar +bar");
var obj:Dynamic = q.toObject();
var ok = q.selected("foo");
if( !ok ) throw 'node should be allowed';
var ok = q.selected("bar");
if( !ok ) throw 'bar should be allowed';
q = new Query("?discount");
var obj:Dynamic = q.toObject();
q.test("?discount","-foo");
var ok = !q.selected("foo");
if( !ok ) throw 'foo should not be allowed';
q = new Query("?");
q.test("?","-foo");
var ok = !q.selected("foo");
if( !ok ) throw 'foo should not be allowed';
q = new Query("?");
var ok = q.selected("foo");
if( !ok ) throw 'foo should not be allowed';
q = new Query("?discount");
q.test("?discount","-foo");
var ok = !q.selected("foo");
if( !ok ) throw 'foo should not be allowed';
q = new Query("?discount +foo");
var obj:Dynamic = q.toObject();
q.test("?discount","-foo");
var ok = !q.selected("foo");
if( !ok ) throw 'foo should not be allowed';
var ok = !q.selected("foo");
if( !ok ) throw 'foo should not be allowed';
trace( (new Filter("foo or bar")).toObject() );
trace( (new Filter("class:fopoer or bar foo:bar")).toObject().or[0] );
trace( (new Filter("-skybox class:foo")).toObject().or[0] );
trace( (new Filter("foo/flop moo or bar")).toObject().or[0] );
trace( (new Filter("-foo/flop moo or bar")).toObject().or[0] );
trace( (new Filter("price:>4 moo or bar")).toObject().or[0] );
trace( (new Filter("price:>=4 moo or bar")).toObject().or[0] );
trace( (new Filter("price:<=4 moo or bar")).toObject().or[0] );
trace( (new Filter("price:!=4 moo or bar")).toObject().or[0] );
trace("all tests passed");
}

View file

@ -0,0 +1,15 @@
[
{"fn":"url","data":"http://foo.com?foo=1#foo*&-sometag&-someid&myid", "expect":{ "fn":"testParsed", "input":"myid","out":true},"label":"myid exists"},
{"fn":"url","data":"http://foo.com?foo=1#tag=bar", "expect":{ "fn":"testParsed", "input":"tag", "out":true},"label":"tag exists"},
{"fn":"url","data":"http://foo.com?foo=1#-tag=bar", "expect":{ "fn":"testParsed", "input":"tag", "out":true},"label":"tag exists"},
{"fn":"url","data":"http://foo.com?foo=1#price=>2", "expect":{ "fn":"testParsed", "input":"price","out":true},"label":"filter test"},
{"fn":"filter","data":"tag=bar", "expect":{ "fn":"testProperty","input":["tag","bar"],"out":true}},
{"fn":"filter","data":"-tag=foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":false}},
{"fn":"filter","data":"-tag*=foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":false}},
{"fn":"filter","data":"-tag=>2", "expect":{ "fn":"testProperty","input":["tag","3"],"out":false}},
{"fn":"filter","data":"price=>2", "expect":{ "fn":"testProperty","input":["price","1"],"out":false}},
{"fn":"filter","data":"price=<2", "expect":{ "fn":"testProperty","input":["price","5"],"out":false}},
{"fn":"filter","data":"price=<2", "expect":{ "fn":"testProperty","input":["price","1"],"out":true}},
{"fn":"url","data":"#foo*", "expect":{ "fn":"testFilterDeep","input":["foo"],"out":1},"label":"foo should be deep"},
{"fn":"url","data":"#foo**", "expect":{ "fn":"testFilterDeep","input":["foo"],"out":2},"label":"foo should be deep incl. embeds"}
]

6
src/spec/pos.json Normal file
View file

@ -0,0 +1,6 @@
[
{"fn":"url","data":"http://foo.com?foo=1#pos=1.2,2.2", "expect":{ "fn":"equal.string", "input":"pos","out":"1.2,2.2"},"label":"equal.string"},
{"fn":"url","data":"http://foo.com?foo=1#pos=1.2,2.2,3", "expect":{ "fn":"equal.xyz", "input":"pos","out":"1.2,2.2,3"},"label":"equal.xyz"},
{"fn":"url","data":"http://foo.com?foo=1#pos=1,2,3", "expect":{ "fn":"equal.xyz", "input":"pos","out":"1,2,3"},"label":"pos equal.xyz"},
{"fn":"url","data":"http://foo.com?foo=1#pos=world2", "expect":{ "fn":"equal.string", "input":"pos","out":"world2"},"label":"pos equal.xyz"}
]

View file

@ -1,2 +0,0 @@
[
]

View file

@ -1,15 +0,0 @@
[
{"fn":"query","data":"price:>=5", "expect":{ "fn":"testProperty","input":["price","10"],"out":true}},
{"fn":"query","data":"price:>=15", "expect":{ "fn":"testProperty","input":["price","10"],"out":false}},
{"fn":"query","data":"price:>=5", "expect":{ "fn":"testProperty","input":["price","4"],"out":false}},
{"fn":"query","data":"price:>=5", "expect":{ "fn":"testProperty","input":["price","0"],"out":false}},
{"fn":"query","data":"price:>=2", "expect":{ "fn":"testProperty","input":["price","2"],"out":true}},
{"fn":"query","data":"price:>=5 price:0", "expect":{ "fn":"testProperty","input":["price","1"],"out":false},"label":"price=1"},
{"fn":"query","data":"price:>=5 price:0", "expect":{ "fn":"testProperty","input":["price","0"],"out":true},"label":"price=0"},
{"fn":"query","data":"price:>=5 price:0", "expect":{ "fn":"testProperty","input":["price","6"],"out":true},"label":"price=6"},
{"fn":"query","data":"tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true}},
{"fn":"query","data":"-tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":false}},
{"fn":"query","data":"-tag:foo", "expect":{ "fn":"testPropertyExclude","input":["tag","foo"],"out":true},"label":"testExclude"},
{"fn":"query","data":".foo price:5 -tag:foo", "expect":{ "fn":"test","input":[{"price":5}],"out":true}},
{"fn":"query","data":".foo price:5 -tag:foo", "expect":{ "fn":"test","input":[{"tag":"foo","price":5}],"out":false}}
]

View file

@ -1,15 +0,0 @@
[
{"fn":"query","data":"tag:bar", "expect":{ "fn":"testProperty","input":["tag","bar"],"out":true}},
{"fn":"query","data":"tag:bar -tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":false}},
{"fn":"query","data":"tag:bar -tag:foo tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true}},
{"fn":"query","data":"tag:bar -tag:bar tag:bar", "expect":{ "fn":"testProperty","input":["tag","bar"],"out":true}},
{"fn":"query","data":"tag:foo -tag:foo tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true},"label":"tag:foo"},
{"fn":"query","data":"tag:foo -tag:foo bar:5 tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true},"label":"tag:foo"},
{"fn":"query","data":"tag:foo -tag:foo bar:>5 tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true},"label":"tag:foo"},
{"fn":"query","data":"tag:foo -tag:foo bar:>5 tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true},"label":"tag:foo"},
{"fn":"query","data":"tag:foo -tag:foo tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true},"label":"tag:foo"},
{"fn":"query","data":"tag:foo -tag:foo tag:foo", "expect":{ "fn":"testProperty","input":["id","foo"],"out":true},"label":"id:foo"},
{"fn":"query","data":"tag:foo -foo foo", "expect":{ "fn":"testProperty","input":["id","foo"],"out":true},"label":"id:foo?"},
{"fn":"query","data":"/foo", "expect":{ "fn":"testQueryRoot","input":["foo"],"out":true},"label":"foo should be root-only"},
{"fn":"query","data":"/foo foo", "expect":{ "fn":"testQueryRoot","input":["foo"],"out":false},"label":"foo should recursively selected"}
]

10
src/spec/t.json Normal file
View file

@ -0,0 +1,10 @@
[
{"fn":"url","data":"http://foo.com?foo=1#t=1", "expect":{ "fn":"equal.x", "input":"t","out":"1"},"label":"a equal.x"},
{"fn":"url","data":"http://foo.com?foo=1#t=-1", "expect":{ "fn":"equal.x", "input":"t","out":"-1"},"label":"a equal.x"},
{"fn":"url","data":"http://foo.com?foo=1#t=-1.02", "expect":{ "fn":"equal.x", "input":"t","out":"-1.02"},"label":"a equal.x"},
{"fn":"url","data":"http://foo.com?foo=1#t=1,2,3", "expect":{ "fn":"equal.xy", "input":"t","out":"1,2"},"label":"a equal.xy"},
{"fn":"url","data":"http://foo.com?foo=1#t=1,2,3", "expect":{ "fn":"equal.xyz", "input":"t","out":"1,2,3"},"label":"a equal.xyz"},
{"fn":"url","data":"http://foo.com?foo=1#t=1,-2,3", "expect":{ "fn":"equal.xyz", "input":"t","out":"1,-2,3"},"label":"a equal.xyz"},
{"fn":"url","data":"http://foo.com?foo=1#t=1,100", "expect":{ "fn":"equal.xy", "input":"t","out":"1,100"},"label":"a equal.xy"},
{"fn":"url","data":"http://foo.com?foo=1#t=2,500", "expect":{ "fn":"testBrowserOverride", "input":"t","out":true},"label":"browser URI can override t (defined in asset)"}
]

Some files were not shown because too many files have changed in this diff Show more