diff --git a/.r3_history b/.r3_history
index 96b0c4d..8560676 100644
--- a/.r3_history
+++ b/.r3_history
@@ -1,8 +1,5 @@
-r3 create VectorApplierAgain extends Event
-r3 create AnotherClass extends R3Object
-r3 create OneMore extends R3Object
-r3 create AgainMore extends R3Object
-r3 create AgainMoreAgain extends R3Object
-r3 create Event normal
+r3 create Event normal
r3 create R3Object extends Event
-r3 create SomeTest extends Event
+r3 create Utils normal
+r3 create Component extends R3Object
+r3 create Project extends R3Object
diff --git a/dist/r3-node/r3-vector-applier-again.js b/dist/r3-node/r3-component.js
similarity index 67%
rename from dist/r3-node/r3-vector-applier-again.js
rename to dist/r3-node/r3-component.js
index fcbba54..201c0d4 100644
--- a/dist/r3-node/r3-vector-applier-again.js
+++ b/dist/r3-node/r3-component.js
@@ -1,12 +1,11 @@
+const Event = require('r3-event');
const Utils = require('r3-utils');
-const Event = require('r3-event.js');
+const R3Object = require('r3-r3-object.js');
/**
OPTIONS_START
- a=2.0
- b=3.0
- something='hello'
+ runtime='default'
OPTIONS_END
INSTANCE_OPTIONS_MAPPING_START
@@ -16,12 +15,12 @@ const Event = require('r3-event.js');
LINKED_OBJECTS_END
EXCLUDED_FROM_INSTANCE_OPTIONS_START
- b
+ runtime
EXCLUDED_FROM_INSTANCE_OPTIONS_END
**/
-class VectorApplierAgain extends Event {
+class Component extends R3Object {
//CONSTRUCTOR_EXTENDS_TEMPLATE_START
constructor(options) {
@@ -30,22 +29,16 @@ class VectorApplierAgain extends Event {
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'VectorApplierAgain (' + options.id + ')';
-
super(options);
this.emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
- if (Utils.UndefinedOrNull(options.a)) {
- options.a = 2.0;
+ if (typeof options === 'undefined') {
+ options = {};
}
- if (Utils.UndefinedOrNull(options.b)) {
- options.b = 3.0;
- }
- if (Utils.UndefinedOrNull(options.something)) {
- options.something = 'hello';
+ if (Utils.UndefinedOrNull(options.runtime)) {
+ options.runtime = 'default';
}
//OPTIONS_INIT_END
@@ -55,6 +48,7 @@ class VectorApplierAgain extends Event {
Object.assign(this, options);
//CUSTOM_BEFORE_INIT_START
+ this.emit(Event.COMPONENT_INITIALIZED, this);
//CUSTOM_BEFORE_INIT_END
this.emit(Event.OBJECT_INITIALIZED, this);
@@ -65,26 +59,21 @@ class VectorApplierAgain extends Event {
createInstance() {
//CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
- 'a': this.a,
- 'something': this.something
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this);
//CREATE_INSTANCE_BEFORE_END
//CUSTOM_CREATE_INSTANCE_START
//CUSTOM_CREATE_INSTANCE_END
//CREATE_INSTANCE_AFTER_START
+ this[this.runtime].createInstance(
+ this,
+ {
+ //CREATE_INSTANCE_OPTIONS_START
+ //CREATE_INSTANCE_OPTIONS_END
+ }
+ )
+
this.emit(Event.INSTANCE_CREATED, this);
//CREATE_INSTANCE_AFTER_END
@@ -99,14 +88,6 @@ class VectorApplierAgain extends Event {
//UPDATE_INSTANCE_BEFORE_END
//UPDATE_INSTANCE_OPTIONS_START
- if (property === 'a') {
- this.instance.a = this.a;
- return;
- }
- if (property === 'something') {
- this.instance.something = this.something;
- return;
- }
//UPDATE_INSTANCE_OPTIONS_END
//CUSTOM_UPDATE_INSTANCE_START
@@ -127,14 +108,6 @@ class VectorApplierAgain extends Event {
//UPDATE_FROM_INSTANCE_BEFORE_END
//UPDATE_FROM_INSTANCE_OPTIONS_START
- if (property === 'a') {
- this.a = this.instance.a;
- return;
- }
- if (property === 'something') {
- this.something = this.instance.something;
- return;
- }
//UPDATE_FROM_INSTANCE_OPTIONS_END
//CUSTOM_UPDATE_FROM_INSTANCE_START
@@ -151,14 +124,21 @@ class VectorApplierAgain extends Event {
dispose() {
//DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
+ this.subscribe(
+ Event.INSTANCE_DISPOSED,
+ function(object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }
+ );
//DISPOSE_BEFORE_END
//CUSTOM_DISPOSE_START
//CUSTOM_DISPOSE_END
//DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
+ this.disposeInstance();
//DISPOSE_AFTER_END
}
@@ -168,15 +148,14 @@ class VectorApplierAgain extends Event {
disposeInstance() {
//DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
+ console.log('Disposing instance of ' + this.name);
//DISPOSE_INSTANCE_BEFORE_END
//CUSTOM_DISPOSE_INSTANCE_START
//CUSTOM_DISPOSE_INSTANCE_END
//DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
+ this.emit(Event.DISPOSE_INSTANCE, this);
//DISPOSE_INSTANCE_AFTER_END
}
@@ -190,4 +169,4 @@ class VectorApplierAgain extends Event {
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END
-module.exports = VectorApplierAgain;
\ No newline at end of file
+module.exports = Component;
\ No newline at end of file
diff --git a/dist/r3-node/r3-event.js b/dist/r3-node/r3-event.js
index 01f62bd..de8d73d 100644
--- a/dist/r3-node/r3-event.js
+++ b/dist/r3-node/r3-event.js
@@ -1,4 +1,3 @@
-const Event = require('r3-event');
const Utils = require('r3-utils');
/**
@@ -6,15 +5,6 @@ const Utils = require('r3-utils');
OPTIONS_START
OPTIONS_END
- INSTANCE_OPTIONS_MAPPING_START
- INSTANCE_OPTIONS_MAPPING_END
-
- LINKED_OBJECTS_START
- LINKED_OBJECTS_END
-
- EXCLUDED_FROM_INSTANCE_OPTIONS_START
- EXCLUDED_FROM_INSTANCE_OPTIONS_END
-
**/
class Event {
@@ -22,16 +12,12 @@ class Event {
//CONSTRUCTOR_TEMPLATE_START
constructor(options) {
- if (Utils.UndefinedOrNull(options)) {
- options = {};
- }
-
- options.id = Utils.RandomId(10);
- options.name = 'Event (' + options.id + ')';
-
Event.Emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
+ if (typeof options === 'undefined') {
+ options = {};
+ }
//OPTIONS_INIT_END
//CUSTOM_OPTIONS_INIT_START
@@ -46,110 +32,6 @@ class Event {
}
//CONSTRUCTOR_TEMPLATE_END
- //CREATE_INSTANCE_TEMPLATE_START
- createInstance() {
-
- //CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
-
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
- //CREATE_INSTANCE_BEFORE_END
-
- //CUSTOM_CREATE_INSTANCE_START
- //CUSTOM_CREATE_INSTANCE_END
-
- //CREATE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_CREATED, this);
- //CREATE_INSTANCE_AFTER_END
-
- }
- //CREATE_INSTANCE_TEMPLATE_END
-
- //UPDATE_INSTANCE_TEMPLATE_START
- updateInstance(property) {
-
- //UPDATE_INSTANCE_BEFORE_START
- this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
- //UPDATE_INSTANCE_BEFORE_END
-
- //UPDATE_INSTANCE_OPTIONS_START
- //UPDATE_INSTANCE_OPTIONS_END
-
- //CUSTOM_UPDATE_INSTANCE_START
- //CUSTOM_UPDATE_INSTANCE_END
-
- //UPDATE_INSTANCE_AFTER_START
- this.emit(Event.UPDATE_INSTANCE_AFTER, this);
- //UPDATE_INSTANCE_AFTER_END
-
- }
- //UPDATE_INSTANCE_TEMPLATE_END
-
- //UPDATE_FROM_INSTANCE_TEMPLATE_START
- updateFromInstance(property) {
-
- //UPDATE_FROM_INSTANCE_BEFORE_START
- this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
- //UPDATE_FROM_INSTANCE_BEFORE_END
-
- //UPDATE_FROM_INSTANCE_OPTIONS_START
- //UPDATE_FROM_INSTANCE_OPTIONS_END
-
- //CUSTOM_UPDATE_FROM_INSTANCE_START
- //CUSTOM_UPDATE_FROM_INSTANCE_END
-
- //UPDATE_FROM_INSTANCE_AFTER_START
- this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
- //UPDATE_FROM_INSTANCE_AFTER_END
-
- }
- //UPDATE_FROM_INSTANCE_TEMPLATE_END
-
- //DISPOSE_TEMPLATE_START
- dispose() {
-
- //DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
- //DISPOSE_BEFORE_END
-
- //CUSTOM_DISPOSE_START
- //CUSTOM_DISPOSE_END
-
- //DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
- //DISPOSE_AFTER_END
-
- }
- //DISPOSE_TEMPLATE_END
-
- //DISPOSE_INSTANCE_TEMPLATE_START
- disposeInstance() {
-
- //DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
- //DISPOSE_INSTANCE_BEFORE_END
-
- //CUSTOM_DISPOSE_INSTANCE_START
- //CUSTOM_DISPOSE_INSTANCE_END
-
- //DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
- //DISPOSE_INSTANCE_AFTER_END
-
- }
- //DISPOSE_INSTANCE_TEMPLATE_END
-
//CUSTOM_IMPLEMENTATION_START
/**
@@ -317,15 +199,15 @@ class Event {
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
//EVENT_GENERATED_START
-Event.CREATE_INSTANCE = 0x1;
-Event.DISPOSE_INSTANCE = 0x2;
-Event.DISPOSE_OBJECT = 0x3;
-Event.GET_RUNTIME = 0x4;
-Event.GET_WINDOW_SIZE = 0x5;
-Event.INSTANCE_CREATED = 0x6;
-Event.INSTANCE_DISPOSED = 0x7;
-Event.OBJECT_CREATED = 0x8;
-Event.OBJECT_DISPOSED = 0x9;
+Event.COMPONENT_INITIALIZED = 0x1;
+Event.CREATE_INSTANCE_BEFORE = 0x2;
+Event.DISPOSE_INSTANCE = 0x3;
+Event.DISPOSE_OBJECT = 0x4;
+Event.GET_RUNTIME = 0x5;
+Event.GET_WINDOW_SIZE = 0x6;
+Event.INSTANCE_CREATED = 0x7;
+Event.INSTANCE_DISPOSED = 0x8;
+Event.OBJECT_CREATED = 0x9;
Event.OBJECT_INITIALIZED = 0xa;
Event.PAUSE = 0xb;
Event.RESTART = 0xc;
@@ -339,15 +221,15 @@ Event.MAX_EVENTS = 0x12;
Event.GetEventName = function(eventId) {
switch(eventId) {
- case 0x1 : return 'create_instance';
- case 0x2 : return 'dispose_instance';
- case 0x3 : return 'dispose_object';
- case 0x4 : return 'get_runtime';
- case 0x5 : return 'get_window_size';
- case 0x6 : return 'instance_created';
- case 0x7 : return 'instance_disposed';
- case 0x8 : return 'object_created';
- case 0x9 : return 'object_disposed';
+ case 0x1 : return 'component_initialized';
+ case 0x2 : return 'create_instance_before';
+ case 0x3 : return 'dispose_instance';
+ case 0x4 : return 'dispose_object';
+ case 0x5 : return 'get_runtime';
+ case 0x6 : return 'get_window_size';
+ case 0x7 : return 'instance_created';
+ case 0x8 : return 'instance_disposed';
+ case 0x9 : return 'object_created';
case 0xa : return 'object_initialized';
case 0xb : return 'pause';
case 0xc : return 'restart';
diff --git a/dist/r3-node/r3-another-class.js b/dist/r3-node/r3-project.js
similarity index 62%
rename from dist/r3-node/r3-another-class.js
rename to dist/r3-node/r3-project.js
index 69204d8..87ff87f 100644
--- a/dist/r3-node/r3-another-class.js
+++ b/dist/r3-node/r3-project.js
@@ -5,28 +5,26 @@ const R3Object = require('r3-r3-object.js');
/**
OPTIONS_START
- x=1
- y=2
- z=3
- register=true
+ isPublic=true
+ applicationMode=Project.APPLICATION_MODE_EDIT
OPTIONS_END
INSTANCE_OPTIONS_MAPPING_START
- x=side.x
- y=side.y
- z=side.z
INSTANCE_OPTIONS_MAPPING_END
LINKED_OBJECTS_START
+ entities=[Entity]
+ controls=[Control]
+ images=[Image]
+ code=[CustomCode]
LINKED_OBJECTS_END
EXCLUDED_FROM_INSTANCE_OPTIONS_START
- register
EXCLUDED_FROM_INSTANCE_OPTIONS_END
**/
-class AnotherClass extends R3Object {
+class Project extends R3Object {
//CONSTRUCTOR_EXTENDS_TEMPLATE_START
constructor(options) {
@@ -35,25 +33,19 @@ class AnotherClass extends R3Object {
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'AnotherClass (' + options.id + ')';
-
super(options);
this.emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
- if (Utils.UndefinedOrNull(options.x)) {
- options.x = 1;
+ if (typeof options === 'undefined') {
+ options = {};
}
- if (Utils.UndefinedOrNull(options.y)) {
- options.y = 2;
+ if (Utils.UndefinedOrNull(options.isPublic)) {
+ options.isPublic = true;
}
- if (Utils.UndefinedOrNull(options.z)) {
- options.z = 3;
- }
- if (Utils.UndefinedOrNull(options.register)) {
- options.register = true;
+ if (Utils.UndefinedOrNull(options.applicationMode)) {
+ options.applicationMode = Project.APPLICATION_MODE_EDIT;
}
//OPTIONS_INIT_END
@@ -73,27 +65,23 @@ class AnotherClass extends R3Object {
createInstance() {
//CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
- 'side.x': this.x,
- 'side.y': this.y,
- 'side.z': this.z
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this);
//CREATE_INSTANCE_BEFORE_END
//CUSTOM_CREATE_INSTANCE_START
//CUSTOM_CREATE_INSTANCE_END
//CREATE_INSTANCE_AFTER_START
+ this[this.runtime].createInstance(
+ this,
+ {
+ //CREATE_INSTANCE_OPTIONS_START
+ 'isPublic': this.isPublic,
+ 'applicationMode': this.applicationMode
+ //CREATE_INSTANCE_OPTIONS_END
+ }
+ )
+
this.emit(Event.INSTANCE_CREATED, this);
//CREATE_INSTANCE_AFTER_END
@@ -108,16 +96,12 @@ class AnotherClass extends R3Object {
//UPDATE_INSTANCE_BEFORE_END
//UPDATE_INSTANCE_OPTIONS_START
- if (property === 'x') {
- this.instance.side.x = this.x;
+ if (property === 'isPublic') {
+ this.instance.isPublic = this.isPublic;
return;
}
- if (property === 'y') {
- this.instance.side.y = this.y;
- return;
- }
- if (property === 'z') {
- this.instance.side.z = this.z;
+ if (property === 'applicationMode') {
+ this.instance.applicationMode = this.applicationMode;
return;
}
//UPDATE_INSTANCE_OPTIONS_END
@@ -140,17 +124,17 @@ class AnotherClass extends R3Object {
//UPDATE_FROM_INSTANCE_BEFORE_END
//UPDATE_FROM_INSTANCE_OPTIONS_START
- if (property === 'x') {
- this.x = this.instance.side.x;
- return;
+ if (property === 'isPublic' || property === 'all') {
+ this.isPublic = this.instance.isPublic;
+ if (property !== 'all') {
+ return;
+ }
}
- if (property === 'y') {
- this.y = this.instance.side.y;
- return;
- }
- if (property === 'z') {
- this.z = this.instance.side.z;
- return;
+ if (property === 'applicationMode' || property === 'all') {
+ this.applicationMode = this.instance.applicationMode;
+ if (property !== 'all') {
+ return;
+ }
}
//UPDATE_FROM_INSTANCE_OPTIONS_END
@@ -168,14 +152,21 @@ class AnotherClass extends R3Object {
dispose() {
//DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
+ this.subscribe(
+ Event.INSTANCE_DISPOSED,
+ function(object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }
+ );
//DISPOSE_BEFORE_END
//CUSTOM_DISPOSE_START
//CUSTOM_DISPOSE_END
//DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
+ this.disposeInstance();
//DISPOSE_AFTER_END
}
@@ -185,15 +176,14 @@ class AnotherClass extends R3Object {
disposeInstance() {
//DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
+ console.log('Disposing instance of ' + this.name);
//DISPOSE_INSTANCE_BEFORE_END
//CUSTOM_DISPOSE_INSTANCE_START
//CUSTOM_DISPOSE_INSTANCE_END
//DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
+ this.emit(Event.DISPOSE_INSTANCE, this);
//DISPOSE_INSTANCE_AFTER_END
}
@@ -205,6 +195,15 @@ class AnotherClass extends R3Object {
}
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
+Project.CAMERA_INDEX_EDIT = 0x0;
+Project.CAMERA_INDEX_RUN = 0x1;
+
+Project.APPLICATION_MODE_EDIT = Project.CAMERA_INDEX_EDIT;
+Project.APPLICATION_MODE_RUN = Project.CAMERA_INDEX_RUN;
+
+Project.RENDERER_INDEX_MAIN = 0x0;
+
+Project.RENDER_TARGET_INDEX_NONE = -0x1;
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END
-module.exports = AnotherClass;
\ No newline at end of file
+module.exports = Project;
\ No newline at end of file
diff --git a/dist/r3-node/r3-r3-object.js b/dist/r3-node/r3-r3-object.js
index e181874..9dc48aa 100644
--- a/dist/r3-node/r3-r3-object.js
+++ b/dist/r3-node/r3-r3-object.js
@@ -4,6 +4,9 @@ const Event = require('r3-event.js');
/**
OPTIONS_START
+ id=Utils.RandomId(10)
+ name=this.constructor.name + '(' + options.id + ')'
+ register=true
OPTIONS_END
INSTANCE_OPTIONS_MAPPING_START
@@ -13,6 +16,9 @@ const Event = require('r3-event.js');
LINKED_OBJECTS_END
EXCLUDED_FROM_INSTANCE_OPTIONS_START
+ id
+ name
+ register
EXCLUDED_FROM_INSTANCE_OPTIONS_END
**/
@@ -26,14 +32,23 @@ class R3Object extends Event {
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'R3Object (' + options.id + ')';
-
super(options);
this.emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
+ if (typeof options === 'undefined') {
+ options = {};
+ }
+ if (Utils.UndefinedOrNull(options.id)) {
+ options.id = Utils.RandomId(10);
+ }
+ if (Utils.UndefinedOrNull(options.name)) {
+ options.name = this.constructor.name + '(' + options.id + ')';
+ }
+ if (Utils.UndefinedOrNull(options.register)) {
+ options.register = true;
+ }
//OPTIONS_INIT_END
//CUSTOM_OPTIONS_INIT_START
@@ -52,25 +67,21 @@ class R3Object extends Event {
createInstance() {
//CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
-
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this);
//CREATE_INSTANCE_BEFORE_END
//CUSTOM_CREATE_INSTANCE_START
//CUSTOM_CREATE_INSTANCE_END
//CREATE_INSTANCE_AFTER_START
+ this[this.runtime].createInstance(
+ this,
+ {
+ //CREATE_INSTANCE_OPTIONS_START
+ //CREATE_INSTANCE_OPTIONS_END
+ }
+ )
+
this.emit(Event.INSTANCE_CREATED, this);
//CREATE_INSTANCE_AFTER_END
@@ -121,14 +132,21 @@ class R3Object extends Event {
dispose() {
//DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
+ this.subscribe(
+ Event.INSTANCE_DISPOSED,
+ function(object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }
+ );
//DISPOSE_BEFORE_END
//CUSTOM_DISPOSE_START
//CUSTOM_DISPOSE_END
//DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
+ this.disposeInstance();
//DISPOSE_AFTER_END
}
@@ -138,15 +156,14 @@ class R3Object extends Event {
disposeInstance() {
//DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
+ console.log('Disposing instance of ' + this.name);
//DISPOSE_INSTANCE_BEFORE_END
//CUSTOM_DISPOSE_INSTANCE_START
//CUSTOM_DISPOSE_INSTANCE_END
//DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
+ this.emit(Event.DISPOSE_INSTANCE, this);
//DISPOSE_INSTANCE_AFTER_END
}
diff --git a/dist/r3-node/r3-utils.js b/dist/r3-node/r3-utils.js
index b3a06e7..250ffeb 100644
--- a/dist/r3-node/r3-utils.js
+++ b/dist/r3-node/r3-utils.js
@@ -1,1247 +1,1275 @@
+const Event = require('r3-event');
+
+/**
+
+ OPTIONS_START
+ OPTIONS_END
+
+ **/
+
class Utils {
- constructor() {
-
- }
-
- /**
- * Gets the first parent of the object which is an instance of constructor
- * @param object
- * @param constructor
- * @returns {*}
- * @constructor
- */
- static GetFirstParent(object, constructor) {
-
- if (Utils.UndefinedOrNull(constructor)) {
- throw new Error('You need to specify a constructor');
- }
-
- if (object.parent === null) {
- return null;
- }
-
- if (object.parent instanceof constructor) {
- return object.parent;
- } else {
- return Utils.GetFirstParent(object.parent, constructor);
- }
-
- };
-
- static SyntaxHighlight(json) {
- if (typeof json != 'string') {
- json = JSON.stringify(json, undefined, 2);
- }
- json = json.replace(/&/g, '&').replace(//g, '>');
- return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
- let cls = 'number';
- if (/^"/.test(match)) {
- if (/:$/.test(match)) {
- cls = 'key';
- } else {
- cls = 'string';
- }
- } else if (/true|false/.test(match)) {
- cls = 'boolean';
- } else if (/null/.test(match)) {
- cls = 'null';
- }
- return '' + match + '';
- });
- };
-
- static GetParentProject(component) {
-
- if (Utils.UndefinedOrNull(component.parent)) {
- throw new Error('Parent not found');
- }
-
- if (component.parent instanceof R3.Project) {
- return component.parent;
- }
-
- return Utils.GetParentProject(component.parent);
- };
-
- static GetParents(component, parents) {
-
- if (Utils.UndefinedOrNull(parents)) {
- parents = [];
- }
-
- if (Utils.UndefinedOrNull(component.parent)) {
- return parents;
- }
-
- parents.push(component.parent);
-
- return Utils.GetParents(component.parent, parents);
-
- };
-
- /**
- * @return {boolean}
- */
- static Instance(component) {
- return Utils.Defined(component) && Utils.Defined(component.instance);
- };
-
- /**
- * Utils.RemoveFromSelect
- * @param select
- * @param id
- * @returns {boolean}
- * @constructor
- */
- static RemoveFromSelect(select, id) {
-
- let i;
-
- for (i = 0; i < select.options.length; i++) {
- if (select.options[i].value === id) {
- select.remove(i);
- return true;
- }
- }
- return false;
- };
-
- /**
- * Utils.GetSelectIndex
- *
- * Get the select index of given id
- *
- * @param select
- * @param id
- * @returns boolean true if successful
- *
- * @constructor
- */
- static SetSelectIndex(select, id) {
- for (let i = 0; i < select.options.length; i++) {
- if (select.options[i].value === id) {
- select.selectedIndex = i;
- return true;
- }
- }
- return false;
- };
-
- static SortSelect(select) {
-
- let tmp = [];
- let i;
-
- for (i = 1; i < select.options.length; i++) {
- tmp[i-1] = [];
- tmp[i-1][0] = select.options[i].text;
- tmp[i-1][1] = select.options[i].value;
- }
-
- tmp.sort();
-
- select.options = [select.options[0]];
-
- for (i = 0; i < tmp.length; i++) {
- select.options[i+1] = new Option(tmp[i][0], tmp[i][1]);
- }
-
- return;
- };
-
- /**
- * Gets the parent of object whith property of optional type constructor. If index is specified, get the parent of the
- * object with property[index] - which means the property should be an array
- * @param object
- * @param property
- * @param index
- * @param constructor
- * @returns {*}
- * @constructor
- */
- static GetParent(object, property, index, constructor) {
-
- if (Utils.UndefinedOrNull(constructor)) {
- constructor = null;
- }
-
- if (Utils.UndefinedOrNull(index)) {
- index = null;
- }
-
- if (object.parent) {
- /**
- * Parent defined
- */
- if (object.parent.hasOwnProperty(property)) {
-
- if (constructor) {
-
- if (index) {
-
- if (object.parent[property][index] instanceof constructor) {
- return object.parent[property][index];
- } else {
-
- if (typeof object.parent.getParent === 'function') {
- return object.parent.getParent(property, index, constructor);
- } else {
- console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
- return null;
- }
- }
-
- } else {
- if (object.parent[property] instanceof constructor) {
- return object.parent[property];
- } else {
-
- if (typeof object.parent.getParent === 'function') {
- return object.parent.getParent(property, index, constructor);
- } else {
- console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
- return null;
- }
-
- }
- }
-
- } else {
-
- if (index) {
- return object.parent[property][index];
- } else {
- return object.parent[property];
- }
-
- }
- } else {
-
- /**
- * This parent does not have the property - go a level higher
- */
- if (typeof object.parent.getParent === 'function') {
- return object.parent.getParent(property, index, constructor);
- } else {
- console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
- return null;
- }
- }
-
- } else {
- /**
- * No parent defined
- */
- console.warn('property : ' + property + ' of type ' + constructor + ' was not found in the parent chain');
- return null;
- }
-
- };
-
-
- /**
- * Strips image extension from given path
- * @param imagePath
- * @constructor
- */
- static StripImageExtension(imagePath) {
- return imagePath.replace(/(\.png$|\.gif$|\.jpeg$|\.jpg$)/,'')
- };
-
- /**
- * Returns true if unloaded
- * @param component
- * @returns {boolean}
- * @constructor
- */
- static Unloaded(component) {
- if (
- Utils.UndefinedOrNull(component) ||
- Utils.UndefinedOrNull(component.instance)
- ) {
- return true;
- }
-
- return false;
- };
-
- /**
- *
- * @param component
- * @returns {boolean}
- * @constructor
- */
- static Loaded(component) {
- if (component && component.instance) {
- return true;
- }
-
- return false;
- };
-
- static BuildVectorSource(result, name, dimension) {
-
- if (dimension === 2) {
- result[name] = {};
- result[name].x = false;
- result[name].y = false;
- return;
- }
-
- if (dimension === 3) {
- result[name] = {};
- result[name].x = false;
- result[name].y = false;
- result[name].y = false;
- return;
- }
-
- if (dimension === 4) {
- result[name] = {};
- result[name].x = false;
- result[name].y = false;
- result[name].z = false;
- result[name].w = false;
- return;
- }
-
- console.warn('unknown dimension : ' + dimension);
- };
-
- /**
- * Returns all 'instances' of the array, or null if an 'instance' is undefined
- * @constructor
- * @param array
- */
- static GetArrayInstances(array) {
- return array.reduce(
- function(result, object) {
-
- if (result === null) {
- return result;
- }
-
- if (Utils.UndefinedOrNull(object.instance)) {
- result = null;
- } else {
- result.push(object.instance);
- }
-
- return result;
- },
- []
- );
- };
-
- static SortFacesByMaterialIndex(faces) {
-
- /**
- * Sorts faces according to material index because later we will create
- * groups for each vertice group
- */
- faces.sort(function(a, b) {
-
- if (a.materialIndex < b.materialIndex) {
- return -1;
- }
-
- if (a.materialIndex > b.materialIndex) {
- return 1;
- }
-
- return 0;
- });
-
- return faces;
- };
-
- static BuildQuaternionSource(result, name) {
- result[name] = {};
- result[name].axis = {};
- result[name].axis.x = false;
- result[name].axis.y = false;
- result[name].axis.z = false;
- result[name].angle = false;
- result[name].x = false;
- result[name].y = false;
- result[name].z = false;
- result[name].w = false;
- };
-
- static ObjectPropertiesAsBoolean(object) {
- return Object.keys(object).reduce(
- function(result, propertyId) {
-
- if (typeof object[propertyId] === 'function') {
- return result;
- }
-
- result[propertyId] = false;
-
- // if (object[propertyId] instanceof R3.Vector2) {
- // Utils.BuildVectorSource(result, propertyId, 2);
- // }
- //
- // if (object[propertyId] instanceof R3.Vector3) {
- // Utils.BuildVectorSource(result, propertyId, 3);
- // }
- //
- // if (object[propertyId] instanceof R3.Vector4) {
- // Utils.BuildVectorSource(result, propertyId, 4);
- // }
- //
- // if (object[propertyId] instanceof R3.Quaternion) {
- // Utils.BuildQuaternionSource(result, propertyId);
- // }
-
- return result;
-
- }.bind(this),
- {}
- );
- };
-
- static GetRuntime() {
-
- let result = null;
-
- R3.Event.Emit(
- R3.Event.GET_RUNTIME,
- null,
- function(runtime) {
- result = runtime;
- }
- );
-
- return result;
- };
-
- /**
- * Returns the window size or null
- * @returns {*}
- * @constructor
- */
- static GetWindowSize() {
-
- let size = null;
-
- R3.Event.Emit(
- R3.Event.GET_WINDOW_SIZE,
- null,
- function(data) {
- size = data;
- }.bind(this)
- );
-
- return size;
-
- };
-
- /**
- * Convenience function to update object width and height members with window size
- * @param object
- * @constructor
- */
- static UpdateWindowSize(object) {
- let size = Utils.GetWindowSize();
- object.width = size.width;
- object.height = size.height;
- };
-
-
- /**
- * Returns id of object with the name if it exists in the array, otherwise null
- * @param name
- * @param array
- * @returns {*}
- * @constructor
- */
- static ObjectIdWithNameInArray(name, array) {
-
- return array.reduce(
- function(result, object) {
-
- if (result) {
- return result;
- }
-
- if (name === object.name) {
- return object.id;
- }
-
- return null;
- },
- null
- );
- };
-
- static LoadIdsFromArrayToIdObject(array, idToObject) {
-
- };
-
- static LoadIdsFromObjectToIdObject(object, idToObject) {
-
-
- };
-
- /**
- * Gets random int exclusive of maximum but inclusive of minimum
- * @param min
- * @param max
- * @returns {*}
- * @constructor
- */
- static GetRandomInt(min, max) {
- min = Math.ceil(min);
- max = Math.floor(max);
- return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
- };
-
- /**
- * Gets random int inclusive of minimum and maximum
- * @param min
- * @param max
- * @returns {*}
- * @constructor
- */
- static GetRandomIntInclusive(min, max) {
- min = Math.ceil(min);
- max = Math.floor(max);
- return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
- };
-
- static InterpolateArray(data, fitCount) {
-
- let linearInterpolate = function(before, after, atPoint) {
- return before + (after - before) * atPoint;
- };
-
- let newData = [];
-
- let springFactor = Number((data.length - 1) / (fitCount - 1));
-
- newData[0] = data[0]; // for new allocation
-
- for ( let i = 1; i < fitCount - 1; i++) {
- let tmp = i * springFactor;
- let before = Number(Math.floor(tmp)).toFixed();
- let after = Number(Math.ceil(tmp)).toFixed();
- let atPoint = tmp - before;
- newData[i] = linearInterpolate(data[before], data[after], atPoint);
- }
-
- newData[fitCount - 1] = data[data.length - 1]; // for new allocation
-
- return newData;
- };
-
- /**
- * Undefined or null check
- * @param variable
- * @returns {boolean}
- * @constructor
- */
- static UndefinedOrNull(
- variable
- ) {
- return typeof variable === 'undefined' || variable === null;
- };
-
- /**
- * The variable is not undefined and not null
- * @param variable
- * @returns {boolean}
- * @constructor
- */
- static Defined(
- variable
- ) {
- return typeof variable !== 'undefined' && variable !== null;
- };
-
- /**
- * Gets function parameters
- * @param fn
- * @constructor
- */
- static GetParameters(fn) {
-
- let FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
- let FN_ARG_SPLIT = /,/;
- let FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
- let STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
-
- let parameters,
- fnText,
- argDecl;
-
- if (typeof fn !== 'function') {
- parameters = [];
- fnText = fn.toString().replace(STRIP_COMMENTS, '');
- argDecl = fnText.match(FN_ARGS);
- argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
- arg.replace(FN_ARG, function(all, underscore, name) {
- parameters.push(name);
- });
- });
- } else {
- throw Error("not a function")
- }
-
- return parameters;
- };
-
- /**
- * Returns either an ID of the object or Null
- * @param object
- * @returns {null}
- * @constructor
- */
- static IdOrNull(object) {
- if (Utils.UndefinedOrNull(object)) {
- return null;
- } else {
- if (Utils.UndefinedOrNull(object.id)) {
- console.warn('saving an object reference with no ID : ', object);
- return null;
- }
- return object.id;
- }
- };
-
- /**
- * Limit a property to values between -pi and +pi
- * @param property
- * @param objectProperty
- * @returns {{configurable?: boolean, enumerable?: boolean, value?, writable?: boolean, get?: Function, set?: Function}}
- * @constructor
- */
- static LimitToPI(property, objectProperty) {
-
- let store = objectProperty;
-
- return {
- get : function() {
- return store;
- },
- set : function(value) {
- while (value > Math.PI) {
- value -= (Math.PI * 2);
- }
-
- while (value < -(Math.PI)) {
- value += (Math.PI * 2);
- }
-
- store = value;
- }
- };
- };
-
- /**
- * Returns an array of IDs representing the objects
- * @param array
- * @returns []
- * @constructor
- */
- static IdArrayOrEmptyArray(array) {
- if (Utils.UndefinedOrNull(array)) {
- return [];
- } else {
-
- return array.map(function(item) {
-
- if (Utils.UndefinedOrNull(item.id)) {
- throw new Error('No ID found while trying to store IDs to array');
- }
-
- return item.id
- });
- }
- };
-
- /**
- * Links an object to its parent through idToObject array
- * @param propertyString
- * @param idToObject
- * @param parentObject
- * @param id
- * @constructor
- */
- static Link(propertyString, idToObject, parentObject, id) {
-
- if (!Utils.UndefinedOrNull(parentObject[propertyString])) {
-
- if (!idToObject.hasOwnProperty(id)) {
- console.warn('Linking failed for object:' + parentObject.name);
- }
-
- parentObject[propertyString] = idToObject[id];
- }
- };
-
- /**
- * Generates a random ID
- * @returns {string}
- * @constructor
- */
- static RandomId(length) {
-
- if (Utils.UndefinedOrNull(length)) {
- length = 10;
- }
-
- return Math.random().toString(36).substr(2, length);
- };
-
- static InvertWindingOrder(triangles) {
-
- for (let i = 0; i < triangles.length; i++) {
- let v1 = triangles[i].v1;
- triangles[i].v1 = triangles[i].v2;
- triangles[i].v2 = v1;
-
- let backupUV = triangles[i].triangle.v1uv;
- triangles[i].triangle.v1uv = triangles[i].triangle.v2uv;
- triangles[i].triangle.v2uv = backupUV;
- }
-
- return triangles;
- };
-
- /**
- * Inverts a mesh winding order (and its instance)
- * @param mesh R3.D3.Mesh
- * @returns {*}
- * @constructor
- */
- static InvertMeshWindingOrder(mesh) {
-
- mesh.faces.forEach(
- function(face) {
-
- let tmpV1 = face.v1;
- face.v1 = face.v2;
- face.v2 = tmpV1;
-
- let tmpV1uv = face.v1uv;
- face.v1uv = face.v2uv;
- face.v2uv = tmpV1uv;
-
- }.bind(this)
- );
-
- //mesh.computeNormals = true;
- //mesh.createInstance();
- };
-
- /**
- * This function resets a the winding order of a mesh from a reference point V (the average center of the mesh)
- */
- static ResetWindingOrder(faces, vertices) {
-
- let vertexList = new R3.API.Vector3.Points();
-
- for (let v = 0; v < vertices.length; v++) {
- vertexList.add(new R3.API.Vector3(
- vertices[v].position.x,
- vertices[v].position.y,
- vertices[v].position.z
- ));
- }
-
- let V = vertexList.average();
-
- let triangles = [];
-
- for (let s = 0; s < faces.length; s += 3) {
-
- let v0 = faces[s];
- let v1 = faces[s+1];
- let v2 = faces[s+2];
-
- triangles.push(
- {
- v0 : v0,
- v1 : v1,
- v2 : v2,
- edges : [
- {v0: v0, v1: v1},
- {v0: v1, v1: v2},
- {v0: v2, v1: v0}
- ],
- winding : 0,
- edgeIndex : -1,
- processed : false
- }
- );
- }
-
- for (let i = 0; i < triangles.length; i++) {
- if (
- R3.API.Vector3.clockwise(
- vertices[triangles[i].v0].position,
- vertices[triangles[i].v1].position,
- vertices[triangles[i].v2].position,
- V
- )
- ) {
- console.log('clockwise');
- let bv1 = triangles[i].v1;
- triangles[i].v1 = triangles[i].v2;
- triangles[i].v2 = bv1;
- } else {
- console.log('not clockwise');
- }
- }
-
- return triangles;
- };
-
- /**
- * This function resets the winding order for triangles in faces, given an initial triangle and orientation edge
- * used pseudocode from
- * http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh
- * We need to use a graph traversal algorithm,
- * lets assume we have method that returns neighbor of triangle on given edge
- *
- * neighbor_on_egde( next_tria, edge )
- *
- * to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it
- * processed = set of processed triangles; initial empty
- *
- * while to_process is not empty:
- * next_tria, orientation_edge = to_process.pop()
- * add next_tria in processed
- * if next_tria is not opposite oriented than orientation_edge:
- * change next_tria (ABC) orientation (B<->C)
- * for each edge (AB) in next_tria:
- * neighbor_tria = neighbor_on_egde( next_tria, edge )
- * if neighbor_tria exists and neighbor_tria not in processed:
- * to_process add (neighbor_tria, edge opposite oriented (BA))
- * @param faces R3.D3.Face[]
- * @param orientationEdge R3.API.Vector2
- * @returns {Array}
- */
- static FixWindingOrder(faces, orientationEdge) {
-
- /**
- * Checks if a Face belonging to a TriangleEdge has already been processed
- * @param processed TriangleEdge[]
- * @param triangle Face
- * @returns {boolean}
- */
- function inProcessed(processed, triangle) {
-
- for (let i = 0; i < processed.length; i++) {
- if (processed[i].triangle.equals(triangle)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns a neighbouring triangle on a specific edge - preserving the edge orientation
- * @param edge R3.API.Vector2
- * @param faces R3.D3.Face[]
- * @param currentTriangle
- * @returns {*}
- */
- function neighbourOnEdge(edge, faces, currentTriangle) {
-
- for (let i = 0; i < faces.length; i++) {
- if (
- (faces[i].v0 === edge.x && faces[i].v1 === edge.y) ||
- (faces[i].v1 === edge.x && faces[i].v2 === edge.y) ||
- (faces[i].v2 === edge.x && faces[i].v0 === edge.y) ||
- (faces[i].v0 === edge.y && faces[i].v1 === edge.x) ||
- (faces[i].v1 === edge.y && faces[i].v2 === edge.x) ||
- (faces[i].v2 === edge.y && faces[i].v0 === edge.x)
- ) {
-
- let triangle = new R3.D3.API.Face(
- null,
- null,
- faces[i].v0index,
- faces[i].v1index,
- faces[i].v2index,
- faces[i].materialIndex,
- faces[i].uvs
- );
-
- if (triangle.equals(currentTriangle)) {
- continue;
- }
-
- return new R3.D3.TriangleEdge(
- triangle,
- edge
- );
- }
- }
-
- return null;
- }
-
- let toProcess = [
- new R3.D3.TriangleEdge(
- new R3.D3.API.Face(
- null,
- null,
- faces[0].v0index,
- faces[0].v1index,
- faces[0].v2index,
- faces[0].materialIndex,
- faces[0].uvs
- ),
- orientationEdge
- )
- ];
-
- let processed = [];
-
- while (toProcess.length > 0) {
-
- let triangleEdge = toProcess.pop();
-
- /**
- * If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed
- * to have the same winding order)
- */
- if (
- (triangleEdge.triangle.v0index === triangleEdge.edge.x &&
- triangleEdge.triangle.v1index === triangleEdge.edge.y) ||
- (triangleEdge.triangle.v1index === triangleEdge.edge.x &&
- triangleEdge.triangle.v2index === triangleEdge.edge.y) ||
- (triangleEdge.triangle.v2index === triangleEdge.edge.x &&
- triangleEdge.triangle.v0index === triangleEdge.edge.y)
- ) {
- let backupV = triangleEdge.triangle.v1index;
- triangleEdge.triangle.v1index = triangleEdge.triangle.v2index;
- triangleEdge.triangle.v2index = backupV;
-
- // let backupUV = triangleEdge.triangle.v1uv;
- // triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv;
- // triangleEdge.triangle.v2uv = backupUV;
- //
- let backupUV = triangleEdge.triangle.uvs[0][1];
- triangleEdge.triangle.uvs[0][1] = triangleEdge.triangle.uvs[0][2];
- triangleEdge.triangle.uvs[0][2] = backupUV;
- }
-
- processed.push(triangleEdge);
-
- let edges = [
- new R3.API.Vector2(
- triangleEdge.triangle.v0index,
- triangleEdge.triangle.v1index
- ),
- new R3.API.Vector2(
- triangleEdge.triangle.v1index,
- triangleEdge.triangle.v2index
- ),
- new R3.API.Vector2(
- triangleEdge.triangle.v2index,
- triangleEdge.triangle.v0index
- )
- ];
-
- for (let j = 0; j < edges.length; j++) {
- let neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle);
- if (neighbour && !inProcessed(processed, neighbour.triangle)) {
- toProcess.push(neighbour);
- }
- }
- }
-
- /**
- * In processed - we will have some duplicates - only add the unique ones
- * @type {Array}
- */
- let triangles = [];
- for (let i = 0; i < processed.length; i++) {
- let found = false;
- for (let k = 0; k < triangles.length; k++) {
- if (triangles[k].equals(processed[i].triangle)){
- found = true;
- break;
- }
- }
- if (!found) {
- triangles.push(processed[i].triangle);
- }
- }
-
- return triangles;
- };
-
- /**
- * This is a work-around function to fix polys which don't triangulate because
- * they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around
- * Z then Y axis
- * @param verticesFlat []
- * @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY
- * @return []
- */
- static FixPolyZPlane(verticesFlat, grain) {
-
- if ((verticesFlat.length % 3) !== 0 && !(verticesFlat.length > 9)) {
- console.log("The vertices are not in the right length : " + verticesFlat.length);
- }
-
- let vertices = [];
-
- let points = new R3.API.Quaternion.Points();
-
- for (let i = 0; i < verticesFlat.length; i += 3) {
- points.add(new R3.API.Vector3(
- verticesFlat[i],
- verticesFlat[i + 1],
- verticesFlat[i + 2]
- ));
- }
-
- points.toOrigin();
-
- points.maximizeXDistance(grain);
-
- points.maximizeYDistance(grain);
-
- for (i = 0; i < points.vectors.length; i++) {
- vertices.push(
- [
- points.vectors[i].x,
- points.vectors[i].y
- ]
- );
- }
-
- return vertices;
- };
-
- static MovingAverage(period) {
- let nums = [];
- return function(num) {
- nums.push(num);
- if (nums.length > period)
- nums.splice(0,1); // remove the first element of the array
- let sum = 0;
- for (let i in nums)
- sum += nums[i];
- let n = period;
- if (nums.length < period)
- n = nums.length;
- return(sum/n);
- }
- };
-
- static Intersect(a, b) {
-
- let t;
-
- /**
- * Loop over shortest array
- */
- if (b.length > a.length) {
- t = b;
- b = a;
- a = t;
- }
-
- return a.filter(
- /**
- * Check if exists
- * @param e
- * @returns {boolean}
- */
- function(e) {
- return (b.indexOf(e) > -1);
- }
- ).filter(
- /**
- * Remove Duplicates
- * @param e
- * @param i
- * @param c
- * @returns {boolean}
- */
- function(e, i, c) {
- return c.indexOf(e) === i;
- }
- );
- };
-
- static Difference(a, b) {
-
- let t;
-
- /**
- * Loop over shortest array
- */
- if (b.length > a.length) {
- t = b;
- b = a;
- a = t;
- }
-
- return a.filter(
- /**
- * Check if exists
- * @param e
- * @returns {boolean}
- */
- function(e) {
- return (b.indexOf(e) === -1);
- }
- ).filter(
- /**
- * Remove Duplicates
- * @param e
- * @param i
- * @param c
- * @returns {boolean}
- */
- function(e, i, c) {
- return c.indexOf(e) === i;
- }
- );
- };
-
- /**
- * Push only if not in there already
- * @param array
- * @param object
- * @constructor
- */
- static PushUnique(array, object) {
-
- if (array.indexOf(object) === -1) {
- array.push(object);
- }
- };
-
- /**
- * Checks whether or not the object is empty
- * @param obj
- * @returns {boolean}
- * @constructor
- */
- static IsEmpty(obj) {
- return (Object.keys(obj).length === 0 && obj.constructor === Object);
- };
-
- static IsString(member) {
- return (typeof member === 'string');
- };
-
- static IsBoolean(member) {
- return (member === true || member === false);
- };
-
- static IsColor(member) {
- return (member instanceof R3.Color);
- };
-
- static IsNumber(member) {
- return (typeof member === 'number');
- };
-
- static IsVector2(member) {
- return (
- member instanceof R3.API.Vector2 ||
- member instanceof R3.Vector2
- );
- };
-
- static IsVector3(member) {
- return (
- member instanceof R3.API.Vector3 ||
- member instanceof R3.Vector3
- );
- };
-
- static IsVector4(member) {
- return (
- member instanceof R3.API.Vector4 ||
- member instanceof R3.Vector4 ||
- member instanceof R3.API.Quaternion ||
- member instanceof R3.Quaternion
- );
- };
-
- static IsObject(member) {
- let type = typeof member;
- return type === 'function' || type === 'object' && !!member;
- };
-
- /**
- * @return {string}
- */
- static LowerUnderscore(name) {
- let string = name.toLowerCase().replace(/\s+/g, '_');
- string = string.replace(/-/g, '_');
- string = string.replace(/\_+/g, '_');
- return string;
- };
-
- static UpperCaseWordsSpaces(input) {
-
- let word = input.replace(/[-_]/g, ' ');
-
- word = word.replace(/\s+/, ' ');
-
- let words = word.split(' ');
-
- return words.reduce(
- function(result, word) {
- result += word[0].toUpperCase() + word.substr(1);
- return result + ' ';
- },
- ''
- ).trim();
- };
-
- /**
- * @return {string}
- */
- static UpperCaseUnderscore(word) {
-
- let str = '';
-
- word.split('').map(function(letter){
- if (letter == letter.toUpperCase()) {
- str += '_' + letter;
- } else {
- str += letter.toUpperCase();
- }
- });
-
- str = str.replace(new RegExp('^_'),'');
-
- return str;
- };
-
- /**
- * Returns Left Padded Text - ex. length 5, padchar 0, string abc = '00abc'
- * @param length
- * @param padChar
- * @param string
- * @returns {string}
- * @constructor
- */
- static PaddedText(length, padChar, string) {
-
- let pad = "";
-
- for (let x = 0; x < length; x++) {
- pad += padChar;
- }
-
- return pad.substring(0, pad.length - string.length) + string;
- };
+ //CONSTRUCTOR_TEMPLATE_START
+ constructor(options) {
+
+ Event.Emit(Event.OBJECT_CREATED, this);
+
+ //OPTIONS_INIT_START
+ if (typeof options === 'undefined') {
+ options = {};
+ }
+ //OPTIONS_INIT_END
+
+ //CUSTOM_OPTIONS_INIT_START
+ //CUSTOM_OPTIONS_INIT_END
+
+ Object.assign(this, options);
+
+ //CUSTOM_BEFORE_INIT_START
+ //CUSTOM_BEFORE_INIT_END
+
+ Event.Emit(Event.OBJECT_INITIALIZED, this);
+ }
+ //CONSTRUCTOR_TEMPLATE_END
+
+ //CUSTOM_IMPLEMENTATION_START
+ static GetFirstParent(object, constructor) {
+
+ if (Utils.UndefinedOrNull(constructor)) {
+ throw new Error('You need to specify a constructor');
+ }
+
+ if (object.parent === null) {
+ return null;
+ }
+
+ if (object.parent instanceof constructor) {
+ return object.parent;
+ } else {
+ return Utils.GetFirstParent(object.parent, constructor);
+ }
+
+ };
+
+ static SyntaxHighlight(json) {
+ if (typeof json != 'string') {
+ json = JSON.stringify(json, undefined, 2);
+ }
+ json = json.replace(/&/g, '&').replace(//g, '>');
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+ let cls = 'number';
+ if (/^"/.test(match)) {
+ if (/:$/.test(match)) {
+ cls = 'key';
+ } else {
+ cls = 'string';
+ }
+ } else if (/true|false/.test(match)) {
+ cls = 'boolean';
+ } else if (/null/.test(match)) {
+ cls = 'null';
+ }
+ return '' + match + '';
+ });
+ };
+
+ static GetParentProject(component) {
+
+ if (Utils.UndefinedOrNull(component.parent)) {
+ throw new Error('Parent not found');
+ }
+
+ if (component.parent instanceof R3.Project) {
+ return component.parent;
+ }
+
+ return Utils.GetParentProject(component.parent);
+ };
+
+ static GetParents(component, parents) {
+
+ if (Utils.UndefinedOrNull(parents)) {
+ parents = [];
+ }
+
+ if (Utils.UndefinedOrNull(component.parent)) {
+ return parents;
+ }
+
+ parents.push(component.parent);
+
+ return Utils.GetParents(component.parent, parents);
+
+ };
+
+ /**
+ * @return {boolean}
+ */
+ static Instance(component) {
+ return Utils.Defined(component) && Utils.Defined(component.instance);
+ };
+
+ /**
+ * Utils.RemoveFromSelect
+ * @param select
+ * @param id
+ * @returns {boolean}
+ * @constructor
+ */
+ static RemoveFromSelect(select, id) {
+
+ let i;
+
+ for (i = 0; i < select.options.length; i++) {
+ if (select.options[i].value === id) {
+ select.remove(i);
+ return true;
+ }
+ }
+ return false;
+ };
+
+ /**
+ * Utils.GetSelectIndex
+ *
+ * Get the select index of given id
+ *
+ * @param select
+ * @param id
+ * @returns boolean true if successful
+ *
+ * @constructor
+ */
+ static SetSelectIndex(select, id) {
+ for (let i = 0; i < select.options.length; i++) {
+ if (select.options[i].value === id) {
+ select.selectedIndex = i;
+ return true;
+ }
+ }
+ return false;
+ };
+
+ static SortSelect(select) {
+
+ let tmp = [];
+ let i;
+
+ for (i = 1; i < select.options.length; i++) {
+ tmp[i-1] = [];
+ tmp[i-1][0] = select.options[i].text;
+ tmp[i-1][1] = select.options[i].value;
+ }
+
+ tmp.sort();
+
+ select.options = [select.options[0]];
+
+ for (i = 0; i < tmp.length; i++) {
+ select.options[i+1] = new Option(tmp[i][0], tmp[i][1]);
+ }
+
+ return;
+ };
+
+ /**
+ * Gets the parent of object whith property of optional type constructor. If index is specified, get the parent of the
+ * object with property[index] - which means the property should be an array
+ * @param object
+ * @param property
+ * @param index
+ * @param constructor
+ * @returns {*}
+ * @constructor
+ */
+ static GetParent(object, property, index, constructor) {
+
+ if (Utils.UndefinedOrNull(constructor)) {
+ constructor = null;
+ }
+
+ if (Utils.UndefinedOrNull(index)) {
+ index = null;
+ }
+
+ if (object.parent) {
+ /**
+ * Parent defined
+ */
+ if (object.parent.hasOwnProperty(property)) {
+
+ if (constructor) {
+
+ if (index) {
+
+ if (object.parent[property][index] instanceof constructor) {
+ return object.parent[property][index];
+ } else {
+
+ if (typeof object.parent.getParent === 'function') {
+ return object.parent.getParent(property, index, constructor);
+ } else {
+ console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
+ return null;
+ }
+ }
+
+ } else {
+ if (object.parent[property] instanceof constructor) {
+ return object.parent[property];
+ } else {
+
+ if (typeof object.parent.getParent === 'function') {
+ return object.parent.getParent(property, index, constructor);
+ } else {
+ console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
+ return null;
+ }
+
+ }
+ }
+
+ } else {
+
+ if (index) {
+ return object.parent[property][index];
+ } else {
+ return object.parent[property];
+ }
+
+ }
+ } else {
+
+ /**
+ * This parent does not have the property - go a level higher
+ */
+ if (typeof object.parent.getParent === 'function') {
+ return object.parent.getParent(property, index, constructor);
+ } else {
+ console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
+ return null;
+ }
+ }
+
+ } else {
+ /**
+ * No parent defined
+ */
+ console.warn('property : ' + property + ' of type ' + constructor + ' was not found in the parent chain');
+ return null;
+ }
+
+ };
+
+
+ /**
+ * Strips image extension from given path
+ * @param imagePath
+ * @constructor
+ */
+ static StripImageExtension(imagePath) {
+ return imagePath.replace(/(\.png$|\.gif$|\.jpeg$|\.jpg$)/,'')
+ };
+
+ /**
+ * Returns true if unloaded
+ * @param component
+ * @returns {boolean}
+ * @constructor
+ */
+ static Unloaded(component) {
+ if (
+ Utils.UndefinedOrNull(component) ||
+ Utils.UndefinedOrNull(component.instance)
+ ) {
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ *
+ * @param component
+ * @returns {boolean}
+ * @constructor
+ */
+ static Loaded(component) {
+ if (component && component.instance) {
+ return true;
+ }
+
+ return false;
+ };
+
+ static BuildVectorSource(result, name, dimension) {
+
+ if (dimension === 2) {
+ result[name] = {};
+ result[name].x = false;
+ result[name].y = false;
+ return;
+ }
+
+ if (dimension === 3) {
+ result[name] = {};
+ result[name].x = false;
+ result[name].y = false;
+ result[name].y = false;
+ return;
+ }
+
+ if (dimension === 4) {
+ result[name] = {};
+ result[name].x = false;
+ result[name].y = false;
+ result[name].z = false;
+ result[name].w = false;
+ return;
+ }
+
+ console.warn('unknown dimension : ' + dimension);
+ };
+
+ /**
+ * Returns all 'instances' of the array, or null if an 'instance' is undefined
+ * @constructor
+ * @param array
+ */
+ static GetArrayInstances(array) {
+ return array.reduce(
+ function(result, object) {
+
+ if (result === null) {
+ return result;
+ }
+
+ if (Utils.UndefinedOrNull(object.instance)) {
+ result = null;
+ } else {
+ result.push(object.instance);
+ }
+
+ return result;
+ },
+ []
+ );
+ };
+
+ static SortFacesByMaterialIndex(faces) {
+
+ /**
+ * Sorts faces according to material index because later we will create
+ * groups for each vertice group
+ */
+ faces.sort(function(a, b) {
+
+ if (a.materialIndex < b.materialIndex) {
+ return -1;
+ }
+
+ if (a.materialIndex > b.materialIndex) {
+ return 1;
+ }
+
+ return 0;
+ });
+
+ return faces;
+ };
+
+ static BuildQuaternionSource(result, name) {
+ result[name] = {};
+ result[name].axis = {};
+ result[name].axis.x = false;
+ result[name].axis.y = false;
+ result[name].axis.z = false;
+ result[name].angle = false;
+ result[name].x = false;
+ result[name].y = false;
+ result[name].z = false;
+ result[name].w = false;
+ };
+
+ static ObjectPropertiesAsBoolean(object) {
+ return Object.keys(object).reduce(
+ function(result, propertyId) {
+
+ if (typeof object[propertyId] === 'function') {
+ return result;
+ }
+
+ result[propertyId] = false;
+
+ // if (object[propertyId] instanceof R3.Vector2) {
+ // Utils.BuildVectorSource(result, propertyId, 2);
+ // }
+ //
+ // if (object[propertyId] instanceof R3.Vector3) {
+ // Utils.BuildVectorSource(result, propertyId, 3);
+ // }
+ //
+ // if (object[propertyId] instanceof R3.Vector4) {
+ // Utils.BuildVectorSource(result, propertyId, 4);
+ // }
+ //
+ // if (object[propertyId] instanceof R3.Quaternion) {
+ // Utils.BuildQuaternionSource(result, propertyId);
+ // }
+
+ return result;
+
+ }.bind(this),
+ {}
+ );
+ };
+
+ static GetRuntime() {
+
+ let result = null;
+
+ R3.Event.Emit(
+ R3.Event.GET_RUNTIME,
+ null,
+ function(runtime) {
+ result = runtime;
+ }
+ );
+
+ return result;
+ };
+
+ /**
+ * Returns the window size or null
+ * @returns {*}
+ * @constructor
+ */
+ static GetWindowSize() {
+
+ let size = null;
+
+ R3.Event.Emit(
+ R3.Event.GET_WINDOW_SIZE,
+ null,
+ function(data) {
+ size = data;
+ }.bind(this)
+ );
+
+ return size;
+
+ };
+
+ /**
+ * Convenience function to update object width and height members with window size
+ * @param object
+ * @constructor
+ */
+ static UpdateWindowSize(object) {
+ let size = Utils.GetWindowSize();
+ object.width = size.width;
+ object.height = size.height;
+ };
+
+
+ /**
+ * Returns id of object with the name if it exists in the array, otherwise null
+ * @param name
+ * @param array
+ * @returns {*}
+ * @constructor
+ */
+ static ObjectIdWithNameInArray(name, array) {
+
+ return array.reduce(
+ function(result, object) {
+
+ if (result) {
+ return result;
+ }
+
+ if (name === object.name) {
+ return object.id;
+ }
+
+ return null;
+ },
+ null
+ );
+ };
+
+ static LoadIdsFromArrayToIdObject(array, idToObject) {
+
+ };
+
+ static LoadIdsFromObjectToIdObject(object, idToObject) {
+
+
+ };
+
+ /**
+ * Gets random int exclusive of maximum but inclusive of minimum
+ * @param min
+ * @param max
+ * @returns {*}
+ * @constructor
+ */
+ static GetRandomInt(min, max) {
+ min = Math.ceil(min);
+ max = Math.floor(max);
+ return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
+ };
+
+ /**
+ * Gets random int inclusive of minimum and maximum
+ * @param min
+ * @param max
+ * @returns {*}
+ * @constructor
+ */
+ static GetRandomIntInclusive(min, max) {
+ min = Math.ceil(min);
+ max = Math.floor(max);
+ return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
+ };
+
+ static InterpolateArray(data, fitCount) {
+
+ let linearInterpolate = function(before, after, atPoint) {
+ return before + (after - before) * atPoint;
+ };
+
+ let newData = [];
+
+ let springFactor = Number((data.length - 1) / (fitCount - 1));
+
+ newData[0] = data[0]; // for new allocation
+
+ for ( let i = 1; i < fitCount - 1; i++) {
+ let tmp = i * springFactor;
+ let before = Number(Math.floor(tmp)).toFixed();
+ let after = Number(Math.ceil(tmp)).toFixed();
+ let atPoint = tmp - before;
+ newData[i] = linearInterpolate(data[before], data[after], atPoint);
+ }
+
+ newData[fitCount - 1] = data[data.length - 1]; // for new allocation
+
+ return newData;
+ };
+
+ /**
+ * Undefined or null check
+ * @param variable
+ * @returns {boolean}
+ * @constructor
+ */
+ static UndefinedOrNull(
+ variable
+ ) {
+ return typeof variable === 'undefined' || variable === null;
+ };
+
+ /**
+ * The variable is not undefined and not null
+ * @param variable
+ * @returns {boolean}
+ * @constructor
+ */
+ static Defined(
+ variable
+ ) {
+ return typeof variable !== 'undefined' && variable !== null;
+ };
+
+ /**
+ * Gets function parameters
+ * @param fn
+ * @constructor
+ */
+ static GetParameters(fn) {
+
+ let FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
+ let FN_ARG_SPLIT = /,/;
+ let FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
+ let STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
+
+ let parameters,
+ fnText,
+ argDecl;
+
+ if (typeof fn !== 'function') {
+ parameters = [];
+ fnText = fn.toString().replace(STRIP_COMMENTS, '');
+ argDecl = fnText.match(FN_ARGS);
+ argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
+ arg.replace(FN_ARG, function(all, underscore, name) {
+ parameters.push(name);
+ });
+ });
+ } else {
+ throw Error("not a function")
+ }
+
+ return parameters;
+ };
+
+ /**
+ * Returns either an ID of the object or Null
+ * @param object
+ * @returns {null}
+ * @constructor
+ */
+ static IdOrNull(object) {
+ if (Utils.UndefinedOrNull(object)) {
+ return null;
+ } else {
+ if (Utils.UndefinedOrNull(object.id)) {
+ console.warn('saving an object reference with no ID : ', object);
+ return null;
+ }
+ return object.id;
+ }
+ };
+
+ /**
+ * Limit a property to values between -pi and +pi
+ * @param property
+ * @param objectProperty
+ * @returns {{configurable?: boolean, enumerable?: boolean, value?, writable?: boolean, get?: Function, set?: Function}}
+ * @constructor
+ */
+ static LimitToPI(property, objectProperty) {
+
+ let store = objectProperty;
+
+ return {
+ get : function() {
+ return store;
+ },
+ set : function(value) {
+ while (value > Math.PI) {
+ value -= (Math.PI * 2);
+ }
+
+ while (value < -(Math.PI)) {
+ value += (Math.PI * 2);
+ }
+
+ store = value;
+ }
+ };
+ };
+
+ /**
+ * Returns an array of IDs representing the objects
+ * @param array
+ * @returns []
+ * @constructor
+ */
+ static IdArrayOrEmptyArray(array) {
+ if (Utils.UndefinedOrNull(array)) {
+ return [];
+ } else {
+
+ return array.map(function(item) {
+
+ if (Utils.UndefinedOrNull(item.id)) {
+ throw new Error('No ID found while trying to store IDs to array');
+ }
+
+ return item.id
+ });
+ }
+ };
+
+ /**
+ * Links an object to its parent through idToObject array
+ * @param propertyString
+ * @param idToObject
+ * @param parentObject
+ * @param id
+ * @constructor
+ */
+ static Link(propertyString, idToObject, parentObject, id) {
+
+ if (!Utils.UndefinedOrNull(parentObject[propertyString])) {
+
+ if (!idToObject.hasOwnProperty(id)) {
+ console.warn('Linking failed for object:' + parentObject.name);
+ }
+
+ parentObject[propertyString] = idToObject[id];
+ }
+ };
+
+ /**
+ * Generates a random ID
+ * @returns {string}
+ * @constructor
+ */
+ static RandomId(length) {
+
+ if (Utils.UndefinedOrNull(length)) {
+ length = 10;
+ }
+
+ return Math.random().toString(36).substr(2, length);
+ };
+
+ static InvertWindingOrder(triangles) {
+
+ for (let i = 0; i < triangles.length; i++) {
+ let v1 = triangles[i].v1;
+ triangles[i].v1 = triangles[i].v2;
+ triangles[i].v2 = v1;
+
+ let backupUV = triangles[i].triangle.v1uv;
+ triangles[i].triangle.v1uv = triangles[i].triangle.v2uv;
+ triangles[i].triangle.v2uv = backupUV;
+ }
+
+ return triangles;
+ };
+
+ /**
+ * Inverts a mesh winding order (and its instance)
+ * @param mesh R3.D3.Mesh
+ * @returns {*}
+ * @constructor
+ */
+ static InvertMeshWindingOrder(mesh) {
+
+ mesh.faces.forEach(
+ function(face) {
+
+ let tmpV1 = face.v1;
+ face.v1 = face.v2;
+ face.v2 = tmpV1;
+
+ let tmpV1uv = face.v1uv;
+ face.v1uv = face.v2uv;
+ face.v2uv = tmpV1uv;
+
+ }.bind(this)
+ );
+
+ //mesh.computeNormals = true;
+ //mesh.createInstance();
+ };
+
+ /**
+ * This function resets a the winding order of a mesh from a reference point V (the average center of the mesh)
+ */
+ static ResetWindingOrder(faces, vertices) {
+
+ let vertexList = new R3.API.Vector3.Points();
+
+ for (let v = 0; v < vertices.length; v++) {
+ vertexList.add(new R3.API.Vector3(
+ vertices[v].position.x,
+ vertices[v].position.y,
+ vertices[v].position.z
+ ));
+ }
+
+ let V = vertexList.average();
+
+ let triangles = [];
+
+ for (let s = 0; s < faces.length; s += 3) {
+
+ let v0 = faces[s];
+ let v1 = faces[s+1];
+ let v2 = faces[s+2];
+
+ triangles.push(
+ {
+ v0 : v0,
+ v1 : v1,
+ v2 : v2,
+ edges : [
+ {v0: v0, v1: v1},
+ {v0: v1, v1: v2},
+ {v0: v2, v1: v0}
+ ],
+ winding : 0,
+ edgeIndex : -1,
+ processed : false
+ }
+ );
+ }
+
+ for (let i = 0; i < triangles.length; i++) {
+ if (
+ R3.API.Vector3.clockwise(
+ vertices[triangles[i].v0].position,
+ vertices[triangles[i].v1].position,
+ vertices[triangles[i].v2].position,
+ V
+ )
+ ) {
+ console.log('clockwise');
+ let bv1 = triangles[i].v1;
+ triangles[i].v1 = triangles[i].v2;
+ triangles[i].v2 = bv1;
+ } else {
+ console.log('not clockwise');
+ }
+ }
+
+ return triangles;
+ };
+
+ /**
+ * This function resets the winding order for triangles in faces, given an initial triangle and orientation edge
+ * used pseudocode from
+ * http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh
+ * We need to use a graph traversal algorithm,
+ * lets assume we have method that returns neighbor of triangle on given edge
+ *
+ * neighbor_on_egde( next_tria, edge )
+ *
+ * to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it
+ * processed = set of processed triangles; initial empty
+ *
+ * while to_process is not empty:
+ * next_tria, orientation_edge = to_process.pop()
+ * add next_tria in processed
+ * if next_tria is not opposite oriented than orientation_edge:
+ * change next_tria (ABC) orientation (B<->C)
+ * for each edge (AB) in next_tria:
+ * neighbor_tria = neighbor_on_egde( next_tria, edge )
+ * if neighbor_tria exists and neighbor_tria not in processed:
+ * to_process add (neighbor_tria, edge opposite oriented (BA))
+ * @param faces R3.D3.Face[]
+ * @param orientationEdge R3.API.Vector2
+ * @returns {Array}
+ */
+ static FixWindingOrder(faces, orientationEdge) {
+
+ /**
+ * Checks if a Face belonging to a TriangleEdge has already been processed
+ * @param processed TriangleEdge[]
+ * @param triangle Face
+ * @returns {boolean}
+ */
+ function inProcessed(processed, triangle) {
+
+ for (let i = 0; i < processed.length; i++) {
+ if (processed[i].triangle.equals(triangle)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a neighbouring triangle on a specific edge - preserving the edge orientation
+ * @param edge R3.API.Vector2
+ * @param faces R3.D3.Face[]
+ * @param currentTriangle
+ * @returns {*}
+ */
+ function neighbourOnEdge(edge, faces, currentTriangle) {
+
+ for (let i = 0; i < faces.length; i++) {
+ if (
+ (faces[i].v0 === edge.x && faces[i].v1 === edge.y) ||
+ (faces[i].v1 === edge.x && faces[i].v2 === edge.y) ||
+ (faces[i].v2 === edge.x && faces[i].v0 === edge.y) ||
+ (faces[i].v0 === edge.y && faces[i].v1 === edge.x) ||
+ (faces[i].v1 === edge.y && faces[i].v2 === edge.x) ||
+ (faces[i].v2 === edge.y && faces[i].v0 === edge.x)
+ ) {
+
+ let triangle = new R3.D3.API.Face(
+ null,
+ null,
+ faces[i].v0index,
+ faces[i].v1index,
+ faces[i].v2index,
+ faces[i].materialIndex,
+ faces[i].uvs
+ );
+
+ if (triangle.equals(currentTriangle)) {
+ continue;
+ }
+
+ return new R3.D3.TriangleEdge(
+ triangle,
+ edge
+ );
+ }
+ }
+
+ return null;
+ }
+
+ let toProcess = [
+ new R3.D3.TriangleEdge(
+ new R3.D3.API.Face(
+ null,
+ null,
+ faces[0].v0index,
+ faces[0].v1index,
+ faces[0].v2index,
+ faces[0].materialIndex,
+ faces[0].uvs
+ ),
+ orientationEdge
+ )
+ ];
+
+ let processed = [];
+
+ while (toProcess.length > 0) {
+
+ let triangleEdge = toProcess.pop();
+
+ /**
+ * If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed
+ * to have the same winding order)
+ */
+ if (
+ (triangleEdge.triangle.v0index === triangleEdge.edge.x &&
+ triangleEdge.triangle.v1index === triangleEdge.edge.y) ||
+ (triangleEdge.triangle.v1index === triangleEdge.edge.x &&
+ triangleEdge.triangle.v2index === triangleEdge.edge.y) ||
+ (triangleEdge.triangle.v2index === triangleEdge.edge.x &&
+ triangleEdge.triangle.v0index === triangleEdge.edge.y)
+ ) {
+ let backupV = triangleEdge.triangle.v1index;
+ triangleEdge.triangle.v1index = triangleEdge.triangle.v2index;
+ triangleEdge.triangle.v2index = backupV;
+
+ // let backupUV = triangleEdge.triangle.v1uv;
+ // triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv;
+ // triangleEdge.triangle.v2uv = backupUV;
+ //
+ let backupUV = triangleEdge.triangle.uvs[0][1];
+ triangleEdge.triangle.uvs[0][1] = triangleEdge.triangle.uvs[0][2];
+ triangleEdge.triangle.uvs[0][2] = backupUV;
+ }
+
+ processed.push(triangleEdge);
+
+ let edges = [
+ new R3.API.Vector2(
+ triangleEdge.triangle.v0index,
+ triangleEdge.triangle.v1index
+ ),
+ new R3.API.Vector2(
+ triangleEdge.triangle.v1index,
+ triangleEdge.triangle.v2index
+ ),
+ new R3.API.Vector2(
+ triangleEdge.triangle.v2index,
+ triangleEdge.triangle.v0index
+ )
+ ];
+
+ for (let j = 0; j < edges.length; j++) {
+ let neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle);
+ if (neighbour && !inProcessed(processed, neighbour.triangle)) {
+ toProcess.push(neighbour);
+ }
+ }
+ }
+
+ /**
+ * In processed - we will have some duplicates - only add the unique ones
+ * @type {Array}
+ */
+ let triangles = [];
+ for (let i = 0; i < processed.length; i++) {
+ let found = false;
+ for (let k = 0; k < triangles.length; k++) {
+ if (triangles[k].equals(processed[i].triangle)){
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ triangles.push(processed[i].triangle);
+ }
+ }
+
+ return triangles;
+ };
+
+ /**
+ * This is a work-around function to fix polys which don't triangulate because
+ * they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around
+ * Z then Y axis
+ * @param verticesFlat []
+ * @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY
+ * @return []
+ */
+ static FixPolyZPlane(verticesFlat, grain) {
+
+ if ((verticesFlat.length % 3) !== 0 && !(verticesFlat.length > 9)) {
+ console.log("The vertices are not in the right length : " + verticesFlat.length);
+ }
+
+ let vertices = [];
+
+ let points = new R3.API.Quaternion.Points();
+
+ for (let i = 0; i < verticesFlat.length; i += 3) {
+ points.add(new R3.API.Vector3(
+ verticesFlat[i],
+ verticesFlat[i + 1],
+ verticesFlat[i + 2]
+ ));
+ }
+
+ points.toOrigin();
+
+ points.maximizeXDistance(grain);
+
+ points.maximizeYDistance(grain);
+
+ for (i = 0; i < points.vectors.length; i++) {
+ vertices.push(
+ [
+ points.vectors[i].x,
+ points.vectors[i].y
+ ]
+ );
+ }
+
+ return vertices;
+ };
+
+ static MovingAverage(period) {
+ let nums = [];
+ return function(num) {
+ nums.push(num);
+ if (nums.length > period)
+ nums.splice(0,1); // remove the first element of the array
+ let sum = 0;
+ for (let i in nums)
+ sum += nums[i];
+ let n = period;
+ if (nums.length < period)
+ n = nums.length;
+ return(sum/n);
+ }
+ };
+
+ static Intersect(a, b) {
+
+ let t;
+
+ /**
+ * Loop over shortest array
+ */
+ if (b.length > a.length) {
+ t = b;
+ b = a;
+ a = t;
+ }
+
+ return a.filter(
+ /**
+ * Check if exists
+ * @param e
+ * @returns {boolean}
+ */
+ function(e) {
+ return (b.indexOf(e) > -1);
+ }
+ ).filter(
+ /**
+ * Remove Duplicates
+ * @param e
+ * @param i
+ * @param c
+ * @returns {boolean}
+ */
+ function(e, i, c) {
+ return c.indexOf(e) === i;
+ }
+ );
+ };
+
+ static Difference(a, b) {
+
+ let t;
+
+ /**
+ * Loop over shortest array
+ */
+ if (b.length > a.length) {
+ t = b;
+ b = a;
+ a = t;
+ }
+
+ return a.filter(
+ /**
+ * Check if exists
+ * @param e
+ * @returns {boolean}
+ */
+ function(e) {
+ return (b.indexOf(e) === -1);
+ }
+ ).filter(
+ /**
+ * Remove Duplicates
+ * @param e
+ * @param i
+ * @param c
+ * @returns {boolean}
+ */
+ function(e, i, c) {
+ return c.indexOf(e) === i;
+ }
+ );
+ };
+
+ /**
+ * Push only if not in there already
+ * @param array
+ * @param object
+ * @constructor
+ */
+ static PushUnique(array, object) {
+
+ if (array.indexOf(object) === -1) {
+ array.push(object);
+ }
+ };
+
+ /**
+ * Checks whether or not the object is empty
+ * @param obj
+ * @returns {boolean}
+ * @constructor
+ */
+ static IsEmpty(obj) {
+ return (Object.keys(obj).length === 0 && obj.constructor === Object);
+ };
+
+ static IsString(member) {
+ return (typeof member === 'string');
+ };
+
+ static IsBoolean(member) {
+ return (member === true || member === false);
+ };
+
+ static IsColor(member) {
+ return (member instanceof R3.Color);
+ };
+
+ static IsNumber(member) {
+ return (typeof member === 'number');
+ };
+
+ static IsVector2(member) {
+ return (
+ member instanceof R3.API.Vector2 ||
+ member instanceof R3.Vector2
+ );
+ };
+
+ static IsVector3(member) {
+ return (
+ member instanceof R3.API.Vector3 ||
+ member instanceof R3.Vector3
+ );
+ };
+
+ static IsVector4(member) {
+ return (
+ member instanceof R3.API.Vector4 ||
+ member instanceof R3.Vector4 ||
+ member instanceof R3.API.Quaternion ||
+ member instanceof R3.Quaternion
+ );
+ };
+
+ static IsObject(member) {
+ let type = typeof member;
+ return type === 'function' || type === 'object' && !!member;
+ };
+
+ /**
+ * @return {string}
+ */
+ static LowerUnderscore(name) {
+ let string = name.toLowerCase().replace(/\s+/g, '_');
+ string = string.replace(/-/g, '_');
+ string = string.replace(/\_+/g, '_');
+ return string;
+ };
+
+ static UpperCaseWordsSpaces(input) {
+
+ let word = input.replace(/[-_]/g, ' ');
+
+ word = word.replace(/\s+/, ' ');
+
+ let words = word.split(' ');
+
+ return words.reduce(
+ function(result, word) {
+ result += word[0].toUpperCase() + word.substr(1);
+ return result + ' ';
+ },
+ ''
+ ).trim();
+ };
+
+ /**
+ * @return {string}
+ */
+ static UpperCaseUnderscore(word) {
+
+ let str = '';
+
+ word.split('').map(
+ function(letter){
+ if (letter === letter.toUpperCase()) {
+ str += '_' + letter;
+ } else {
+ str += letter.toUpperCase();
+ }
+ });
+
+ str = str.replace(new RegExp('^_'),'');
+
+ return str;
+ };
+
+ /**
+ * Returns Left Padded Text - ex. length 5, padchar 0, string abc = '00abc'
+ * @param length
+ * @param padChar
+ * @param string
+ * @returns {string}
+ * @constructor
+ */
+ static PaddedText(length, padChar, string) {
+
+ let pad = "";
+
+ for (let x = 0; x < length; x++) {
+ pad += padChar;
+ }
+
+ return pad.substring(0, pad.length - string.length) + string;
+ };
+ //CUSTOM_IMPLEMENTATION_END
+
}
+//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
+//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END
+
module.exports = Utils;
\ No newline at end of file
diff --git a/dist/r3-node/r3.js b/dist/r3-node/r3.js
index 0557603..3abc49a 100644
--- a/dist/r3-node/r3.js
+++ b/dist/r3-node/r3.js
@@ -7,7 +7,7 @@ class R3 {
}
static version() {
- return 'Sun Jun 20 2021 11:02:42 GMT+0000 (Coordinated Universal Time)';
+ return 'Sun Jun 20 2021 18:45:42 GMT+0000 (Coordinated Universal Time)';
}
}
diff --git a/dist/r3.js b/dist/r3.js
index 8acdea3..c34c9e6 100644
--- a/dist/r3.js
+++ b/dist/r3.js
@@ -106,9 +106,266 @@ module.exports = R3;
!*** ./src/r3/r3-event.js ***!
\****************************/
/*! no static exports found */
-/***/ (function(module, exports) {
+/***/ (function(module, exports, __webpack_require__) {
-throw new Error("Module build failed (from ./node_modules/babel-loader/lib/index.js):\nSyntaxError: /app/src/r3/r3-event.js: Identifier 'Event' has already been declared. (20:6)\n\n 18 | **/\n 19 |\n> 20 | class Event {\n | ^\n 21 |\n 22 | //CONSTRUCTOR_TEMPLATE_START\n 23 | constructor(options) {\n at Parser._raise (/app/node_modules/@babel/parser/lib/index.js:816:17)\n at Parser.raiseWithData (/app/node_modules/@babel/parser/lib/index.js:809:17)\n at Parser.raise (/app/node_modules/@babel/parser/lib/index.js:770:17)\n at ScopeHandler.checkRedeclarationInScope (/app/node_modules/@babel/parser/lib/index.js:1432:12)\n at ScopeHandler.declareName (/app/node_modules/@babel/parser/lib/index.js:1398:12)\n at Parser.checkLVal (/app/node_modules/@babel/parser/lib/index.js:10431:24)\n at Parser.parseClassId (/app/node_modules/@babel/parser/lib/index.js:13617:14)\n at Parser.parseClass (/app/node_modules/@babel/parser/lib/index.js:13301:10)\n at Parser.parseStatementContent (/app/node_modules/@babel/parser/lib/index.js:12587:21)\n at Parser.parseStatement (/app/node_modules/@babel/parser/lib/index.js:12545:17)");
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
+
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+var Utils = __webpack_require__(!(function webpackMissingModule() { var e = new Error("Cannot find module 'r3-utils'"); e.code = 'MODULE_NOT_FOUND'; throw e; }()));
+/**
+
+ OPTIONS_START
+ OPTIONS_END
+
+ **/
+
+
+var Event = /*#__PURE__*/function () {
+ //CONSTRUCTOR_TEMPLATE_START
+ function Event(options) {
+ _classCallCheck(this, Event);
+
+ Event.Emit(Event.OBJECT_CREATED, this); //OPTIONS_INIT_START
+
+ if (typeof options === 'undefined') {
+ options = {};
+ } //OPTIONS_INIT_END
+ //CUSTOM_OPTIONS_INIT_START
+ //CUSTOM_OPTIONS_INIT_END
+
+
+ Object.assign(this, options); //CUSTOM_BEFORE_INIT_START
+ //CUSTOM_BEFORE_INIT_END
+
+ Event.Emit(Event.OBJECT_INITIALIZED, this);
+ } //CONSTRUCTOR_TEMPLATE_END
+ //CUSTOM_IMPLEMENTATION_START
+
+ /**
+ * Some nice Events handling
+ * @type {{}}
+ */
+
+
+ _createClass(Event, [{
+ key: "subscribe",
+ value:
+ /**
+ * Subscribe to some events
+ * @param eventName
+ * @param callback
+ */
+ function subscribe(eventName, callback) {
+ return Event.Subscribe(eventName, callback.bind(this));
+ }
+ }, {
+ key: "emit",
+ value: function emit(eventName, data, clientCallback, clientErrorCallback) {
+ return Event.Emit(eventName, data, clientCallback, clientErrorCallback);
+ }
+ /**
+ * Execute the functions which subscribe to this event, but don't process the client callback - the subscription function
+ * should execute the client callback
+ * @param eventId
+ * @param data
+ * @param clientCallback
+ * @param clientErrorCallback
+ * @returns {number}
+ * @constructor
+ */
+
+ }], [{
+ key: "Subscribe",
+ value: function Subscribe(eventName, fn) {
+ /**
+ * Todo - maybe eventually store a boolean which indicates if the function has been executed
+ */
+ var subscriptionId = Utils.RandomId(10);
+
+ if (Event.Subscriptions.hasOwnProperty(eventName)) {
+ if (Event.Subscriptions[eventName][subscriptionId]) {
+ throw new Error('A component can only subscribe to a particular event ID once');
+ }
+
+ Event.Subscriptions[eventName][subscriptionId] = fn;
+ } else {
+ Event.Subscriptions[eventName] = {};
+ Event.Subscriptions[eventName][subscriptionId] = fn;
+ }
+ /**
+ * Return a handle to the caller to allow us to unsubscribe to this event
+ */
+
+
+ return {
+ fn: fn,
+ remove: function (eventId, subscriptionId) {
+ return function () {
+ /**
+ * Stop listening for this event from this component
+ */
+ delete Event.Subscriptions[eventId][subscriptionId];
+ /**
+ * If the length of listeners is 0, stop referencing this event
+ * @type {string[]}
+ */
+
+ var listeners = Object.keys(Event.Subscriptions[eventId]);
+
+ if (listeners.length === 0) {
+ delete Event.Subscriptions[eventId];
+ }
+ };
+ }(eventName, subscriptionId),
+ subscriptionId: subscriptionId
+ };
+ }
+ }, {
+ key: "Emit",
+ value:
+ /**
+ * Static Synchronous Event - Calls clientCallback directly after the event result is obtained
+ * @param eventId
+ * @param data
+ * @param clientCallback is executed ideally when the event completed
+ * @param clientErrorCallback
+ * @returns {number} of callbacks executed
+ * @constructor
+ */
+ function Emit(eventId, data, clientCallback, clientErrorCallback) {
+ if (Event.Subscriptions.hasOwnProperty(eventId)) {
+ var subscriptionIds = Object.keys(Event.Subscriptions[eventId]);
+ subscriptionIds.map(function (subscriptionId) {
+ try {
+ var result = Event.Subscriptions[eventId][subscriptionId](data);
+
+ if (clientCallback) {
+ clientCallback(result);
+ }
+ } catch (error) {
+ if (clientErrorCallback) {
+ clientErrorCallback(error);
+ } else {
+ console.error(error);
+ throw error;
+ }
+ }
+ });
+ }
+ }
+ }, {
+ key: "Async",
+ value: function Async(eventId, data, clientCallback, clientErrorCallback) {
+ if (Event.Subscriptions.hasOwnProperty(eventId)) {
+ var subscriptionIds = Object.keys(Event.Subscriptions[eventId]);
+ subscriptionIds.map(function (subscriptionId) {
+ try {
+ Event.Subscriptions[eventId][subscriptionId](data, clientCallback, clientErrorCallback);
+ } catch (error) {
+ if (clientErrorCallback) {
+ clientErrorCallback(error);
+ } else {
+ console.error(error);
+ throw error;
+ }
+ }
+ });
+ }
+ }
+ }]);
+
+ return Event;
+}();
+
+_defineProperty(Event, "Subscriptions", {});
+
+//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
+//EVENT_GENERATED_START
+Event.COMPONENT_INITIALIZED = 0x1;
+Event.CREATE_INSTANCE_BEFORE = 0x2;
+Event.DISPOSE_INSTANCE = 0x3;
+Event.DISPOSE_OBJECT = 0x4;
+Event.GET_RUNTIME = 0x5;
+Event.GET_WINDOW_SIZE = 0x6;
+Event.INSTANCE_CREATED = 0x7;
+Event.INSTANCE_DISPOSED = 0x8;
+Event.OBJECT_CREATED = 0x9;
+Event.OBJECT_INITIALIZED = 0xa;
+Event.PAUSE = 0xb;
+Event.RESTART = 0xc;
+Event.START = 0xd;
+Event.UPDATE_FROM_INSTANCE_AFTER = 0xe;
+Event.UPDATE_FROM_INSTANCE_BEFORE = 0xf;
+Event.UPDATE_INSTANCE_AFTER = 0x10;
+Event.UPDATE_INSTANCE_BEFORE = 0x11;
+Event.MAX_EVENTS = 0x12;
+
+Event.GetEventName = function (eventId) {
+ switch (eventId) {
+ case 0x1:
+ return 'component_initialized';
+
+ case 0x2:
+ return 'create_instance_before';
+
+ case 0x3:
+ return 'dispose_instance';
+
+ case 0x4:
+ return 'dispose_object';
+
+ case 0x5:
+ return 'get_runtime';
+
+ case 0x6:
+ return 'get_window_size';
+
+ case 0x7:
+ return 'instance_created';
+
+ case 0x8:
+ return 'instance_disposed';
+
+ case 0x9:
+ return 'object_created';
+
+ case 0xa:
+ return 'object_initialized';
+
+ case 0xb:
+ return 'pause';
+
+ case 0xc:
+ return 'restart';
+
+ case 0xd:
+ return 'start';
+
+ case 0xe:
+ return 'update_from_instance_after';
+
+ case 0xf:
+ return 'update_from_instance_before';
+
+ case 0x10:
+ return 'update_instance_after';
+
+ case 0x11:
+ return 'update_instance_before';
+
+ default:
+ throw new Error('Event type not defined : ' + eventId);
+ }
+}; //EVENT_GENERATED_END
+//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END
+
+
+module.exports = Event;
/***/ }),
@@ -127,10 +384,6 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
-function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }
-
-function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
-
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
@@ -151,6 +404,9 @@ var Event = __webpack_require__(!(function webpackMissingModule() { var e = new
/**
OPTIONS_START
+ id=Utils.RandomId(10)
+ name=this.constructor.name + '(' + options.id + ')'
+ register=true
OPTIONS_END
INSTANCE_OPTIONS_MAPPING_START
@@ -160,6 +416,9 @@ var Event = __webpack_require__(!(function webpackMissingModule() { var e = new
LINKED_OBJECTS_END
EXCLUDED_FROM_INSTANCE_OPTIONS_START
+ id
+ name
+ register
EXCLUDED_FROM_INSTANCE_OPTIONS_END
**/
@@ -180,12 +439,26 @@ var R3Object = /*#__PURE__*/function (_Event) {
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'R3Object (' + options.id + ')';
_this = _super.call(this, options);
_this.emit(Event.OBJECT_CREATED, _assertThisInitialized(_this)); //OPTIONS_INIT_START
- //OPTIONS_INIT_END
+
+
+ if (typeof options === 'undefined') {
+ options = {};
+ }
+
+ if (Utils.UndefinedOrNull(options.id)) {
+ options.id = Utils.RandomId(10);
+ }
+
+ if (Utils.UndefinedOrNull(options.name)) {
+ options.name = _this.constructor.name + '(' + options.id + ')';
+ }
+
+ if (Utils.UndefinedOrNull(options.register)) {
+ options.register = true;
+ } //OPTIONS_INIT_END
//CUSTOM_OPTIONS_INIT_START
//CUSTOM_OPTIONS_INIT_END
@@ -204,20 +477,14 @@ var R3Object = /*#__PURE__*/function (_Event) {
key: "createInstance",
value: function createInstance() {
//CREATE_INSTANCE_BEFORE_START
- _get(_getPrototypeOf(R3Object.prototype), "createInstance", this).call(this);
-
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance({//CREATE_INSTANCE_OPTIONS_START
- //CREATE_INSTANCE_OPTIONS_END
- }, this);
- } //CREATE_INSTANCE_BEFORE_END
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this); //CREATE_INSTANCE_BEFORE_END
//CUSTOM_CREATE_INSTANCE_START
//CUSTOM_CREATE_INSTANCE_END
//CREATE_INSTANCE_AFTER_START
-
+ this[this.runtime].createInstance(this, {//CREATE_INSTANCE_OPTIONS_START
+ //CREATE_INSTANCE_OPTIONS_END
+ });
this.emit(Event.INSTANCE_CREATED, this); //CREATE_INSTANCE_AFTER_END
} //CREATE_INSTANCE_TEMPLATE_END
//UPDATE_INSTANCE_TEMPLATE_START
@@ -256,12 +523,16 @@ var R3Object = /*#__PURE__*/function (_Event) {
key: "dispose",
value: function dispose() {
//DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this); //DISPOSE_BEFORE_END
+ this.subscribe(Event.INSTANCE_DISPOSED, function (object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }); //DISPOSE_BEFORE_END
//CUSTOM_DISPOSE_START
//CUSTOM_DISPOSE_END
//DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this); //DISPOSE_AFTER_END
+ this.disposeInstance(); //DISPOSE_AFTER_END
} //DISPOSE_TEMPLATE_END
//DISPOSE_INSTANCE_TEMPLATE_START
@@ -269,14 +540,12 @@ var R3Object = /*#__PURE__*/function (_Event) {
key: "disposeInstance",
value: function disposeInstance() {
//DISPOSE_INSTANCE_BEFORE_START
- _get(_getPrototypeOf(R3Object.prototype), "disposeInstance", this).call(this);
-
- this.emit(Event.DISPOSE_INSTANCE, this); //DISPOSE_INSTANCE_BEFORE_END
+ console.log('Disposing instance of ' + this.name); //DISPOSE_INSTANCE_BEFORE_END
//CUSTOM_DISPOSE_INSTANCE_START
//CUSTOM_DISPOSE_INSTANCE_END
//DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this); //DISPOSE_INSTANCE_AFTER_END
+ this.emit(Event.DISPOSE_INSTANCE, this); //DISPOSE_INSTANCE_AFTER_END
} //DISPOSE_INSTANCE_TEMPLATE_END
//CUSTOM_IMPLEMENTATION_START
//CUSTOM_IMPLEMENTATION_END
@@ -507,7 +776,7 @@ var R3 = /*#__PURE__*/function () {
_createClass(R3, null, [{
key: "version",
value: function version() {
- return 'Sun Jun 20 2021 11:02:42 GMT+0000 (Coordinated Universal Time)';
+ return 'Sun Jun 20 2021 18:45:42 GMT+0000 (Coordinated Universal Time)';
}
}]);
@@ -523,4 +792,4 @@ module.exports = R3;
/***/ })
/******/ });
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vc3JjL3IzL2luZGV4LmpzIiwid2VicGFjazovLy8uL3NyYy9yMy9yMy1yMy1vYmplY3QuanMiLCJ3ZWJwYWNrOi8vLy4vc3JjL3IzL3IzLXN5c3RlbS9pbmRleC5qcyIsIndlYnBhY2s6Ly8vLi9zcmMvcjMvcjMtc3lzdGVtL3IzLXN5c3RlbS1saW5raW5nLmpzIiwid2VicGFjazovLy8uL3NyYy9yMy9yMy1zeXN0ZW0vcjMtc3lzdGVtLXNvY2tldC5qcyIsIndlYnBhY2s6Ly8vLi9zcmMvcjMvcjMtc3lzdGVtL3IzLXN5c3RlbS5qcyIsIndlYnBhY2s6Ly8vLi9zcmMvcjMvcjMuanMiXSwibmFtZXMiOlsiUjMiLCJyZXF1aXJlIiwiU3lzdGVtIiwiTGlua2luZyIsInN0YXJ0IiwiU29ja2V0IiwibW9kdWxlIiwiZXhwb3J0cyIsIlV0aWxzIiwiRXZlbnQiLCJSM09iamVjdCIsIm9wdGlvbnMiLCJVbmRlZmluZWRPck51bGwiLCJpZCIsIlJhbmRvbUlkIiwibmFtZSIsImVtaXQiLCJPQkpFQ1RfQ1JFQVRFRCIsIk9iamVjdCIsImFzc2lnbiIsIk9CSkVDVF9JTklUSUFMSVpFRCIsIkNSRUFURV9JTlNUQU5DRSIsInJ1bnRpbWUiLCJncmFwaGljcyIsImNyZWF0ZUluc3RhbmNlIiwiSU5TVEFOQ0VfQ1JFQVRFRCIsInByb3BlcnR5IiwiVVBEQVRFX0lOU1RBTkNFX0JFRk9SRSIsIlVQREFURV9JTlNUQU5DRV9BRlRFUiIsIlVQREFURV9GUk9NX0lOU1RBTkNFX0JFRk9SRSIsIlVQREFURV9GUk9NX0lOU1RBTkNFX0FGVEVSIiwiRElTUE9TRV9PQkpFQ1QiLCJPQkpFQ1RfRElTUE9TRUQiLCJESVNQT1NFX0lOU1RBTkNFIiwiSU5TVEFOQ0VfRElTUE9TRUQiLCJTeXN0ZW1MaW5raW5nIiwiU3lzdGVtU29ja2V0IiwiTGlua2luZ1N5c3RlbSIsImNvbnNvbGUiLCJsb2ciLCJTdWJz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QixDOzs7Ozs7Ozs7Ozs7Ozs7OztBQ1JBLGVBQThDRCxtQkFBTyxDQUFDLGdEQUFELENBQXJEO0FBQUEsSUFBT0MsTUFBUCxZQUFPQSxNQUFQO0FBQUEsSUFBZWlDLGFBQWYsWUFBZUEsYUFBZjtBQUFBLElBQThCQyxZQUE5QixZQUE4QkEsWUFBOUI7O0FBQ0EsSUFBTTFCLFFBQVEsR0FBR1QsbUJBQU8sQ0FBQyxnREFBRCxDQUF4Qjs7SUFFTUQsRTtBQUVMLGdCQUFjO0FBQUE7QUFDYjs7OztXQUVELG1CQUFpQjtBQUNoQixhQUFPLFVBQVA7QUFDQTs7Ozs7O0FBSUZBLEVBQUUsQ0FBQ1UsUUFBSCxHQUFnQkEsUUFBaEI7QUFDQVYsRUFBRSxDQUFDRSxNQUFILEdBQWVBLE1BQWY7QUFDQUYsRUFBRSxDQUFDRSxNQUFILENBQVVDLE9BQVYsR0FBb0JnQyxhQUFwQjtBQUNBbkMsRUFBRSxDQUFDRSxNQUFILENBQVVHLE1BQVYsR0FBbUIrQixZQUFuQjtBQUVBOUIsTUFBTSxDQUFDQyxPQUFQLEdBQWlCUCxFQUFqQixDIiwiZmlsZSI6InIzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuIFx0XHR9XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBjcmVhdGUgYSBmYWtlIG5hbWVzcGFjZSBvYmplY3RcbiBcdC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuIFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXG4gXHQvLyBtb2RlICYgNDogcmV0dXJuIHZhbHVlIHdoZW4gYWxyZWFkeSBucyBvYmplY3RcbiBcdC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcbiBcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XG4gXHRcdGlmKG1vZGUgJiAxKSB2YWx1ZSA9IF9fd2VicGFja19yZXF1aXJlX18odmFsdWUpO1xuIFx0XHRpZihtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuIFx0XHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xuIFx0XHR2YXIgbnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIobnMpO1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XG4gXHRcdGlmKG1vZGUgJiAyICYmIHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykgZm9yKHZhciBrZXkgaW4gdmFsdWUpIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0uYmluZChudWxsLCBrZXkpKTtcbiBcdFx0cmV0dXJuIG5zO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9zcmMvcjMvaW5kZXguanNcIik7XG4iLCJjb25zdCBSMyA9IHJlcXVpcmUoJy4vcjMuanMnKTtcblxuUjMuU3lzdGVtLkxpbmtpbmcuc3RhcnQoKTtcblIzLlN5c3RlbS5Tb2NrZXQuc3RhcnQoKTtcblxubW9kdWxlLmV4cG9ydHMgPSBSMztcbiIsImNvbnN0IFV0aWxzID0gcmVxdWlyZSgncjMtdXRpbHMnKTtcbmNvbnN0IEV2ZW50ID0gcmVxdWlyZSgncjMtZXZlbnQuanMnKTtcblxuLyoqXG5cbiBPUFRJT05TX1NUQVJUXG4gT1BUSU9OU19FTkRcblxuIElOU1RBTkNFX09QVElPTlNfTUFQUElOR19TVEFSVFxuIElOU1RBTkNFX09QVElPTlNfTUFQUElOR19FTkRcblxuIExJTktFRF9PQkpFQ1RTX1NUQVJUXG4gTElOS0VEX09CSkVDVFNfRU5EXG5cbiBFWENMVURFRF9GUk9NX0lOU1RBTkNFX09QVElPTlNfU1RBUlRcbiBFWENMVURFRF9GUk9NX0lOU1RBTkNFX09QVElPTlNfRU5EXG5cbiAqKi9cblxuY2xhc3MgUjNPYmplY3QgZXh0ZW5kcyBFdmVudCB7XG5cbiAgLy9DT05TVFJVQ1RPUl9FWFRFTkRTX1RFTVBMQVRFX1NUQVJUXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHtcblxuICAgIGlmIChVdGlscy5VbmRlZmluZWRPck51bGwob3B0aW9ucykpIHtcbiAgICAgIG9wdGlvbnMgPSB7fTtcbiAgICB9XG5cbiAgICBvcHRpb25zLmlkID0gVXRpbHMuUmFuZG9tSWQoMTApO1xuICAgIG9wdGlvbnMubmFtZSA9ICdSM09iamVjdCAoJyArIG9wdGlvbnMuaWQgKyAnKSc7XG5cbiAgICBzdXBlcihvcHRpb25zKTtcblxuICAgIHRoaXMuZW1pdChFdmVudC5PQkpFQ1RfQ1JFQVRFRCwgdGhpcyk7XG5cbiAgICAvL09QVElPTlNfSU5JVF9TVEFSVFxuXHRcdC8vT1BUSU9OU19JTklUX0VORFxuXG4gICAgLy9DVVNUT01fT1BUSU9OU19JTklUX1NUQVJUXG4gICAgLy9DVVNUT01fT1BUSU9OU19JTklUX0VORFxuXG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBvcHRpb25zKTtcblxuICAgIC8vQ1VTVE9NX0JFRk9SRV9JTklUX1NUQVJUXG4gICAgLy9DVVNUT01fQkVGT1JFX0lOSVRfRU5EXG5cbiAgICB0aGlzLmVtaXQoRXZlbnQuT0JKRUNUX0lOSVRJQUxJWkVELCB0aGlzKTtcbiAgfVxuXHQvL0NPTlNUUlVDVE9SX0VYVEVORFNfVEVNUExBVEVfRU5EXG5cbiAgLy9DUkVBVEVfSU5TVEFOQ0VfVEVNUExBVEVfU1RBUlRcbiAgY3JlYXRlSW5zdGFuY2UoKSB7XG5cbiAgICAvL0NSRUFURV9JTlNUQU5DRV9CRUZPUkVfU1RBUlRcbiAgICBzdXBlci5jcmVhdGVJbnN0YW5jZSgpO1xuICAgIHRoaXMuZW1pdChFdmVudC5DUkVBVEVfSU5TVEFOQ0UsIHRoaXMpO1xuXG4gICAgaWYgKHRoaXMucnVudGltZSA9PT0gJ2dyYXBoaWNzJykge1xuICAgICAgdGhpcy5ncmFwaGljcy5jcmVhdGVJbnN0YW5jZShcbiAgICAgICAge1xuICAgICAgICAgIC8vQ1JFQVRFX0lOU1RBTkNFX09QVElPTlNfU1RBUlRcblxuXHRcdFx0XHRcdC8vQ1JFQVRFX0lOU1RBTkNFX09QVElPTlNfRU5EXG4gICAgICAgIH0sXG4gICAgICAgIHRoaXNcbiAgICAgIClcbiAgICB9XG5cdFx0Ly9DUkVBVEVfSU5TVEFOQ0VfQkVGT1JFX0VORFxuXG4gICAgLy9DVVNUT01fQ1JFQVRFX0lOU1RBTkNFX1NUQVJUXG4gICAgLy9DVVNUT01fQ1JFQVRFX0lOU1RBTkNFX0VORFxuXG4gICAgLy9DUkVBVEVfSU5TVEFOQ0VfQUZURVJfU1RBUlRcbiAgICB0aGlzLmVtaXQoRXZlbnQuSU5TVEFOQ0VfQ1JFQVRFRCwgdGhpcyk7XG5cdFx0Ly9DUkVBVEVfSU5TVEFOQ0VfQUZURVJfRU5EXG5cbiAgfVxuXHQvL0NSRUFURV9JTlNUQU5DRV9URU1QTEFURV9FTkRcblxuICAvL1VQREFURV9JTlNUQU5DRV9URU1QTEFURV9TVEFSVFxuICB1cGRhdGVJbnN0YW5jZShwcm9wZXJ0eSkge1xuXG4gICAgLy9VUERBVEVfSU5TVEFOQ0VfQkVGT1JFX1NUQVJUXG4gICAgdGhpcy5lbWl0KEV2ZW50LlVQREFURV9JTlNUQU5DRV9CRUZPUkUsIHRoaXMpO1xuXHRcdC8vVVBEQVRFX0lOU1RBTkNFX0JFRk9SRV9FTkRcblxuICAgIC8vVVBEQVRFX0lOU1RBTkNFX09QVElPTlNfU1RBUlRcblx0XHQvL1VQREFURV9JTlNUQU5DRV9PUFRJT05TX0VORFxuXG4gICAgLy9DVVNUT01fVVBEQVRFX0lOU1RBTkNFX1NUQVJUXG4gICAgLy9DVVNUT01fVVBEQVRFX0lOU1RBTkNFX0VORFxuXG4gICAgLy9VUERBVEVfSU5TVEFOQ0VfQUZURVJfU1RBUlRcbiAgICB0aGlzLmVtaXQoRXZlbnQuVVBEQVRFX0lOU1RBTkNFX0FGVEVSLCB0aGlzKTtcblx0XHQvL1VQREFURV9JTlNUQU5DRV9BRlRFUl9FTkRcblxuICB9XG5cdC8vVVBEQVRFX0lOU1RBTkNFX1RFTVBMQVRFX0VORFxuXG4gIC8vVVBEQVRFX0ZST01fSU5TVEFOQ0VfVEVNUExBVEVfU1RBUlRcbiAgdXBkYXRlRnJvbUluc3RhbmNlKHByb3BlcnR5KSB7XG5cbiAgICAvL1VQREFURV9GUk9NX0lOU1RBTkNFX0JFRk9SRV9TVEFSVFxuICAgIHRoaXMuZW1pdChFdmVudC5VUERBVEVfRlJPTV9JTlNUQU5DRV9CRUZPUkUsIHRoaXMpO1xuXHRcdC8vVVBEQVRFX0ZST01fSU5TVEFOQ0VfQkVGT1JFX0VORFxuXG4gICAgLy9VUERBVEVfRlJPTV9JTlNUQU5DRV9PUFRJT05TX1NUQVJUXG5cdFx0Ly9VUERBVEVfRlJPTV9JTlNUQU5DRV9PUFRJT05TX0VORFxuXG4gICAgLy9DVVNUT01fVVBEQVRFX0ZST01fSU5TVEFOQ0VfU1RBUlRcbiAgICAvL0NVU1RPTV9VUERBVEVfRlJPTV9JTlNUQU5DRV9FTkRcblxuICAgIC8vVVBEQVRFX0ZST01fSU5TVEFOQ0VfQUZURVJfU1RBUlRcbiAgICB0aGlzLmVtaXQoRXZlbnQuVVBEQVRFX0ZST01fSU5TVEFOQ0VfQUZURVIsIHRoaXMpO1xuXHRcdC8vVVBEQVRFX0ZST01fSU5TVEFOQ0VfQUZURVJfRU5EXG5cbiAgfVxuXHQvL1VQREFURV9GUk9NX0lOU1RBTkNFX1RFTVBMQVRFX0VORFxuXG4gIC8vRElTUE9TRV9URU1QTEFURV9TVEFSVFxuICBkaXNwb3NlKCkge1xuXG4gICAgLy9ESVNQT1NFX0JFRk9SRV9TVEFSVFxuICAgIHRoaXMuZW1pdChFdmVudC5ESVNQT1NFX09CSkVDVCwgdGhpcyk7XG5cdFx0Ly9ESVNQT1NFX0JFRk9SRV9FTkRcblxuICAgIC8vQ1VTVE9NX0RJU1BPU0VfU1RBUlRcbiAgICAvL0NVU1RPTV9ESVNQT1NFX0VORFxuXG4gICAgLy9ESVNQT1NFX0FGVEVSX1NUQVJUXG4gICAgdGhpcy5lbWl0KEV2ZW50Lk9CSkVDVF9ESVNQT1NFRCwgdGhpcyk7XG5cdFx0Ly9ESVNQT1NFX0FGVEVSX0VORFxuXG4gIH1cblx0Ly9ESVNQT1NFX1RFTVBMQVRFX0VORFxuXG4gIC8vRElTUE9TRV9JTlNUQU5DRV9URU1QTEFURV9TVEFSVFxuICBkaXNwb3NlSW5zdGFuY2UoKSB7XG5cbiAgICAvL0RJU1BPU0VfSU5TVEFOQ0VfQkVGT1JFX1NUQVJUXG4gICAgc3VwZXIuZGlzcG9zZUluc3RhbmNlKCk7XG4gICAgdGhpcy5lbWl0KEV2ZW50LkRJU1BPU0VfSU5TVEFOQ0UsIHRoaXMpO1xuXHRcdC8vRElTUE9TRV9JTlNUQU5DRV9CRUZPUkVfRU5EXG5cbiAgICAvL0NVU1RPTV9ESVNQT1NFX0lOU1RBTkNFX1NUQVJUXG4gICAgLy9DVVNUT01fRElTUE9TRV9JTlNUQU5DRV9FTkRcblxuICAgIC8vRElTUE9TRV9JTlNUQU5DRV9BRlRFUl9TVEFSVFxuICAgIHRoaXMuZW1pdChFdmVudC5JTlNUQU5DRV9ESVNQT1NFRCwgdGhpcyk7XG5cdFx0Ly9ESVNQT1NFX0lOU1RBTkNFX0FGVEVSX0VORFxuXG4gIH1cblx0Ly9ESVNQT1NFX0lOU1RBTkNFX1RFTVBMQVRFX0VORFxuXG4gIC8vQ1VTVE9NX0lNUExFTUVOVEFUSU9OX1NUQVJUXG4gIC8vQ1VTVE9NX0lNUExFTUVOVEFUSU9OX0VORFxuXG59XG5cbi8vQ1VTVE9NX09VVF9PRl9DTEFTU19JTVBMRU1FTlRBVElPTl9TVEFSVFxuLy9DVVNUT01fT1VUX09GX0NMQVNTX0lNUExFTUVOVEFUSU9OX0VORFxuXG5tb2R1bGUuZXhwb3J0cyA9IFIzT2JqZWN0OyIsImNvbnN0IFN5c3RlbSA9IHJlcXVpcmUoJy4vcjMtc3lzdGVtLmpzJyk7XG5jb25zdCBTeXN0ZW1MaW5raW5nID0gcmVxdWlyZSgnLi9yMy1zeXN0ZW0tbGlua2luZy5qcycpO1xuY29uc3QgU3lzdGVtU29ja2V0ID0gcmVxdWlyZSgnLi9yMy1zeXN0ZW0tc29ja2V0LmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBTeXN0ZW0sXG4gIFN5c3RlbUxpbmtpbmcsXG4gIFN5c3RlbVNvY2tldFxufSIsImNvbnN0IFN5c3RlbSA9IHJlcXVpcmUoJy4vcjMtc3lzdGVtJyk7XG5jb25zdCBSM09iamVjdCA9IHJlcXVpcmUoJy4uL3IzLXIzLW9iamVjdCcpO1xuY29uc3QgRXZlbnQgPSByZXF1aXJlKCcuLi9yMy1ldmVudCcpO1xuXG5jbGFzcyBMaW5raW5nU3lzdGVtIGV4dGVuZHMgU3lzdGVtIHtcblxuXHRzdGF0aWMgc3RhcnQoKSB7XG5cblx0XHRzdXBlci5zdGFydCgpO1xuXHRcdFxuXHRcdGNvbnNvbGUubG9nKCdzdGFydGluZyBsaW5raW5nIHN5c3RlbScpO1xuXG5cdFx0RXZlbnQuU3Vic2NyaWJlKFxuXHRcdFx0RXZlbnQuT0JKRUNUX0NSRUFURUQsXG5cdFx0XHQoKSA9PiB7XG5cdFx0XHRcdGNvbnNvbGUubG9nKCdsaW5raW5nIHN5c3RlbSBkaXNjb3ZlcmVkIGFuIG9iamVjdCcpO1xuXHRcdFx0fVxuXHRcdCk7XG5cblx0XHRsZXQgb2JqZWN0ID0gbmV3IFIzT2JqZWN0KCk7XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XHRcblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IExpbmtpbmdTeXN0ZW07XG4iLCJjb25zdCBTeXN0ZW0gPSByZXF1aXJlKCcuL3IzLXN5c3RlbS5qcycpO1xuXG5jbGFzcyBTb2NrZXRTeXN0ZW0gZXh0ZW5kcyBTeXN0ZW0ge1xuXG5cdHN0YXRpYyBzdGFydCgpIHtcblxuXHRcdHN1cGVyLnN0YXJ0KCk7XG5cdFx0XG5cdFx0Y29uc29sZS5sb2coJ3N0YXJ0aW5nIHNvY2tldCBzeXN0ZW0nKTtcblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFNvY2tldFN5c3RlbTsiLCJjbGFzcyBTeXN0ZW0ge1xuXG5cdHN0YXRpYyBzdGFydCgpIHtcblx0XHRjb25zb2xlLmxvZygnc3RhcnRpbmcgYSBzeXN0ZW0nKTtcdFxuXHR9XG5cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBTeXN0ZW07XG4iLCJjb25zdCB7U3lzdGVtLCBTeXN0ZW1MaW5raW5nLCBTeXN0ZW1Tb2NrZXR9ID0gcmVxdWlyZSgnLi9yMy1zeXN0ZW0nKTtcbmNvbnN0IFIzT2JqZWN0ID0gcmVxdWlyZSgnLi9yMy1yMy1vYmplY3QnKTtcblxuY2xhc3MgUjMge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXHR9XG5cblx0c3RhdGljIHZlcnNpb24oKSB7XG5cdFx0cmV0dXJuICdfX0RBVEVfXyc7XG5cdH1cblxufVxuXG5SMy5SM09iamVjdCBcdFx0PSBSM09iamVjdDtcblIzLlN5c3RlbSBcdFx0XHQ9IFN5c3RlbTtcblIzLlN5c3RlbS5MaW5raW5nXHQ9IFN5c3RlbUxpbmtpbmc7XG5SMy5TeXN0ZW0uU29ja2V0XHQ9IFN5c3RlbVNvY2tldDtcblxubW9kdWxlLmV4cG9ydHMgPSBSMztcbiJdLCJzb3VyY2VSb290IjoiIn0=
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vc3JjL3IzL2luZGV4LmpzIiwid2VicGFjazovLy8uL3NyYy9yMy9yMy1ldmVudC5qcyIsIndlYnBhY2s6Ly8vLi9zcmMvcjMvcjMtcjMtb2JqZWN0LmpzIiwid2VicGFjazovLy8uL3NyYy9yMy9yMy1zeXN0ZW0vaW5kZXguanMiLCJ3ZWJwYWNrOi8vLy4vc3JjL3IzL3IzLXN5c3RlbS9yMy1zeXN0ZW0tbGlua2luZy5qcyIsIndlYnBhY2s6Ly8vLi9zcmMvcjMvcjMtc3lzdGVtL3IzLXN5c3RlbS1zb2NrZXQuanMiLCJ3ZWJwYWNrOi8vLy4vc3JjL3IzL3IzLXN5c3RlbS9yMy1zeXN0ZW0uanMiLCJ3ZWJwYWNrOi8vLy4vc3JjL3IzL3IzLmpzIl0sIm5hbWVzIjpbIlIzIiwicmVxdWlyZSIsIlN5c3RlbSIsIkxpbmtpbmciLCJzdGFydCIsIlNvY2tldCIsIm1vZHVsZSIsImV4cG9ydHMiLCJVdGlscyIsIkV2ZW50Iiwib3B0aW9ucyIsIkVtaXQiLCJPQkpFQ1RfQ1JFQVRFRCIsIk9iamVjdCIsImFzc2lnbiIsIk9CSkVDVF9JTklUSUFMSVpFRCIsImV2ZW50TmFtZSIsImNhbGxiYWNrIiwiU3Vic2NyaWJlIiwiYmluZCIsImRhdGEiLCJjbGllbnRDYWxsYmFjayIsImNsaWVudEVycm9yQ2FsbGJhY2siLCJmbiIsInN1YnNjcmlwdGlvbklkIiwiUmFuZG9tSWQiLCJTdWJzY3JpcHRpb25zIiwiaGFzT3duUHJvcGVydHkiLCJFcnJvciIsInJlbW92ZSIsImV2ZW50SWQiLCJsaXN0ZW5lcnMiLCJrZXlzIiwibGVuZ3RoIiwic3Vic2NyaXB0aW9uSWRzIiwibWFwIiwicmVzdWx0IiwiZXJyb3IiLCJjb25zb2xlIiwiQ09NUE9ORU5UX0lOSVRJQUxJWkVEIiwiQ1JFQVRFX0lOU1RBTkNFX0JFRk9SRSIsIkRJU1BPU0VfSU5TVEFOQ0UiLCJESVNQT1NFX09CSkVDVCIsIkdFVF9SVU5USU1FIiwiR0VUX1dJTkRPV19TSVpFIiwiSU5TVEFOQ0VfQ1JFQVRFRCIsIklOU1RBTkNFX0RJU1BPU0VEIiwiUEFVU0UiLCJSRVNUQVJUIiwiU1RBUlQiLCJVUERBVEVfRlJPTV9JTlNUQU5DRV9BRlRFUiIsIlVQREFURV9GUk9NX0lOU1RBTkNFX0JFRk9SRSIsIlVQREFURV9JTlNUQU5DRV9BRlRFUiIsIlVQREFURV9JTlNUQU5DRV9CRUZPUkUiLCJNQVhfRVZFTlRTIiwiR2V0RXZlbnROYW1lIiwiUjNPYmplY3QiLCJVbmRlZmluZWRPck51bGwiLCJlbWl0IiwiaWQiLCJuYW1lIiwiY29uc3RydWN0b3IiLCJyZWdpc3RlciIsInJ1bnRpbWUiLCJjcmVhdGVJbnN0YW5jZSIsInByb3BlcnR5Iiwic3Vic2NyaWJlIiwib2JqZWN0IiwiZGlzcG9zZUluc3RhbmNlIiwibG9nIiwiU3lzdGVtTGlua2luZyIsIlN5c3RlbVNvY2tldCIsIkxpbmtpbmdTeXN0ZW0iLCJTb2NrZXRTeXN0ZW0iXSwibWFwcGluZ3MiOiI7UUFBQTtRQUNBOztRQUVBO1FBQ0E7O1FBRUE7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7O1FBRUE7UUFDQTs7UUFFQTtRQUNBOztRQUVBO1FBQ0E7UUFDQTs7O1FBR0E7UUFDQTs7UUFFQTtRQUNBOztRQUVBO1FBQ0E7UUFDQTtRQUNBLDBDQUEwQyxnQ0FBZ0M7UUFDMUU7UUFDQTs7UUFFQTtRQUNBO1FBQ0E7UUFDQSx3REFBd0Qsa0JBQWtCO1FBQzFFO1FBQ0EsaURBQWlELGNBQWM7UUFDL0Q7O1FBRUE7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBO1FBQ0E7UUFDQTtRQUNBLHlDQUF5QyxpQ0FBaUM7UUFDMUUsZ0hBQWdILG1CQUFtQixFQUFFO1FBQ3JJO1FBQ0E7O1FBRUE7UUFDQTtRQUNBO1FBQ0EsMkJBQTJCLDBCQUEwQixFQUFFO1FBQ3ZELGlDQUFpQyxlQUFlO1FBQ2hEO1FBQ0E7UUFDQTs7UUFFQTtRQUNBLHNEQUFz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Q0FBeEI7O0lBRU1ELEU7QUFFTCxnQkFBYztBQUFBO0FBQ2I7Ozs7V0FFRCxtQkFBaUI7QUFDaEIsYUFBTyxVQUFQO0FBQ0E7Ozs7OztBQUlGQSxFQUFFLENBQUN3RCxRQUFILEdBQWdCQSxRQUFoQjtBQUNBeEQsRUFBRSxDQUFDRSxNQUFILEdBQWVBLE1BQWY7QUFDQUYsRUFBRSxDQUFDRSxNQUFILENBQVVDLE9BQVYsR0FBb0JtRSxhQUFwQjtBQUNBdEUsRUFBRSxDQUFDRSxNQUFILENBQVVHLE1BQVYsR0FBbUJrRSxZQUFuQjtBQUVBakUsTUFBTSxDQUFDQyxPQUFQLEdBQWlCUCxFQUFqQixDIiwiZmlsZSI6InIzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuIFx0XHR9XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBjcmVhdGUgYSBmYWtlIG5hbWVzcGFjZSBvYmplY3RcbiBcdC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuIFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXG4gXHQvLyBtb2RlICYgNDogcmV0dXJuIHZhbHVlIHdoZW4gYWxyZWFkeSBucyBvYmplY3RcbiBcdC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcbiBcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XG4gXHRcdGlmKG1vZGUgJiAxKSB2YWx1ZSA9IF9fd2VicGFja19yZXF1aXJlX18odmFsdWUpO1xuIFx0XHRpZihtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuIFx0XHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xuIFx0XHR2YXIgbnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIobnMpO1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XG4gXHRcdGlmKG1vZGUgJiAyICYmIHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykgZm9yKHZhciBrZXkgaW4gdmFsdWUpIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0uYmluZChudWxsLCBrZXkpKTtcbiBcdFx0cmV0dXJuIG5zO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9zcmMvcjMvaW5kZXguanNcIik7XG4iLCJjb25zdCBSMyA9IHJlcXVpcmUoJy4vcjMuanMnKTtcblxuUjMuU3lzdGVtLkxpbmtpbmcuc3RhcnQoKTtcblIzLlN5c3RlbS5Tb2NrZXQuc3RhcnQoKTtcblxubW9kdWxlLmV4cG9ydHMgPSBSMztcbiIsImNvbnN0IFV0aWxzID0gcmVxdWlyZSgncjMtdXRpbHMnKTtcblxuLyoqXG5cbiBPUFRJT05TX1NUQVJUXG4gT1BUSU9OU19FTkRcblxuICoqL1xuXG5jbGFzcyBFdmVudCB7XG5cbiAgLy9DT05TVFJVQ1RPUl9URU1QTEFURV9TVEFSVFxuICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7XG5cbiAgICBFdmVudC5FbWl0KEV2ZW50Lk9CSkVDVF9DUkVBVEVELCB0aGlzKTtcblxuICAgIC8vT1BUSU9OU19JTklUX1NUQVJUXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICBvcHRpb25zID0ge307XG4gICAgfVxuXHRcdC8vT1BUSU9OU19JTklUX0VORFxuXG4gICAgLy9DVVNUT01fT1BUSU9OU19JTklUX1NUQVJUXG4gICAgLy9DVVNUT01fT1BUSU9OU19JTklUX0VORFxuXG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBvcHRpb25zKTtcblxuICAgIC8vQ1VTVE9NX0JFRk9SRV9JTklUX1NUQVJUXG4gICAgLy9DVVNUT01fQkVGT1JFX0lOSVRfRU5EXG5cbiAgICBFdmVudC5FbWl0KEV2ZW50Lk9CSkVDVF9JTklUSUFMSVpFRCwgdGhpcyk7XG4gIH1cblx0Ly9DT05TVFJVQ1RPUl9URU1QTEFURV9FTkRcblxuICAvL0NVU1RPTV9JTVBMRU1FTlRBVElPTl9TVEFSVFxuXG5cdC8qKlxuXHQgKiBTb21lIG5pY2UgRXZlbnRzIGhhbmRsaW5nXG5cdCAqIEB0eXBlIHt7fX1cblx0ICovXG5cdHN0YXRpYyBTdWJzY3JpcHRpb25zID0ge307XG5cblx0c3RhdGljIFN1YnNjcmliZShcblx0XHRldmVudE5hbWUsXG5cdFx0Zm5cblx0KSB7XG5cdFx0LyoqXG5cdFx0ICogVG9kbyAtIG1heWJlIGV2ZW50dWFsbHkgc3RvcmUgYSBib29sZWFuIHdoaWNoIGluZGljYXRlcyBpZiB0aGUgZnVuY3Rpb24gaGFzIGJlZW4gZXhlY3V0ZWRcblx0XHQgKi9cblx0XHRsZXQgc3Vic2NyaXB0aW9uSWQgPSBVdGlscy5SYW5kb21JZCgxMCk7XG5cblx0XHRpZiAoRXZlbnQuU3Vic2NyaXB0aW9ucy5oYXNPd25Qcm9wZXJ0eShldmVudE5hbWUpKSB7XG5cblx0XHRcdGlmIChFdmVudC5TdWJzY3JpcHRpb25zW2V2ZW50TmFtZV1bc3Vic2NyaXB0aW9uSWRdKSB7XG5cdFx0XHRcdHRocm93IG5ldyBFcnJvcignQSBjb21wb25lbnQgY2FuIG9ubHkgc3Vic2NyaWJlIHRvIGEgcGFydGljdWxhciBldmVudCBJRCBvbmNlJyk7XG5cdFx0XHR9XG5cblx0XHRcdEV2ZW50LlN1YnNjcmlwdGlvbnNbZXZlbnROYW1lXVtzdWJzY3JpcHRpb25JZF0gPSBmbjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0RXZlbnQuU3Vic2NyaXB0aW9uc1tldmVudE5hbWVdID0ge307XG5cdFx0XHRFdmVudC5TdWJzY3JpcHRpb25zW2V2ZW50TmFtZV1bc3Vic2NyaXB0aW9uSWRdID0gZm47XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogUmV0dXJuIGEgaGFuZGxlIHRvIHRoZSBjYWxsZXIgdG8gYWxsb3cgdXMgdG8gdW5zdWJzY3JpYmUgdG8gdGhpcyBldmVudFxuXHRcdCAqL1xuXHRcdHJldHVybiB7XG5cdFx0XHRmbjogZm4sXG5cdFx0XHRyZW1vdmU6IGZ1bmN0aW9uIChldmVudElkLCBzdWJzY3JpcHRpb25JZCkge1xuXG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdFx0XHQvKipcblx0XHRcdFx0XHQgKiBTdG9wIGxpc3RlbmluZyBmb3IgdGhpcyBldmVudCBmcm9tIHRoaXMgY29tcG9uZW50XG5cdFx0XHRcdFx0ICovXG5cdFx0XHRcdFx0ZGVsZXRlIEV2ZW50LlN1YnNjcmlwdGlvbnNbZXZlbnRJZF1bc3Vic2NyaXB0aW9uSWRdO1xuXG5cdFx0XHRcdFx0LyoqXG5cdFx0XHRcdFx0ICogSWYgdGhlIGxlbmd0aCBvZiBsaXN0ZW5lcnMgaXMgMCwgc3RvcCByZWZlcmVuY2luZyB0aGlzIGV2ZW50XG5cdFx0XHRcdFx0ICogQHR5cGUge3N0cmluZ1tdfVxuXHRcdFx0XHRcdCAqL1xuXHRcdFx0XHRcdGxldCBsaXN0ZW5lcnMgPSBPYmplY3Qua2V5cyhFdmVudC5TdWJzY3JpcHRpb25zW2V2ZW50SWRdKTtcblx0XHRcdFx0XHRpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHRcdFx0ZGVsZXRlIEV2ZW50LlN1YnNjcmlwdGlvbnNbZXZlbnRJZF07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdH0oZXZlbnROYW1lLCBzdWJzY3JpcHRpb25JZCksXG5cdFx0XHRzdWJzY3JpcHRpb25JZCA6IHN1YnNjcmlwdGlvbklkXG5cdFx0fTtcblx0fTtcblxuXHQvKipcblx0ICogU3Vic2NyaWJlIHRvIHNvbWUgZXZlbnRzXG5cdCAqIEBwYXJhbSBldmVudE5hbWVcblx0ICogQHBhcmFtIGNhbGxiYWNrXG5cdCAqL1xuXHRzdWJzY3JpYmUoXG5cdFx0ZXZlbnROYW1lLFxuXHRcdGNhbGxiYWNrXG5cdCkge1xuXHRcdHJldHVybiBFdmVudC5TdWJzY3JpYmUoZXZlbnROYW1lLCBjYWxsYmFjay5iaW5kKHRoaXMpKTtcblx0fTtcblxuXHQvKipcblx0ICogU3RhdGljIFN5bmNocm9ub3VzIEV2ZW50IC0gQ2FsbHMgY2xpZW50Q2FsbGJhY2sgZGlyZWN0bHkgYWZ0ZXIgdGhlIGV2ZW50IHJlc3VsdCBpcyBvYnRhaW5lZFxuXHQgKiBAcGFyYW0gZXZlbnRJZFxuXHQgKiBAcGFyYW0gZGF0YVxuXHQgKiBAcGFyYW0gY2xpZW50Q2FsbGJhY2sgaXMgZXhlY3V0ZWQgaWRlYWxseSB3aGVuIHRoZSBldmVudCBjb21wbGV0ZWRcblx0ICogQHBhcmFtIGNsaWVudEVycm9yQ2FsbGJhY2tcblx0ICogQHJldHVybnMge251bWJlcn0gb2YgY2FsbGJhY2tzIGV4ZWN1dGVkXG5cdCAqIEBjb25zdHJ1Y3RvclxuXHQgKi9cblx0c3RhdGljIEVtaXQoXG5cdFx0ZXZlbnRJZCxcblx0XHRkYXRhLFxuXHRcdGNsaWVudENhbGxiYWNrLFxuXHRcdGNsaWVudEVycm9yQ2FsbGJhY2tcblx0KSB7XG5cdFx0aWYgKEV2ZW50LlN1YnNjcmlwdGlvbnMuaGFzT3duUHJvcGVydHkoZXZlbnRJZCkpIHtcblxuXHRcdFx0bGV0IHN1YnNjcmlwdGlvbklkcyA9IE9iamVjdC5rZXlzKEV2ZW50LlN1YnNjcmlwdGlvbnNbZXZlbnRJZF0pO1xuXG5cdFx0XHRzdWJzY3JpcHRpb25JZHMubWFwKFxuXHRcdFx0XHRmdW5jdGlvbihzdWJzY3JpcHRpb25JZCkge1xuXHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRsZXQgcmVzdWx0ID0gRXZlbnQuU3Vic2NyaXB0aW9uc1tldmVudElkXVtzdWJzY3JpcHRpb25JZF0oZGF0YSk7XG5cblx0XHRcdFx0XHRcdGlmIChjbGllbnRDYWxsYmFjaykge1xuXHRcdFx0XHRcdFx0XHRjbGllbnRDYWxsYmFjayhyZXN1bHQpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdFx0XHRpZiAoY2xpZW50RXJyb3JDYWxsYmFjaykge1xuXHRcdFx0XHRcdFx0XHRjbGllbnRFcnJvckNhbGxiYWNrKGVycm9yKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuXHRcdFx0XHRcdFx0XHR0aHJvdyBlcnJvcjtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdClcblx0XHR9XG5cdH1cblxuXHRlbWl0KFxuXHRcdGV2ZW50TmFtZSxcblx0XHRkYXRhLFxuXHRcdGNsaWVudENhbGxiYWNrLFxuXHRcdGNsaWVudEVycm9yQ2FsbGJhY2tcblx0KSB7XG5cdFx0cmV0dXJuIEV2ZW50LkVtaXQoXG5cdFx0XHRldmVudE5hbWUsXG5cdFx0XHRkYXRhLFxuXHRcdFx0Y2xpZW50Q2FsbGJhY2ssXG5cdFx0XHRjbGllbnRFcnJvckNhbGxiYWNrXG5cdFx0KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBFeGVjdXRlIHRoZSBmdW5jdGlvbnMgd2hpY2ggc3Vic2NyaWJlIHRvIHRoaXMgZXZlbnQsIGJ1dCBkb24ndCBwcm9jZXNzIHRoZSBjbGllbnQgY2FsbGJhY2sgLSB0aGUgc3Vic2NyaXB0aW9uIGZ1bmN0aW9uXG5cdCAqIHNob3VsZCBleGVjdXRlIHRoZSBjbGllbnQgY2FsbGJhY2tcblx0ICogQHBhcmFtIGV2ZW50SWRcblx0ICogQHBhcmFtIGRhdGFcblx0ICogQHBhcmFtIGNsaWVudENhbGxiYWNrXG5cdCAqIEBwYXJhbSBjbGllbnRFcnJvckNhbGxiYWNrXG5cdCAqIEByZXR1cm5zIHtudW1iZXJ9XG5cdCAqIEBjb25zdHJ1Y3RvclxuXHQgKi9cblx0c3RhdGljIEFzeW5jKFxuXHRcdGV2ZW50SWQsXG5cdFx0ZGF0YSxcblx0XHRjbGllbnRDYWxsYmFjayxcblx0XHRjbGllbnRFcnJvckNhbGxiYWNrXG5cdCkge1xuXHRcdGlmIChFdmVudC5TdWJzY3JpcHRpb25zLmhhc093blByb3BlcnR5KGV2ZW50SWQpKSB7XG5cblx0XHRcdGxldCBzdWJzY3JpcHRpb25JZHMgPSBPYmplY3Qua2V5cyhFdmVudC5TdWJzY3JpcHRpb25zW2V2ZW50SWRdKTtcblxuXHRcdFx0c3Vic2NyaXB0aW9uSWRzLm1hcChcblx0XHRcdFx0ZnVuY3Rpb24oc3Vic2NyaXB0aW9uSWQpIHtcblx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0RXZlbnQuU3Vic2NyaXB0aW9uc1tldmVudElkXVtzdWJzY3JpcHRpb25JZF0oZGF0YSwgY2xpZW50Q2FsbGJhY2ssIGNsaWVudEVycm9yQ2FsbGJhY2spO1xuXHRcdFx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdFx0XHRpZiAoY2xpZW50RXJyb3JDYWxsYmFjaykge1xuXHRcdFx0XHRcdFx0XHRjbGllbnRFcnJvckNhbGxiYWNrKGVycm9yKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuXHRcdFx0XHRcdFx0XHR0aHJvdyBlcnJvcjtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdClcblx0XHR9XG5cdH07XG4gIC8vQ1VTVE9NX0lNUExFTUVOVEFUSU9OX0VORFxuXG59XG5cbi8vQ1VTVE9NX09VVF9PRl9DTEFTU19JTVBMRU1FTlRBVElPTl9TVEFSVFxuXG4vL0VWRU5UX0dFTkVSQVRFRF9TVEFSVFxuRXZlbnQuQ09NUE9ORU5UX0lOSVRJQUxJWkVEID0gMHgxO1xuRXZlbnQuQ1JFQVRFX0lOU1RBTkNFX0JFRk9SRSA9IDB4MjtcbkV2ZW50LkRJU1BPU0VfSU5TVEFOQ0UgPSAweDM7XG5FdmVudC5ESVNQT1NFX09CSkVDVCA9IDB4NDtcbkV2ZW50LkdFVF9SVU5USU1FID0gMHg1O1xuRXZlbnQuR0VUX1dJTkRPV19TSVpFID0gMHg2O1xuRXZlbnQuSU5TVEFOQ0VfQ1JFQVRFRCA9IDB4NztcbkV2ZW50LklOU1RBTkNFX0RJU1BPU0VEID0gMHg4O1xuRXZlbnQuT0JKRUNUX0NSRUFURUQgPSAweDk7XG5FdmVudC5PQkpFQ1RfSU5JVElBTElaRUQgPSAweGE7XG5FdmVudC5QQVVTRSA9IDB4YjtcbkV2ZW50LlJFU1RBUlQgPSAweGM7XG5FdmVudC5TVEFSVCA9IDB4ZDtcbkV2ZW50LlVQREFURV9GUk9NX0lOU1RBTkNFX0FGVEVSID0gMHhlO1xuRXZlbnQuVVBEQVRFX0ZST01fSU5TVEFOQ0VfQkVGT1JFID0gMHhmO1xuRXZlbnQuVVBEQVRFX0lOU1RBTkNFX0FGVEVSID0gMHgxMDtcbkV2ZW50LlVQREFURV9JTlNUQU5DRV9CRUZPUkUgPSAweDExO1xuRXZlbnQuTUFYX0VWRU5UUyA9IDB4MTI7XG5cbkV2ZW50LkdldEV2ZW50TmFtZSA9IGZ1bmN0aW9uKGV2ZW50SWQpIHtcblxuXHRzd2l0Y2goZXZlbnRJZCkge1xuXHRcdGNhc2UgMHgxIDogcmV0dXJuICdjb21wb25lbnRfaW5pdGlhbGl6ZWQnO1xuXHRcdGNhc2UgMHgyIDogcmV0dXJuICdjcmVhdGVfaW5zdGFuY2VfYmVmb3JlJztcblx0XHRjYXNlIDB4MyA6IHJldHVybiAnZGlzcG9zZV9pbnN0YW5jZSc7XG5cdFx0Y2FzZSAweDQgOiByZXR1cm4gJ2Rpc3Bvc2Vfb2JqZWN0Jztcblx0XHRjYXNlIDB4NSA6IHJldHVybiAnZ2V0X3J1bnRpbWUnO1xuXHRcdGNhc2UgMHg2IDogcmV0dXJuICdnZXRfd2luZG93X3NpemUnO1xuXHRcdGNhc2UgMHg3IDogcmV0dXJuICdpbnN0YW5jZV9jcmVhdGVkJztcblx0XHRjYXNlIDB4OCA6IHJldHVybiAnaW5zdGFuY2VfZGlzcG9zZWQnO1xuXHRcdGNhc2UgMHg5IDogcmV0dXJuICdvYmplY3RfY3JlYXRlZCc7XG5cdFx0Y2FzZSAweGEgOiByZXR1cm4gJ29iamVjdF9pbml0aWFsaXplZCc7XG5cdFx0Y2FzZSAweGIgOiByZXR1cm4gJ3BhdXNlJztcblx0XHRjYXNlIDB4YyA6IHJldHVybiAncmVzdGFydCc7XG5cdFx0Y2FzZSAweGQgOiByZXR1cm4gJ3N0YXJ0Jztcblx0XHRjYXNlIDB4ZSA6IHJldHVybiAndXBkYXRlX2Zyb21faW5zdGFuY2VfYWZ0ZXInO1xuXHRcdGNhc2UgMHhmIDogcmV0dXJuICd1cGRhdGVfZnJvbV9pbnN0YW5jZV9iZWZvcmUnO1xuXHRcdGNhc2UgMHgxMCA6IHJldHVybiAndXBkYXRlX2luc3RhbmNlX2FmdGVyJztcblx0XHRjYXNlIDB4MTEgOiByZXR1cm4gJ3VwZGF0ZV9pbnN0YW5jZV9iZWZvcmUnO1xuXHRcdGRlZmF1bHQgOlxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdFdmVudCB0eXBlIG5vdCBkZWZpbmVkIDogJyArIGV2ZW50SWQpO1xuXHR9XG5cbn07XG4vL0VWRU5UX0dFTkVSQVRFRF9FTkRcblxuLy9DVVNUT01fT1VUX09GX0NMQVNTX0lNUExFTUVOVEFUSU9OX0VORFxuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50OyIsImNvbnN0IFV0aWxzID0gcmVxdWlyZSgncjMtdXRpbHMnKTtcbmNvbnN0IEV2ZW50ID0gcmVxdWlyZSgncjMtZXZlbnQuanMnKTtcblxuLyoqXG5cbiBPUFRJT05TX1NUQVJUXG4gaWQ9VXRpbHMuUmFuZG9tSWQoMTApXG4gbmFtZT10aGlzLmNvbnN0cnVjdG9yLm5hbWUgKyAnKCcgKyBvcHRpb25zLmlkICsgJyknXG4gcmVnaXN0ZXI9dHJ1ZVxuIE9QVElPTlNfRU5EXG5cbiBJTlNUQU5DRV9PUFRJT05TX01BUFBJTkdfU1RBUlRcbiBJTlNUQU5DRV9PUFRJT05TX01BUFBJTkdfRU5EXG5cbiBMSU5LRURfT0JKRUNUU19TVEFSVFxuIExJTktFRF9PQkpFQ1RTX0VORFxuXG4gRVhDTFVERURfRlJPTV9JTlNUQU5DRV9PUFRJT05TX1NUQVJUXG4gaWRcbiBuYW1lXG4gcmVnaXN0ZXJcbiBFWENMVURFRF9GUk9NX0lOU1RBTkNFX09QVElPTlNfRU5EXG5cbiAqKi9cblxuY2xhc3MgUjNPYmplY3QgZXh0ZW5kcyBFdmVudCB7XG5cbiAgLy9DT05TVFJVQ1RPUl9FWFRFTkRTX1RFTVBMQVRFX1NUQVJUXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnMpIHtcblxuICAgIGlmIChVdGlscy5VbmRlZmluZWRPck51bGwob3B0aW9ucykpIHtcbiAgICAgIG9wdGlvbnMgPSB7fTtcbiAgICB9XG5cbiAgICBzdXBlcihvcHRpb25zKTtcblxuICAgIHRoaXMuZW1pdChFdmVudC5PQkpFQ1RfQ1JFQVRFRCwgdGhpcyk7XG5cbiAgICAvL09QVElPTlNfSU5JVF9TVEFSVFxuICAgIGlmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgb3B0aW9ucyA9IHt9O1xuICAgIH1cbiAgICBpZiAoVXRpbHMuVW5kZWZpbmVkT3JOdWxsKG9wdGlvbnMuaWQpKSB7XG4gICAgICBvcHRpb25zLmlkID0gVXRpbHMuUmFuZG9tSWQoMTApO1xuICAgIH1cbiAgICBpZiAoVXRpbHMuVW5kZWZpbmVkT3JOdWxsKG9wdGlvbnMubmFtZSkpIHtcbiAgICAgIG9wdGlvbnMubmFtZSA9IHRoaXMuY29uc3RydWN0b3IubmFtZSArICcoJyArIG9wdGlvbnMuaWQgKyAnKSc7XG4gICAgfVxuICAgIGlmIChVdGlscy5VbmRlZmluZWRPck51bGwob3B0aW9ucy5yZWdpc3RlcikpIHtcbiAgICAgIG9wdGlvbnMucmVnaXN0ZXIgPSB0cnVlO1xuICAgIH1cblx0XHQvL09QVElPTlNfSU5JVF9FTkRcblxuICAgIC8vQ1VTVE9NX09QVElPTlNfSU5JVF9TVEFSVFxuICAgIC8vQ1VTVE9NX09QVElPTlNfSU5JVF9FTkRcblxuICAgIE9iamVjdC5hc3NpZ24odGhpcywgb3B0aW9ucyk7XG5cbiAgICAvL0NVU1RPTV9CRUZPUkVfSU5JVF9TVEFSVFxuICAgIC8vQ1VTVE9NX0JFRk9SRV9JTklUX0VORFxuXG4gICAgdGhpcy5lbWl0KEV2ZW50Lk9CSkVDVF9JTklUSUFMSVpFRCwgdGhpcyk7XG4gIH1cblx0Ly9DT05TVFJVQ1RPUl9FWFRFTkRTX1RFTVBMQVRFX0VORFxuXG4gIC8vQ1JFQVRFX0lOU1RBTkNFX1RFTVBMQVRFX1NUQVJUXG4gIGNyZWF0ZUluc3RhbmNlKCkge1xuXG4gICAgLy9DUkVBVEVfSU5TVEFOQ0VfQkVGT1JFX1NUQVJUXG4gICAgdGhpcy5lbWl0KEV2ZW50LkNSRUFURV9JTlNUQU5DRV9CRUZPUkUsIHRoaXMpO1xuXHRcdC8vQ1JFQVRFX0lOU1RBTkNFX0JFRk9SRV9FTkRcblxuICAgIC8vQ1VTVE9NX0NSRUFURV9JTlNUQU5DRV9TVEFSVFxuICAgIC8vQ1VTVE9NX0NSRUFURV9JTlNUQU5DRV9FTkRcblxuICAgIC8vQ1JFQVRFX0lOU1RBTkNFX0FGVEVSX1NUQVJUXG4gICAgdGhpc1t0aGlzLnJ1bnRpbWVdLmNyZWF0ZUluc3RhbmNlKFxuICAgICAgdGhpcyxcbiAgICAgIHtcbiAgICAgICAgLy9DUkVBVEVfSU5TVEFOQ0VfT1BUSU9OU19TVEFSVFxuICAgICAgICAvL0NSRUFURV9JTlNUQU5DRV9PUFRJT05TX0VORFxuICAgICAgfVxuICAgIClcblxuICAgIHRoaXMuZW1pdChFdmVudC5JTlNUQU5DRV9DUkVBVEVELCB0aGlzKTtcblx0XHQvL0NSRUFURV9JTlNUQU5DRV9BRlRFUl9FTkRcblxuICB9XG5cdC8vQ1JFQVRFX0lOU1RBTkNFX1RFTVBMQVRFX0VORFxuXG4gIC8vVVBEQVRFX0lOU1RBTkNFX1RFTVBMQVRFX1NUQVJUXG4gIHVwZGF0ZUluc3RhbmNlKHByb3BlcnR5KSB7XG5cbiAgICAvL1VQREFURV9JTlNUQU5DRV9CRUZPUkVfU1RBUlRcbiAgICB0aGlzLmVtaXQoRXZlbnQuVVBEQVRFX0lOU1RBTkNFX0JFRk9SRSwgdGhpcyk7XG5cdFx0Ly9VUERBVEVfSU5TVEFOQ0VfQkVGT1JFX0VORFxuXG4gICAgLy9VUERBVEVfSU5TVEFOQ0VfT1BUSU9OU19TVEFSVFxuXHRcdC8vVVBEQVRFX0lOU1RBTkNFX09QVElPTlNfRU5EXG5cbiAgICAvL0NVU1RPTV9VUERBVEVfSU5TVEFOQ0VfU1RBUlRcbiAgICAvL0NVU1RPTV9VUERBVEVfSU5TVEFOQ0VfRU5EXG5cbiAgICAvL1VQREFURV9JTlNUQU5DRV9BRlRFUl9TVEFSVFxuICAgIHRoaXMuZW1pdChFdmVudC5VUERBVEVfSU5TVEFOQ0VfQUZURVIsIHRoaXMpO1xuXHRcdC8vVVBEQVRFX0lOU1RBTkNFX0FGVEVSX0VORFxuXG4gIH1cblx0Ly9VUERBVEVfSU5TVEFOQ0VfVEVNUExBVEVfRU5EXG5cbiAgLy9VUERBVEVfRlJPTV9JTlNUQU5DRV9URU1QTEFURV9TVEFSVFxuICB1cGRhdGVGcm9tSW5zdGFuY2UocHJvcGVydHkpIHtcblxuICAgIC8vVVBEQVRFX0ZST01fSU5TVEFOQ0VfQkVGT1JFX1NUQVJUXG4gICAgdGhpcy5lbWl0KEV2ZW50LlVQREFURV9GUk9NX0lOU1RBTkNFX0JFRk9SRSwgdGhpcyk7XG5cdFx0Ly9VUERBVEVfRlJPTV9JTlNUQU5DRV9CRUZPUkVfRU5EXG5cbiAgICAvL1VQREFURV9GUk9NX0lOU1RBTkNFX09QVElPTlNfU1RBUlRcblx0XHQvL1VQREFURV9GUk9NX0lOU1RBTkNFX09QVElPTlNfRU5EXG5cbiAgICAvL0NVU1RPTV9VUERBVEVfRlJPTV9JTlNUQU5DRV9TVEFSVFxuICAgIC8vQ1VTVE9NX1VQREFURV9GUk9NX0lOU1RBTkNFX0VORFxuXG4gICAgLy9VUERBVEVfRlJPTV9JTlNUQU5DRV9BRlRFUl9TVEFSVFxuICAgIHRoaXMuZW1pdChFdmVudC5VUERBVEVfRlJPTV9JTlNUQU5DRV9BRlRFUiwgdGhpcyk7XG5cdFx0Ly9VUERBVEVfRlJPTV9JTlNUQU5DRV9BRlRFUl9FTkRcblxuICB9XG5cdC8vVVBEQVRFX0ZST01fSU5TVEFOQ0VfVEVNUExBVEVfRU5EXG5cbiAgLy9ESVNQT1NFX1RFTVBMQVRFX1NUQVJUXG4gIGRpc3Bvc2UoKSB7XG5cbiAgICAvL0RJU1BPU0VfQkVGT1JFX1NUQVJUXG4gICAgdGhpcy5zdWJzY3JpYmUoXG4gICAgICBFdmVudC5JTlNUQU5DRV9ESVNQT1NFRCxcbiAgICAgIGZ1bmN0aW9uKG9iamVjdCkge1xuICAgICAgICBpZiAob2JqZWN0ID09PSB0aGlzKSB7XG4gICAgICAgICAgdGhpcy5lbWl0KEV2ZW50LkRJU1BPU0VfT0JKRUNULCB0aGlzKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG5cdFx0Ly9ESVNQT1NFX0JFRk9SRV9FTkRcblxuICAgIC8vQ1VTVE9NX0RJU1BPU0VfU1RBUlRcbiAgICAvL0NVU1RPTV9ESVNQT1NFX0VORFxuXG4gICAgLy9ESVNQT1NFX0FGVEVSX1NUQVJUXG4gICAgdGhpcy5kaXNwb3NlSW5zdGFuY2UoKTtcblx0XHQvL0RJU1BPU0VfQUZURVJfRU5EXG5cbiAgfVxuXHQvL0RJU1BPU0VfVEVNUExBVEVfRU5EXG5cbiAgLy9ESVNQT1NFX0lOU1RBTkNFX1RFTVBMQVRFX1NUQVJUXG4gIGRpc3Bvc2VJbnN0YW5jZSgpIHtcblxuICAgIC8vRElTUE9TRV9JTlNUQU5DRV9CRUZPUkVfU1RBUlRcbiAgICBjb25zb2xlLmxvZygnRGlzcG9zaW5nIGluc3RhbmNlIG9mICcgKyB0aGlzLm5hbWUpO1xuXHRcdC8vRElTUE9TRV9JTlNUQU5DRV9CRUZPUkVfRU5EXG5cbiAgICAvL0NVU1RPTV9ESVNQT1NFX0lOU1RBTkNFX1NUQVJUXG4gICAgLy9DVVNUT01fRElTUE9TRV9JTlNUQU5DRV9FTkRcblxuICAgIC8vRElTUE9TRV9JTlNUQU5DRV9BRlRFUl9TVEFSVFxuICAgIHRoaXMuZW1pdChFdmVudC5ESVNQT1NFX0lOU1RBTkNFLCB0aGlzKTtcblx0XHQvL0RJU1BPU0VfSU5TVEFOQ0VfQUZURVJfRU5EXG5cbiAgfVxuXHQvL0RJU1BPU0VfSU5TVEFOQ0VfVEVNUExBVEVfRU5EXG5cbiAgLy9DVVNUT01fSU1QTEVNRU5UQVRJT05fU1RBUlRcbiAgLy9DVVNUT01fSU1QTEVNRU5UQVRJT05fRU5EXG5cbn1cblxuLy9DVVNUT01fT1VUX09GX0NMQVNTX0lNUExFTUVOVEFUSU9OX1NUQVJUXG4vL0NVU1RPTV9PVVRfT0ZfQ0xBU1NfSU1QTEVNRU5UQVRJT05fRU5EXG5cbm1vZHVsZS5leHBvcnRzID0gUjNPYmplY3Q7IiwiY29uc3QgU3lzdGVtID0gcmVxdWlyZSgnLi9yMy1zeXN0ZW0uanMnKTtcbmNvbnN0IFN5c3RlbUxpbmtpbmcgPSByZXF1aXJlKCcuL3IzLXN5c3RlbS1saW5raW5nLmpzJyk7XG5jb25zdCBTeXN0ZW1Tb2NrZXQgPSByZXF1aXJlKCcuL3IzLXN5c3RlbS1zb2NrZXQuanMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIFN5c3RlbSxcbiAgU3lzdGVtTGlua2luZyxcbiAgU3lzdGVtU29ja2V0XG59IiwiY29uc3QgU3lzdGVtID0gcmVxdWlyZSgnLi9yMy1zeXN0ZW0nKTtcbmNvbnN0IFIzT2JqZWN0ID0gcmVxdWlyZSgnLi4vcjMtcjMtb2JqZWN0Jyk7XG5jb25zdCBFdmVudCA9IHJlcXVpcmUoJy4uL3IzLWV2ZW50Jyk7XG5cbmNsYXNzIExpbmtpbmdTeXN0ZW0gZXh0ZW5kcyBTeXN0ZW0ge1xuXG5cdHN0YXRpYyBzdGFydCgpIHtcblxuXHRcdHN1cGVyLnN0YXJ0KCk7XG5cdFx0XG5cdFx0Y29uc29sZS5sb2coJ3N0YXJ0aW5nIGxpbmtpbmcgc3lzdGVtJyk7XG5cblx0XHRFdmVudC5TdWJzY3JpYmUoXG5cdFx0XHRFdmVudC5PQkpFQ1RfQ1JFQVRFRCxcblx0XHRcdCgpID0+IHtcblx0XHRcdFx0Y29uc29sZS5sb2coJ2xpbmtpbmcgc3lzdGVtIGRpc2NvdmVyZWQgYW4gb2JqZWN0Jyk7XG5cdFx0XHR9XG5cdFx0KTtcblxuXHRcdGxldCBvYmplY3QgPSBuZXcgUjNPYmplY3QoKTtcblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cdFxuXG59XG5cbm1vZHVsZS5leHBvcnRzID0gTGlua2luZ1N5c3RlbTtcbiIsImNvbnN0IFN5c3RlbSA9IHJlcXVpcmUoJy4vcjMtc3lzdGVtLmpzJyk7XG5cbmNsYXNzIFNvY2tldFN5c3RlbSBleHRlbmRzIFN5c3RlbSB7XG5cblx0c3RhdGljIHN0YXJ0KCkge1xuXG5cdFx0c3VwZXIuc3RhcnQoKTtcblx0XHRcblx0XHRjb25zb2xlLmxvZygnc3RhcnRpbmcgc29ja2V0IHN5c3RlbScpO1xuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG59XG5cbm1vZHVsZS5leHBvcnRzID0gU29ja2V0U3lzdGVtOyIsImNsYXNzIFN5c3RlbSB7XG5cblx0c3RhdGljIHN0YXJ0KCkge1xuXHRcdGNvbnNvbGUubG9nKCdzdGFydGluZyBhIHN5c3RlbScpO1x0XG5cdH1cblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFN5c3RlbTtcbiIsImNvbnN0IHtTeXN0ZW0sIFN5c3RlbUxpbmtpbmcsIFN5c3RlbVNvY2tldH0gPSByZXF1aXJlKCcuL3IzLXN5c3RlbScpO1xuY29uc3QgUjNPYmplY3QgPSByZXF1aXJlKCcuL3IzLXIzLW9iamVjdCcpO1xuXG5jbGFzcyBSMyB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cdH1cblxuXHRzdGF0aWMgdmVyc2lvbigpIHtcblx0XHRyZXR1cm4gJ19fREFURV9fJztcblx0fVxuXG59XG5cblIzLlIzT2JqZWN0IFx0XHQ9IFIzT2JqZWN0O1xuUjMuU3lzdGVtIFx0XHRcdD0gU3lzdGVtO1xuUjMuU3lzdGVtLkxpbmtpbmdcdD0gU3lzdGVtTGlua2luZztcblIzLlN5c3RlbS5Tb2NrZXRcdD0gU3lzdGVtU29ja2V0O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFIzO1xuIl0sInNvdXJjZVJvb3QiOiIifQ==
\ No newline at end of file
diff --git a/src/r3/r3-vector-applier-again.js b/src/r3/r3-component.js
similarity index 67%
rename from src/r3/r3-vector-applier-again.js
rename to src/r3/r3-component.js
index fcbba54..201c0d4 100644
--- a/src/r3/r3-vector-applier-again.js
+++ b/src/r3/r3-component.js
@@ -1,12 +1,11 @@
+const Event = require('r3-event');
const Utils = require('r3-utils');
-const Event = require('r3-event.js');
+const R3Object = require('r3-r3-object.js');
/**
OPTIONS_START
- a=2.0
- b=3.0
- something='hello'
+ runtime='default'
OPTIONS_END
INSTANCE_OPTIONS_MAPPING_START
@@ -16,12 +15,12 @@ const Event = require('r3-event.js');
LINKED_OBJECTS_END
EXCLUDED_FROM_INSTANCE_OPTIONS_START
- b
+ runtime
EXCLUDED_FROM_INSTANCE_OPTIONS_END
**/
-class VectorApplierAgain extends Event {
+class Component extends R3Object {
//CONSTRUCTOR_EXTENDS_TEMPLATE_START
constructor(options) {
@@ -30,22 +29,16 @@ class VectorApplierAgain extends Event {
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'VectorApplierAgain (' + options.id + ')';
-
super(options);
this.emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
- if (Utils.UndefinedOrNull(options.a)) {
- options.a = 2.0;
+ if (typeof options === 'undefined') {
+ options = {};
}
- if (Utils.UndefinedOrNull(options.b)) {
- options.b = 3.0;
- }
- if (Utils.UndefinedOrNull(options.something)) {
- options.something = 'hello';
+ if (Utils.UndefinedOrNull(options.runtime)) {
+ options.runtime = 'default';
}
//OPTIONS_INIT_END
@@ -55,6 +48,7 @@ class VectorApplierAgain extends Event {
Object.assign(this, options);
//CUSTOM_BEFORE_INIT_START
+ this.emit(Event.COMPONENT_INITIALIZED, this);
//CUSTOM_BEFORE_INIT_END
this.emit(Event.OBJECT_INITIALIZED, this);
@@ -65,26 +59,21 @@ class VectorApplierAgain extends Event {
createInstance() {
//CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
- 'a': this.a,
- 'something': this.something
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this);
//CREATE_INSTANCE_BEFORE_END
//CUSTOM_CREATE_INSTANCE_START
//CUSTOM_CREATE_INSTANCE_END
//CREATE_INSTANCE_AFTER_START
+ this[this.runtime].createInstance(
+ this,
+ {
+ //CREATE_INSTANCE_OPTIONS_START
+ //CREATE_INSTANCE_OPTIONS_END
+ }
+ )
+
this.emit(Event.INSTANCE_CREATED, this);
//CREATE_INSTANCE_AFTER_END
@@ -99,14 +88,6 @@ class VectorApplierAgain extends Event {
//UPDATE_INSTANCE_BEFORE_END
//UPDATE_INSTANCE_OPTIONS_START
- if (property === 'a') {
- this.instance.a = this.a;
- return;
- }
- if (property === 'something') {
- this.instance.something = this.something;
- return;
- }
//UPDATE_INSTANCE_OPTIONS_END
//CUSTOM_UPDATE_INSTANCE_START
@@ -127,14 +108,6 @@ class VectorApplierAgain extends Event {
//UPDATE_FROM_INSTANCE_BEFORE_END
//UPDATE_FROM_INSTANCE_OPTIONS_START
- if (property === 'a') {
- this.a = this.instance.a;
- return;
- }
- if (property === 'something') {
- this.something = this.instance.something;
- return;
- }
//UPDATE_FROM_INSTANCE_OPTIONS_END
//CUSTOM_UPDATE_FROM_INSTANCE_START
@@ -151,14 +124,21 @@ class VectorApplierAgain extends Event {
dispose() {
//DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
+ this.subscribe(
+ Event.INSTANCE_DISPOSED,
+ function(object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }
+ );
//DISPOSE_BEFORE_END
//CUSTOM_DISPOSE_START
//CUSTOM_DISPOSE_END
//DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
+ this.disposeInstance();
//DISPOSE_AFTER_END
}
@@ -168,15 +148,14 @@ class VectorApplierAgain extends Event {
disposeInstance() {
//DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
+ console.log('Disposing instance of ' + this.name);
//DISPOSE_INSTANCE_BEFORE_END
//CUSTOM_DISPOSE_INSTANCE_START
//CUSTOM_DISPOSE_INSTANCE_END
//DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
+ this.emit(Event.DISPOSE_INSTANCE, this);
//DISPOSE_INSTANCE_AFTER_END
}
@@ -190,4 +169,4 @@ class VectorApplierAgain extends Event {
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END
-module.exports = VectorApplierAgain;
\ No newline at end of file
+module.exports = Component;
\ No newline at end of file
diff --git a/src/r3/r3-event.bak.js b/src/r3/r3-event.bak.js
deleted file mode 100644
index 48aa5fa..0000000
--- a/src/r3/r3-event.bak.js
+++ /dev/null
@@ -1,60 +0,0 @@
-const Utils = require('./r3-utils');
-
-class Event {
-
- constructor(options) {
- console.log('Event created');
- }
-
-
-
-}
-
-//EVENT_GENERATED_START
-Event.CREATE_INSTANCE = 0x1;
-Event.DISPOSE_INSTANCE = 0x2;
-Event.DISPOSE_OBJECT = 0x3;
-Event.GET_RUNTIME = 0x4;
-Event.GET_WINDOW_SIZE = 0x5;
-Event.INSTANCE_CREATED = 0x6;
-Event.INSTANCE_DISPOSED = 0x7;
-Event.OBJECT_CREATED = 0x8;
-Event.OBJECT_DISPOSED = 0x9;
-Event.OBJECT_INITIALIZED = 0xa;
-Event.PAUSE = 0xb;
-Event.RESTART = 0xc;
-Event.START = 0xd;
-Event.UPDATE_FROM_INSTANCE_AFTER = 0xe;
-Event.UPDATE_FROM_INSTANCE_BEFORE = 0xf;
-Event.UPDATE_INSTANCE_AFTER = 0x10;
-Event.UPDATE_INSTANCE_BEFORE = 0x11;
-Event.MAX_EVENTS = 0x12;
-
-Event.GetEventName = function(eventId) {
-
- switch(eventId) {
- case 0x1 : return 'create_instance';
- case 0x2 : return 'dispose_instance';
- case 0x3 : return 'dispose_object';
- case 0x4 : return 'get_runtime';
- case 0x5 : return 'get_window_size';
- case 0x6 : return 'instance_created';
- case 0x7 : return 'instance_disposed';
- case 0x8 : return 'object_created';
- case 0x9 : return 'object_disposed';
- case 0xa : return 'object_initialized';
- case 0xb : return 'pause';
- case 0xc : return 'restart';
- case 0xd : return 'start';
- case 0xe : return 'update_from_instance_after';
- case 0xf : return 'update_from_instance_before';
- case 0x10 : return 'update_instance_after';
- case 0x11 : return 'update_instance_before';
- default :
- throw new Error('Event type not defined : ' + eventId);
- }
-
-};
-//EVENT_GENERATED_END
-
-module.exports = Event;
diff --git a/src/r3/r3-event.js b/src/r3/r3-event.js
index 01f62bd..de8d73d 100644
--- a/src/r3/r3-event.js
+++ b/src/r3/r3-event.js
@@ -1,4 +1,3 @@
-const Event = require('r3-event');
const Utils = require('r3-utils');
/**
@@ -6,15 +5,6 @@ const Utils = require('r3-utils');
OPTIONS_START
OPTIONS_END
- INSTANCE_OPTIONS_MAPPING_START
- INSTANCE_OPTIONS_MAPPING_END
-
- LINKED_OBJECTS_START
- LINKED_OBJECTS_END
-
- EXCLUDED_FROM_INSTANCE_OPTIONS_START
- EXCLUDED_FROM_INSTANCE_OPTIONS_END
-
**/
class Event {
@@ -22,16 +12,12 @@ class Event {
//CONSTRUCTOR_TEMPLATE_START
constructor(options) {
- if (Utils.UndefinedOrNull(options)) {
- options = {};
- }
-
- options.id = Utils.RandomId(10);
- options.name = 'Event (' + options.id + ')';
-
Event.Emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
+ if (typeof options === 'undefined') {
+ options = {};
+ }
//OPTIONS_INIT_END
//CUSTOM_OPTIONS_INIT_START
@@ -46,110 +32,6 @@ class Event {
}
//CONSTRUCTOR_TEMPLATE_END
- //CREATE_INSTANCE_TEMPLATE_START
- createInstance() {
-
- //CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
-
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
- //CREATE_INSTANCE_BEFORE_END
-
- //CUSTOM_CREATE_INSTANCE_START
- //CUSTOM_CREATE_INSTANCE_END
-
- //CREATE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_CREATED, this);
- //CREATE_INSTANCE_AFTER_END
-
- }
- //CREATE_INSTANCE_TEMPLATE_END
-
- //UPDATE_INSTANCE_TEMPLATE_START
- updateInstance(property) {
-
- //UPDATE_INSTANCE_BEFORE_START
- this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
- //UPDATE_INSTANCE_BEFORE_END
-
- //UPDATE_INSTANCE_OPTIONS_START
- //UPDATE_INSTANCE_OPTIONS_END
-
- //CUSTOM_UPDATE_INSTANCE_START
- //CUSTOM_UPDATE_INSTANCE_END
-
- //UPDATE_INSTANCE_AFTER_START
- this.emit(Event.UPDATE_INSTANCE_AFTER, this);
- //UPDATE_INSTANCE_AFTER_END
-
- }
- //UPDATE_INSTANCE_TEMPLATE_END
-
- //UPDATE_FROM_INSTANCE_TEMPLATE_START
- updateFromInstance(property) {
-
- //UPDATE_FROM_INSTANCE_BEFORE_START
- this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
- //UPDATE_FROM_INSTANCE_BEFORE_END
-
- //UPDATE_FROM_INSTANCE_OPTIONS_START
- //UPDATE_FROM_INSTANCE_OPTIONS_END
-
- //CUSTOM_UPDATE_FROM_INSTANCE_START
- //CUSTOM_UPDATE_FROM_INSTANCE_END
-
- //UPDATE_FROM_INSTANCE_AFTER_START
- this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
- //UPDATE_FROM_INSTANCE_AFTER_END
-
- }
- //UPDATE_FROM_INSTANCE_TEMPLATE_END
-
- //DISPOSE_TEMPLATE_START
- dispose() {
-
- //DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
- //DISPOSE_BEFORE_END
-
- //CUSTOM_DISPOSE_START
- //CUSTOM_DISPOSE_END
-
- //DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
- //DISPOSE_AFTER_END
-
- }
- //DISPOSE_TEMPLATE_END
-
- //DISPOSE_INSTANCE_TEMPLATE_START
- disposeInstance() {
-
- //DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
- //DISPOSE_INSTANCE_BEFORE_END
-
- //CUSTOM_DISPOSE_INSTANCE_START
- //CUSTOM_DISPOSE_INSTANCE_END
-
- //DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
- //DISPOSE_INSTANCE_AFTER_END
-
- }
- //DISPOSE_INSTANCE_TEMPLATE_END
-
//CUSTOM_IMPLEMENTATION_START
/**
@@ -317,15 +199,15 @@ class Event {
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
//EVENT_GENERATED_START
-Event.CREATE_INSTANCE = 0x1;
-Event.DISPOSE_INSTANCE = 0x2;
-Event.DISPOSE_OBJECT = 0x3;
-Event.GET_RUNTIME = 0x4;
-Event.GET_WINDOW_SIZE = 0x5;
-Event.INSTANCE_CREATED = 0x6;
-Event.INSTANCE_DISPOSED = 0x7;
-Event.OBJECT_CREATED = 0x8;
-Event.OBJECT_DISPOSED = 0x9;
+Event.COMPONENT_INITIALIZED = 0x1;
+Event.CREATE_INSTANCE_BEFORE = 0x2;
+Event.DISPOSE_INSTANCE = 0x3;
+Event.DISPOSE_OBJECT = 0x4;
+Event.GET_RUNTIME = 0x5;
+Event.GET_WINDOW_SIZE = 0x6;
+Event.INSTANCE_CREATED = 0x7;
+Event.INSTANCE_DISPOSED = 0x8;
+Event.OBJECT_CREATED = 0x9;
Event.OBJECT_INITIALIZED = 0xa;
Event.PAUSE = 0xb;
Event.RESTART = 0xc;
@@ -339,15 +221,15 @@ Event.MAX_EVENTS = 0x12;
Event.GetEventName = function(eventId) {
switch(eventId) {
- case 0x1 : return 'create_instance';
- case 0x2 : return 'dispose_instance';
- case 0x3 : return 'dispose_object';
- case 0x4 : return 'get_runtime';
- case 0x5 : return 'get_window_size';
- case 0x6 : return 'instance_created';
- case 0x7 : return 'instance_disposed';
- case 0x8 : return 'object_created';
- case 0x9 : return 'object_disposed';
+ case 0x1 : return 'component_initialized';
+ case 0x2 : return 'create_instance_before';
+ case 0x3 : return 'dispose_instance';
+ case 0x4 : return 'dispose_object';
+ case 0x5 : return 'get_runtime';
+ case 0x6 : return 'get_window_size';
+ case 0x7 : return 'instance_created';
+ case 0x8 : return 'instance_disposed';
+ case 0x9 : return 'object_created';
case 0xa : return 'object_initialized';
case 0xb : return 'pause';
case 0xc : return 'restart';
diff --git a/src/r3/r3-another-class.js b/src/r3/r3-project.js
similarity index 62%
rename from src/r3/r3-another-class.js
rename to src/r3/r3-project.js
index 69204d8..87ff87f 100644
--- a/src/r3/r3-another-class.js
+++ b/src/r3/r3-project.js
@@ -5,28 +5,26 @@ const R3Object = require('r3-r3-object.js');
/**
OPTIONS_START
- x=1
- y=2
- z=3
- register=true
+ isPublic=true
+ applicationMode=Project.APPLICATION_MODE_EDIT
OPTIONS_END
INSTANCE_OPTIONS_MAPPING_START
- x=side.x
- y=side.y
- z=side.z
INSTANCE_OPTIONS_MAPPING_END
LINKED_OBJECTS_START
+ entities=[Entity]
+ controls=[Control]
+ images=[Image]
+ code=[CustomCode]
LINKED_OBJECTS_END
EXCLUDED_FROM_INSTANCE_OPTIONS_START
- register
EXCLUDED_FROM_INSTANCE_OPTIONS_END
**/
-class AnotherClass extends R3Object {
+class Project extends R3Object {
//CONSTRUCTOR_EXTENDS_TEMPLATE_START
constructor(options) {
@@ -35,25 +33,19 @@ class AnotherClass extends R3Object {
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'AnotherClass (' + options.id + ')';
-
super(options);
this.emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
- if (Utils.UndefinedOrNull(options.x)) {
- options.x = 1;
+ if (typeof options === 'undefined') {
+ options = {};
}
- if (Utils.UndefinedOrNull(options.y)) {
- options.y = 2;
+ if (Utils.UndefinedOrNull(options.isPublic)) {
+ options.isPublic = true;
}
- if (Utils.UndefinedOrNull(options.z)) {
- options.z = 3;
- }
- if (Utils.UndefinedOrNull(options.register)) {
- options.register = true;
+ if (Utils.UndefinedOrNull(options.applicationMode)) {
+ options.applicationMode = Project.APPLICATION_MODE_EDIT;
}
//OPTIONS_INIT_END
@@ -73,27 +65,23 @@ class AnotherClass extends R3Object {
createInstance() {
//CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
- 'side.x': this.x,
- 'side.y': this.y,
- 'side.z': this.z
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this);
//CREATE_INSTANCE_BEFORE_END
//CUSTOM_CREATE_INSTANCE_START
//CUSTOM_CREATE_INSTANCE_END
//CREATE_INSTANCE_AFTER_START
+ this[this.runtime].createInstance(
+ this,
+ {
+ //CREATE_INSTANCE_OPTIONS_START
+ 'isPublic': this.isPublic,
+ 'applicationMode': this.applicationMode
+ //CREATE_INSTANCE_OPTIONS_END
+ }
+ )
+
this.emit(Event.INSTANCE_CREATED, this);
//CREATE_INSTANCE_AFTER_END
@@ -108,16 +96,12 @@ class AnotherClass extends R3Object {
//UPDATE_INSTANCE_BEFORE_END
//UPDATE_INSTANCE_OPTIONS_START
- if (property === 'x') {
- this.instance.side.x = this.x;
+ if (property === 'isPublic') {
+ this.instance.isPublic = this.isPublic;
return;
}
- if (property === 'y') {
- this.instance.side.y = this.y;
- return;
- }
- if (property === 'z') {
- this.instance.side.z = this.z;
+ if (property === 'applicationMode') {
+ this.instance.applicationMode = this.applicationMode;
return;
}
//UPDATE_INSTANCE_OPTIONS_END
@@ -140,17 +124,17 @@ class AnotherClass extends R3Object {
//UPDATE_FROM_INSTANCE_BEFORE_END
//UPDATE_FROM_INSTANCE_OPTIONS_START
- if (property === 'x') {
- this.x = this.instance.side.x;
- return;
+ if (property === 'isPublic' || property === 'all') {
+ this.isPublic = this.instance.isPublic;
+ if (property !== 'all') {
+ return;
+ }
}
- if (property === 'y') {
- this.y = this.instance.side.y;
- return;
- }
- if (property === 'z') {
- this.z = this.instance.side.z;
- return;
+ if (property === 'applicationMode' || property === 'all') {
+ this.applicationMode = this.instance.applicationMode;
+ if (property !== 'all') {
+ return;
+ }
}
//UPDATE_FROM_INSTANCE_OPTIONS_END
@@ -168,14 +152,21 @@ class AnotherClass extends R3Object {
dispose() {
//DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
+ this.subscribe(
+ Event.INSTANCE_DISPOSED,
+ function(object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }
+ );
//DISPOSE_BEFORE_END
//CUSTOM_DISPOSE_START
//CUSTOM_DISPOSE_END
//DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
+ this.disposeInstance();
//DISPOSE_AFTER_END
}
@@ -185,15 +176,14 @@ class AnotherClass extends R3Object {
disposeInstance() {
//DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
+ console.log('Disposing instance of ' + this.name);
//DISPOSE_INSTANCE_BEFORE_END
//CUSTOM_DISPOSE_INSTANCE_START
//CUSTOM_DISPOSE_INSTANCE_END
//DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
+ this.emit(Event.DISPOSE_INSTANCE, this);
//DISPOSE_INSTANCE_AFTER_END
}
@@ -205,6 +195,15 @@ class AnotherClass extends R3Object {
}
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
+Project.CAMERA_INDEX_EDIT = 0x0;
+Project.CAMERA_INDEX_RUN = 0x1;
+
+Project.APPLICATION_MODE_EDIT = Project.CAMERA_INDEX_EDIT;
+Project.APPLICATION_MODE_RUN = Project.CAMERA_INDEX_RUN;
+
+Project.RENDERER_INDEX_MAIN = 0x0;
+
+Project.RENDER_TARGET_INDEX_NONE = -0x1;
//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END
-module.exports = AnotherClass;
\ No newline at end of file
+module.exports = Project;
\ No newline at end of file
diff --git a/src/r3/r3-r3-object.js b/src/r3/r3-r3-object.js
index e181874..9dc48aa 100644
--- a/src/r3/r3-r3-object.js
+++ b/src/r3/r3-r3-object.js
@@ -4,6 +4,9 @@ const Event = require('r3-event.js');
/**
OPTIONS_START
+ id=Utils.RandomId(10)
+ name=this.constructor.name + '(' + options.id + ')'
+ register=true
OPTIONS_END
INSTANCE_OPTIONS_MAPPING_START
@@ -13,6 +16,9 @@ const Event = require('r3-event.js');
LINKED_OBJECTS_END
EXCLUDED_FROM_INSTANCE_OPTIONS_START
+ id
+ name
+ register
EXCLUDED_FROM_INSTANCE_OPTIONS_END
**/
@@ -26,14 +32,23 @@ class R3Object extends Event {
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'R3Object (' + options.id + ')';
-
super(options);
this.emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
+ if (typeof options === 'undefined') {
+ options = {};
+ }
+ if (Utils.UndefinedOrNull(options.id)) {
+ options.id = Utils.RandomId(10);
+ }
+ if (Utils.UndefinedOrNull(options.name)) {
+ options.name = this.constructor.name + '(' + options.id + ')';
+ }
+ if (Utils.UndefinedOrNull(options.register)) {
+ options.register = true;
+ }
//OPTIONS_INIT_END
//CUSTOM_OPTIONS_INIT_START
@@ -52,25 +67,21 @@ class R3Object extends Event {
createInstance() {
//CREATE_INSTANCE_BEFORE_START
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
-
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this);
//CREATE_INSTANCE_BEFORE_END
//CUSTOM_CREATE_INSTANCE_START
//CUSTOM_CREATE_INSTANCE_END
//CREATE_INSTANCE_AFTER_START
+ this[this.runtime].createInstance(
+ this,
+ {
+ //CREATE_INSTANCE_OPTIONS_START
+ //CREATE_INSTANCE_OPTIONS_END
+ }
+ )
+
this.emit(Event.INSTANCE_CREATED, this);
//CREATE_INSTANCE_AFTER_END
@@ -121,14 +132,21 @@ class R3Object extends Event {
dispose() {
//DISPOSE_BEFORE_START
- this.emit(Event.DISPOSE_OBJECT, this);
+ this.subscribe(
+ Event.INSTANCE_DISPOSED,
+ function(object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }
+ );
//DISPOSE_BEFORE_END
//CUSTOM_DISPOSE_START
//CUSTOM_DISPOSE_END
//DISPOSE_AFTER_START
- this.emit(Event.OBJECT_DISPOSED, this);
+ this.disposeInstance();
//DISPOSE_AFTER_END
}
@@ -138,15 +156,14 @@ class R3Object extends Event {
disposeInstance() {
//DISPOSE_INSTANCE_BEFORE_START
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
+ console.log('Disposing instance of ' + this.name);
//DISPOSE_INSTANCE_BEFORE_END
//CUSTOM_DISPOSE_INSTANCE_START
//CUSTOM_DISPOSE_INSTANCE_END
//DISPOSE_INSTANCE_AFTER_START
- this.emit(Event.INSTANCE_DISPOSED, this);
+ this.emit(Event.DISPOSE_INSTANCE, this);
//DISPOSE_INSTANCE_AFTER_END
}
diff --git a/src/r3/r3-utils.js b/src/r3/r3-utils.js
index b3a06e7..250ffeb 100644
--- a/src/r3/r3-utils.js
+++ b/src/r3/r3-utils.js
@@ -1,1247 +1,1275 @@
+const Event = require('r3-event');
+
+/**
+
+ OPTIONS_START
+ OPTIONS_END
+
+ **/
+
class Utils {
- constructor() {
-
- }
-
- /**
- * Gets the first parent of the object which is an instance of constructor
- * @param object
- * @param constructor
- * @returns {*}
- * @constructor
- */
- static GetFirstParent(object, constructor) {
-
- if (Utils.UndefinedOrNull(constructor)) {
- throw new Error('You need to specify a constructor');
- }
-
- if (object.parent === null) {
- return null;
- }
-
- if (object.parent instanceof constructor) {
- return object.parent;
- } else {
- return Utils.GetFirstParent(object.parent, constructor);
- }
-
- };
-
- static SyntaxHighlight(json) {
- if (typeof json != 'string') {
- json = JSON.stringify(json, undefined, 2);
- }
- json = json.replace(/&/g, '&').replace(//g, '>');
- return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
- let cls = 'number';
- if (/^"/.test(match)) {
- if (/:$/.test(match)) {
- cls = 'key';
- } else {
- cls = 'string';
- }
- } else if (/true|false/.test(match)) {
- cls = 'boolean';
- } else if (/null/.test(match)) {
- cls = 'null';
- }
- return '' + match + '';
- });
- };
-
- static GetParentProject(component) {
-
- if (Utils.UndefinedOrNull(component.parent)) {
- throw new Error('Parent not found');
- }
-
- if (component.parent instanceof R3.Project) {
- return component.parent;
- }
-
- return Utils.GetParentProject(component.parent);
- };
-
- static GetParents(component, parents) {
-
- if (Utils.UndefinedOrNull(parents)) {
- parents = [];
- }
-
- if (Utils.UndefinedOrNull(component.parent)) {
- return parents;
- }
-
- parents.push(component.parent);
-
- return Utils.GetParents(component.parent, parents);
-
- };
-
- /**
- * @return {boolean}
- */
- static Instance(component) {
- return Utils.Defined(component) && Utils.Defined(component.instance);
- };
-
- /**
- * Utils.RemoveFromSelect
- * @param select
- * @param id
- * @returns {boolean}
- * @constructor
- */
- static RemoveFromSelect(select, id) {
-
- let i;
-
- for (i = 0; i < select.options.length; i++) {
- if (select.options[i].value === id) {
- select.remove(i);
- return true;
- }
- }
- return false;
- };
-
- /**
- * Utils.GetSelectIndex
- *
- * Get the select index of given id
- *
- * @param select
- * @param id
- * @returns boolean true if successful
- *
- * @constructor
- */
- static SetSelectIndex(select, id) {
- for (let i = 0; i < select.options.length; i++) {
- if (select.options[i].value === id) {
- select.selectedIndex = i;
- return true;
- }
- }
- return false;
- };
-
- static SortSelect(select) {
-
- let tmp = [];
- let i;
-
- for (i = 1; i < select.options.length; i++) {
- tmp[i-1] = [];
- tmp[i-1][0] = select.options[i].text;
- tmp[i-1][1] = select.options[i].value;
- }
-
- tmp.sort();
-
- select.options = [select.options[0]];
-
- for (i = 0; i < tmp.length; i++) {
- select.options[i+1] = new Option(tmp[i][0], tmp[i][1]);
- }
-
- return;
- };
-
- /**
- * Gets the parent of object whith property of optional type constructor. If index is specified, get the parent of the
- * object with property[index] - which means the property should be an array
- * @param object
- * @param property
- * @param index
- * @param constructor
- * @returns {*}
- * @constructor
- */
- static GetParent(object, property, index, constructor) {
-
- if (Utils.UndefinedOrNull(constructor)) {
- constructor = null;
- }
-
- if (Utils.UndefinedOrNull(index)) {
- index = null;
- }
-
- if (object.parent) {
- /**
- * Parent defined
- */
- if (object.parent.hasOwnProperty(property)) {
-
- if (constructor) {
-
- if (index) {
-
- if (object.parent[property][index] instanceof constructor) {
- return object.parent[property][index];
- } else {
-
- if (typeof object.parent.getParent === 'function') {
- return object.parent.getParent(property, index, constructor);
- } else {
- console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
- return null;
- }
- }
-
- } else {
- if (object.parent[property] instanceof constructor) {
- return object.parent[property];
- } else {
-
- if (typeof object.parent.getParent === 'function') {
- return object.parent.getParent(property, index, constructor);
- } else {
- console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
- return null;
- }
-
- }
- }
-
- } else {
-
- if (index) {
- return object.parent[property][index];
- } else {
- return object.parent[property];
- }
-
- }
- } else {
-
- /**
- * This parent does not have the property - go a level higher
- */
- if (typeof object.parent.getParent === 'function') {
- return object.parent.getParent(property, index, constructor);
- } else {
- console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
- return null;
- }
- }
-
- } else {
- /**
- * No parent defined
- */
- console.warn('property : ' + property + ' of type ' + constructor + ' was not found in the parent chain');
- return null;
- }
-
- };
-
-
- /**
- * Strips image extension from given path
- * @param imagePath
- * @constructor
- */
- static StripImageExtension(imagePath) {
- return imagePath.replace(/(\.png$|\.gif$|\.jpeg$|\.jpg$)/,'')
- };
-
- /**
- * Returns true if unloaded
- * @param component
- * @returns {boolean}
- * @constructor
- */
- static Unloaded(component) {
- if (
- Utils.UndefinedOrNull(component) ||
- Utils.UndefinedOrNull(component.instance)
- ) {
- return true;
- }
-
- return false;
- };
-
- /**
- *
- * @param component
- * @returns {boolean}
- * @constructor
- */
- static Loaded(component) {
- if (component && component.instance) {
- return true;
- }
-
- return false;
- };
-
- static BuildVectorSource(result, name, dimension) {
-
- if (dimension === 2) {
- result[name] = {};
- result[name].x = false;
- result[name].y = false;
- return;
- }
-
- if (dimension === 3) {
- result[name] = {};
- result[name].x = false;
- result[name].y = false;
- result[name].y = false;
- return;
- }
-
- if (dimension === 4) {
- result[name] = {};
- result[name].x = false;
- result[name].y = false;
- result[name].z = false;
- result[name].w = false;
- return;
- }
-
- console.warn('unknown dimension : ' + dimension);
- };
-
- /**
- * Returns all 'instances' of the array, or null if an 'instance' is undefined
- * @constructor
- * @param array
- */
- static GetArrayInstances(array) {
- return array.reduce(
- function(result, object) {
-
- if (result === null) {
- return result;
- }
-
- if (Utils.UndefinedOrNull(object.instance)) {
- result = null;
- } else {
- result.push(object.instance);
- }
-
- return result;
- },
- []
- );
- };
-
- static SortFacesByMaterialIndex(faces) {
-
- /**
- * Sorts faces according to material index because later we will create
- * groups for each vertice group
- */
- faces.sort(function(a, b) {
-
- if (a.materialIndex < b.materialIndex) {
- return -1;
- }
-
- if (a.materialIndex > b.materialIndex) {
- return 1;
- }
-
- return 0;
- });
-
- return faces;
- };
-
- static BuildQuaternionSource(result, name) {
- result[name] = {};
- result[name].axis = {};
- result[name].axis.x = false;
- result[name].axis.y = false;
- result[name].axis.z = false;
- result[name].angle = false;
- result[name].x = false;
- result[name].y = false;
- result[name].z = false;
- result[name].w = false;
- };
-
- static ObjectPropertiesAsBoolean(object) {
- return Object.keys(object).reduce(
- function(result, propertyId) {
-
- if (typeof object[propertyId] === 'function') {
- return result;
- }
-
- result[propertyId] = false;
-
- // if (object[propertyId] instanceof R3.Vector2) {
- // Utils.BuildVectorSource(result, propertyId, 2);
- // }
- //
- // if (object[propertyId] instanceof R3.Vector3) {
- // Utils.BuildVectorSource(result, propertyId, 3);
- // }
- //
- // if (object[propertyId] instanceof R3.Vector4) {
- // Utils.BuildVectorSource(result, propertyId, 4);
- // }
- //
- // if (object[propertyId] instanceof R3.Quaternion) {
- // Utils.BuildQuaternionSource(result, propertyId);
- // }
-
- return result;
-
- }.bind(this),
- {}
- );
- };
-
- static GetRuntime() {
-
- let result = null;
-
- R3.Event.Emit(
- R3.Event.GET_RUNTIME,
- null,
- function(runtime) {
- result = runtime;
- }
- );
-
- return result;
- };
-
- /**
- * Returns the window size or null
- * @returns {*}
- * @constructor
- */
- static GetWindowSize() {
-
- let size = null;
-
- R3.Event.Emit(
- R3.Event.GET_WINDOW_SIZE,
- null,
- function(data) {
- size = data;
- }.bind(this)
- );
-
- return size;
-
- };
-
- /**
- * Convenience function to update object width and height members with window size
- * @param object
- * @constructor
- */
- static UpdateWindowSize(object) {
- let size = Utils.GetWindowSize();
- object.width = size.width;
- object.height = size.height;
- };
-
-
- /**
- * Returns id of object with the name if it exists in the array, otherwise null
- * @param name
- * @param array
- * @returns {*}
- * @constructor
- */
- static ObjectIdWithNameInArray(name, array) {
-
- return array.reduce(
- function(result, object) {
-
- if (result) {
- return result;
- }
-
- if (name === object.name) {
- return object.id;
- }
-
- return null;
- },
- null
- );
- };
-
- static LoadIdsFromArrayToIdObject(array, idToObject) {
-
- };
-
- static LoadIdsFromObjectToIdObject(object, idToObject) {
-
-
- };
-
- /**
- * Gets random int exclusive of maximum but inclusive of minimum
- * @param min
- * @param max
- * @returns {*}
- * @constructor
- */
- static GetRandomInt(min, max) {
- min = Math.ceil(min);
- max = Math.floor(max);
- return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
- };
-
- /**
- * Gets random int inclusive of minimum and maximum
- * @param min
- * @param max
- * @returns {*}
- * @constructor
- */
- static GetRandomIntInclusive(min, max) {
- min = Math.ceil(min);
- max = Math.floor(max);
- return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
- };
-
- static InterpolateArray(data, fitCount) {
-
- let linearInterpolate = function(before, after, atPoint) {
- return before + (after - before) * atPoint;
- };
-
- let newData = [];
-
- let springFactor = Number((data.length - 1) / (fitCount - 1));
-
- newData[0] = data[0]; // for new allocation
-
- for ( let i = 1; i < fitCount - 1; i++) {
- let tmp = i * springFactor;
- let before = Number(Math.floor(tmp)).toFixed();
- let after = Number(Math.ceil(tmp)).toFixed();
- let atPoint = tmp - before;
- newData[i] = linearInterpolate(data[before], data[after], atPoint);
- }
-
- newData[fitCount - 1] = data[data.length - 1]; // for new allocation
-
- return newData;
- };
-
- /**
- * Undefined or null check
- * @param variable
- * @returns {boolean}
- * @constructor
- */
- static UndefinedOrNull(
- variable
- ) {
- return typeof variable === 'undefined' || variable === null;
- };
-
- /**
- * The variable is not undefined and not null
- * @param variable
- * @returns {boolean}
- * @constructor
- */
- static Defined(
- variable
- ) {
- return typeof variable !== 'undefined' && variable !== null;
- };
-
- /**
- * Gets function parameters
- * @param fn
- * @constructor
- */
- static GetParameters(fn) {
-
- let FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
- let FN_ARG_SPLIT = /,/;
- let FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
- let STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
-
- let parameters,
- fnText,
- argDecl;
-
- if (typeof fn !== 'function') {
- parameters = [];
- fnText = fn.toString().replace(STRIP_COMMENTS, '');
- argDecl = fnText.match(FN_ARGS);
- argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
- arg.replace(FN_ARG, function(all, underscore, name) {
- parameters.push(name);
- });
- });
- } else {
- throw Error("not a function")
- }
-
- return parameters;
- };
-
- /**
- * Returns either an ID of the object or Null
- * @param object
- * @returns {null}
- * @constructor
- */
- static IdOrNull(object) {
- if (Utils.UndefinedOrNull(object)) {
- return null;
- } else {
- if (Utils.UndefinedOrNull(object.id)) {
- console.warn('saving an object reference with no ID : ', object);
- return null;
- }
- return object.id;
- }
- };
-
- /**
- * Limit a property to values between -pi and +pi
- * @param property
- * @param objectProperty
- * @returns {{configurable?: boolean, enumerable?: boolean, value?, writable?: boolean, get?: Function, set?: Function}}
- * @constructor
- */
- static LimitToPI(property, objectProperty) {
-
- let store = objectProperty;
-
- return {
- get : function() {
- return store;
- },
- set : function(value) {
- while (value > Math.PI) {
- value -= (Math.PI * 2);
- }
-
- while (value < -(Math.PI)) {
- value += (Math.PI * 2);
- }
-
- store = value;
- }
- };
- };
-
- /**
- * Returns an array of IDs representing the objects
- * @param array
- * @returns []
- * @constructor
- */
- static IdArrayOrEmptyArray(array) {
- if (Utils.UndefinedOrNull(array)) {
- return [];
- } else {
-
- return array.map(function(item) {
-
- if (Utils.UndefinedOrNull(item.id)) {
- throw new Error('No ID found while trying to store IDs to array');
- }
-
- return item.id
- });
- }
- };
-
- /**
- * Links an object to its parent through idToObject array
- * @param propertyString
- * @param idToObject
- * @param parentObject
- * @param id
- * @constructor
- */
- static Link(propertyString, idToObject, parentObject, id) {
-
- if (!Utils.UndefinedOrNull(parentObject[propertyString])) {
-
- if (!idToObject.hasOwnProperty(id)) {
- console.warn('Linking failed for object:' + parentObject.name);
- }
-
- parentObject[propertyString] = idToObject[id];
- }
- };
-
- /**
- * Generates a random ID
- * @returns {string}
- * @constructor
- */
- static RandomId(length) {
-
- if (Utils.UndefinedOrNull(length)) {
- length = 10;
- }
-
- return Math.random().toString(36).substr(2, length);
- };
-
- static InvertWindingOrder(triangles) {
-
- for (let i = 0; i < triangles.length; i++) {
- let v1 = triangles[i].v1;
- triangles[i].v1 = triangles[i].v2;
- triangles[i].v2 = v1;
-
- let backupUV = triangles[i].triangle.v1uv;
- triangles[i].triangle.v1uv = triangles[i].triangle.v2uv;
- triangles[i].triangle.v2uv = backupUV;
- }
-
- return triangles;
- };
-
- /**
- * Inverts a mesh winding order (and its instance)
- * @param mesh R3.D3.Mesh
- * @returns {*}
- * @constructor
- */
- static InvertMeshWindingOrder(mesh) {
-
- mesh.faces.forEach(
- function(face) {
-
- let tmpV1 = face.v1;
- face.v1 = face.v2;
- face.v2 = tmpV1;
-
- let tmpV1uv = face.v1uv;
- face.v1uv = face.v2uv;
- face.v2uv = tmpV1uv;
-
- }.bind(this)
- );
-
- //mesh.computeNormals = true;
- //mesh.createInstance();
- };
-
- /**
- * This function resets a the winding order of a mesh from a reference point V (the average center of the mesh)
- */
- static ResetWindingOrder(faces, vertices) {
-
- let vertexList = new R3.API.Vector3.Points();
-
- for (let v = 0; v < vertices.length; v++) {
- vertexList.add(new R3.API.Vector3(
- vertices[v].position.x,
- vertices[v].position.y,
- vertices[v].position.z
- ));
- }
-
- let V = vertexList.average();
-
- let triangles = [];
-
- for (let s = 0; s < faces.length; s += 3) {
-
- let v0 = faces[s];
- let v1 = faces[s+1];
- let v2 = faces[s+2];
-
- triangles.push(
- {
- v0 : v0,
- v1 : v1,
- v2 : v2,
- edges : [
- {v0: v0, v1: v1},
- {v0: v1, v1: v2},
- {v0: v2, v1: v0}
- ],
- winding : 0,
- edgeIndex : -1,
- processed : false
- }
- );
- }
-
- for (let i = 0; i < triangles.length; i++) {
- if (
- R3.API.Vector3.clockwise(
- vertices[triangles[i].v0].position,
- vertices[triangles[i].v1].position,
- vertices[triangles[i].v2].position,
- V
- )
- ) {
- console.log('clockwise');
- let bv1 = triangles[i].v1;
- triangles[i].v1 = triangles[i].v2;
- triangles[i].v2 = bv1;
- } else {
- console.log('not clockwise');
- }
- }
-
- return triangles;
- };
-
- /**
- * This function resets the winding order for triangles in faces, given an initial triangle and orientation edge
- * used pseudocode from
- * http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh
- * We need to use a graph traversal algorithm,
- * lets assume we have method that returns neighbor of triangle on given edge
- *
- * neighbor_on_egde( next_tria, edge )
- *
- * to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it
- * processed = set of processed triangles; initial empty
- *
- * while to_process is not empty:
- * next_tria, orientation_edge = to_process.pop()
- * add next_tria in processed
- * if next_tria is not opposite oriented than orientation_edge:
- * change next_tria (ABC) orientation (B<->C)
- * for each edge (AB) in next_tria:
- * neighbor_tria = neighbor_on_egde( next_tria, edge )
- * if neighbor_tria exists and neighbor_tria not in processed:
- * to_process add (neighbor_tria, edge opposite oriented (BA))
- * @param faces R3.D3.Face[]
- * @param orientationEdge R3.API.Vector2
- * @returns {Array}
- */
- static FixWindingOrder(faces, orientationEdge) {
-
- /**
- * Checks if a Face belonging to a TriangleEdge has already been processed
- * @param processed TriangleEdge[]
- * @param triangle Face
- * @returns {boolean}
- */
- function inProcessed(processed, triangle) {
-
- for (let i = 0; i < processed.length; i++) {
- if (processed[i].triangle.equals(triangle)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns a neighbouring triangle on a specific edge - preserving the edge orientation
- * @param edge R3.API.Vector2
- * @param faces R3.D3.Face[]
- * @param currentTriangle
- * @returns {*}
- */
- function neighbourOnEdge(edge, faces, currentTriangle) {
-
- for (let i = 0; i < faces.length; i++) {
- if (
- (faces[i].v0 === edge.x && faces[i].v1 === edge.y) ||
- (faces[i].v1 === edge.x && faces[i].v2 === edge.y) ||
- (faces[i].v2 === edge.x && faces[i].v0 === edge.y) ||
- (faces[i].v0 === edge.y && faces[i].v1 === edge.x) ||
- (faces[i].v1 === edge.y && faces[i].v2 === edge.x) ||
- (faces[i].v2 === edge.y && faces[i].v0 === edge.x)
- ) {
-
- let triangle = new R3.D3.API.Face(
- null,
- null,
- faces[i].v0index,
- faces[i].v1index,
- faces[i].v2index,
- faces[i].materialIndex,
- faces[i].uvs
- );
-
- if (triangle.equals(currentTriangle)) {
- continue;
- }
-
- return new R3.D3.TriangleEdge(
- triangle,
- edge
- );
- }
- }
-
- return null;
- }
-
- let toProcess = [
- new R3.D3.TriangleEdge(
- new R3.D3.API.Face(
- null,
- null,
- faces[0].v0index,
- faces[0].v1index,
- faces[0].v2index,
- faces[0].materialIndex,
- faces[0].uvs
- ),
- orientationEdge
- )
- ];
-
- let processed = [];
-
- while (toProcess.length > 0) {
-
- let triangleEdge = toProcess.pop();
-
- /**
- * If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed
- * to have the same winding order)
- */
- if (
- (triangleEdge.triangle.v0index === triangleEdge.edge.x &&
- triangleEdge.triangle.v1index === triangleEdge.edge.y) ||
- (triangleEdge.triangle.v1index === triangleEdge.edge.x &&
- triangleEdge.triangle.v2index === triangleEdge.edge.y) ||
- (triangleEdge.triangle.v2index === triangleEdge.edge.x &&
- triangleEdge.triangle.v0index === triangleEdge.edge.y)
- ) {
- let backupV = triangleEdge.triangle.v1index;
- triangleEdge.triangle.v1index = triangleEdge.triangle.v2index;
- triangleEdge.triangle.v2index = backupV;
-
- // let backupUV = triangleEdge.triangle.v1uv;
- // triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv;
- // triangleEdge.triangle.v2uv = backupUV;
- //
- let backupUV = triangleEdge.triangle.uvs[0][1];
- triangleEdge.triangle.uvs[0][1] = triangleEdge.triangle.uvs[0][2];
- triangleEdge.triangle.uvs[0][2] = backupUV;
- }
-
- processed.push(triangleEdge);
-
- let edges = [
- new R3.API.Vector2(
- triangleEdge.triangle.v0index,
- triangleEdge.triangle.v1index
- ),
- new R3.API.Vector2(
- triangleEdge.triangle.v1index,
- triangleEdge.triangle.v2index
- ),
- new R3.API.Vector2(
- triangleEdge.triangle.v2index,
- triangleEdge.triangle.v0index
- )
- ];
-
- for (let j = 0; j < edges.length; j++) {
- let neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle);
- if (neighbour && !inProcessed(processed, neighbour.triangle)) {
- toProcess.push(neighbour);
- }
- }
- }
-
- /**
- * In processed - we will have some duplicates - only add the unique ones
- * @type {Array}
- */
- let triangles = [];
- for (let i = 0; i < processed.length; i++) {
- let found = false;
- for (let k = 0; k < triangles.length; k++) {
- if (triangles[k].equals(processed[i].triangle)){
- found = true;
- break;
- }
- }
- if (!found) {
- triangles.push(processed[i].triangle);
- }
- }
-
- return triangles;
- };
-
- /**
- * This is a work-around function to fix polys which don't triangulate because
- * they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around
- * Z then Y axis
- * @param verticesFlat []
- * @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY
- * @return []
- */
- static FixPolyZPlane(verticesFlat, grain) {
-
- if ((verticesFlat.length % 3) !== 0 && !(verticesFlat.length > 9)) {
- console.log("The vertices are not in the right length : " + verticesFlat.length);
- }
-
- let vertices = [];
-
- let points = new R3.API.Quaternion.Points();
-
- for (let i = 0; i < verticesFlat.length; i += 3) {
- points.add(new R3.API.Vector3(
- verticesFlat[i],
- verticesFlat[i + 1],
- verticesFlat[i + 2]
- ));
- }
-
- points.toOrigin();
-
- points.maximizeXDistance(grain);
-
- points.maximizeYDistance(grain);
-
- for (i = 0; i < points.vectors.length; i++) {
- vertices.push(
- [
- points.vectors[i].x,
- points.vectors[i].y
- ]
- );
- }
-
- return vertices;
- };
-
- static MovingAverage(period) {
- let nums = [];
- return function(num) {
- nums.push(num);
- if (nums.length > period)
- nums.splice(0,1); // remove the first element of the array
- let sum = 0;
- for (let i in nums)
- sum += nums[i];
- let n = period;
- if (nums.length < period)
- n = nums.length;
- return(sum/n);
- }
- };
-
- static Intersect(a, b) {
-
- let t;
-
- /**
- * Loop over shortest array
- */
- if (b.length > a.length) {
- t = b;
- b = a;
- a = t;
- }
-
- return a.filter(
- /**
- * Check if exists
- * @param e
- * @returns {boolean}
- */
- function(e) {
- return (b.indexOf(e) > -1);
- }
- ).filter(
- /**
- * Remove Duplicates
- * @param e
- * @param i
- * @param c
- * @returns {boolean}
- */
- function(e, i, c) {
- return c.indexOf(e) === i;
- }
- );
- };
-
- static Difference(a, b) {
-
- let t;
-
- /**
- * Loop over shortest array
- */
- if (b.length > a.length) {
- t = b;
- b = a;
- a = t;
- }
-
- return a.filter(
- /**
- * Check if exists
- * @param e
- * @returns {boolean}
- */
- function(e) {
- return (b.indexOf(e) === -1);
- }
- ).filter(
- /**
- * Remove Duplicates
- * @param e
- * @param i
- * @param c
- * @returns {boolean}
- */
- function(e, i, c) {
- return c.indexOf(e) === i;
- }
- );
- };
-
- /**
- * Push only if not in there already
- * @param array
- * @param object
- * @constructor
- */
- static PushUnique(array, object) {
-
- if (array.indexOf(object) === -1) {
- array.push(object);
- }
- };
-
- /**
- * Checks whether or not the object is empty
- * @param obj
- * @returns {boolean}
- * @constructor
- */
- static IsEmpty(obj) {
- return (Object.keys(obj).length === 0 && obj.constructor === Object);
- };
-
- static IsString(member) {
- return (typeof member === 'string');
- };
-
- static IsBoolean(member) {
- return (member === true || member === false);
- };
-
- static IsColor(member) {
- return (member instanceof R3.Color);
- };
-
- static IsNumber(member) {
- return (typeof member === 'number');
- };
-
- static IsVector2(member) {
- return (
- member instanceof R3.API.Vector2 ||
- member instanceof R3.Vector2
- );
- };
-
- static IsVector3(member) {
- return (
- member instanceof R3.API.Vector3 ||
- member instanceof R3.Vector3
- );
- };
-
- static IsVector4(member) {
- return (
- member instanceof R3.API.Vector4 ||
- member instanceof R3.Vector4 ||
- member instanceof R3.API.Quaternion ||
- member instanceof R3.Quaternion
- );
- };
-
- static IsObject(member) {
- let type = typeof member;
- return type === 'function' || type === 'object' && !!member;
- };
-
- /**
- * @return {string}
- */
- static LowerUnderscore(name) {
- let string = name.toLowerCase().replace(/\s+/g, '_');
- string = string.replace(/-/g, '_');
- string = string.replace(/\_+/g, '_');
- return string;
- };
-
- static UpperCaseWordsSpaces(input) {
-
- let word = input.replace(/[-_]/g, ' ');
-
- word = word.replace(/\s+/, ' ');
-
- let words = word.split(' ');
-
- return words.reduce(
- function(result, word) {
- result += word[0].toUpperCase() + word.substr(1);
- return result + ' ';
- },
- ''
- ).trim();
- };
-
- /**
- * @return {string}
- */
- static UpperCaseUnderscore(word) {
-
- let str = '';
-
- word.split('').map(function(letter){
- if (letter == letter.toUpperCase()) {
- str += '_' + letter;
- } else {
- str += letter.toUpperCase();
- }
- });
-
- str = str.replace(new RegExp('^_'),'');
-
- return str;
- };
-
- /**
- * Returns Left Padded Text - ex. length 5, padchar 0, string abc = '00abc'
- * @param length
- * @param padChar
- * @param string
- * @returns {string}
- * @constructor
- */
- static PaddedText(length, padChar, string) {
-
- let pad = "";
-
- for (let x = 0; x < length; x++) {
- pad += padChar;
- }
-
- return pad.substring(0, pad.length - string.length) + string;
- };
+ //CONSTRUCTOR_TEMPLATE_START
+ constructor(options) {
+
+ Event.Emit(Event.OBJECT_CREATED, this);
+
+ //OPTIONS_INIT_START
+ if (typeof options === 'undefined') {
+ options = {};
+ }
+ //OPTIONS_INIT_END
+
+ //CUSTOM_OPTIONS_INIT_START
+ //CUSTOM_OPTIONS_INIT_END
+
+ Object.assign(this, options);
+
+ //CUSTOM_BEFORE_INIT_START
+ //CUSTOM_BEFORE_INIT_END
+
+ Event.Emit(Event.OBJECT_INITIALIZED, this);
+ }
+ //CONSTRUCTOR_TEMPLATE_END
+
+ //CUSTOM_IMPLEMENTATION_START
+ static GetFirstParent(object, constructor) {
+
+ if (Utils.UndefinedOrNull(constructor)) {
+ throw new Error('You need to specify a constructor');
+ }
+
+ if (object.parent === null) {
+ return null;
+ }
+
+ if (object.parent instanceof constructor) {
+ return object.parent;
+ } else {
+ return Utils.GetFirstParent(object.parent, constructor);
+ }
+
+ };
+
+ static SyntaxHighlight(json) {
+ if (typeof json != 'string') {
+ json = JSON.stringify(json, undefined, 2);
+ }
+ json = json.replace(/&/g, '&').replace(//g, '>');
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+ let cls = 'number';
+ if (/^"/.test(match)) {
+ if (/:$/.test(match)) {
+ cls = 'key';
+ } else {
+ cls = 'string';
+ }
+ } else if (/true|false/.test(match)) {
+ cls = 'boolean';
+ } else if (/null/.test(match)) {
+ cls = 'null';
+ }
+ return '' + match + '';
+ });
+ };
+
+ static GetParentProject(component) {
+
+ if (Utils.UndefinedOrNull(component.parent)) {
+ throw new Error('Parent not found');
+ }
+
+ if (component.parent instanceof R3.Project) {
+ return component.parent;
+ }
+
+ return Utils.GetParentProject(component.parent);
+ };
+
+ static GetParents(component, parents) {
+
+ if (Utils.UndefinedOrNull(parents)) {
+ parents = [];
+ }
+
+ if (Utils.UndefinedOrNull(component.parent)) {
+ return parents;
+ }
+
+ parents.push(component.parent);
+
+ return Utils.GetParents(component.parent, parents);
+
+ };
+
+ /**
+ * @return {boolean}
+ */
+ static Instance(component) {
+ return Utils.Defined(component) && Utils.Defined(component.instance);
+ };
+
+ /**
+ * Utils.RemoveFromSelect
+ * @param select
+ * @param id
+ * @returns {boolean}
+ * @constructor
+ */
+ static RemoveFromSelect(select, id) {
+
+ let i;
+
+ for (i = 0; i < select.options.length; i++) {
+ if (select.options[i].value === id) {
+ select.remove(i);
+ return true;
+ }
+ }
+ return false;
+ };
+
+ /**
+ * Utils.GetSelectIndex
+ *
+ * Get the select index of given id
+ *
+ * @param select
+ * @param id
+ * @returns boolean true if successful
+ *
+ * @constructor
+ */
+ static SetSelectIndex(select, id) {
+ for (let i = 0; i < select.options.length; i++) {
+ if (select.options[i].value === id) {
+ select.selectedIndex = i;
+ return true;
+ }
+ }
+ return false;
+ };
+
+ static SortSelect(select) {
+
+ let tmp = [];
+ let i;
+
+ for (i = 1; i < select.options.length; i++) {
+ tmp[i-1] = [];
+ tmp[i-1][0] = select.options[i].text;
+ tmp[i-1][1] = select.options[i].value;
+ }
+
+ tmp.sort();
+
+ select.options = [select.options[0]];
+
+ for (i = 0; i < tmp.length; i++) {
+ select.options[i+1] = new Option(tmp[i][0], tmp[i][1]);
+ }
+
+ return;
+ };
+
+ /**
+ * Gets the parent of object whith property of optional type constructor. If index is specified, get the parent of the
+ * object with property[index] - which means the property should be an array
+ * @param object
+ * @param property
+ * @param index
+ * @param constructor
+ * @returns {*}
+ * @constructor
+ */
+ static GetParent(object, property, index, constructor) {
+
+ if (Utils.UndefinedOrNull(constructor)) {
+ constructor = null;
+ }
+
+ if (Utils.UndefinedOrNull(index)) {
+ index = null;
+ }
+
+ if (object.parent) {
+ /**
+ * Parent defined
+ */
+ if (object.parent.hasOwnProperty(property)) {
+
+ if (constructor) {
+
+ if (index) {
+
+ if (object.parent[property][index] instanceof constructor) {
+ return object.parent[property][index];
+ } else {
+
+ if (typeof object.parent.getParent === 'function') {
+ return object.parent.getParent(property, index, constructor);
+ } else {
+ console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
+ return null;
+ }
+ }
+
+ } else {
+ if (object.parent[property] instanceof constructor) {
+ return object.parent[property];
+ } else {
+
+ if (typeof object.parent.getParent === 'function') {
+ return object.parent.getParent(property, index, constructor);
+ } else {
+ console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
+ return null;
+ }
+
+ }
+ }
+
+ } else {
+
+ if (index) {
+ return object.parent[property][index];
+ } else {
+ return object.parent[property];
+ }
+
+ }
+ } else {
+
+ /**
+ * This parent does not have the property - go a level higher
+ */
+ if (typeof object.parent.getParent === 'function') {
+ return object.parent.getParent(property, index, constructor);
+ } else {
+ console.warn('getParent not defined on API object : ' + object.parent + ' - you should avoid having these messsages');
+ return null;
+ }
+ }
+
+ } else {
+ /**
+ * No parent defined
+ */
+ console.warn('property : ' + property + ' of type ' + constructor + ' was not found in the parent chain');
+ return null;
+ }
+
+ };
+
+
+ /**
+ * Strips image extension from given path
+ * @param imagePath
+ * @constructor
+ */
+ static StripImageExtension(imagePath) {
+ return imagePath.replace(/(\.png$|\.gif$|\.jpeg$|\.jpg$)/,'')
+ };
+
+ /**
+ * Returns true if unloaded
+ * @param component
+ * @returns {boolean}
+ * @constructor
+ */
+ static Unloaded(component) {
+ if (
+ Utils.UndefinedOrNull(component) ||
+ Utils.UndefinedOrNull(component.instance)
+ ) {
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ *
+ * @param component
+ * @returns {boolean}
+ * @constructor
+ */
+ static Loaded(component) {
+ if (component && component.instance) {
+ return true;
+ }
+
+ return false;
+ };
+
+ static BuildVectorSource(result, name, dimension) {
+
+ if (dimension === 2) {
+ result[name] = {};
+ result[name].x = false;
+ result[name].y = false;
+ return;
+ }
+
+ if (dimension === 3) {
+ result[name] = {};
+ result[name].x = false;
+ result[name].y = false;
+ result[name].y = false;
+ return;
+ }
+
+ if (dimension === 4) {
+ result[name] = {};
+ result[name].x = false;
+ result[name].y = false;
+ result[name].z = false;
+ result[name].w = false;
+ return;
+ }
+
+ console.warn('unknown dimension : ' + dimension);
+ };
+
+ /**
+ * Returns all 'instances' of the array, or null if an 'instance' is undefined
+ * @constructor
+ * @param array
+ */
+ static GetArrayInstances(array) {
+ return array.reduce(
+ function(result, object) {
+
+ if (result === null) {
+ return result;
+ }
+
+ if (Utils.UndefinedOrNull(object.instance)) {
+ result = null;
+ } else {
+ result.push(object.instance);
+ }
+
+ return result;
+ },
+ []
+ );
+ };
+
+ static SortFacesByMaterialIndex(faces) {
+
+ /**
+ * Sorts faces according to material index because later we will create
+ * groups for each vertice group
+ */
+ faces.sort(function(a, b) {
+
+ if (a.materialIndex < b.materialIndex) {
+ return -1;
+ }
+
+ if (a.materialIndex > b.materialIndex) {
+ return 1;
+ }
+
+ return 0;
+ });
+
+ return faces;
+ };
+
+ static BuildQuaternionSource(result, name) {
+ result[name] = {};
+ result[name].axis = {};
+ result[name].axis.x = false;
+ result[name].axis.y = false;
+ result[name].axis.z = false;
+ result[name].angle = false;
+ result[name].x = false;
+ result[name].y = false;
+ result[name].z = false;
+ result[name].w = false;
+ };
+
+ static ObjectPropertiesAsBoolean(object) {
+ return Object.keys(object).reduce(
+ function(result, propertyId) {
+
+ if (typeof object[propertyId] === 'function') {
+ return result;
+ }
+
+ result[propertyId] = false;
+
+ // if (object[propertyId] instanceof R3.Vector2) {
+ // Utils.BuildVectorSource(result, propertyId, 2);
+ // }
+ //
+ // if (object[propertyId] instanceof R3.Vector3) {
+ // Utils.BuildVectorSource(result, propertyId, 3);
+ // }
+ //
+ // if (object[propertyId] instanceof R3.Vector4) {
+ // Utils.BuildVectorSource(result, propertyId, 4);
+ // }
+ //
+ // if (object[propertyId] instanceof R3.Quaternion) {
+ // Utils.BuildQuaternionSource(result, propertyId);
+ // }
+
+ return result;
+
+ }.bind(this),
+ {}
+ );
+ };
+
+ static GetRuntime() {
+
+ let result = null;
+
+ R3.Event.Emit(
+ R3.Event.GET_RUNTIME,
+ null,
+ function(runtime) {
+ result = runtime;
+ }
+ );
+
+ return result;
+ };
+
+ /**
+ * Returns the window size or null
+ * @returns {*}
+ * @constructor
+ */
+ static GetWindowSize() {
+
+ let size = null;
+
+ R3.Event.Emit(
+ R3.Event.GET_WINDOW_SIZE,
+ null,
+ function(data) {
+ size = data;
+ }.bind(this)
+ );
+
+ return size;
+
+ };
+
+ /**
+ * Convenience function to update object width and height members with window size
+ * @param object
+ * @constructor
+ */
+ static UpdateWindowSize(object) {
+ let size = Utils.GetWindowSize();
+ object.width = size.width;
+ object.height = size.height;
+ };
+
+
+ /**
+ * Returns id of object with the name if it exists in the array, otherwise null
+ * @param name
+ * @param array
+ * @returns {*}
+ * @constructor
+ */
+ static ObjectIdWithNameInArray(name, array) {
+
+ return array.reduce(
+ function(result, object) {
+
+ if (result) {
+ return result;
+ }
+
+ if (name === object.name) {
+ return object.id;
+ }
+
+ return null;
+ },
+ null
+ );
+ };
+
+ static LoadIdsFromArrayToIdObject(array, idToObject) {
+
+ };
+
+ static LoadIdsFromObjectToIdObject(object, idToObject) {
+
+
+ };
+
+ /**
+ * Gets random int exclusive of maximum but inclusive of minimum
+ * @param min
+ * @param max
+ * @returns {*}
+ * @constructor
+ */
+ static GetRandomInt(min, max) {
+ min = Math.ceil(min);
+ max = Math.floor(max);
+ return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive
+ };
+
+ /**
+ * Gets random int inclusive of minimum and maximum
+ * @param min
+ * @param max
+ * @returns {*}
+ * @constructor
+ */
+ static GetRandomIntInclusive(min, max) {
+ min = Math.ceil(min);
+ max = Math.floor(max);
+ return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive
+ };
+
+ static InterpolateArray(data, fitCount) {
+
+ let linearInterpolate = function(before, after, atPoint) {
+ return before + (after - before) * atPoint;
+ };
+
+ let newData = [];
+
+ let springFactor = Number((data.length - 1) / (fitCount - 1));
+
+ newData[0] = data[0]; // for new allocation
+
+ for ( let i = 1; i < fitCount - 1; i++) {
+ let tmp = i * springFactor;
+ let before = Number(Math.floor(tmp)).toFixed();
+ let after = Number(Math.ceil(tmp)).toFixed();
+ let atPoint = tmp - before;
+ newData[i] = linearInterpolate(data[before], data[after], atPoint);
+ }
+
+ newData[fitCount - 1] = data[data.length - 1]; // for new allocation
+
+ return newData;
+ };
+
+ /**
+ * Undefined or null check
+ * @param variable
+ * @returns {boolean}
+ * @constructor
+ */
+ static UndefinedOrNull(
+ variable
+ ) {
+ return typeof variable === 'undefined' || variable === null;
+ };
+
+ /**
+ * The variable is not undefined and not null
+ * @param variable
+ * @returns {boolean}
+ * @constructor
+ */
+ static Defined(
+ variable
+ ) {
+ return typeof variable !== 'undefined' && variable !== null;
+ };
+
+ /**
+ * Gets function parameters
+ * @param fn
+ * @constructor
+ */
+ static GetParameters(fn) {
+
+ let FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
+ let FN_ARG_SPLIT = /,/;
+ let FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
+ let STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/mg;
+
+ let parameters,
+ fnText,
+ argDecl;
+
+ if (typeof fn !== 'function') {
+ parameters = [];
+ fnText = fn.toString().replace(STRIP_COMMENTS, '');
+ argDecl = fnText.match(FN_ARGS);
+ argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
+ arg.replace(FN_ARG, function(all, underscore, name) {
+ parameters.push(name);
+ });
+ });
+ } else {
+ throw Error("not a function")
+ }
+
+ return parameters;
+ };
+
+ /**
+ * Returns either an ID of the object or Null
+ * @param object
+ * @returns {null}
+ * @constructor
+ */
+ static IdOrNull(object) {
+ if (Utils.UndefinedOrNull(object)) {
+ return null;
+ } else {
+ if (Utils.UndefinedOrNull(object.id)) {
+ console.warn('saving an object reference with no ID : ', object);
+ return null;
+ }
+ return object.id;
+ }
+ };
+
+ /**
+ * Limit a property to values between -pi and +pi
+ * @param property
+ * @param objectProperty
+ * @returns {{configurable?: boolean, enumerable?: boolean, value?, writable?: boolean, get?: Function, set?: Function}}
+ * @constructor
+ */
+ static LimitToPI(property, objectProperty) {
+
+ let store = objectProperty;
+
+ return {
+ get : function() {
+ return store;
+ },
+ set : function(value) {
+ while (value > Math.PI) {
+ value -= (Math.PI * 2);
+ }
+
+ while (value < -(Math.PI)) {
+ value += (Math.PI * 2);
+ }
+
+ store = value;
+ }
+ };
+ };
+
+ /**
+ * Returns an array of IDs representing the objects
+ * @param array
+ * @returns []
+ * @constructor
+ */
+ static IdArrayOrEmptyArray(array) {
+ if (Utils.UndefinedOrNull(array)) {
+ return [];
+ } else {
+
+ return array.map(function(item) {
+
+ if (Utils.UndefinedOrNull(item.id)) {
+ throw new Error('No ID found while trying to store IDs to array');
+ }
+
+ return item.id
+ });
+ }
+ };
+
+ /**
+ * Links an object to its parent through idToObject array
+ * @param propertyString
+ * @param idToObject
+ * @param parentObject
+ * @param id
+ * @constructor
+ */
+ static Link(propertyString, idToObject, parentObject, id) {
+
+ if (!Utils.UndefinedOrNull(parentObject[propertyString])) {
+
+ if (!idToObject.hasOwnProperty(id)) {
+ console.warn('Linking failed for object:' + parentObject.name);
+ }
+
+ parentObject[propertyString] = idToObject[id];
+ }
+ };
+
+ /**
+ * Generates a random ID
+ * @returns {string}
+ * @constructor
+ */
+ static RandomId(length) {
+
+ if (Utils.UndefinedOrNull(length)) {
+ length = 10;
+ }
+
+ return Math.random().toString(36).substr(2, length);
+ };
+
+ static InvertWindingOrder(triangles) {
+
+ for (let i = 0; i < triangles.length; i++) {
+ let v1 = triangles[i].v1;
+ triangles[i].v1 = triangles[i].v2;
+ triangles[i].v2 = v1;
+
+ let backupUV = triangles[i].triangle.v1uv;
+ triangles[i].triangle.v1uv = triangles[i].triangle.v2uv;
+ triangles[i].triangle.v2uv = backupUV;
+ }
+
+ return triangles;
+ };
+
+ /**
+ * Inverts a mesh winding order (and its instance)
+ * @param mesh R3.D3.Mesh
+ * @returns {*}
+ * @constructor
+ */
+ static InvertMeshWindingOrder(mesh) {
+
+ mesh.faces.forEach(
+ function(face) {
+
+ let tmpV1 = face.v1;
+ face.v1 = face.v2;
+ face.v2 = tmpV1;
+
+ let tmpV1uv = face.v1uv;
+ face.v1uv = face.v2uv;
+ face.v2uv = tmpV1uv;
+
+ }.bind(this)
+ );
+
+ //mesh.computeNormals = true;
+ //mesh.createInstance();
+ };
+
+ /**
+ * This function resets a the winding order of a mesh from a reference point V (the average center of the mesh)
+ */
+ static ResetWindingOrder(faces, vertices) {
+
+ let vertexList = new R3.API.Vector3.Points();
+
+ for (let v = 0; v < vertices.length; v++) {
+ vertexList.add(new R3.API.Vector3(
+ vertices[v].position.x,
+ vertices[v].position.y,
+ vertices[v].position.z
+ ));
+ }
+
+ let V = vertexList.average();
+
+ let triangles = [];
+
+ for (let s = 0; s < faces.length; s += 3) {
+
+ let v0 = faces[s];
+ let v1 = faces[s+1];
+ let v2 = faces[s+2];
+
+ triangles.push(
+ {
+ v0 : v0,
+ v1 : v1,
+ v2 : v2,
+ edges : [
+ {v0: v0, v1: v1},
+ {v0: v1, v1: v2},
+ {v0: v2, v1: v0}
+ ],
+ winding : 0,
+ edgeIndex : -1,
+ processed : false
+ }
+ );
+ }
+
+ for (let i = 0; i < triangles.length; i++) {
+ if (
+ R3.API.Vector3.clockwise(
+ vertices[triangles[i].v0].position,
+ vertices[triangles[i].v1].position,
+ vertices[triangles[i].v2].position,
+ V
+ )
+ ) {
+ console.log('clockwise');
+ let bv1 = triangles[i].v1;
+ triangles[i].v1 = triangles[i].v2;
+ triangles[i].v2 = bv1;
+ } else {
+ console.log('not clockwise');
+ }
+ }
+
+ return triangles;
+ };
+
+ /**
+ * This function resets the winding order for triangles in faces, given an initial triangle and orientation edge
+ * used pseudocode from
+ * http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh
+ * We need to use a graph traversal algorithm,
+ * lets assume we have method that returns neighbor of triangle on given edge
+ *
+ * neighbor_on_egde( next_tria, edge )
+ *
+ * to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it
+ * processed = set of processed triangles; initial empty
+ *
+ * while to_process is not empty:
+ * next_tria, orientation_edge = to_process.pop()
+ * add next_tria in processed
+ * if next_tria is not opposite oriented than orientation_edge:
+ * change next_tria (ABC) orientation (B<->C)
+ * for each edge (AB) in next_tria:
+ * neighbor_tria = neighbor_on_egde( next_tria, edge )
+ * if neighbor_tria exists and neighbor_tria not in processed:
+ * to_process add (neighbor_tria, edge opposite oriented (BA))
+ * @param faces R3.D3.Face[]
+ * @param orientationEdge R3.API.Vector2
+ * @returns {Array}
+ */
+ static FixWindingOrder(faces, orientationEdge) {
+
+ /**
+ * Checks if a Face belonging to a TriangleEdge has already been processed
+ * @param processed TriangleEdge[]
+ * @param triangle Face
+ * @returns {boolean}
+ */
+ function inProcessed(processed, triangle) {
+
+ for (let i = 0; i < processed.length; i++) {
+ if (processed[i].triangle.equals(triangle)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a neighbouring triangle on a specific edge - preserving the edge orientation
+ * @param edge R3.API.Vector2
+ * @param faces R3.D3.Face[]
+ * @param currentTriangle
+ * @returns {*}
+ */
+ function neighbourOnEdge(edge, faces, currentTriangle) {
+
+ for (let i = 0; i < faces.length; i++) {
+ if (
+ (faces[i].v0 === edge.x && faces[i].v1 === edge.y) ||
+ (faces[i].v1 === edge.x && faces[i].v2 === edge.y) ||
+ (faces[i].v2 === edge.x && faces[i].v0 === edge.y) ||
+ (faces[i].v0 === edge.y && faces[i].v1 === edge.x) ||
+ (faces[i].v1 === edge.y && faces[i].v2 === edge.x) ||
+ (faces[i].v2 === edge.y && faces[i].v0 === edge.x)
+ ) {
+
+ let triangle = new R3.D3.API.Face(
+ null,
+ null,
+ faces[i].v0index,
+ faces[i].v1index,
+ faces[i].v2index,
+ faces[i].materialIndex,
+ faces[i].uvs
+ );
+
+ if (triangle.equals(currentTriangle)) {
+ continue;
+ }
+
+ return new R3.D3.TriangleEdge(
+ triangle,
+ edge
+ );
+ }
+ }
+
+ return null;
+ }
+
+ let toProcess = [
+ new R3.D3.TriangleEdge(
+ new R3.D3.API.Face(
+ null,
+ null,
+ faces[0].v0index,
+ faces[0].v1index,
+ faces[0].v2index,
+ faces[0].materialIndex,
+ faces[0].uvs
+ ),
+ orientationEdge
+ )
+ ];
+
+ let processed = [];
+
+ while (toProcess.length > 0) {
+
+ let triangleEdge = toProcess.pop();
+
+ /**
+ * If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed
+ * to have the same winding order)
+ */
+ if (
+ (triangleEdge.triangle.v0index === triangleEdge.edge.x &&
+ triangleEdge.triangle.v1index === triangleEdge.edge.y) ||
+ (triangleEdge.triangle.v1index === triangleEdge.edge.x &&
+ triangleEdge.triangle.v2index === triangleEdge.edge.y) ||
+ (triangleEdge.triangle.v2index === triangleEdge.edge.x &&
+ triangleEdge.triangle.v0index === triangleEdge.edge.y)
+ ) {
+ let backupV = triangleEdge.triangle.v1index;
+ triangleEdge.triangle.v1index = triangleEdge.triangle.v2index;
+ triangleEdge.triangle.v2index = backupV;
+
+ // let backupUV = triangleEdge.triangle.v1uv;
+ // triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv;
+ // triangleEdge.triangle.v2uv = backupUV;
+ //
+ let backupUV = triangleEdge.triangle.uvs[0][1];
+ triangleEdge.triangle.uvs[0][1] = triangleEdge.triangle.uvs[0][2];
+ triangleEdge.triangle.uvs[0][2] = backupUV;
+ }
+
+ processed.push(triangleEdge);
+
+ let edges = [
+ new R3.API.Vector2(
+ triangleEdge.triangle.v0index,
+ triangleEdge.triangle.v1index
+ ),
+ new R3.API.Vector2(
+ triangleEdge.triangle.v1index,
+ triangleEdge.triangle.v2index
+ ),
+ new R3.API.Vector2(
+ triangleEdge.triangle.v2index,
+ triangleEdge.triangle.v0index
+ )
+ ];
+
+ for (let j = 0; j < edges.length; j++) {
+ let neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle);
+ if (neighbour && !inProcessed(processed, neighbour.triangle)) {
+ toProcess.push(neighbour);
+ }
+ }
+ }
+
+ /**
+ * In processed - we will have some duplicates - only add the unique ones
+ * @type {Array}
+ */
+ let triangles = [];
+ for (let i = 0; i < processed.length; i++) {
+ let found = false;
+ for (let k = 0; k < triangles.length; k++) {
+ if (triangles[k].equals(processed[i].triangle)){
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ triangles.push(processed[i].triangle);
+ }
+ }
+
+ return triangles;
+ };
+
+ /**
+ * This is a work-around function to fix polys which don't triangulate because
+ * they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around
+ * Z then Y axis
+ * @param verticesFlat []
+ * @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY
+ * @return []
+ */
+ static FixPolyZPlane(verticesFlat, grain) {
+
+ if ((verticesFlat.length % 3) !== 0 && !(verticesFlat.length > 9)) {
+ console.log("The vertices are not in the right length : " + verticesFlat.length);
+ }
+
+ let vertices = [];
+
+ let points = new R3.API.Quaternion.Points();
+
+ for (let i = 0; i < verticesFlat.length; i += 3) {
+ points.add(new R3.API.Vector3(
+ verticesFlat[i],
+ verticesFlat[i + 1],
+ verticesFlat[i + 2]
+ ));
+ }
+
+ points.toOrigin();
+
+ points.maximizeXDistance(grain);
+
+ points.maximizeYDistance(grain);
+
+ for (i = 0; i < points.vectors.length; i++) {
+ vertices.push(
+ [
+ points.vectors[i].x,
+ points.vectors[i].y
+ ]
+ );
+ }
+
+ return vertices;
+ };
+
+ static MovingAverage(period) {
+ let nums = [];
+ return function(num) {
+ nums.push(num);
+ if (nums.length > period)
+ nums.splice(0,1); // remove the first element of the array
+ let sum = 0;
+ for (let i in nums)
+ sum += nums[i];
+ let n = period;
+ if (nums.length < period)
+ n = nums.length;
+ return(sum/n);
+ }
+ };
+
+ static Intersect(a, b) {
+
+ let t;
+
+ /**
+ * Loop over shortest array
+ */
+ if (b.length > a.length) {
+ t = b;
+ b = a;
+ a = t;
+ }
+
+ return a.filter(
+ /**
+ * Check if exists
+ * @param e
+ * @returns {boolean}
+ */
+ function(e) {
+ return (b.indexOf(e) > -1);
+ }
+ ).filter(
+ /**
+ * Remove Duplicates
+ * @param e
+ * @param i
+ * @param c
+ * @returns {boolean}
+ */
+ function(e, i, c) {
+ return c.indexOf(e) === i;
+ }
+ );
+ };
+
+ static Difference(a, b) {
+
+ let t;
+
+ /**
+ * Loop over shortest array
+ */
+ if (b.length > a.length) {
+ t = b;
+ b = a;
+ a = t;
+ }
+
+ return a.filter(
+ /**
+ * Check if exists
+ * @param e
+ * @returns {boolean}
+ */
+ function(e) {
+ return (b.indexOf(e) === -1);
+ }
+ ).filter(
+ /**
+ * Remove Duplicates
+ * @param e
+ * @param i
+ * @param c
+ * @returns {boolean}
+ */
+ function(e, i, c) {
+ return c.indexOf(e) === i;
+ }
+ );
+ };
+
+ /**
+ * Push only if not in there already
+ * @param array
+ * @param object
+ * @constructor
+ */
+ static PushUnique(array, object) {
+
+ if (array.indexOf(object) === -1) {
+ array.push(object);
+ }
+ };
+
+ /**
+ * Checks whether or not the object is empty
+ * @param obj
+ * @returns {boolean}
+ * @constructor
+ */
+ static IsEmpty(obj) {
+ return (Object.keys(obj).length === 0 && obj.constructor === Object);
+ };
+
+ static IsString(member) {
+ return (typeof member === 'string');
+ };
+
+ static IsBoolean(member) {
+ return (member === true || member === false);
+ };
+
+ static IsColor(member) {
+ return (member instanceof R3.Color);
+ };
+
+ static IsNumber(member) {
+ return (typeof member === 'number');
+ };
+
+ static IsVector2(member) {
+ return (
+ member instanceof R3.API.Vector2 ||
+ member instanceof R3.Vector2
+ );
+ };
+
+ static IsVector3(member) {
+ return (
+ member instanceof R3.API.Vector3 ||
+ member instanceof R3.Vector3
+ );
+ };
+
+ static IsVector4(member) {
+ return (
+ member instanceof R3.API.Vector4 ||
+ member instanceof R3.Vector4 ||
+ member instanceof R3.API.Quaternion ||
+ member instanceof R3.Quaternion
+ );
+ };
+
+ static IsObject(member) {
+ let type = typeof member;
+ return type === 'function' || type === 'object' && !!member;
+ };
+
+ /**
+ * @return {string}
+ */
+ static LowerUnderscore(name) {
+ let string = name.toLowerCase().replace(/\s+/g, '_');
+ string = string.replace(/-/g, '_');
+ string = string.replace(/\_+/g, '_');
+ return string;
+ };
+
+ static UpperCaseWordsSpaces(input) {
+
+ let word = input.replace(/[-_]/g, ' ');
+
+ word = word.replace(/\s+/, ' ');
+
+ let words = word.split(' ');
+
+ return words.reduce(
+ function(result, word) {
+ result += word[0].toUpperCase() + word.substr(1);
+ return result + ' ';
+ },
+ ''
+ ).trim();
+ };
+
+ /**
+ * @return {string}
+ */
+ static UpperCaseUnderscore(word) {
+
+ let str = '';
+
+ word.split('').map(
+ function(letter){
+ if (letter === letter.toUpperCase()) {
+ str += '_' + letter;
+ } else {
+ str += letter.toUpperCase();
+ }
+ });
+
+ str = str.replace(new RegExp('^_'),'');
+
+ return str;
+ };
+
+ /**
+ * Returns Left Padded Text - ex. length 5, padchar 0, string abc = '00abc'
+ * @param length
+ * @param padChar
+ * @param string
+ * @returns {string}
+ * @constructor
+ */
+ static PaddedText(length, padChar, string) {
+
+ let pad = "";
+
+ for (let x = 0; x < length; x++) {
+ pad += padChar;
+ }
+
+ return pad.substring(0, pad.length - string.length) + string;
+ };
+ //CUSTOM_IMPLEMENTATION_END
+
}
+//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_START
+//CUSTOM_OUT_OF_CLASS_IMPLEMENTATION_END
+
module.exports = Utils;
\ No newline at end of file
diff --git a/src/templates/constructor.template b/src/templates/constructor.template
index c0e53de..5960e0d 100644
--- a/src/templates/constructor.template
+++ b/src/templates/constructor.template
@@ -1,12 +1,5 @@
constructor(options) {
- if (Utils.UndefinedOrNull(options)) {
- options = {};
- }
-
- options.id = Utils.RandomId(10);
- options.name = 'CLASS_NAME (' + options.id + ')';
-
Event.Emit(Event.OBJECT_CREATED, this);
//OPTIONS_INIT_START
diff --git a/src/templates/constructor_extends.template b/src/templates/constructor_extends.template
index 9644f3e..cee154f 100644
--- a/src/templates/constructor_extends.template
+++ b/src/templates/constructor_extends.template
@@ -4,9 +4,6 @@
options = {};
}
- options.id = Utils.RandomId(10);
- options.name = 'CLASS_NAME (' + options.id + ')';
-
super(options);
this.emit(Event.OBJECT_CREATED, this);
diff --git a/src/templates/create_instance_after.template b/src/templates/create_instance_after.template
index b45c537..90cfb15 100644
--- a/src/templates/create_instance_after.template
+++ b/src/templates/create_instance_after.template
@@ -1 +1,9 @@
+ this[this.runtime].createInstance(
+ this,
+ {
+ //CREATE_INSTANCE_OPTIONS_START
+ //CREATE_INSTANCE_OPTIONS_END
+ }
+ )
+
this.emit(Event.INSTANCE_CREATED, this);
\ No newline at end of file
diff --git a/src/templates/create_instance_before.template b/src/templates/create_instance_before.template
index 9b66076..0395cc6 100644
--- a/src/templates/create_instance_before.template
+++ b/src/templates/create_instance_before.template
@@ -1,12 +1 @@
- super.createInstance();
- this.emit(Event.CREATE_INSTANCE, this);
-
- if (this.runtime === 'graphics') {
- this.graphics.createInstance(
- {
- //CREATE_INSTANCE_OPTIONS_START
- //CREATE_INSTANCE_OPTIONS_END
- },
- this
- )
- }
+ this.emit(Event.CREATE_INSTANCE_BEFORE, this);
\ No newline at end of file
diff --git a/src/templates/create_instance_options.template b/src/templates/create_instance_options.template
index 9b63302..6ac3651 100644
--- a/src/templates/create_instance_options.template
+++ b/src/templates/create_instance_options.template
@@ -1 +1 @@
- 'INSTANCE_KEY': this.KEY
\ No newline at end of file
+ 'INSTANCE_KEY': this.KEY
\ No newline at end of file
diff --git a/src/templates/dispose_after.template b/src/templates/dispose_after.template
index 7f58934..30d8d5d 100644
--- a/src/templates/dispose_after.template
+++ b/src/templates/dispose_after.template
@@ -1 +1 @@
- this.emit(Event.OBJECT_DISPOSED, this);
\ No newline at end of file
+ this.disposeInstance();
\ No newline at end of file
diff --git a/src/templates/dispose_before.template b/src/templates/dispose_before.template
index 65c3a8c..2a39b52 100644
--- a/src/templates/dispose_before.template
+++ b/src/templates/dispose_before.template
@@ -1 +1,8 @@
- this.emit(Event.DISPOSE_OBJECT, this);
\ No newline at end of file
+ this.subscribe(
+ Event.INSTANCE_DISPOSED,
+ function(object) {
+ if (object === this) {
+ this.emit(Event.DISPOSE_OBJECT, this);
+ }
+ }
+ );
\ No newline at end of file
diff --git a/src/templates/dispose_instance_after.template b/src/templates/dispose_instance_after.template
index 6a8293f..264796c 100644
--- a/src/templates/dispose_instance_after.template
+++ b/src/templates/dispose_instance_after.template
@@ -1 +1 @@
- this.emit(Event.INSTANCE_DISPOSED, this);
\ No newline at end of file
+ this.emit(Event.DISPOSE_INSTANCE, this);
\ No newline at end of file
diff --git a/src/templates/dispose_instance_before.template b/src/templates/dispose_instance_before.template
index 5b1a418..596b4dd 100644
--- a/src/templates/dispose_instance_before.template
+++ b/src/templates/dispose_instance_before.template
@@ -1,2 +1 @@
- super.disposeInstance();
- this.emit(Event.DISPOSE_INSTANCE, this);
\ No newline at end of file
+ console.log('Disposing instance of ' + this.name);
\ No newline at end of file
diff --git a/src/templates/normal.template b/src/templates/normal.template
index 56d7bfd..45bcbd9 100644
--- a/src/templates/normal.template
+++ b/src/templates/normal.template
@@ -6,15 +6,6 @@ const Utils = require('r3-utils');
OPTIONS_START
OPTIONS_END
- INSTANCE_OPTIONS_MAPPING_START
- INSTANCE_OPTIONS_MAPPING_END
-
- LINKED_OBJECTS_START
- LINKED_OBJECTS_END
-
- EXCLUDED_FROM_INSTANCE_OPTIONS_START
- EXCLUDED_FROM_INSTANCE_OPTIONS_END
-
**/
class CLASS_NAME {
@@ -22,21 +13,6 @@ class CLASS_NAME {
//CONSTRUCTOR_TEMPLATE_START
//CONSTRUCTOR_TEMPLATE_END
- //CREATE_INSTANCE_TEMPLATE_START
- //CREATE_INSTANCE_TEMPLATE_END
-
- //UPDATE_INSTANCE_TEMPLATE_START
- //UPDATE_INSTANCE_TEMPLATE_END
-
- //UPDATE_FROM_INSTANCE_TEMPLATE_START
- //UPDATE_FROM_INSTANCE_TEMPLATE_END
-
- //DISPOSE_TEMPLATE_START
- //DISPOSE_TEMPLATE_END
-
- //DISPOSE_INSTANCE_TEMPLATE_START
- //DISPOSE_INSTANCE_TEMPLATE_END
-
//CUSTOM_IMPLEMENTATION_START
//CUSTOM_IMPLEMENTATION_END
diff --git a/src/templates/options_init_header.template b/src/templates/options_init_header.template
new file mode 100644
index 0000000..0384ea5
--- /dev/null
+++ b/src/templates/options_init_header.template
@@ -0,0 +1,3 @@
+ if (typeof options === 'undefined') {
+ options = {};
+ }
diff --git a/src/templates/update_from_instance_options.template b/src/templates/update_from_instance_options.template
index 519906f..ac5e593 100644
--- a/src/templates/update_from_instance_options.template
+++ b/src/templates/update_from_instance_options.template
@@ -1,4 +1,6 @@
- if (property === 'KEY') {
+ if (property === 'KEY' || property === 'all') {
this.KEY = this.instance.INSTANCE_KEY;
- return;
+ if (property !== 'all') {
+ return;
+ }
}
diff --git a/update_options.php b/update_options.php
index 8e21bcf..2c3ef09 100755
--- a/update_options.php
+++ b/update_options.php
@@ -157,9 +157,10 @@ foreach ($files as $file) {
/**
* Process the constructor options
*/
+ $header = file_get_contents('src/templates/options_init_header.template');
$template = file_get_contents('src/templates/options_init.template');
- $newOptions = '';
+ $newOptions = $header;
foreach ($options as $key => $value) {
$updated = str_replace('KEY', $key, $template);
@@ -200,16 +201,18 @@ foreach ($files as $file) {
array_push($newOptions, $updated);
}
- $contents = file_get_contents($file);
+ if (sizeof($newOptions) > 0) {
- $contents = preg_replace(
- '/\/\/\bCREATE_INSTANCE_OPTIONS_START\b.*?\/\/\bCREATE_INSTANCE_OPTIONS_END\b/s',
- "//CREATE_INSTANCE_OPTIONS_START\n" . implode(",\n", $newOptions) . "\n\t\t\t\t\t//CREATE_INSTANCE_OPTIONS_END",
- $contents
- );
+ $contents = file_get_contents($file);
- file_put_contents($file, $contents);
+ $contents = preg_replace(
+ '/\/\/\bCREATE_INSTANCE_OPTIONS_START\b.*?\/\/\bCREATE_INSTANCE_OPTIONS_END\b/s',
+ "//CREATE_INSTANCE_OPTIONS_START\n" . implode(",\n", $newOptions) . "\n\t\t\t\t//CREATE_INSTANCE_OPTIONS_END",
+ $contents
+ );
+ file_put_contents($file, $contents);
+ }
/**
* Process updateInstance options
*/
diff --git a/update_templates.php b/update_templates.php
index e27b1c3..417d327 100755
--- a/update_templates.php
+++ b/update_templates.php
@@ -161,6 +161,7 @@ foreach ($files as $file) {
echo "Restored file " . $file;
+ unlink($saveFile);
}
}