6780 lines
154 KiB
JavaScript
6780 lines
154 KiB
JavaScript
|
|
|
|
class R3 {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Version - Current R3 version
|
|
*/
|
|
R3.Version = '3.0.346';
|
|
|
|
/**
|
|
* static CompileDate - Current compile date of R3
|
|
*/
|
|
R3.CompileDate = '2021 Oct 10 - 16:15:59 pm';
|
|
|
|
class System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
System.DOM = 0x0;
|
|
System.INPUT = 0x1;
|
|
System.LINKING = 0x2;
|
|
System.RENDER = 0x3;
|
|
System.RUNTIME = 0x4;
|
|
System.SOCKET = 0x5;
|
|
System.STORAGE = 0x6;
|
|
System.MAX_SYSTEM = 0x7;
|
|
|
|
class SystemDOM extends System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* Start()
|
|
* - Starts the system by registering subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Start(options) {
|
|
|
|
SystemDOM.Subscriptions['DOM_COMPONENT_INITIALIZED'] = Event.Subscribe(
|
|
Event.DOM_COMPONENT_INITIALIZED,
|
|
SystemDOM.OnDomComponentInitialized
|
|
);
|
|
|
|
SystemDOM.Started = true;
|
|
|
|
console.log('Started system: SystemDOM');
|
|
|
|
}
|
|
|
|
/**
|
|
* Stop()
|
|
* - Stops the system by removing these subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Stop(options) {
|
|
|
|
SystemDOM.Subscriptions['DOM_COMPONENT_INITIALIZED'].remove();
|
|
delete SystemDOM.Subscriptions['DOM_COMPONENT_INITIALIZED'];
|
|
|
|
SystemDOM.Started = false;
|
|
|
|
console.log('Stopped system: SystemDOM');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnDomComponentInitialized()
|
|
* - Listens to events of type Event.DOM_COMPONENT_INITIALIZED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnDomComponentInitialized(object) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Started - Indicates whether or not this system is running or not
|
|
*/
|
|
SystemDOM.Started = false;
|
|
|
|
/**
|
|
* static Subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
SystemDOM.Subscriptions = {};
|
|
|
|
class SystemInput extends System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* Start()
|
|
* - Starts the system by registering subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Start(options) {
|
|
|
|
SystemInput.Subscriptions['SLIDER_ENTITY_INITIALIZED'] = Event.Subscribe(
|
|
Event.SLIDER_ENTITY_INITIALIZED,
|
|
SystemInput.OnSliderEntityInitialized
|
|
);
|
|
|
|
SystemInput.Subscriptions['TOUCH_START'] = Event.Subscribe(
|
|
Event.TOUCH_START,
|
|
SystemInput.OnTouchStart
|
|
);
|
|
|
|
SystemInput.Subscriptions['TOUCH_END'] = Event.Subscribe(
|
|
Event.TOUCH_END,
|
|
SystemInput.OnTouchEnd
|
|
);
|
|
|
|
SystemInput.Subscriptions['TOUCH_MOVE'] = Event.Subscribe(
|
|
Event.TOUCH_MOVE,
|
|
SystemInput.OnTouchMove
|
|
);
|
|
|
|
SystemInput.Subscriptions['TOUCH_CANCEL'] = Event.Subscribe(
|
|
Event.TOUCH_CANCEL,
|
|
SystemInput.OnTouchCancel
|
|
);
|
|
|
|
SystemInput.Subscriptions['KEYBOARD_DOWN'] = Event.Subscribe(
|
|
Event.KEYBOARD_DOWN,
|
|
SystemInput.OnKeyboardDown
|
|
);
|
|
|
|
SystemInput.Subscriptions['KEYBOARD_UP'] = Event.Subscribe(
|
|
Event.KEYBOARD_UP,
|
|
SystemInput.OnKeyboardUp
|
|
);
|
|
|
|
SystemInput.Subscriptions['MOUSE_DOWN'] = Event.Subscribe(
|
|
Event.MOUSE_DOWN,
|
|
SystemInput.OnMouseDown
|
|
);
|
|
|
|
SystemInput.Subscriptions['MOUSE_UP'] = Event.Subscribe(
|
|
Event.MOUSE_UP,
|
|
SystemInput.OnMouseUp
|
|
);
|
|
|
|
SystemInput.Subscriptions['MOUSE_MOVE'] = Event.Subscribe(
|
|
Event.MOUSE_MOVE,
|
|
SystemInput.OnMouseMove
|
|
);
|
|
|
|
SystemInput.Subscriptions['MOUSE_WHEEL'] = Event.Subscribe(
|
|
Event.MOUSE_WHEEL,
|
|
SystemInput.OnMouseWheel
|
|
);
|
|
|
|
SystemInput.Started = true;
|
|
|
|
console.log('Started system: SystemInput');
|
|
|
|
}
|
|
|
|
/**
|
|
* Stop()
|
|
* - Stops the system by removing these subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Stop(options) {
|
|
|
|
SystemInput.Subscriptions['SLIDER_ENTITY_INITIALIZED'].remove();
|
|
delete SystemInput.Subscriptions['SLIDER_ENTITY_INITIALIZED'];
|
|
|
|
SystemInput.Subscriptions['TOUCH_START'].remove();
|
|
delete SystemInput.Subscriptions['TOUCH_START'];
|
|
|
|
SystemInput.Subscriptions['TOUCH_END'].remove();
|
|
delete SystemInput.Subscriptions['TOUCH_END'];
|
|
|
|
SystemInput.Subscriptions['TOUCH_MOVE'].remove();
|
|
delete SystemInput.Subscriptions['TOUCH_MOVE'];
|
|
|
|
SystemInput.Subscriptions['TOUCH_CANCEL'].remove();
|
|
delete SystemInput.Subscriptions['TOUCH_CANCEL'];
|
|
|
|
SystemInput.Subscriptions['KEYBOARD_DOWN'].remove();
|
|
delete SystemInput.Subscriptions['KEYBOARD_DOWN'];
|
|
|
|
SystemInput.Subscriptions['KEYBOARD_UP'].remove();
|
|
delete SystemInput.Subscriptions['KEYBOARD_UP'];
|
|
|
|
SystemInput.Subscriptions['MOUSE_DOWN'].remove();
|
|
delete SystemInput.Subscriptions['MOUSE_DOWN'];
|
|
|
|
SystemInput.Subscriptions['MOUSE_UP'].remove();
|
|
delete SystemInput.Subscriptions['MOUSE_UP'];
|
|
|
|
SystemInput.Subscriptions['MOUSE_MOVE'].remove();
|
|
delete SystemInput.Subscriptions['MOUSE_MOVE'];
|
|
|
|
SystemInput.Subscriptions['MOUSE_WHEEL'].remove();
|
|
delete SystemInput.Subscriptions['MOUSE_WHEEL'];
|
|
|
|
SystemInput.Started = false;
|
|
|
|
console.log('Stopped system: SystemInput');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnSliderEntityInitialized()
|
|
* - Listens to events of type Event.SLIDER_ENTITY_INITIALIZED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnSliderEntityInitialized(object) {
|
|
|
|
console.log('Slider Entity Initialized');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnTouchStart()
|
|
* - Listens to events of type Event.TOUCH_START and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnTouchStart(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnTouchEnd()
|
|
* - Listens to events of type Event.TOUCH_END and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnTouchEnd(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnTouchMove()
|
|
* - Listens to events of type Event.TOUCH_MOVE and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnTouchMove(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnTouchCancel()
|
|
* - Listens to events of type Event.TOUCH_CANCEL and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnTouchCancel(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnKeyboardDown()
|
|
* - Listens to events of type Event.KEYBOARD_DOWN and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnKeyboardDown(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnKeyboardUp()
|
|
* - Listens to events of type Event.KEYBOARD_UP and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnKeyboardUp(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnMouseDown()
|
|
* - Listens to events of type Event.MOUSE_DOWN and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnMouseDown(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnMouseUp()
|
|
* - Listens to events of type Event.MOUSE_UP and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnMouseUp(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnMouseMove()
|
|
* - Listens to events of type Event.MOUSE_MOVE and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnMouseMove(object) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnMouseWheel()
|
|
* - Listens to events of type Event.MOUSE_WHEEL and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnMouseWheel(object) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Started - Indicates whether or not this system is running or not
|
|
*/
|
|
SystemInput.Started = false;
|
|
|
|
/**
|
|
* static Subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
SystemInput.Subscriptions = {};
|
|
|
|
class SystemLinking extends System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* Start()
|
|
* - Starts the system by registering subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Start(options) {
|
|
|
|
SystemLinking.Subscriptions['OBJECT_CREATED'] = Event.Subscribe(
|
|
Event.OBJECT_CREATED,
|
|
SystemLinking.OnObjectCreated
|
|
);
|
|
|
|
SystemLinking.Subscriptions['COMPONENT_INITIALIZED'] = Event.Subscribe(
|
|
Event.COMPONENT_INITIALIZED,
|
|
SystemLinking.OnComponentInitialized
|
|
);
|
|
|
|
SystemLinking.Subscriptions['ENTITY_INITIALIZED'] = Event.Subscribe(
|
|
Event.ENTITY_INITIALIZED,
|
|
SystemLinking.OnEntityInitialized
|
|
);
|
|
|
|
SystemLinking.Subscriptions['INSTANCE_CREATED'] = Event.Subscribe(
|
|
Event.INSTANCE_CREATED,
|
|
SystemLinking.OnInstanceCreated
|
|
);
|
|
|
|
SystemLinking.Subscriptions['CREATE_INSTANCE_BEFORE'] = Event.Subscribe(
|
|
Event.CREATE_INSTANCE_BEFORE,
|
|
SystemLinking.OnCreateInstanceBefore
|
|
);
|
|
|
|
SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATE'] = Event.Subscribe(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
SystemLinking.OnObjectPropertyUpdate
|
|
);
|
|
|
|
SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATED'] = Event.Subscribe(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
SystemLinking.OnObjectPropertyUpdated
|
|
);
|
|
|
|
SystemLinking.Subscriptions['ON_READY_STATE_CHANGE'] = Event.Subscribe(
|
|
Event.ON_READY_STATE_CHANGE,
|
|
SystemLinking.OnOnReadyStateChange
|
|
);
|
|
|
|
SystemLinking.Subscriptions['FINAL_INITIALIZE'] = Event.Subscribe(
|
|
Event.FINAL_INITIALIZE,
|
|
SystemLinking.OnFinalInitialize
|
|
);
|
|
|
|
SystemLinking.Started = true;
|
|
|
|
console.log('Started system: SystemLinking');
|
|
|
|
}
|
|
|
|
/**
|
|
* Stop()
|
|
* - Stops the system by removing these subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Stop(options) {
|
|
|
|
SystemLinking.Subscriptions['OBJECT_CREATED'].remove();
|
|
delete SystemLinking.Subscriptions['OBJECT_CREATED'];
|
|
|
|
SystemLinking.Subscriptions['COMPONENT_INITIALIZED'].remove();
|
|
delete SystemLinking.Subscriptions['COMPONENT_INITIALIZED'];
|
|
|
|
SystemLinking.Subscriptions['ENTITY_INITIALIZED'].remove();
|
|
delete SystemLinking.Subscriptions['ENTITY_INITIALIZED'];
|
|
|
|
SystemLinking.Subscriptions['INSTANCE_CREATED'].remove();
|
|
delete SystemLinking.Subscriptions['INSTANCE_CREATED'];
|
|
|
|
SystemLinking.Subscriptions['CREATE_INSTANCE_BEFORE'].remove();
|
|
delete SystemLinking.Subscriptions['CREATE_INSTANCE_BEFORE'];
|
|
|
|
SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATE'].remove();
|
|
delete SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATE'];
|
|
|
|
SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATED'].remove();
|
|
delete SystemLinking.Subscriptions['OBJECT_PROPERTY_UPDATED'];
|
|
|
|
SystemLinking.Subscriptions['ON_READY_STATE_CHANGE'].remove();
|
|
delete SystemLinking.Subscriptions['ON_READY_STATE_CHANGE'];
|
|
|
|
SystemLinking.Subscriptions['FINAL_INITIALIZE'].remove();
|
|
delete SystemLinking.Subscriptions['FINAL_INITIALIZE'];
|
|
|
|
SystemLinking.Started = false;
|
|
|
|
console.log('Stopped system: SystemLinking');
|
|
|
|
}
|
|
|
|
/**
|
|
* SanityChecks()
|
|
* - When an object gets some value assigned to a property, we need to check if this property is a required
|
|
* property, and if so, the value assigned to this property needs to conform to the type restrictions enforced by
|
|
* the requirements objects.
|
|
* @param r3Object
|
|
* @param property
|
|
* @param value
|
|
*/
|
|
static SanityChecks(
|
|
r3Object,
|
|
property,
|
|
value
|
|
) {
|
|
|
|
for (let r = 0; r < r3Object.required.length; r++) {
|
|
|
|
/**
|
|
* First we check if this is a required property
|
|
*/
|
|
if (!r3Object.required[r].hasOwnProperty(property)) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* We know this property is required - so continue..
|
|
*/
|
|
if (r3Object.required[r][property] instanceof Array) {
|
|
|
|
/**
|
|
* First we need to check that this value conforms to the requirement of being an Array
|
|
*/
|
|
if (!(value instanceof Array)) {
|
|
|
|
if (r3Object.underConstruction) {
|
|
/**
|
|
* We are about to throw during a construction process. This means this r3Object will not
|
|
* be created - and so we need tell all of its children that this object is no longer their
|
|
* parent so that it can be garbage collected
|
|
*/
|
|
r3Object.children.map(
|
|
function(child) {
|
|
Utils.RemoveFromArray(child.parents, r3Object);
|
|
}
|
|
);
|
|
}
|
|
|
|
throw new TypeError('The property ' + property + ' of ' + r3Object.name + ' was not properly defined - it should be an array');
|
|
}
|
|
|
|
if (value.length === 0) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Check all items in the array are valid objects of type r3Object.required[property]
|
|
*/
|
|
for (let i = 0; i < value.length; i++) {
|
|
r3Object.required[r][property].map(
|
|
function (constructor) {
|
|
if (!(value[i] instanceof constructor)) {
|
|
|
|
if (r3Object.underConstruction) {
|
|
/**
|
|
* We are about to throw during a construction process. This means this r3Object will not
|
|
* be created - and so we need tell all of its children that this object is no longer their
|
|
* parent so that it can be garbage collected
|
|
*/
|
|
r3Object.children.map(
|
|
function(child) {
|
|
Utils.RemoveFromArray(child.parents, r3Object);
|
|
}
|
|
);
|
|
}
|
|
|
|
throw new TypeError('The child item inside ' + property + '[] of this object is not of the correct type');
|
|
}
|
|
}
|
|
);
|
|
}
|
|
} else {
|
|
|
|
if (value === null) {
|
|
return;
|
|
}
|
|
|
|
if (typeof value === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
if (!(value instanceof r3Object.required[r][property])) {
|
|
|
|
if (r3Object.underConstruction) {
|
|
/**
|
|
* We are about to throw during a construction process. This means this r3Object will not
|
|
* be created - and so we need tell all of its children that this object is no longer their
|
|
* parent so that it can be garbage collected
|
|
*/
|
|
r3Object.children.map(
|
|
function(child) {
|
|
Utils.RemoveFromArray(child.parents, r3Object);
|
|
}
|
|
);
|
|
}
|
|
|
|
throw new TypeError('The property ' + property + ' of ' + r3Object.name + ' is not of the correct type')
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* SetParentChildRelationships()
|
|
* - When an object gets some value assigned to a property, and it is a required property, we need to ensure that
|
|
* the proper parent and child relationships are maintained
|
|
* @param r3Object
|
|
* @param property
|
|
* @param value
|
|
*/
|
|
static SetParentChildRelationships(
|
|
r3Object,
|
|
property,
|
|
value
|
|
) {
|
|
|
|
if (value instanceof Array) {
|
|
|
|
/**
|
|
* We need to check if we removed an item from the existing array
|
|
*/
|
|
if (r3Object[property].length > 0) {
|
|
/**
|
|
* Find the missing value (if any) from the old array
|
|
*/
|
|
|
|
let unlinked = r3Object[property].reduce(
|
|
function(result, object) {
|
|
if (value.indexOf(object) === -1) {
|
|
result.push(object);
|
|
}
|
|
return result;
|
|
},
|
|
[]
|
|
);
|
|
|
|
unlinked.map(
|
|
function(unlinkObject) {
|
|
Utils.RemoveFromArray(unlinkObject.parents, r3Object);
|
|
Utils.RemoveFromArray(r3Object.children, unlinkObject);
|
|
if (r3Object instanceof Entity) {
|
|
Utils.RemoveFromArray(r3Object.components, unlinkObject);
|
|
}
|
|
}
|
|
);
|
|
|
|
}
|
|
|
|
for (let i = 0; i < value.length; i++) {
|
|
if (value[i] instanceof R3Object) {
|
|
Utils.PushUnique(value[i].parents, r3Object);
|
|
Utils.PushUnique(r3Object.children, value[i]);
|
|
if (r3Object instanceof Entity) {
|
|
Utils.PushUnique(r3Object.components, value[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (value instanceof R3Object) {
|
|
Utils.PushUnique(value.parents, r3Object);
|
|
Utils.PushUnique(r3Object.children, value);
|
|
if (r3Object instanceof Entity) {
|
|
Utils.PushUnique(r3Object.components, value);
|
|
}
|
|
}
|
|
|
|
if (value === null || typeof value === 'undefined') {
|
|
|
|
if (r3Object[property] instanceof R3Object) {
|
|
Utils.RemoveFromArray(r3Object[property].parents, r3Object);
|
|
Utils.RemoveFromArray(r3Object.children, r3Object[property]);
|
|
if (r3Object instanceof Entity) {
|
|
Utils.RemoveFromArray(r3Object.components, r3Object[property]);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* DetermineFutureReadyState()
|
|
* - When an object is assigned some value to one of its required properties, we should determine the future
|
|
* 'readiness' state of this R3 Object. Only if its ready state becomes false, we need to cascade this
|
|
* information to all parents forcing them to emit a Only if its ready state becomes false, we force all parents
|
|
* to emit a READY_STATE_PENDING_FALSE event.
|
|
* @param r3Object
|
|
* @param property
|
|
* @param value
|
|
*/
|
|
static DetermineFutureReadyState(
|
|
r3Object,
|
|
property,
|
|
value
|
|
) {
|
|
|
|
console.log('Determining future ready state of ' + r3Object.name + ' because of property change : ' + property);
|
|
|
|
for (let r = 0; r < r3Object.required.length; r++) {
|
|
|
|
if (r3Object.ready[r]) {
|
|
|
|
/**
|
|
* This object is currently ready - we need to check if this object will fall out of a ready state.
|
|
* We only need to compare the current property.
|
|
*/
|
|
|
|
let ready = true;
|
|
|
|
let requirements = r3Object.required[r];
|
|
|
|
if (requirements.hasOwnProperty(property)) {
|
|
ready = r3Object.requirementValueCheck(requirements[property], value);
|
|
}
|
|
|
|
if (!ready) {
|
|
/**
|
|
* This object will fall out of readiness state - notify all systems
|
|
*/
|
|
console.log('Future ready state will transition from true to false');
|
|
SystemLinking.CascadeFutureReadyState(r3Object, R3Object.READY_STATE_PENDING_FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* CascadeFutureReadyState()
|
|
* - We start at the current node - emit READY_STATE_PENDING_FALSE event, afterwards calling asking all parents to
|
|
* emit a READY_STATE_PENDING_FALSE event. This allows the SystemLinking to stop Entities before the cleanup
|
|
* occurs.
|
|
* @param r3Object
|
|
* @param readyState
|
|
*/
|
|
static CascadeFutureReadyState(
|
|
r3Object,
|
|
readyState
|
|
) {
|
|
|
|
let node = new Node(
|
|
{
|
|
object : r3Object
|
|
}
|
|
);
|
|
|
|
let graph = new Graph(
|
|
{
|
|
startNode : node,
|
|
relevant : ['parents']
|
|
}
|
|
)
|
|
|
|
let nodes = graph.closed;
|
|
|
|
/**
|
|
* nodes contains a list of current node and parent Objects which are affected by the ready state of this object.
|
|
*/
|
|
for (let n = 0; n < nodes.length; n++) {
|
|
|
|
let node = nodes[n];
|
|
|
|
/**
|
|
* The parent does not know directly why it falls out of ready state necessarily - because from its perspective
|
|
* it may have all its children requirements met - however a child of one of its children is going out of ready
|
|
* state. So - without adding too much complexity here, we just notify all parents (including the current node)
|
|
* that it's impending ready state will be false. We don't care about the readyStateIndex because of this. (for
|
|
* the sake of complexity)
|
|
*/
|
|
Event.Emit(
|
|
Event.ON_READY_STATE_CHANGE,
|
|
{
|
|
r3Object: node.object,
|
|
readyState: readyState
|
|
}
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* CascadeActualReadyState()
|
|
* - We start at the current node, determine its current ready state (it triggers the appropriate events),
|
|
* afterwards we work from the first parent upwards, determining it's ready state, taking appropriate action and
|
|
* cascading upwards.
|
|
* @param r3Object
|
|
*/
|
|
static CascadeActualReadyState(r3Object) {
|
|
|
|
console.log('Cascading actual ready state of ' + r3Object.name);
|
|
|
|
let node = new Node(
|
|
{
|
|
object : r3Object
|
|
}
|
|
);
|
|
|
|
let graph = new Graph(
|
|
{
|
|
startNode : node,
|
|
relevant : ['parents']
|
|
}
|
|
)
|
|
|
|
let nodes = graph.closed;
|
|
|
|
/**
|
|
* nodes contains the current node as it's first object, followed by its parents
|
|
*/
|
|
for (let n = 0; n < nodes.length; n++) {
|
|
|
|
let node = nodes[n];
|
|
|
|
/**
|
|
* A simple node.object.isReady() check will trigger the required READY_STATE_CHANGE events
|
|
*/
|
|
node.object.isReady();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* OnObjectCreated()
|
|
* - Listens to events of type Event.OBJECT_CREATED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnObjectCreated(object) {
|
|
|
|
console.log('Object created : ' + object.name);
|
|
|
|
}
|
|
|
|
/**
|
|
* OnComponentInitialized()
|
|
* - Listens to events of type Event.COMPONENT_INITIALIZED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnComponentInitialized(object) {
|
|
|
|
console.log('component initialized');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnEntityInitialized()
|
|
* - Listens to events of type Event.ENTITY_INITIALIZED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnEntityInitialized(object) {
|
|
|
|
console.log('entity initialized');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnInstanceCreated()
|
|
* - Listens to events of type Event.INSTANCE_CREATED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnInstanceCreated(object) {
|
|
|
|
console.log('instance created');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnCreateInstanceBefore()
|
|
* - Listens to events of type Event.CREATE_INSTANCE_BEFORE and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return boolean delayInstance which indicates whether or not instance creation is delayed (handled) by
|
|
* another system. (i.e. where instance creation order is of importance)
|
|
*/
|
|
static OnCreateInstanceBefore(object) {
|
|
|
|
for (let i = 0; i < SystemLinking.BlacklistedComponents.length; i++) {
|
|
if (object instanceof SystemLinking.BlacklistedComponents) {
|
|
|
|
/**
|
|
* If an object is 'Blacklisted' - we need to fire an event
|
|
* to notify other systems that this component requests
|
|
* to have its instance created.
|
|
*
|
|
* Should no system respond to this event we should continue
|
|
* to create the instance
|
|
*/
|
|
|
|
let delayInstance = false;
|
|
|
|
Event.Emit(
|
|
Event.BLACKLISTED_COMPONENT_INSTANCE_REQUEST,
|
|
object,
|
|
function(response) {
|
|
delayInstance = response;
|
|
}
|
|
);
|
|
|
|
return delayInstance;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/**
|
|
* OnObjectPropertyUpdate()
|
|
* - Listens to events of type Event.OBJECT_PROPERTY_UPDATE and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnObjectPropertyUpdate(object) {
|
|
|
|
let {value, property, r3Object} = object;
|
|
|
|
// object = object.object;
|
|
|
|
console.log('Object property update: ' + r3Object.constructor.name + '.' + property);
|
|
|
|
/**
|
|
* First we need to perform some sanity checks on the property
|
|
*/
|
|
SystemLinking.SanityChecks(r3Object, property, value);
|
|
|
|
/**
|
|
* Set the parent relationships
|
|
*/
|
|
SystemLinking.SetParentChildRelationships(r3Object, property, value);
|
|
|
|
/**
|
|
* Determine the future ready state of the r3Object
|
|
*/
|
|
SystemLinking.DetermineFutureReadyState(r3Object, property, value);
|
|
|
|
/**
|
|
* The value was unassigned - remove the parent relationships of the existing
|
|
* components (if available)
|
|
*/
|
|
// if (value === null || typeof value === 'undefined') {
|
|
// if (r3Object[property] instanceof R3Object) {
|
|
// r3Object.dirty = true;
|
|
// Utils.RemoveFromArray(r3Object[property].parents, r3Object);
|
|
// }
|
|
// }
|
|
//
|
|
// if (!r3Object.underConstruction) {
|
|
//
|
|
// if (r3Object.initialized) {
|
|
// /**
|
|
// * Check if this object will still be initialized after this assignment completes
|
|
// */
|
|
// r3Object.setInitialized(property, value);
|
|
// if (!r3Object.initialized) {
|
|
// //We set this object back to initialized because it is still initialized - it WILL be not initialized in the future
|
|
// r3Object.initialized = true;
|
|
// r3Object.stop();
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
}
|
|
|
|
/**
|
|
* OnObjectPropertyUpdated()
|
|
* - Listens to events of type Event.OBJECT_PROPERTY_UPDATED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnObjectPropertyUpdated(object) {
|
|
|
|
let {r3Object} = object;
|
|
|
|
/**
|
|
* Determine the actual ready state of the r3Object
|
|
*/
|
|
SystemLinking.CascadeActualReadyState(r3Object);
|
|
|
|
}
|
|
|
|
/**
|
|
* OnOnReadyStateChange()
|
|
* - Listens to events of type Event.ON_READY_STATE_CHANGE and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnOnReadyStateChange(object) {
|
|
|
|
let {r3Object, readyState, readyStateIndex} = object;
|
|
|
|
if (readyState === R3Object.READY_STATE_TRUE) {
|
|
|
|
console.log('Ready state changed to true for ' + r3Object.name + ' by passing requirements set ' + readyStateIndex);
|
|
|
|
/**
|
|
* If it is a Component and it has no instance, call its createInstance().
|
|
*/
|
|
if (r3Object instanceof Component && !r3Object.instance) {
|
|
r3Object.createInstance();
|
|
}
|
|
|
|
/**
|
|
* If it is an Entity and it is stopped, call the start() method.
|
|
*/
|
|
if (r3Object instanceof Entity && r3Object.started === false) {
|
|
r3Object.start();
|
|
}
|
|
|
|
}
|
|
|
|
if (readyState === R3Object.READY_STATE_FALSE) {
|
|
console.log('Ready state false for : ' + r3Object.name);
|
|
|
|
/**
|
|
* If it is a Component and it has an instance, dispose of it
|
|
*/
|
|
if (r3Object instanceof Component && r3Object.instance) {
|
|
r3Object.disposeInstance();
|
|
}
|
|
}
|
|
|
|
if (readyState === R3Object.READY_STATE_PENDING_FALSE) {
|
|
console.log('Ready state pending false for : ' + r3Object.name);
|
|
|
|
/**
|
|
* If it is an Entity and is started, stop it.
|
|
*/
|
|
if (r3Object instanceof Entity && r3Object.started === true) {
|
|
r3Object.stop();
|
|
}
|
|
}
|
|
|
|
if (readyState === R3Object.READY_STATE_PENDING_TRUE) {
|
|
|
|
/**
|
|
* We don't do anything at the moment - we just log this information.
|
|
*/
|
|
console.log('Ready state pending true for ' + r3Object.name + ' by passing requirements set ' + readyStateIndex);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* OnFinalInitialize()
|
|
* - Listens to events of type Event.FINAL_INITIALIZE and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnFinalInitialize(object) {
|
|
|
|
if (object instanceof Component) {
|
|
if (object.required.length === 0) {
|
|
object.createInstance();
|
|
}
|
|
}
|
|
|
|
if (object instanceof Entity) {
|
|
if (object.required.length === 0) {
|
|
object.start();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Started - Indicates whether or not this system is running or not
|
|
*/
|
|
SystemLinking.Started = false;
|
|
|
|
/**
|
|
* static Subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
SystemLinking.Subscriptions = {};
|
|
|
|
/**
|
|
* static BlacklistedComponents - A list of component constructors which should not be permitted to create instances
|
|
* immediately
|
|
*/
|
|
SystemLinking.BlacklistedComponents = [];
|
|
|
|
class SystemRender extends System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* Start()
|
|
* - Starts the system by registering subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Start(options) {
|
|
|
|
SystemRender.Subscriptions['INSTANCE_CREATED'] = Event.Subscribe(
|
|
Event.INSTANCE_CREATED,
|
|
SystemRender.OnInstanceCreated
|
|
);
|
|
|
|
SystemRender.Started = true;
|
|
|
|
console.log('Started system: SystemRender');
|
|
|
|
}
|
|
|
|
/**
|
|
* Stop()
|
|
* - Stops the system by removing these subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Stop(options) {
|
|
|
|
SystemRender.Subscriptions['INSTANCE_CREATED'].remove();
|
|
delete SystemRender.Subscriptions['INSTANCE_CREATED'];
|
|
|
|
SystemRender.Started = false;
|
|
|
|
console.log('Stopped system: SystemRender');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnInstanceCreated()
|
|
* - Listens to events of type Event.INSTANCE_CREATED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnInstanceCreated(object) {
|
|
|
|
if (object instanceof ComponentDOM) {
|
|
if (object.runtime instanceof RuntimeDocument) {
|
|
document.body.appendChild(object.instance);
|
|
}
|
|
}
|
|
|
|
if (object instanceof ComponentImage) {
|
|
if (object.runtime instanceof RuntimeWebImage) {
|
|
document.body.appendChild(object.instance);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Started - Indicates whether or not this system is running or not
|
|
*/
|
|
SystemRender.Started = false;
|
|
|
|
/**
|
|
* static Subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
SystemRender.Subscriptions = {};
|
|
|
|
class SystemRuntime extends System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* Start()
|
|
* - Starts the system by registering subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Start(options) {
|
|
|
|
SystemRuntime.Subscriptions['RUNTIME_CREATED'] = Event.Subscribe(
|
|
Event.RUNTIME_CREATED,
|
|
SystemRuntime.OnRuntimeCreated
|
|
);
|
|
|
|
SystemRuntime.Subscriptions['GET_RUNTIME'] = Event.Subscribe(
|
|
Event.GET_RUNTIME,
|
|
SystemRuntime.OnGetRuntime
|
|
);
|
|
|
|
SystemRuntime.Subscriptions['PROJECT_INITIALIZED'] = Event.Subscribe(
|
|
Event.PROJECT_INITIALIZED,
|
|
SystemRuntime.OnProjectInitialized
|
|
);
|
|
|
|
SystemRuntime.Subscriptions['GET_API_URL'] = Event.Subscribe(
|
|
Event.GET_API_URL,
|
|
SystemRuntime.OnGetApiUrl
|
|
);
|
|
|
|
SystemRuntime.Started = true;
|
|
|
|
console.log('Started system: SystemRuntime');
|
|
|
|
}
|
|
|
|
/**
|
|
* Stop()
|
|
* - Stops the system by removing these subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Stop(options) {
|
|
|
|
SystemRuntime.Subscriptions['RUNTIME_CREATED'].remove();
|
|
delete SystemRuntime.Subscriptions['RUNTIME_CREATED'];
|
|
|
|
SystemRuntime.Subscriptions['GET_RUNTIME'].remove();
|
|
delete SystemRuntime.Subscriptions['GET_RUNTIME'];
|
|
|
|
SystemRuntime.Subscriptions['PROJECT_INITIALIZED'].remove();
|
|
delete SystemRuntime.Subscriptions['PROJECT_INITIALIZED'];
|
|
|
|
SystemRuntime.Subscriptions['GET_API_URL'].remove();
|
|
delete SystemRuntime.Subscriptions['GET_API_URL'];
|
|
|
|
SystemRuntime.Started = false;
|
|
|
|
console.log('Stopped system: SystemRuntime');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnRuntimeCreated()
|
|
* - Listens to events of type Event.RUNTIME_CREATED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnRuntimeCreated(object) {
|
|
|
|
console.log('Runtime created : ' + object.name);
|
|
|
|
}
|
|
|
|
/**
|
|
* OnGetRuntime()
|
|
* - Listens to events of type Event.GET_RUNTIME and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnGetRuntime(object) {
|
|
|
|
/**
|
|
* DOM and Input Components are typically managed through
|
|
* the DOM.
|
|
*/
|
|
if (
|
|
object instanceof ComponentDOM ||
|
|
object instanceof ComponentImage ||
|
|
object instanceof ComponentInput
|
|
) {
|
|
if (SystemRuntime.CurrentProject === null) {
|
|
|
|
if (SystemRuntime.ServerSide) {
|
|
|
|
if (!SystemRuntime.RuntimeDOM.JS) {
|
|
SystemRuntime.RuntimeDOM.JS = new RuntimeJSDOM();
|
|
}
|
|
|
|
return SystemRuntime.RuntimeDOM.JS;
|
|
|
|
} else {
|
|
|
|
if (!SystemRuntime.RuntimeDOM.Web) {
|
|
SystemRuntime.RuntimeDOM.Web = new RuntimeWebDOM();
|
|
}
|
|
|
|
return SystemRuntime.RuntimeDOM.Web;
|
|
|
|
}
|
|
} else {
|
|
console.log('TODO: implement a project based DOM runtime');
|
|
}
|
|
}
|
|
|
|
if (object instanceof ComponentCode) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* OnProjectInitialized()
|
|
* - Listens to events of type Event.PROJECT_INITIALIZED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnProjectInitialized(object) {
|
|
|
|
Utils.PushUnique(SystemRuntime.Projects, object);
|
|
SystemRuntime.CurrentProject = object;
|
|
|
|
}
|
|
|
|
/**
|
|
* OnGetApiUrl()
|
|
* - Listens to events of type Event.GET_API_URL and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnGetApiUrl(object) {
|
|
|
|
if (SystemRuntime.CurrentProject === null) {
|
|
/**
|
|
* Check if we are running server side or client side
|
|
*/
|
|
if (process && process.env) {
|
|
const {API_URL} = process.env;
|
|
|
|
if (typeof API_URL === 'undefined') {
|
|
throw new Error('No API_URL defined for this process');
|
|
}
|
|
|
|
return API_URL;
|
|
} else {
|
|
return 'http://api.r3js.local';
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Started - Indicates whether or not this system is running or not
|
|
*/
|
|
SystemRuntime.Started = false;
|
|
|
|
/**
|
|
* static Subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
SystemRuntime.Subscriptions = {};
|
|
|
|
/**
|
|
* static Projects - No comment
|
|
*/
|
|
SystemRuntime.Projects = [];
|
|
|
|
/**
|
|
* static CurrentProject - No comment
|
|
*/
|
|
SystemRuntime.CurrentProject = null;
|
|
|
|
/**
|
|
* static ServerSide - No comment
|
|
*/
|
|
SystemRuntime.ServerSide = (typeof process !== 'undefined');
|
|
|
|
/**
|
|
* static RuntimeCoder - No comment
|
|
*/
|
|
SystemRuntime.RuntimeCoder = {};
|
|
|
|
/**
|
|
* static RuntimeDOM - No comment
|
|
*/
|
|
SystemRuntime.RuntimeDOM = {};
|
|
|
|
/**
|
|
* static RuntimeGUI - No comment
|
|
*/
|
|
SystemRuntime.RuntimeGUI = {};
|
|
|
|
/**
|
|
* static RuntimeGraphics - No comment
|
|
*/
|
|
SystemRuntime.RuntimeGraphics = {};
|
|
|
|
/**
|
|
* static RuntimePhysics - No comment
|
|
*/
|
|
SystemRuntime.RuntimePhysics = {};
|
|
|
|
/**
|
|
* static RuntimeStatistics - No comment
|
|
*/
|
|
SystemRuntime.RuntimeStatistics = {};
|
|
|
|
class SystemSocket extends System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* Start()
|
|
* - Starts the system by registering subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Start(options) {
|
|
|
|
SystemSocket.Started = true;
|
|
|
|
console.log('Started system: SystemSocket');
|
|
|
|
}
|
|
|
|
/**
|
|
* Stop()
|
|
* - Stops the system by removing these subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Stop(options) {
|
|
|
|
SystemSocket.Started = false;
|
|
|
|
console.log('Stopped system: SystemSocket');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Started - Indicates whether or not this system is running or not
|
|
*/
|
|
SystemSocket.Started = false;
|
|
|
|
/**
|
|
* static Subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
SystemSocket.Subscriptions = {};
|
|
|
|
class SystemStorage extends System {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* Start()
|
|
* - Starts the system by registering subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Start(options) {
|
|
|
|
SystemStorage.Subscriptions['IMAGE_INSTANCE_CREATED'] = Event.Subscribe(
|
|
Event.IMAGE_INSTANCE_CREATED,
|
|
SystemStorage.OnImageInstanceCreated
|
|
);
|
|
|
|
SystemStorage.Started = true;
|
|
|
|
console.log('Started system: SystemStorage');
|
|
|
|
}
|
|
|
|
/**
|
|
* Stop()
|
|
* - Stops the system by removing these subscriptions to events
|
|
* @param options
|
|
*/
|
|
static Stop(options) {
|
|
|
|
SystemStorage.Subscriptions['IMAGE_INSTANCE_CREATED'].remove();
|
|
delete SystemStorage.Subscriptions['IMAGE_INSTANCE_CREATED'];
|
|
|
|
SystemStorage.Started = false;
|
|
|
|
console.log('Stopped system: SystemStorage');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnImageInstanceCreated()
|
|
* - Listens to events of type Event.IMAGE_INSTANCE_CREATED and executes this function.
|
|
* @param object (The event data passed as argument - typically an R3Object)
|
|
* @return
|
|
*/
|
|
static OnImageInstanceCreated(object) {
|
|
|
|
Event.Emit(
|
|
Event.GET_API_URL,
|
|
null,
|
|
function(apiUrl) {
|
|
console.log('about to download image at: ' + apiUrl + object.external_path);
|
|
}
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* static Started - Indicates whether or not this system is running or not
|
|
*/
|
|
SystemStorage.Started = false;
|
|
|
|
/**
|
|
* static Subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
SystemStorage.Subscriptions = {};
|
|
|
|
class Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Runtime.BASE_CODER = 0x0;
|
|
Runtime.BASE_DOM = 0x1;
|
|
Runtime.BASE_GUI = 0x2;
|
|
Runtime.BASE_GRAPHICS = 0x3;
|
|
Runtime.BASE_IMAGE = 0x4;
|
|
Runtime.BASE_PHYSICS = 0x5;
|
|
Runtime.BASE_SOCKET = 0x6;
|
|
Runtime.BASE_STATISTICS = 0x7;
|
|
Runtime.CODE_MIRROR = 0x8;
|
|
Runtime.JSDOM = 0x9;
|
|
Runtime.WEB_DOM = 0xa;
|
|
Runtime.CONTROL_KIT = 0xb;
|
|
Runtime.THREE = 0xc;
|
|
Runtime.BULLET = 0xd;
|
|
Runtime.STATS = 0xe;
|
|
|
|
class RuntimeCoder extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeCodeMirror extends RuntimeCoder {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* buildInstance()
|
|
* - Creates a runtime instance object based on the R3.Component representing it.
|
|
* @param component
|
|
*/
|
|
buildInstance(component) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeDOM extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeJSDOM extends RuntimeDOM {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* dom - No comment
|
|
*/
|
|
if (typeof options.dom === 'undefined') {
|
|
options.dom = new JSDOM(`<!DOCTYPE html><p>R3 NodeJS DOM</p>`);;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* buildInstance()
|
|
* - Creates a runtime instance object based on the R3.Component representing it.
|
|
* @param component
|
|
*/
|
|
buildInstance(component) {
|
|
|
|
if (component instanceof ComponentCanvas) {
|
|
let canvas = this.dom.window.document.createElement('canvas');
|
|
canvas.setAttribute('width', component.width);
|
|
canvas.setAttribute('height', component.height);
|
|
canvas.setAttribute('style', component.style);
|
|
return canvas;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeWebDOM extends RuntimeDOM {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* buildInstance()
|
|
* - Creates a runtime instance object based on the R3.Component representing it.
|
|
* @param component
|
|
*/
|
|
buildInstance(component) {
|
|
|
|
if (component instanceof ComponentCanvas) {
|
|
let canvas = document.createElement('canvas');
|
|
canvas.setAttribute('width', component.width);
|
|
canvas.setAttribute('height', component.height);
|
|
canvas.setAttribute('style', component.style);
|
|
return canvas;
|
|
}
|
|
|
|
if (component instanceof ComponentImage) {
|
|
let image = document.createElement('img');
|
|
image.setAttribute('src', component.src);
|
|
image.setAttribute('alt', component.alt);
|
|
return image;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeGUI extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeControlKit extends RuntimeGUI {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* buildInstance()
|
|
* - Creates a runtime instance object based on the R3.Component representing it.
|
|
* @param component
|
|
*/
|
|
buildInstance(component) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeGraphics extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeThree extends RuntimeGraphics {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* buildInstance()
|
|
* - Creates a runtime instance object based on the R3.Component representing it.
|
|
* @param component
|
|
*/
|
|
buildInstance(component) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeImage extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimePhysics extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeBullet extends RuntimePhysics {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* buildInstance()
|
|
* - Creates a runtime instance object based on the R3.Component representing it.
|
|
* @param component
|
|
*/
|
|
buildInstance(component) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeSocket extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeStatistics extends Runtime {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* name - Name of the runtime
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name;
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
Event.Emit(Event.RUNTIME_CREATED, this);
|
|
}
|
|
|
|
}
|
|
|
|
class RuntimeStats extends RuntimeStatistics {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* buildInstance()
|
|
* - Creates a runtime instance object based on the R3.Component representing it.
|
|
* @param component
|
|
*/
|
|
buildInstance(component) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Event {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
/**
|
|
* async()
|
|
* - Simply calls 'Async()' passing it the arguments
|
|
* @param eventId
|
|
* @param data
|
|
* @param clientCallback
|
|
* @param clientErrorCallback
|
|
*/
|
|
async(
|
|
eventId,
|
|
data,
|
|
clientCallback,
|
|
clientErrorCallback
|
|
) {
|
|
|
|
return Event.Async(
|
|
eventId,
|
|
data,
|
|
clientCallback,
|
|
clientErrorCallback
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
* emit()
|
|
* - Simply calls 'Emit()' passing it the arguments
|
|
* @param eventId
|
|
* @param data
|
|
* @param clientCallback
|
|
* @param clientErrorCallback
|
|
*/
|
|
emit(
|
|
eventId,
|
|
data,
|
|
clientCallback,
|
|
clientErrorCallback
|
|
) {
|
|
|
|
return Event.Emit(
|
|
eventId,
|
|
data,
|
|
clientCallback,
|
|
clientErrorCallback
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
* subscribe()
|
|
* - Simply calls 'Subscribe()' passing it the arguments
|
|
* @param eventId
|
|
* @param callback
|
|
*/
|
|
subscribe(
|
|
eventId,
|
|
callback
|
|
) {
|
|
|
|
return Event.Subscribe(eventId, callback.bind(this));
|
|
|
|
}
|
|
|
|
/**
|
|
* Async()
|
|
* - Calls all subscription functions registered to eventId with data, clientCallback and clientErrorCallback as
|
|
* arguments. If an error occurs during clientCallback it additionally will execute clientErrorCallback with the
|
|
* error as argument.
|
|
* @param eventId
|
|
* @param data
|
|
* @param clientCallback
|
|
* @param clientErrorCallback
|
|
*/
|
|
static Async(
|
|
eventId,
|
|
data,
|
|
clientCallback,
|
|
clientErrorCallback
|
|
) {
|
|
|
|
if (Event.Subscriptions.hasOwnProperty(eventId)) {
|
|
|
|
let 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;
|
|
}
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Emit()
|
|
* - Calls all subscription functions registered to eventId with data as arg. Calls clientCallback directly after
|
|
* the event result is obtained, passing it the result. If an exception occurs during execution, the
|
|
* clientErrorCallback is called with the error as argument.
|
|
* @param eventId
|
|
* @param data
|
|
* @param clientCallback
|
|
* @param clientErrorCallback
|
|
*/
|
|
static Emit(
|
|
eventId,
|
|
data,
|
|
clientCallback,
|
|
clientErrorCallback
|
|
) {
|
|
|
|
if (Event.Subscriptions.hasOwnProperty(eventId)) {
|
|
|
|
let subscriptionIds = Object.keys(Event.Subscriptions[eventId]);
|
|
|
|
subscriptionIds.map(
|
|
function(subscriptionId) {
|
|
try {
|
|
|
|
let result = Event.Subscriptions[eventId][subscriptionId](data);
|
|
|
|
if (clientCallback) {
|
|
clientCallback(result);
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
if (clientErrorCallback) {
|
|
clientErrorCallback(error);
|
|
} else {
|
|
console.error(error);
|
|
throw error;
|
|
}
|
|
|
|
}
|
|
}
|
|
)
|
|
} else {
|
|
if (clientCallback) {
|
|
clientCallback();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Subscribe()
|
|
* - Subscribes to 'eventName', ex. Event.BEFORE_RENDER and executes 'callback()' when eventName is raised
|
|
* @param eventId
|
|
* @param callback
|
|
* @returns {Object} - A handle to the subscription which can be removed by calling handle.remove()
|
|
*/
|
|
static Subscribe(
|
|
eventId,
|
|
callback
|
|
) {
|
|
|
|
let subscriptionId = Utils.RandomId(10);
|
|
|
|
if (Event.Subscriptions.hasOwnProperty(eventId)) {
|
|
|
|
if (Event.Subscriptions[eventId][subscriptionId]) {
|
|
throw new Error('A component can only subscribe to a particular event ID once');
|
|
}
|
|
|
|
Event.Subscriptions[eventId][subscriptionId] = callback;
|
|
|
|
} else {
|
|
Event.Subscriptions[eventId] = {};
|
|
Event.Subscriptions[eventId][subscriptionId] = callback;
|
|
}
|
|
|
|
/**
|
|
* Return a handle to the caller to allow us to unsubscribe to this event
|
|
*/
|
|
return {
|
|
fn: callback,
|
|
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[]}
|
|
*/
|
|
let listeners = Object.keys(Event.Subscriptions[eventId]);
|
|
if (listeners.length === 0) {
|
|
delete Event.Subscriptions[eventId];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
}(eventId, subscriptionId),
|
|
subscriptionId : subscriptionId
|
|
};
|
|
|
|
}
|
|
|
|
/**
|
|
* Some nice Events handling
|
|
* @type {{}}
|
|
*/
|
|
static Subscriptions = {};
|
|
|
|
}
|
|
|
|
Event.BEFORE_RENDER = 0x1;
|
|
Event.BLACKLISTED_COMPONENT_INSTANCE_REQUEST = 0x2;
|
|
Event.CANVAS_COMPONENT_INITIALIZED = 0x3;
|
|
Event.COMPONENT_CREATED = 0x4;
|
|
Event.COMPONENT_INITIALIZED = 0x5;
|
|
Event.CREATE_INSTANCE_BEFORE = 0x6;
|
|
Event.DISPOSE_INSTANCE = 0x7;
|
|
Event.DISPOSE_OBJECT = 0x8;
|
|
Event.DOM_COMPONENT_INITIALIZED = 0x9;
|
|
Event.ENTITY_CREATED = 0xa;
|
|
Event.ENTITY_INITIALIZED = 0xb;
|
|
Event.ENTITY_STARTED = 0xc;
|
|
Event.FINAL_INITIALIZE = 0xd;
|
|
Event.GET_API_URL = 0xe;
|
|
Event.GET_RUNTIME = 0xf;
|
|
Event.GET_WINDOW_SIZE = 0x10;
|
|
Event.GRAPHICS_COMPONENT_INITIALIZED = 0x11;
|
|
Event.IMAGE_COMPONENT_INITIALIZED = 0x12;
|
|
Event.IMAGE_INSTANCE_CREATED = 0x13;
|
|
Event.INPUT_COMPONENT_INITIALIZED = 0x14;
|
|
Event.INSTANCE_CREATED = 0x15;
|
|
Event.INSTANCE_DISPOSED = 0x16;
|
|
Event.KEYBOARD_DOWN = 0x17;
|
|
Event.KEYBOARD_UP = 0x18;
|
|
Event.MOUSE_DOWN = 0x19;
|
|
Event.MOUSE_MOVE = 0x1a;
|
|
Event.MOUSE_UP = 0x1b;
|
|
Event.MOUSE_WHEEL = 0x1c;
|
|
Event.OBJECT_CREATED = 0x1d;
|
|
Event.OBJECT_PROPERTY_UPDATE = 0x1e;
|
|
Event.OBJECT_PROPERTY_UPDATED = 0x1f;
|
|
Event.ON_READY_STATE_CHANGE = 0x20;
|
|
Event.PAUSE = 0x21;
|
|
Event.PROJECT_INITIALIZED = 0x22;
|
|
Event.RESTART = 0x23;
|
|
Event.RUNTIME_CREATED = 0x24;
|
|
Event.SLIDER_ENTITY_INITIALIZED = 0x25;
|
|
Event.START = 0x26;
|
|
Event.TOUCH_CANCEL = 0x27;
|
|
Event.TOUCH_COMPONENT_INITIALIZED = 0x28;
|
|
Event.TOUCH_END = 0x29;
|
|
Event.TOUCH_MOVE = 0x2a;
|
|
Event.TOUCH_START = 0x2b;
|
|
Event.UPDATE_FROM_INSTANCE_AFTER = 0x2c;
|
|
Event.UPDATE_FROM_INSTANCE_BEFORE = 0x2d;
|
|
Event.UPDATE_INSTANCE_AFTER = 0x2e;
|
|
Event.UPDATE_INSTANCE_BEFORE = 0x2f;
|
|
Event.UPDATE_INSTANCE_PROPERTY = 0x30;
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE = 0x31;
|
|
Event.MAX_EVENTS = 0x32;
|
|
|
|
Event.GetEventName = function(eventId) {
|
|
|
|
switch(eventId) {
|
|
case 0x1 : return 'before_render';
|
|
case 0x2 : return 'blacklisted_component_instance_request';
|
|
case 0x3 : return 'canvas_component_initialized';
|
|
case 0x4 : return 'component_created';
|
|
case 0x5 : return 'component_initialized';
|
|
case 0x6 : return 'create_instance_before';
|
|
case 0x7 : return 'dispose_instance';
|
|
case 0x8 : return 'dispose_object';
|
|
case 0x9 : return 'dom_component_initialized';
|
|
case 0xa : return 'entity_created';
|
|
case 0xb : return 'entity_initialized';
|
|
case 0xc : return 'entity_started';
|
|
case 0xd : return 'final_initialize';
|
|
case 0xe : return 'get_api_url';
|
|
case 0xf : return 'get_runtime';
|
|
case 0x10 : return 'get_window_size';
|
|
case 0x11 : return 'graphics_component_initialized';
|
|
case 0x12 : return 'image_component_initialized';
|
|
case 0x13 : return 'image_instance_created';
|
|
case 0x14 : return 'input_component_initialized';
|
|
case 0x15 : return 'instance_created';
|
|
case 0x16 : return 'instance_disposed';
|
|
case 0x17 : return 'keyboard_down';
|
|
case 0x18 : return 'keyboard_up';
|
|
case 0x19 : return 'mouse_down';
|
|
case 0x1a : return 'mouse_move';
|
|
case 0x1b : return 'mouse_up';
|
|
case 0x1c : return 'mouse_wheel';
|
|
case 0x1d : return 'object_created';
|
|
case 0x1e : return 'object_property_update';
|
|
case 0x1f : return 'object_property_updated';
|
|
case 0x20 : return 'on_ready_state_change';
|
|
case 0x21 : return 'pause';
|
|
case 0x22 : return 'project_initialized';
|
|
case 0x23 : return 'restart';
|
|
case 0x24 : return 'runtime_created';
|
|
case 0x25 : return 'slider_entity_initialized';
|
|
case 0x26 : return 'start';
|
|
case 0x27 : return 'touch_cancel';
|
|
case 0x28 : return 'touch_component_initialized';
|
|
case 0x29 : return 'touch_end';
|
|
case 0x2a : return 'touch_move';
|
|
case 0x2b : return 'touch_start';
|
|
case 0x2c : return 'update_from_instance_after';
|
|
case 0x2d : return 'update_from_instance_before';
|
|
case 0x2e : return 'update_instance_after';
|
|
case 0x2f : return 'update_instance_before';
|
|
case 0x30 : return 'update_instance_property';
|
|
case 0x31 : return 'update_property_from_instance';
|
|
default :
|
|
throw new Error('Event type not defined : ' + eventId);
|
|
}
|
|
|
|
};
|
|
|
|
class R3Object extends Event {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* id - Each Object receives an 15 digit random ID which uniquely identifies it everywhere (client
|
|
* and server side)
|
|
*/
|
|
if (typeof options.id === 'undefined') {
|
|
options.id = Utils.RandomId(15);
|
|
}
|
|
/**
|
|
* name - Each Object has a name
|
|
*/
|
|
if (typeof options.name === 'undefined') {
|
|
options.name = this.constructor.name + '(' + options.id + ')';
|
|
}
|
|
/**
|
|
* ready - Normally all objects are 'ready' to have their instances created, unless it has some
|
|
* required Object which is not present at time of construction and will be assigned later.
|
|
* All objects have multiple sets of 'required' objects which affect its 'ready' state.
|
|
*/
|
|
if (typeof options.ready === 'undefined') {
|
|
options.ready = [];
|
|
}
|
|
/**
|
|
* dirty - When dirty is true, it means that this object is in transition from having a child Object
|
|
* to not having this child Object, and will probably end up in an uninitialized state.
|
|
* During the next few clock cycles this child Object will have its parent reference to this
|
|
* Object removed.
|
|
*/
|
|
if (typeof options.dirty === 'undefined') {
|
|
options.dirty = false;
|
|
}
|
|
/**
|
|
* initialized - A boolean which indicates whether or not this Object has initialized
|
|
*/
|
|
if (typeof options.initialized === 'undefined') {
|
|
options.initialized = false;
|
|
}
|
|
/**
|
|
* initializeDepth - The amount of times this Object passed through initialize() functions
|
|
*/
|
|
if (typeof options.initializeDepth === 'undefined') {
|
|
options.initializeDepth = 0;
|
|
}
|
|
/**
|
|
* parents - All Objects could have parent(s)
|
|
*/
|
|
if (typeof options.parents === 'undefined') {
|
|
options.parents = [];
|
|
}
|
|
/**
|
|
* children - All Objects could have some children
|
|
*/
|
|
if (typeof options.children === 'undefined') {
|
|
options.children = [];
|
|
}
|
|
/**
|
|
* required - All Objects could have some required Objects which need to initialize before this Object
|
|
* can initialize
|
|
*/
|
|
if (typeof options.required === 'undefined') {
|
|
options.required = [];
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.emit(Event.OBJECT_CREATED, this);
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Initializes this Object if all of its required Objects are initialized
|
|
*/
|
|
initialize() {
|
|
|
|
this.initialized = true;
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
throw new Error('You should not try to instantiate this base class - extend it rather...');
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* isReady()
|
|
* - Checks whether or not at least one set of requirements pass the ready state (i.e. required objects are
|
|
* assigned and ready)
|
|
*/
|
|
isReady() {
|
|
|
|
if (this.required.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
|
|
/**
|
|
* We assume it is ready and will fail the ready test if a requirementValueCheck() fails
|
|
*/
|
|
let ready = true;
|
|
|
|
let requirements = this.required[r];
|
|
|
|
for (let property in requirements) {
|
|
if (requirements.hasOwnProperty(property)) {
|
|
if (!this.requirementValueCheck(requirements[property], this[property])) {
|
|
ready = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The ready state could have changed or not - regardless it should cascade this information in case
|
|
* new instances need to be created (ex. an image is added to an array and needs its instance created).
|
|
*/
|
|
|
|
let readyStateChange = false;
|
|
|
|
if (this.ready[r] !== ready) {
|
|
readyStateChange = true;
|
|
}
|
|
|
|
this.ready[r] = ready;
|
|
|
|
if (readyStateChange) {
|
|
if (this.ready[r]) {
|
|
this.emit(
|
|
Event.ON_READY_STATE_CHANGE,
|
|
{
|
|
r3Object: this,
|
|
readyState: R3Object.READY_STATE_TRUE,
|
|
readyStateIndex: r
|
|
}
|
|
);
|
|
} else {
|
|
this.emit(
|
|
Event.ON_READY_STATE_CHANGE,
|
|
{
|
|
r3Object: this,
|
|
readyState: R3Object.READY_STATE_FALSE,
|
|
readyStateIndex: r
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* If at least one requirements set pass - return true.
|
|
*/
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
if (this.ready[r]) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/**
|
|
* requirementValueCheck()
|
|
* - Checks whether or not the property / value pair meets the requirements of setting this ready to true. It
|
|
* handles values of type Object and Array properly.
|
|
* @param property
|
|
* @param value
|
|
*/
|
|
requirementValueCheck(
|
|
property,
|
|
value
|
|
) {
|
|
|
|
/**
|
|
* The property change is one of the required properties of this Object, so it affects the overall
|
|
* 'readiness' of this object.
|
|
*/
|
|
if (property instanceof Array) {
|
|
|
|
if (!(value instanceof Array)) {
|
|
return false;
|
|
}
|
|
|
|
if (value.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
for (let v = 0; v < value.length; v++) {
|
|
if (!(value[v] instanceof property[0])) {
|
|
return false;
|
|
}
|
|
|
|
if (!(value[v].isReady())) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
if (!(value instanceof property)) {
|
|
return false;
|
|
}
|
|
|
|
return value.isReady();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
R3Object.PROJECT = 0x0;
|
|
R3Object.ENTITY = 0x1;
|
|
R3Object.ENTITY_SLIDER = 0x2;
|
|
R3Object.COMPONENT = 0x3;
|
|
R3Object.COMPONENT_CODE = 0x4;
|
|
R3Object.COMPONENT_DOM = 0x5;
|
|
R3Object.COMPONENT_CANVAS = 0x6;
|
|
R3Object.COMPONENT_GEOMETRY = 0x7;
|
|
R3Object.COMPONENT_BUFFER_GEOMETRY = 0x8;
|
|
R3Object.COMPONENT_PLANE_GEOMETRY = 0x9;
|
|
R3Object.COMPONENT_GRAPHICS = 0xa;
|
|
R3Object.COMPONENT_IMAGE = 0xb;
|
|
R3Object.COMPONENT_INPUT = 0xc;
|
|
R3Object.COMPONENT_TOUCH = 0xd;
|
|
R3Object.COMPONENT_MATERIAL = 0xe;
|
|
R3Object.COMPONENT_MESH = 0xf;
|
|
R3Object.COMPONENT_TEXTURE = 0x10;
|
|
R3Object.MAX_R3OBJECT = 0x11;
|
|
|
|
R3Object.READY_STATE_FALSE = 0x1;
|
|
R3Object.READY_STATE_PENDING_FALSE = 0x2;
|
|
R3Object.READY_STATE_PENDING_TRUE = 0x3;
|
|
R3Object.READY_STATE_TRUE = 0x4;
|
|
|
|
class Project extends R3Object {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.initialized === 'undefined') {
|
|
options.initialized = false;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Initializes this Object if all of its required Objects are initialized
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Entity extends R3Object {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.emit(Event.ENTITY_CREATED, this);
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Starts the Entity if all of its sub-Components are initialized
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.ENTITY_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
throw new Error('You should not try to instantiate this base class - extend it rather...');
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Entity.SLIDER = 0x0;
|
|
Entity.MAX_ENTITY = 0x1;
|
|
|
|
/**
|
|
|
|
[0]images=[ComponentImage] - We need a list of at least one Image which to slide
|
|
[0]canvas=ComponentCanvas - We need a Canvas to attach our Input events
|
|
[0]touch=ComponentTouch - We need a Touch Component to respond to TOUCH Events
|
|
|
|
**/
|
|
|
|
class EntitySlider extends Entity {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* components - A list of components that this entity is composed of
|
|
*/
|
|
if (typeof options.components === 'undefined') {
|
|
options.components = [];
|
|
}
|
|
/**
|
|
* started - Indicates whether or not this entity is active (subscribing to events) or not
|
|
*/
|
|
if (typeof options.started === 'undefined') {
|
|
options.started = false;
|
|
}
|
|
/**
|
|
* subscriptions - An association object which hold the subscription handles for Events this system is
|
|
* listening to. The system can stop receiving events by calling remove() on a handle.
|
|
*/
|
|
if (typeof options.subscriptions === 'undefined') {
|
|
options.subscriptions = {};
|
|
}
|
|
|
|
/**
|
|
* We need to assign some options here to the entity
|
|
* because SystemLinking requires 'components[]' to
|
|
* exist when determining parent / child relationships
|
|
*/
|
|
Object.assign(this, options);
|
|
|
|
/**
|
|
* canvas - The Canvas Component to which this entity binds its custom code components
|
|
*/
|
|
if (typeof options.canvas === 'undefined') {
|
|
options.canvas = null;
|
|
}
|
|
/**
|
|
* touch - The slider component reacts to TOUCH Events, for this a touch component is required
|
|
*/
|
|
if (typeof options.touch === 'undefined') {
|
|
options.touch = null;
|
|
}
|
|
/**
|
|
* images - The Image Components which will be used to slide from one image to the next
|
|
*/
|
|
if (typeof options.images === 'undefined') {
|
|
options.images = [];
|
|
}
|
|
|
|
/**
|
|
* images - We need a list of at least one Image which to slide
|
|
*/
|
|
if (typeof options.required[0] === 'undefined') {
|
|
options.required[0] = {};
|
|
}
|
|
|
|
options.required[0].images = [ComponentImage];
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['images'] = options.images;
|
|
Object.defineProperty(
|
|
this,
|
|
'images',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'images',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['images'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'images',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['images'];
|
|
}
|
|
}
|
|
) /**
|
|
* canvas - We need a Canvas to attach our Input events
|
|
*/
|
|
if (typeof options.required[0] === 'undefined') {
|
|
options.required[0] = {};
|
|
}
|
|
|
|
options.required[0].canvas = ComponentCanvas;
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['canvas'] = options.canvas;
|
|
Object.defineProperty(
|
|
this,
|
|
'canvas',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'canvas',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['canvas'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'canvas',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['canvas'];
|
|
}
|
|
}
|
|
) /**
|
|
* touch - We need a Touch Component to respond to TOUCH Events
|
|
*/
|
|
if (typeof options.required[0] === 'undefined') {
|
|
options.required[0] = {};
|
|
}
|
|
|
|
options.required[0].touch = ComponentTouch;
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['touch'] = options.touch;
|
|
Object.defineProperty(
|
|
this,
|
|
'touch',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'touch',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['touch'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'touch',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['touch'];
|
|
}
|
|
}
|
|
)
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Starts the Entity if all of its sub-Components are initialized. Calls the parent initialize().
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.SLIDER_ENTITY_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* start()
|
|
* - Starts the entity by subscribing to all events
|
|
*/
|
|
start() {
|
|
|
|
this.subscriptions['BEFORE_RENDER'] = this.subscribe(
|
|
Event.BEFORE_RENDER,
|
|
this.OnBeforeRender
|
|
);
|
|
|
|
this.subscriptions['TOUCH_START'] = this.subscribe(
|
|
Event.TOUCH_START,
|
|
this.OnTouchStart
|
|
);
|
|
|
|
this.subscriptions['TOUCH_MOVE'] = this.subscribe(
|
|
Event.TOUCH_MOVE,
|
|
this.OnTouchMove
|
|
);
|
|
|
|
this.subscriptions['TOUCH_END'] = this.subscribe(
|
|
Event.TOUCH_END,
|
|
this.OnTouchEnd
|
|
);
|
|
|
|
this.started = true;
|
|
|
|
if (this instanceof Entity) {
|
|
this.emit(
|
|
Event.ENTITY_STARTED,
|
|
this
|
|
);
|
|
}
|
|
|
|
console.log('Started transient system: EntitySlider');
|
|
|
|
}
|
|
|
|
/**
|
|
* stop()
|
|
* - Stops this entity by removing all subscriptions to events
|
|
*/
|
|
stop() {
|
|
|
|
this.subscriptions['BEFORE_RENDER'].remove();
|
|
delete this.subscriptions['BEFORE_RENDER'];
|
|
|
|
this.subscriptions['TOUCH_START'].remove();
|
|
delete this.subscriptions['TOUCH_START'];
|
|
|
|
this.subscriptions['TOUCH_MOVE'].remove();
|
|
delete this.subscriptions['TOUCH_MOVE'];
|
|
|
|
this.subscriptions['TOUCH_END'].remove();
|
|
delete this.subscriptions['TOUCH_END'];
|
|
|
|
this.started = false;
|
|
|
|
console.log('Stopped transient system: EntitySlider');
|
|
|
|
}
|
|
|
|
/**
|
|
* OnBeforeRender()
|
|
* - Listens to events of type Event.BEFORE_RENDER and executes this function.
|
|
* @param data (The event data passed as argument - typically an R3Object)
|
|
* @return null
|
|
*/
|
|
OnBeforeRender(data) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnTouchStart()
|
|
* - Listens to events of type Event.TOUCH_START and executes this function.
|
|
* @param data (The event data passed as argument - typically an R3Object)
|
|
* @return null
|
|
*/
|
|
OnTouchStart(data) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnTouchMove()
|
|
* - Listens to events of type Event.TOUCH_MOVE and executes this function.
|
|
* @param data (The event data passed as argument - typically an R3Object)
|
|
* @return null
|
|
*/
|
|
OnTouchMove(data) {
|
|
|
|
}
|
|
|
|
/**
|
|
* OnTouchEnd()
|
|
* - Listens to events of type Event.TOUCH_END and executes this function.
|
|
* @param data (The event data passed as argument - typically an R3Object)
|
|
* @return null
|
|
*/
|
|
OnTouchEnd(data) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Component extends R3Object {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.emit(Event.COMPONENT_CREATED, this);
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Should raises an event(s) which indicates that this object initialized
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.COMPONENT_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
throw new Error('You should not try to instantiate this base class - extend it rather...');
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* createInstance()
|
|
* - Creates an instance of this object based on the current runtime
|
|
*/
|
|
createInstance() {
|
|
|
|
this.emit(
|
|
Event.CREATE_INSTANCE_BEFORE,
|
|
this,
|
|
function(delayInstance) {
|
|
if (delayInstance === true) {
|
|
console.log('Instance creation delayed for ' + this.name);
|
|
} else {
|
|
/**
|
|
* Set the runtime
|
|
*/
|
|
this.setRuntime();
|
|
|
|
/**
|
|
* Let the runtime build the instance
|
|
*/
|
|
this.instance = this.runtime.buildInstance(this);
|
|
|
|
/**
|
|
* Notify anyone who might be interested
|
|
*/
|
|
this.emit(Event.INSTANCE_CREATED, this);
|
|
}
|
|
}.bind(this)
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
* dispose()
|
|
* - Disposes of this object by disposing the instance first.
|
|
*/
|
|
dispose() {
|
|
|
|
this.subscribe(
|
|
Event.INSTANCE_DISPOSED,
|
|
function(object) {
|
|
if (object === this) {
|
|
this.emit(Event.DISPOSE_OBJECT, this);
|
|
}
|
|
}
|
|
);
|
|
|
|
this.disposeInstance();
|
|
|
|
}
|
|
|
|
/**
|
|
* disposeInstance()
|
|
* - Disposes of the runtime instance.
|
|
*/
|
|
disposeInstance() {
|
|
|
|
console.log('Disposing instance of ' + this.name);
|
|
this.emit(Event.DISPOSE_INSTANCE, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* setRuntime()
|
|
* - Sets the runtime property of this component required for constructing an instance of this component.
|
|
*/
|
|
setRuntime() {
|
|
|
|
this.emit(
|
|
Event.GET_RUNTIME,
|
|
this,
|
|
function(runtime) {
|
|
this.runtime = runtime;
|
|
}.bind(this)
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Component.CODE = 0x0;
|
|
Component.DOM = 0x1;
|
|
Component.CANVAS = 0x2;
|
|
Component.GEOMETRY = 0x3;
|
|
Component.BUFFER_GEOMETRY = 0x4;
|
|
Component.PLANE_GEOMETRY = 0x5;
|
|
Component.GRAPHICS = 0x6;
|
|
Component.IMAGE = 0x7;
|
|
Component.INPUT = 0x8;
|
|
Component.TOUCH = 0x9;
|
|
Component.MATERIAL = 0xa;
|
|
Component.MESH = 0xb;
|
|
Component.TEXTURE = 0xc;
|
|
Component.MAX_COMPONENT = 0xd;
|
|
|
|
class ComponentCode extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentDOM extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.DOM_COMPONENT_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'instance') {
|
|
this.instance.instance = this.instance;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'instance',
|
|
instanceProperty : 'instance'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'instance' || property === 'all') {
|
|
this.instance = this.instance.instance;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'instance',
|
|
instanceProperty : 'instance'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentCanvas extends ComponentDOM {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
/**
|
|
* type - No comment
|
|
*/
|
|
if (typeof options.type === 'undefined') {
|
|
options.type = 'canvas';
|
|
}
|
|
/**
|
|
* width - The initial width of the canvas (You can override it with CSS)
|
|
*/
|
|
if (typeof options.width === 'undefined') {
|
|
options.width = 500;
|
|
}
|
|
/**
|
|
* height - The initial height of the canvas (You can override it with CSS)
|
|
*/
|
|
if (typeof options.height === 'undefined') {
|
|
options.height = 500;
|
|
}
|
|
/**
|
|
* style - No comment
|
|
*/
|
|
if (typeof options.style === 'undefined') {
|
|
options.style = 'border:1px solid #00bb00;';
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.CANVAS_COMPONENT_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'width') {
|
|
this.instance.width = this.width;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'width',
|
|
instanceProperty : 'width'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'height') {
|
|
this.instance.height = this.height;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'height',
|
|
instanceProperty : 'height'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'style') {
|
|
this.instance.style = this.style;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'style',
|
|
instanceProperty : 'style'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'width' || property === 'all') {
|
|
this.width = this.instance.width;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'width',
|
|
instanceProperty : 'width'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'height' || property === 'all') {
|
|
this.height = this.instance.height;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'height',
|
|
instanceProperty : 'height'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'style' || property === 'all') {
|
|
this.style = this.instance.style;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'style',
|
|
instanceProperty : 'style'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentGeometry extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentBufferGeometry extends ComponentGeometry {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentPlaneGeometry extends ComponentBufferGeometry {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentGraphics extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.GRAPHICS_COMPONENT_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentImage extends ComponentGraphics {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
/**
|
|
* src - The src attribute of this image, defaults to a 15% opaque 1x1 green pixel
|
|
*/
|
|
if (typeof options.src === 'undefined') {
|
|
options.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TpSotDu0g4pChumhBVMRRq1CECqFWaNXB5NIvaNKQpLg4Cq4FBz8Wqw4uzro6uAqC4AeIm5uToouU+L+k0CLWg+N+vLv3uHsHCPUy06yucUDTbTOViIuZ7KoYeEUvwgghgFGZWcacJCXRcXzdw8fXuxjP6nzuzxFScxYDfCLxLDNMm3iDeHrTNjjvE0dYUVaJz4nHTLog8SPXFY/fOBdcFnhmxEyn5okjxGKhjZU2ZkVTI54ijqqaTvlCxmOV8xZnrVxlzXvyFwZz+soy12kOIYFFLEGCCAVVlFCGjRitOikWUrQf7+AfdP0SuRRylcDIsYAKNMiuH/wPfndr5ScnvKRgHOh+cZyPYSCwCzRqjvN97DiNE8D/DFzpLX+lDsx8kl5radEjoH8buLhuacoecLkDDDwZsim7kp+mkM8D72f0TVkgfAv0rXm9Nfdx+gCkqavkDXBwCIwUKHu9w7t72nv790yzvx9QEXKZwXQv9wAAAAZiS0dEADIANAAxUB4d7wAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+UJEw0JHX/9/lIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADUlEQVQI12Ng+M+gBgADKAEm2Ka93QAAAABJRU5ErkJggg==';
|
|
}
|
|
/**
|
|
* alt - The alt attribute of this image
|
|
*/
|
|
if (typeof options.alt === 'undefined') {
|
|
options.alt = '15% opaque 1x1 green pixel';
|
|
}
|
|
/**
|
|
* fileName - Name of the image under which it is stored
|
|
*/
|
|
if (typeof options.fileName === 'undefined') {
|
|
options.fileName = Utils.LowerUnderscore(options.name);
|
|
}
|
|
/**
|
|
* extension - Extension of the file name including the '.' (ex. '.jpg')
|
|
*/
|
|
if (typeof options.extension === 'undefined') {
|
|
options.extension = '.png';
|
|
}
|
|
/**
|
|
* external_path - Path to the image relative to the project defined API URL
|
|
*/
|
|
if (typeof options.external_path === 'undefined') {
|
|
options.external_path = '/images/' + options.id + '.png';
|
|
}
|
|
/**
|
|
* internal_path - Server side path on the server to the file, excluding filename
|
|
*/
|
|
if (typeof options.internal_path === 'undefined') {
|
|
options.internal_path = '/tmp/' + options.id + '.png';
|
|
}
|
|
/**
|
|
* contentType - Content type of the file (based on the extension, ex. 'image/jpeg')
|
|
*/
|
|
if (typeof options.contentType === 'undefined') {
|
|
options.contentType = 'image/png';
|
|
}
|
|
/**
|
|
* size - Size of the file in bytes
|
|
*/
|
|
if (typeof options.size === 'undefined') {
|
|
options.size = 565;
|
|
}
|
|
/**
|
|
* width - Width of the image in pixels
|
|
*/
|
|
if (typeof options.width === 'undefined') {
|
|
options.width = 1;
|
|
}
|
|
/**
|
|
* height - height of the image in pixels
|
|
*/
|
|
if (typeof options.height === 'undefined') {
|
|
options.height = 1;
|
|
}
|
|
/**
|
|
* orientation - The orientation of the image, one of 'square', 'landscape', 'portrait'
|
|
*/
|
|
if (typeof options.orientation === 'undefined') {
|
|
options.orientation = 'square';
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
if (options.extension.match(/(png)$/i)) {
|
|
options.contentType = 'image/png';
|
|
}
|
|
|
|
if (options.extension.match(/(jpg|jpeg)$/i)) {
|
|
options.contentType = 'image/jpeg';
|
|
}
|
|
|
|
if (options.extension.match(/(gif)$/i)) {
|
|
options.contentType = 'image/gif';
|
|
}
|
|
|
|
if (options.width > options.height) {
|
|
options.orientation = 'landscape';
|
|
}
|
|
|
|
if (options.width < options.height) {
|
|
options.orientation = 'portrait';
|
|
}
|
|
|
|
if (options.width === options.height) {
|
|
options.orientation = 'square';
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.IMAGE_COMPONENT_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'src') {
|
|
this.instance.src = this.src;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'src',
|
|
instanceProperty : 'src'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'alt') {
|
|
this.instance.alt = this.alt;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'alt',
|
|
instanceProperty : 'alt'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'external_path') {
|
|
this.instance.external_path = this.external_path;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'external_path',
|
|
instanceProperty : 'external_path'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'internal_path') {
|
|
this.instance.internal_path = this.internal_path;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'internal_path',
|
|
instanceProperty : 'internal_path'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'size') {
|
|
this.instance.size = this.size;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'size',
|
|
instanceProperty : 'size'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'width') {
|
|
this.instance.width = this.width;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'width',
|
|
instanceProperty : 'width'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'height') {
|
|
this.instance.height = this.height;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'height',
|
|
instanceProperty : 'height'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'orientation') {
|
|
this.instance.orientation = this.orientation;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'orientation',
|
|
instanceProperty : 'orientation'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'src' || property === 'all') {
|
|
this.src = this.instance.src;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'src',
|
|
instanceProperty : 'src'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'alt' || property === 'all') {
|
|
this.alt = this.instance.alt;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'alt',
|
|
instanceProperty : 'alt'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'external_path' || property === 'all') {
|
|
this.external_path = this.instance.external_path;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'external_path',
|
|
instanceProperty : 'external_path'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'internal_path' || property === 'all') {
|
|
this.internal_path = this.instance.internal_path;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'internal_path',
|
|
instanceProperty : 'internal_path'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'size' || property === 'all') {
|
|
this.size = this.instance.size;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'size',
|
|
instanceProperty : 'size'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'width' || property === 'all') {
|
|
this.width = this.instance.width;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'width',
|
|
instanceProperty : 'width'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'height' || property === 'all') {
|
|
this.height = this.instance.height;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'height',
|
|
instanceProperty : 'height'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
if (property === 'orientation' || property === 'all') {
|
|
this.orientation = this.instance.orientation;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'orientation',
|
|
instanceProperty : 'orientation'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentInput extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.INPUT_COMPONENT_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
[0]domComponent=ComponentDOM
|
|
|
|
**/
|
|
|
|
class ComponentTouch extends ComponentInput {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
/**
|
|
* domComponent - A Touch Component requires a Canvas component to bind to.
|
|
*/
|
|
if (typeof options.domComponent === 'undefined') {
|
|
options.domComponent = null;
|
|
}
|
|
|
|
/**
|
|
* domComponent - No comment
|
|
*/
|
|
if (typeof options.required[0] === 'undefined') {
|
|
options.required[0] = {};
|
|
}
|
|
|
|
options.required[0].domComponent = ComponentDOM;
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['domComponent'] = options.domComponent;
|
|
Object.defineProperty(
|
|
this,
|
|
'domComponent',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'domComponent',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['domComponent'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'domComponent',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['domComponent'];
|
|
}
|
|
}
|
|
)
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
Event.Emit(Event.TOUCH_COMPONENT_INITIALIZED, this);
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'domComponent') {
|
|
this.instance.domComponent = this.domComponent;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'domComponent',
|
|
instanceProperty : 'domComponent'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'domComponent' || property === 'all') {
|
|
this.domComponent = this.instance.domComponent;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'domComponent',
|
|
instanceProperty : 'domComponent'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentMaterial extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
[0]material=ComponentMaterial
|
|
[0]geometry=ComponentGeometry
|
|
[1]material=[ComponentMaterial]
|
|
[1]geometry=ComponentGeometry
|
|
|
|
**/
|
|
|
|
class ComponentMesh extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
/**
|
|
* material - No comment
|
|
*/
|
|
if (typeof options.material === 'undefined') {
|
|
options.material = null;
|
|
}
|
|
|
|
/**
|
|
* material - No comment
|
|
*/
|
|
if (typeof options.required[0] === 'undefined') {
|
|
options.required[0] = {};
|
|
}
|
|
|
|
options.required[0].material = ComponentMaterial;
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['material'] = options.material;
|
|
Object.defineProperty(
|
|
this,
|
|
'material',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'material',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['material'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'material',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['material'];
|
|
}
|
|
}
|
|
) /**
|
|
* geometry - No comment
|
|
*/
|
|
if (typeof options.required[0] === 'undefined') {
|
|
options.required[0] = {};
|
|
}
|
|
|
|
options.required[0].geometry = ComponentGeometry;
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['geometry'] = options.geometry;
|
|
Object.defineProperty(
|
|
this,
|
|
'geometry',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'geometry',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['geometry'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'geometry',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['geometry'];
|
|
}
|
|
}
|
|
) /**
|
|
* material - No comment
|
|
*/
|
|
if (typeof options.required[1] === 'undefined') {
|
|
options.required[1] = {};
|
|
}
|
|
|
|
options.required[1].material = [ComponentMaterial];
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['material'] = options.material;
|
|
Object.defineProperty(
|
|
this,
|
|
'material',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'material',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['material'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'material',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['material'];
|
|
}
|
|
}
|
|
) /**
|
|
* geometry - No comment
|
|
*/
|
|
if (typeof options.required[1] === 'undefined') {
|
|
options.required[1] = {};
|
|
}
|
|
|
|
options.required[1].geometry = ComponentGeometry;
|
|
|
|
if (typeof this._cache === 'undefined') {
|
|
this._cache = {};
|
|
}
|
|
|
|
this._cache['geometry'] = options.geometry;
|
|
Object.defineProperty(
|
|
this,
|
|
'geometry',
|
|
{
|
|
configurable : true,
|
|
enumerable : true,
|
|
set: (x) => {
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATE,
|
|
{
|
|
r3Object : this,
|
|
property : 'geometry',
|
|
value : x
|
|
}
|
|
);
|
|
this._cache['geometry'] = x;
|
|
Event.Emit(
|
|
Event.OBJECT_PROPERTY_UPDATED,
|
|
{
|
|
r3Object : this,
|
|
property : 'geometry',
|
|
value : x
|
|
}
|
|
);
|
|
return x;
|
|
},
|
|
get : () => {
|
|
return this._cache['geometry'];
|
|
}
|
|
}
|
|
)
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'material') {
|
|
this.instance.material = this.material;
|
|
this.emit(
|
|
Event.UPDATE_INSTANCE_PROPERTY,
|
|
{
|
|
component : this,
|
|
property : 'material',
|
|
instanceProperty : 'material'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
if (property === 'material' || property === 'all') {
|
|
this.material = this.instance.material;
|
|
this.emit(
|
|
Event.UPDATE_PROPERTY_FROM_INSTANCE,
|
|
{
|
|
component : this,
|
|
property : 'material',
|
|
instanceProperty : 'material'
|
|
}
|
|
);
|
|
if (property !== 'all') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class ComponentTexture extends Component {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
if (typeof options.maxDepth === 'undefined') {
|
|
options.maxDepth = 0;
|
|
}
|
|
|
|
if (typeof options.callDepth === 'undefined') {
|
|
options.callDepth = 0;
|
|
} else {
|
|
options.callDepth++;
|
|
}
|
|
|
|
options.maxDepth = options.callDepth;
|
|
|
|
super(options);
|
|
|
|
/**
|
|
* instance - Holds the current instance of this object as determined (built) by the runtime object.
|
|
*/
|
|
if (typeof options.instance === 'undefined') {
|
|
options.instance = null;
|
|
}
|
|
|
|
for (let r = 0; r < this.required.length; r++) {
|
|
this.ready[r] = true;
|
|
}
|
|
|
|
this.underConstruction = true;
|
|
|
|
Object.assign(this, options);
|
|
|
|
this.underConstruction = false;
|
|
|
|
if (options.callDepth === 0) {
|
|
this.initialize();
|
|
} else {
|
|
options.callDepth--;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* initialize()
|
|
* - Notifies all systems listening that this component initialized.
|
|
*/
|
|
initialize() {
|
|
|
|
super.initialize();
|
|
|
|
if (this.initializeDepth === this.maxDepth) {
|
|
this.emit(Event.FINAL_INITIALIZE, this);
|
|
} else {
|
|
this.initializeDepth++;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* updateInstance()
|
|
* - Updates this object by copying the values of the current object into it's instance object.
|
|
* @param property
|
|
*/
|
|
updateInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
/**
|
|
* updateFromInstance()
|
|
* - Updates this object by copying the values of its instance into the current object.
|
|
* @param property
|
|
*/
|
|
updateFromInstance(property) {
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_BEFORE, this);
|
|
|
|
this.emit(Event.UPDATE_FROM_INSTANCE_AFTER, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Graph {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
/**
|
|
* open - Internal structure required for traversing the graph
|
|
*/
|
|
if (typeof options.open === 'undefined') {
|
|
options.open = [];
|
|
}
|
|
/**
|
|
* closed - Internal structure required for traversing the graph
|
|
*/
|
|
if (typeof options.closed === 'undefined') {
|
|
options.closed = [];
|
|
}
|
|
/**
|
|
* relevant - By default we traverse all parents and children of a node when performing a search
|
|
*/
|
|
if (typeof options.relevant === 'undefined') {
|
|
options.relevant = ['parents', 'children'];
|
|
}
|
|
/**
|
|
* solutions - Internal structure for holding solutions from n0 to n. n passed the goalFunction() test.
|
|
*/
|
|
if (typeof options.solutions === 'undefined') {
|
|
options.solutions = [];
|
|
}
|
|
/**
|
|
* terminateOnFirstGoal - By default we want to collect all goal nodes which pass the goalFunction(). Set this to
|
|
* true to terminate immediately after discovering the first goal node.
|
|
*/
|
|
if (typeof options.terminateOnFirstGoal === 'undefined') {
|
|
options.terminateOnFirstGoal = false;
|
|
}
|
|
/**
|
|
* startNode - The start node from which the graph will build
|
|
*/
|
|
if (typeof options.startNode === 'undefined') {
|
|
options.startNode = null;
|
|
}
|
|
/**
|
|
* goalFunction - By having no goal as a default, on construction of a Graph object we will traverse and
|
|
* build the entire graph starting from the startNode.
|
|
*/
|
|
if (typeof options.goalFunction === 'undefined') {
|
|
options.goalFunction = (node)=>{return false;};
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
if (this.startNode) {
|
|
this.build();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* build()
|
|
* - Uses A* algorithm to build a graph of all nodes which represents the dependency structure of this graph.
|
|
*/
|
|
build() {
|
|
|
|
if (this.startNode === null) {
|
|
throw new Error('startNode cannot be null');
|
|
}
|
|
|
|
/**
|
|
* Step 1. Push start node on open[]
|
|
*/
|
|
this.open.push(this.startNode);
|
|
|
|
/**
|
|
* Step 2. Clear the closed[] list (we also clear the solutions[] list because we maintain it this way)
|
|
*/
|
|
this.closed = [];
|
|
this.solutions = [];
|
|
|
|
/**
|
|
* Start with step 3 to 8
|
|
*/
|
|
this.process();
|
|
|
|
}
|
|
|
|
/**
|
|
* process()
|
|
* - Repeats steps 3 to 8. Should indicate whether a goal node was found.
|
|
*/
|
|
process() {
|
|
|
|
/**
|
|
* Step 3. If open[] is empty - exit with failure
|
|
*/
|
|
if (this.open.length === 0) {
|
|
console.log('open[] is empty');
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Step 4. Select first node on open[] - remove it from open[] and put it on closed[]
|
|
*/
|
|
let node = this.open.pop();
|
|
this.closed.push(node);
|
|
|
|
/**
|
|
* Step 5. If node is a goal function - exit successfully (or continue if we do not terminate on first goal)
|
|
*/
|
|
if (this.goalFunction(node)) {
|
|
|
|
this.solutions.push(this.buildSolution(node));
|
|
|
|
if (this.terminateOnFirstGoal) {
|
|
return this.solutions[0];
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Step 6.a Expand node n, generating the set M of its successors that are not already ancestors of n in G.
|
|
*/
|
|
let M = this.expand(node);
|
|
|
|
/**
|
|
* Step 7 - Establish pointers to node
|
|
*/
|
|
this.establishPointers(M, node);
|
|
|
|
/**
|
|
* Step 8 - Re-Order nodes in OPEN in order of increasing ~f values. Ties among minimal ~f values are resolved
|
|
* in favor of the deepest node in the search tree.
|
|
* We skip this step because we are not so interested in the shortest path to the solution (yet, for now at least)
|
|
*/
|
|
//this.reOrder();
|
|
|
|
/**
|
|
* Continue back to step 3
|
|
*/
|
|
this.process();
|
|
|
|
}
|
|
|
|
/**
|
|
* expand()
|
|
* - Expands a node generating a set M of its successors which are not already ancestors of the node (n) in the
|
|
* graph (G). i.e. *NOT* already in either OPEN or CLOSED. Install those members of M as successors of n in G.
|
|
* @param node
|
|
*/
|
|
expand(node) {
|
|
|
|
let successors = {
|
|
onOpen : [],
|
|
onClosed : [],
|
|
notInG : []
|
|
};
|
|
|
|
for (let r = 0; r < this.relevant.length; r++) {
|
|
|
|
let relevant = this.relevant[r];
|
|
|
|
for (let n = 0; n < node.object[relevant].length; n++) {
|
|
|
|
let notInG = true;
|
|
|
|
/**
|
|
* Check if this child is part of an open[] node
|
|
*/
|
|
let onOpen = this.open.reduce(
|
|
(onOpen, openNode) => {
|
|
if (openNode.object === node.object[relevant][n]) {
|
|
onOpen = true;
|
|
notInG = false;
|
|
}
|
|
return onOpen;
|
|
},
|
|
false
|
|
);
|
|
|
|
let onClosed = this.closed.reduce(
|
|
(onClosed, closedNode) => {
|
|
if (closedNode.object === node.object[relevant][n]) {
|
|
onClosed = true;
|
|
notInG = false;
|
|
}
|
|
return onClosed;
|
|
},
|
|
false
|
|
);
|
|
|
|
let type = 'child';
|
|
|
|
if (relevant === 'parents') {
|
|
type = 'parent';
|
|
}
|
|
|
|
let newNode = new Node(
|
|
{
|
|
object: node.object[relevant][n],
|
|
type: type
|
|
}
|
|
);
|
|
|
|
if (onOpen) {
|
|
successors.onOpen.push(newNode);
|
|
}
|
|
|
|
if (onClosed) {
|
|
successors.onClosed.push(newNode);
|
|
}
|
|
|
|
if (notInG) {
|
|
successors.notInG.push(newNode);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the set of successors (M) to be used later in processing
|
|
*/
|
|
return successors;
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* establishPointers()
|
|
* - Establish a pointer to n from each of those members of M that were not already in G. Add these members of M to
|
|
* OPEN. For each member M that was already on OPEN or CLOSED, update the pointer to point to n if the best path
|
|
* so far is through n. For each member of M that was already on CLOSED, redirect the pointers of each of its
|
|
* descendants in G so that they point backward along the best paths found so far to these descendants.
|
|
* @param M
|
|
* @param node
|
|
*/
|
|
establishPointers(
|
|
M,
|
|
node
|
|
) {
|
|
|
|
/**
|
|
* We now have a list of successors (M) which is not already an ancestor of n in G.
|
|
* Install them as successors of n in G. We do part of step 7 here to save some processing steps:
|
|
* We additionally set the pointer of the successor to n, and we push the successor to OPEN.
|
|
*/
|
|
M.notInG.map(
|
|
(successor) => {
|
|
successor.pointer = node;
|
|
node.successors.push(successor);
|
|
this.open.push(successor);
|
|
}
|
|
)
|
|
|
|
/**
|
|
* Redirect pointers of successors that were in OPEN to n
|
|
*/
|
|
M.onOpen.map(
|
|
(successor) => {
|
|
successor.pointer = node;
|
|
}
|
|
);
|
|
|
|
/**
|
|
* Redirect pointers of successors that were in CLOSED to n
|
|
*/
|
|
M.onClosed.map(
|
|
(successor) => {
|
|
successor.pointer = node;
|
|
/**
|
|
* We skip a part of 7 here - we could alternatively redirect the pointers of each descendant of the successor
|
|
* in G to point backward along the best paths found so far to these descendants - but we don't do this because
|
|
* we are not really interested in the shortest paths -
|
|
*/
|
|
}
|
|
)
|
|
|
|
}
|
|
|
|
/**
|
|
* reOrder()
|
|
* - Re-Order nodes in OPEN in order of increasing ~f values. Ties among minimal ~f values are resolved in favor of
|
|
* the deepest node in the search tree.
|
|
*/
|
|
reOrder() {
|
|
|
|
}
|
|
|
|
/**
|
|
* buildSolution()
|
|
* - Traverses node pointers from n (goal node) to n0 (start node) and stores the path in a solution list.
|
|
* @param node
|
|
* @param solution=[]
|
|
*/
|
|
buildSolution(
|
|
node,
|
|
solution=[]
|
|
) {
|
|
|
|
solution.push(node);
|
|
|
|
if (node.pointer) {
|
|
this.buildSolution(node.pointer, solution);
|
|
} else {
|
|
return solution;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* isGoal()
|
|
* - No comment
|
|
* @param callback
|
|
*/
|
|
isGoal(callback) {
|
|
|
|
return callback();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Node {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
/**
|
|
* object - No comment
|
|
*/
|
|
if (typeof options.object === 'undefined') {
|
|
options.object = null;
|
|
}
|
|
/**
|
|
* pointer - No comment
|
|
*/
|
|
if (typeof options.pointer === 'undefined') {
|
|
options.pointer = null;
|
|
}
|
|
/**
|
|
* type - No comment
|
|
*/
|
|
if (typeof options.type === 'undefined') {
|
|
options.type = 'start-node';
|
|
}
|
|
/**
|
|
* successors - No comment
|
|
*/
|
|
if (typeof options.successors === 'undefined') {
|
|
options.successors = [];
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Utils {
|
|
|
|
constructor(options) {
|
|
|
|
if (typeof options === 'undefined') {
|
|
options = {};
|
|
}
|
|
|
|
Object.assign(this, options);
|
|
|
|
}
|
|
|
|
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, '<').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 '<span class="' + cls + '">' + match + '</span>';
|
|
});
|
|
};
|
|
|
|
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 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
|
|
);
|
|
};
|
|
|
|
/**
|
|
* 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*(_?)(.+?)\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
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
};
|
|
|
|
static RemoveFromArray(array, object) {
|
|
let index = array.indexOf(object);
|
|
if (index !== -1) {
|
|
array.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
};
|
|
|
|
}
|
|
|
|
console.log('r3.js - version ' + R3.Version + ' compiled ' + R3.CompileDate);
|
|
|
|
Component.Code = ComponentCode;
|
|
Component.DOM = ComponentDOM;
|
|
Component.DOM.Canvas = ComponentCanvas;
|
|
Component.Geometry = ComponentGeometry;
|
|
Component.Geometry.BufferGeometry = ComponentBufferGeometry;
|
|
Component.Geometry.BufferGeometry.PlaneGeometry = ComponentPlaneGeometry;
|
|
Component.Graphics = ComponentGraphics;
|
|
Component.Graphics.Image = ComponentImage;
|
|
Component.Input = ComponentInput;
|
|
Component.Input.Touch = ComponentTouch;
|
|
Component.Material = ComponentMaterial;
|
|
Component.Mesh = ComponentMesh;
|
|
Component.Texture = ComponentTexture;
|
|
Entity.Slider = EntitySlider;
|
|
R3Object.Project = Project;
|
|
R3Object.Entity = Entity;
|
|
R3Object.Entity.Slider = EntitySlider;
|
|
R3Object.Component = Component;
|
|
R3Object.Component.Code = ComponentCode;
|
|
R3Object.Component.DOM = ComponentDOM;
|
|
R3Object.Component.DOM.Canvas = ComponentCanvas;
|
|
R3Object.Component.Geometry = ComponentGeometry;
|
|
R3Object.Component.Geometry.BufferGeometry = ComponentBufferGeometry;
|
|
R3Object.Component.Geometry.BufferGeometry.PlaneGeometry = ComponentPlaneGeometry;
|
|
R3Object.Component.Graphics = ComponentGraphics;
|
|
R3Object.Component.Graphics.Image = ComponentImage;
|
|
R3Object.Component.Input = ComponentInput;
|
|
R3Object.Component.Input.Touch = ComponentTouch;
|
|
R3Object.Component.Material = ComponentMaterial;
|
|
R3Object.Component.Mesh = ComponentMesh;
|
|
R3Object.Component.Texture = ComponentTexture;
|
|
Runtime.Coder = RuntimeCoder;
|
|
Runtime.Coder.CodeMirror = RuntimeCodeMirror;
|
|
Runtime.DOM = RuntimeDOM;
|
|
Runtime.DOM.JSDOM = RuntimeJSDOM;
|
|
Runtime.DOM.WebDOM = RuntimeWebDOM;
|
|
Runtime.GUI = RuntimeGUI;
|
|
Runtime.GUI.ControlKit = RuntimeControlKit;
|
|
Runtime.Graphics = RuntimeGraphics;
|
|
Runtime.Graphics.Three = RuntimeThree;
|
|
Runtime.Image = RuntimeImage;
|
|
Runtime.Physics = RuntimePhysics;
|
|
Runtime.Physics.Bullet = RuntimeBullet;
|
|
Runtime.Socket = RuntimeSocket;
|
|
Runtime.Statistics = RuntimeStatistics;
|
|
Runtime.Statistics.Stats = RuntimeStats;
|
|
System.DOM = SystemDOM;
|
|
System.Input = SystemInput;
|
|
System.Linking = SystemLinking;
|
|
System.Render = SystemRender;
|
|
System.Runtime = SystemRuntime;
|
|
System.Socket = SystemSocket;
|
|
System.Storage = SystemStorage;
|
|
R3.System = System;
|
|
R3.Runtime = Runtime;
|
|
R3.Event = Event;
|
|
R3.Graph = Graph;
|
|
R3.Node = Node;
|
|
R3.Utils = Utils;
|
|
R3.Object = R3Object;
|
|
R3.Project = Project;
|
|
R3.Entity = Entity;
|
|
R3.Component = Component;
|
|
R3.Code = R3Object.Component.Code;
|
|
R3.Canvas = R3Object.Component.DOM.Canvas;
|
|
R3.PlaneGeometry = R3Object.Component.Geometry.BufferGeometry.PlaneGeometry;
|
|
R3.Image = R3Object.Component.Graphics.Image;
|
|
R3.Touch = R3Object.Component.Input.Touch;
|
|
R3.Material = R3Object.Component.Material;
|
|
R3.Mesh = R3Object.Component.Mesh;
|
|
R3.Texture = R3Object.Component.Texture;
|
|
R3.System.DOM.Start();
|
|
R3.System.Input.Start();
|
|
R3.System.Linking.Start();
|
|
R3.System.Render.Start();
|
|
R3.System.Runtime.Start();
|
|
R3.System.Socket.Start();
|
|
R3.System.Storage.Start();
|