diff --git a/src/game-lib-d3-api-input-a.js b/bak/game-lib-d3-api-input-a.js similarity index 100% rename from src/game-lib-d3-api-input-a.js rename to bak/game-lib-d3-api-input-a.js diff --git a/src/game-lib-d3-api-input-drive.js b/bak/game-lib-d3-api-input-drive.js similarity index 100% rename from src/game-lib-d3-api-input-drive.js rename to bak/game-lib-d3-api-input-drive.js diff --git a/src/game-lib-d3-api-input-editor.js b/bak/game-lib-d3-api-input-editor.js similarity index 100% rename from src/game-lib-d3-api-input-editor.js rename to bak/game-lib-d3-api-input-editor.js diff --git a/src/game-lib-d3-input-a.js b/bak/game-lib-d3-input-a.js similarity index 100% rename from src/game-lib-d3-input-a.js rename to bak/game-lib-d3-input-a.js diff --git a/src/game-lib-d3-input-drive.js b/bak/game-lib-d3-input-drive.js similarity index 100% rename from src/game-lib-d3-input-drive.js rename to bak/game-lib-d3-input-drive.js diff --git a/bak/game-lib-d3-input-editor.js b/bak/game-lib-d3-input-editor.js new file mode 100644 index 0000000..a1fb987 --- /dev/null +++ b/bak/game-lib-d3-input-editor.js @@ -0,0 +1,90 @@ +/** + * Input parent class + * @param graphics GameLib.D3.Graphics + * @param apiInputEditor GameLib.D3.API.Input.Editor + * @constructor + */ +GameLib.D3.Input.Editor = function ( + graphics, + apiInputEditor +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiInputEditor)) { + apiInputEditor = {}; + } + + if (apiInputEditor instanceof GameLib.D3.Input.Editor) { + return apiInputEditor; + } + + GameLib.D3.API.Input.Editor.call( + this, + apiInputEditor.id, + apiInputEditor.name, + apiInputEditor.domElement, + apiInputEditor.camera, + apiInputEditor.parentEntity + ); + + if (this.domElement instanceof GameLib.API.DomElement) { + this.domElement = new GameLib.DomElement( + this.domElement + ) + } + + if (this.camera instanceof GameLib.D3.API.Camera) { + this.camera = new GameLib.D3.Camera( + this.graphics, + this.camera + ) + } + + GameLib.Component.call( + this, + GameLib.Component.COMPONENT_INPUT_EDITOR, + { + 'camera' : GameLib.D3.Camera + } + ); +}; + +GameLib.D3.Input.Editor.prototype = Object.create(GameLib.D3.API.Input.Editor.prototype); +GameLib.D3.Input.Editor.prototype.constructor = GameLib.D3.Input.Editor; + +GameLib.D3.Input.Editor.prototype.createInstance = function() { + return true; +}; + +GameLib.D3.Input.Editor.prototype.updateInstance = function() { +}; + +/** + * GameLib.D3.Input.Editor to GameLib.D3.API.Input.Editor + * @returns {GameLib.D3.API.Input.Editor} + */ +GameLib.D3.Input.Editor.prototype.toApiObject = function() { + + var apiInputEditor = new GameLib.D3.API.Input.Editor( + this.id, + this.name, + this.domElementId, + GameLib.Utils.IdOrNull(this.camera), + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiInputEditor; +}; + +GameLib.D3.Input.Editor.FromObject = function(graphics, objectComponent) { + + var apiInputEditor = GameLib.D3.API.Input.Editor.FromObject(objectComponent); + + return new GameLib.D3.Input.Editor( + graphics, + apiInputEditor + ); +}; + diff --git a/src/game-lib-a-1-event.js b/src/game-lib-a-1-event.js index 6f5917e..b09e7ad 100644 --- a/src/game-lib-a-1-event.js +++ b/src/game-lib-a-1-event.js @@ -20,43 +20,106 @@ GameLib.Event.PARENT_SCENE_CHANGE = 0x2; GameLib.Event.PARENT_ENTITY_CHANGE = 0x3; GameLib.Event.IMAGE_INSTANCE_CREATED = 0x4; GameLib.Event.LOAD_IMAGE = 0x5; -GameLib.Event.NEW_ENTITY = 0x7; -GameLib.Event.MATERIAL_TYPE_CHANGED = 0x8; -GameLib.Event.SAVE_COMPONENT = 0x9; -GameLib.Event.SAVE_COMPONENT_ERROR = 0xa; -GameLib.Event.COMPONENT_SAVED = 0xb; -GameLib.Event.LOAD_COMPONENT = 0xc; -GameLib.Event.LOAD_COMPONENT_ERROR = 0xd; -GameLib.Event.LOGGED_IN = 0xf; -GameLib.Event.COMPONENT_CREATED = 0x10; -GameLib.Event.SCENE_INSTANCE_CREATED = 0x11; -GameLib.Event.SCENE_OBJECT_INSTANCE_CREATED = 0x12; -GameLib.Event.WORLD_INSTANCE_CREATED = 0x13; -GameLib.Event.RIGID_BODY_INSTANCE_CREATED = 0x14; -GameLib.Event.TEXTURE_INSTANCE_CREATED = 0x15; -GameLib.Event.TEXTURE_INSTANCE_UPDATED = 0x16; -GameLib.Event.MATERIAL_INSTANCE_CREATED = 0x17; -GameLib.Event.MATERIAL_INSTANCE_UPDATED = 0x18; -GameLib.Event.MESH_INSTANCE_CREATED = 0x19; -GameLib.Event.MESH_INSTANCE_UPDATED = 0x1a; -GameLib.Event.LIGHT_INSTANCE_CREATED = 0x1b; -GameLib.Event.LIGHT_INSTANCE_UPDATED = 0x1c; -GameLib.Event.DELETE_COMPONENT = 0x1d; -GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE = 0x1e; -GameLib.Event.COMPONENTS_LINKED = 0x1f; -GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE = 0x20; -GameLib.Event.REGISTER_UPDATE = 0x21; -GameLib.Event.BUILD_GUI = 0x22; -GameLib.Event.MESH_DELETED = 0x23; -GameLib.Event.MESH_SELECTED = 0x24; -GameLib.Event.MESH_DESELECTED = 0x25; -GameLib.Event.COMPONENT_REGISTER = 0x26; -GameLib.Event.IMAGE_NOT_FOUND = 0x27; -GameLib.Event.BLENDER_DATA_RECEIVED = 0x28; -GameLib.Event.IMAGE_UPLOAD_COMPLETE = 0x29; -GameLib.Event.COMPONENT_REMOVE = 0x2a; +GameLib.Event.NEW_ENTITY = 0x6; +GameLib.Event.MATERIAL_TYPE_CHANGED = 0x7; +GameLib.Event.SAVE_COMPONENT = 0x8; +GameLib.Event.SAVE_COMPONENT_ERROR = 0x9; +GameLib.Event.COMPONENT_SAVED = 0xa; +GameLib.Event.LOAD_COMPONENT = 0xb; +GameLib.Event.LOAD_COMPONENT_ERROR = 0xc; +GameLib.Event.LOGGED_IN = 0xd; +GameLib.Event.COMPONENT_CREATED = 0xe; +GameLib.Event.SCENE_INSTANCE_CREATED = 0xf; +GameLib.Event.SCENE_OBJECT_INSTANCE_CREATED = 0x10; +GameLib.Event.WORLD_INSTANCE_CREATED = 0x11; +GameLib.Event.RIGID_BODY_INSTANCE_CREATED = 0x12; +GameLib.Event.TEXTURE_INSTANCE_CREATED = 0x13; +GameLib.Event.TEXTURE_INSTANCE_UPDATED = 0x14; +GameLib.Event.MATERIAL_INSTANCE_CREATED = 0x15; +GameLib.Event.MATERIAL_INSTANCE_UPDATED = 0x16; +GameLib.Event.MESH_INSTANCE_CREATED = 0x17; +GameLib.Event.MESH_INSTANCE_UPDATED = 0x18; +GameLib.Event.LIGHT_INSTANCE_CREATED = 0x19; +GameLib.Event.LIGHT_INSTANCE_UPDATED = 0x1a; +GameLib.Event.DELETE_COMPONENT = 0x1b; +GameLib.Event.COMPONENT_DOWNLOAD_COMPLETE = 0x1c; +GameLib.Event.COMPONENTS_LINKED = 0x1d; +GameLib.Event.UNRESOLVED_DEPENDENCIES_UPDATE = 0x1e; +GameLib.Event.REGISTER_UPDATE = 0x1f; +GameLib.Event.BUILD_GUI = 0x20; +GameLib.Event.MESH_DELETED = 0x21; +GameLib.Event.MESH_SELECTED = 0x22; +GameLib.Event.MESH_DESELECTED = 0x23; +GameLib.Event.COMPONENT_REGISTER = 0x24; +GameLib.Event.IMAGE_NOT_FOUND = 0x25; +GameLib.Event.BLENDER_DATA_RECEIVED = 0x26; +GameLib.Event.IMAGE_UPLOAD_COMPLETE = 0x27; +GameLib.Event.COMPONENT_REMOVE = 0x28; +GameLib.Event.KEY_DOWN = 0x29; +GameLib.Event.KEY_UP = 0x2a; +GameLib.Event.RENDER = 0x2b; +GameLib.Event.EVENT_LIST = 0x2c; +/** + * Returns string name of event ID + * @param number + * @returns {*} + * @constructor + */ +GameLib.Event.GetEventName = function(number) { + + switch(number) { + case 0x1 : return 'window_resize'; + case 0x2 : return 'parent_scene_change'; + case 0x3 : return 'parent_entity_change'; + case 0x4 : return 'image_instance_created'; + case 0x5 : return 'load_image'; + case 0x6 : return 'new_entity'; + case 0x7 : return 'material_type_changed'; + case 0x8 : return 'save_component'; + case 0x9 : return 'save_component_error'; + case 0xa : return 'component_saved'; + case 0xb : return 'load_component'; + case 0xc : return 'load_component_error'; + case 0xd : return 'logged_in'; + case 0xe : return 'component_created'; + case 0xf : return 'scene_instance_created'; + case 0x10 : return 'scene_object_instance_created'; + case 0x11 : return 'world_instance_created'; + case 0x12 : return 'rigid_body_instance_created'; + case 0x13 : return 'texture_instance_created'; + case 0x14 : return 'texture_instance_updated'; + case 0x15 : return 'material_instance_created'; + case 0x16 : return 'material_instance_updated'; + case 0x17 : return 'mesh_instance_created'; + case 0x18 : return 'mesh_instance_updated'; + case 0x19 : return 'light_instance_created'; + case 0x1a : return 'light_instance_updated'; + case 0x1b : return 'delete_component'; + case 0x1c : return 'component_download_complete'; + case 0x1d : return 'components_linked'; + case 0x1e : return 'unresolved_dependencies_update'; + case 0x1f : return 'register_update'; + case 0x20 : return 'build_gui'; + case 0x21 : return 'mesh_deleted'; + case 0x22 : return 'mesh_selected'; + case 0x23 : return 'mesh_deselected'; + case 0x24 : return 'component_register'; + case 0x25 : return 'image_not_found'; + case 0x26 : return 'blender_data_received'; + case 0x27 : return 'image_upload_complete'; + case 0x28 : return 'component_remove'; + case 0x29 : return 'key_down'; + case 0x2a : return 'key_up'; + case 0x2b : return 'render'; + case 0x2c : return 'event_list'; + break; + } + + throw new error('unknown event id: ' + number ); +}; + /** * Subscribe to some events * @param eventName diff --git a/src/game-lib-a-component-a.js b/src/game-lib-a-component-a.js index c3cae1e..4128683 100644 --- a/src/game-lib-a-component-a.js +++ b/src/game-lib-a-component-a.js @@ -142,6 +142,9 @@ GameLib.Component.COMPONENT_SHAPE_CONVEX_HULL = 0x2c; GameLib.Component.COMPONENT_SHAPE_CYLINDER = 0x2d; GameLib.Component.COMPONENT_SHAPE_HEIGHT_MAP = 0x2e; GameLib.Component.COMPONENT_SHAPE_PLANE = 0x2f; +GameLib.Component.COMPONENT_CONTROLS = 0x30; +GameLib.Component.COMPONENT_CONTROLS_EDITOR = 0x31; +GameLib.Component.COMPONENT_CONTROLS_FLY = 0x32; /** * Returns string name for component number @@ -198,6 +201,9 @@ GameLib.Component.GetComponentName = function(number) { case 0x2d : return 'GameLib.D3.Shape.Cylinder'; case 0x2e : return 'GameLib.D3.Shape.HeightMap'; case 0x2f : return 'GameLib.D3.Shape.Plane'; + case 0x30 : return 'GameLib.D3.Controls'; + case 0x31 : return 'GameLib.D3.Controls.Editor'; + case 0x32 : return 'GameLib.D3.Controls.Fly'; break; } diff --git a/src/game-lib-d3-api-controls.js b/src/game-lib-d3-api-controls.js new file mode 100644 index 0000000..c23ba29 --- /dev/null +++ b/src/game-lib-d3-api-controls.js @@ -0,0 +1,54 @@ +/** + * Raw Controls API object - should always correspond with the Controls Schema + * @param id + * @param controlsType + * @param name + * @param parentEntity + * @constructor + */ +GameLib.D3.API.Controls = function( + id, + controlsType, + name, + parentEntity +) { + if (GameLib.Utils.UndefinedOrNull(id)) { + id = GameLib.Utils.RandomId(); + } + this.id = id; + + if (GameLib.Utils.UndefinedOrNull(controlsType)) { + controlsType = GameLib.D3.Controls.CONTROLS_TYPE_EDITOR; + } + this.controlsType = controlsType; + + if (GameLib.Utils.UndefinedOrNull(name)) { + name = 'Controls (' + this.id + ')'; + if (controlsType === GameLib.D3.Controls.CONTROLS_TYPE_EDITOR) { + name = 'Controls for Editing'; + } + } + this.name = name; + + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { + parentEntity = null; + } + this.parentEntity = parentEntity; +}; + +GameLib.D3.API.Controls.prototype = Object.create(GameLib.Component.prototype); +GameLib.D3.API.Controls.prototype.constructor = GameLib.D3.API.Controls; + +/** + * Returns an API Controls from an Object + * @param objectControls + * @constructor + */ +GameLib.D3.API.Controls.FromObject = function (objectControls){ + return new GameLib.D3.API.Controls( + objectControls.id, + objectControls.controlsType, + objectControls.name, + objectControls.parentEntity + ); +}; diff --git a/src/game-lib-d3-api-custom-code.js b/src/game-lib-d3-api-custom-code.js index c684878..b9a594d 100644 --- a/src/game-lib-d3-api-custom-code.js +++ b/src/game-lib-d3-api-custom-code.js @@ -2,19 +2,17 @@ * Custom Code Component * @param id * @param name - * @param parentEntity + * @param eventId * @param code - * @param domElementId - * @param args + * @param parentEntity * @constructor */ GameLib.D3.API.CustomCode = function ( - id, - name, - parentEntity, - code, - domElementId, - args + id, + name, + eventId, + code, + parentEntity ) { if (GameLib.Utils.UndefinedOrNull(id)) { id = GameLib.Utils.RandomId(); @@ -26,25 +24,21 @@ GameLib.D3.API.CustomCode = function ( } this.name = name; + if (GameLib.Utils.UndefinedOrNull(eventId)) { + eventId = 0; + } + this.eventId = eventId; + + if (GameLib.Utils.UndefinedOrNull(code)) { + code = 'return null;'; + } + this.code = code; + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { parentEntity = null; } this.parentEntity = parentEntity; - if (GameLib.Utils.UndefinedOrNull(code)) { - code = ''; - } - this.code = code; - - if (GameLib.Utils.UndefinedOrNull(domElementId)) { - domElementId = "CustomCode_" + this.id; - } - this.domElementId = domElementId; - - if (GameLib.Utils.UndefinedOrNull(args)) { - args = []; - } - this.args = args; }; GameLib.D3.API.CustomCode.prototype = Object.create(GameLib.Component.prototype); @@ -60,9 +54,8 @@ GameLib.D3.API.CustomCode.FromObject = function(objectComponent) { return new GameLib.D3.API.CustomCode( objectComponent.id, objectComponent.name, - objectComponent.parentEntity, + objectComponent.eventId, objectComponent.code, - objectComponent.domElementId, - objectComponent.args + objectComponent.parentEntity ); }; diff --git a/src/game-lib-d3-api-renderer.js b/src/game-lib-d3-api-renderer.js index 39a57a2..6dd59d5 100644 --- a/src/game-lib-d3-api-renderer.js +++ b/src/game-lib-d3-api-renderer.js @@ -8,6 +8,9 @@ * @param height * @param domElement * @param clearColor + * @param camera + * @param scenes + * @param viewports * @param parentEntity * @param preserveDrawingBuffer * @constructor @@ -22,6 +25,9 @@ GameLib.D3.API.Renderer = function ( preserveDrawingBuffer, domElement, clearColor, + camera, + scenes, + viewports, parentEntity ) { if (GameLib.Utils.UndefinedOrNull(id)) { @@ -69,6 +75,21 @@ GameLib.D3.API.Renderer = function ( } this.clearColor = clearColor; + if (GameLib.Utils.UndefinedOrNull(camera)) { + camera = null; + } + this.camera = camera; + + if (GameLib.Utils.UndefinedOrNull(scenes)) { + scenes = []; + } + this.scenes = scenes; + + if (GameLib.Utils.UndefinedOrNull(viewports)) { + viewports = []; + } + this.viewports = viewports; + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { parentEntity = null; } @@ -95,6 +116,9 @@ GameLib.D3.API.Renderer.FromObject = function(objectComponent) { objectComponent.preserveDrawingBuffer, objectComponent.domElement, objectComponent.clearColor, + objectComponent.camera, + objectComponent.scenes, + objectComponent.viewports, objectComponent.parentEntity ); }; diff --git a/src/game-lib-d3-api-viewport.js b/src/game-lib-d3-api-viewport.js index d8b987f..75d05d4 100644 --- a/src/game-lib-d3-api-viewport.js +++ b/src/game-lib-d3-api-viewport.js @@ -6,7 +6,6 @@ * @param height * @param x * @param y - * @param scenes * @param parentEntity * @constructor */ @@ -17,7 +16,6 @@ GameLib.D3.API.Viewport = function( height, x, y, - scenes, parentEntity ) { @@ -51,11 +49,6 @@ GameLib.D3.API.Viewport = function( } this.y = y; - if (GameLib.Utils.UndefinedOrNull(scenes)) { - scenes = []; - } - this.scenes = scenes; - if (GameLib.Utils.UndefinedOrNull(parentEntity)) { parentEntity = null; } @@ -78,7 +71,6 @@ GameLib.D3.API.Viewport.FromObject = function(objectViewport) { objectViewport.height, objectViewport.x, objectViewport.y, - objectViewport.scenes, objectViewport.parentEntity ); }; diff --git a/src/game-lib-d3-controls-0.js b/src/game-lib-d3-controls-0.js new file mode 100644 index 0000000..11441bb --- /dev/null +++ b/src/game-lib-d3-controls-0.js @@ -0,0 +1,110 @@ +/** + * Controls Superset - The apiControls properties get moved into the Controls object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiControls GameLib.D3.API.Controls + * @constructor + */ +GameLib.D3.Controls = function ( + graphics, + apiControls +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(apiControls)) { + apiControls = {}; + } + + if (apiControls instanceof GameLib.D3.Controls) { + return apiControls; + } + + GameLib.D3.API.Controls.call( + this, + apiControls.id, + apiControls.controlsType, + apiControls.name, + apiControls.parentEntity + ); + + var componentType = GameLib.Component.COMPONENT_CONTROLS; + + var linkedObjects = null; + + if (this.controlsType === GameLib.D3.Controls.CONTROLS_TYPE_EDITOR) { + + componentType = GameLib.Component.COMPONENT_CONTROLS_EDITOR; + + linkedObjects = { + 'raycaster' : GameLib.D3.Raycaster, + 'renderer' : GameLib.D3.Renderer + } + } + + if (this.controlsType === GameLib.D3.Controls.CONTROLS_TYPE_FLY) { + componentType = GameLib.Component.COMPONENT_CONTROLS_FLY + } + + GameLib.Component.call( + this, + componentType, + linkedObjects + ); +}; + +GameLib.D3.Controls.prototype = Object.create(GameLib.D3.API.Controls.prototype); +GameLib.D3.Controls.prototype.constructor = GameLib.D3.Controls; + +/** + * Controls Type + * @type {number} + */ +GameLib.D3.Controls.CONTROLS_TYPE_EDITOR = 0x0; +GameLib.D3.Controls.CONTROLS_TYPE_FLY = 0x1; + +/** + * Creates a mesh instance or updates it + */ +GameLib.D3.Controls.prototype.createInstance = function() { + console.log('default controls create instance'); +}; + +/** + * Updates the mesh instance + */ +GameLib.D3.Controls.prototype.updateInstance = function() { + console.log('default controls update instance'); +}; + +/** + * Converts a GameLib.D3.Controls to a GameLib.D3.API.Controls + * @returns {GameLib.D3.API.Controls} + */ +GameLib.D3.Controls.prototype.toApiObject = function() { + + var apiControls = new GameLib.D3.API.Controls( + this.id, + this.controlsType, + this.name, + GameLib.Utils.IdOrNull(this.parentEntity) + ); + + return apiControls; +}; + +/** + * Converts a data object to a GameLib.D3.Controls + * @param graphics GameLib.D3.Graphics + * @param objectControls {Object} + * @constructor + */ +GameLib.D3.Controls.FromObject = function(graphics, objectControls) { + + var apiControls = GameLib.D3.API.Controls.FromObject(objectControls); + + return new GameLib.D3.Controls( + graphics, + apiControls + ); + +}; diff --git a/src/game-lib-d3-controls-editor.js b/src/game-lib-d3-controls-editor.js new file mode 100644 index 0000000..feccc08 --- /dev/null +++ b/src/game-lib-d3-controls-editor.js @@ -0,0 +1,147 @@ +/** + * Controls Superset - The apiControls properties get moved into the Controls object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiControls GameLib.D3.API.Controls + * @param raycaster + * @param renderer + * @constructor + */ +GameLib.D3.Controls.Editor = function ( + graphics, + apiControls, + raycaster, + renderer +) { + + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(raycaster)) { + raycaster = null; + } + this.raycaster = raycaster; + + if (GameLib.Utils.UndefinedOrNull(renderer)) { + renderer = null; + } + this.renderer = renderer; + + if (this.raycaster instanceof GameLib.D3.API.Raycaster) { + this.raycaster = new GameLib.D3.Raycaster( + this.graphics, + this.raycaster + ); + } + + if (this.renderer instanceof GameLib.D3.API.Renderer) { + this.renderer = new GameLib.D3.Renderer( + this.graphics, + this.renderer + ) + } + + GameLib.D3.Controls.call( + this, + this.graphics, + apiControls + ); +}; + +/** + * Inheritance + * @type {GameLib.D3.Controls} + */ +GameLib.D3.Controls.Editor.prototype = Object.create(GameLib.D3.Controls.prototype); +GameLib.D3.Controls.Editor.prototype.constructor = GameLib.D3.Controls.Editor; + +/** + * Create Instance + * @returns {THREE.EditorControls} + */ +GameLib.D3.Controls.Editor.prototype.createInstance = function() { + console.log('delaying controls instance creation - call GameLib.D3.Controls.Editor.delayInstance() to create the instance'); +}; + +GameLib.D3.Controls.Editor.prototype.delayedInstance = function() { + + console.log('GameLib.D3.Controls.Editor.delayedInstance() called'); + + if (!this.renderer) { + throw new Error('No renderer at time of creating instance'); + } + + if (!this.renderer.camera) { + throw new Error('No camera at time of instance'); + } + + if (!this.renderer.domElement) { + throw new Error('No dom element at time of instance'); + } + + if (!this.renderer.camera.instance) { + throw new Error('No camera instance at time of instance'); + } + + if (!this.renderer.domElement.instance) { + throw new Error('No dom element instance at time of instance'); + } + + var instance = new THREE.EditorControls( + this.renderer.camera.instance, + this.renderer.domElement.instance + ); + + return instance; +}; + +/** + * Update Instance + */ +GameLib.D3.Controls.Editor.prototype.updateInstance = function() { + + console.warn('an update instance was called on editor controls - which, if not called from within a running system at the right time will affect the order of input event handling and cause system instability'); + + if (this.instance) { + this.instance.dispose(); + delete this.instance; + } + + this.instance = this.delayedInstance(); + + GameLib.D3.Controls.prototype.updateInstance.call(this); +}; + +/** + * Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Mesh} + */ +GameLib.D3.Controls.Editor.prototype.toApiObject = function() { + + var apiMesh = GameLib.D3.Mesh.prototype.toApiObject.call(this); + + apiMesh.raycaster = GameLib.Utils.IdOrNull(this.raycaster); + apiMesh.renderer = GameLib.Utils.IdOrNull(this.renderer); + + return apiMesh; +}; + +/** + * Construct an Editor Controls object from data + * @param graphics + * @param objectMesh + * @returns {GameLib.D3.Controls.Editor} + * @constructor + */ +GameLib.D3.Controls.Editor.FromObject = function(graphics, objectMesh) { + + var apiMesh = GameLib.D3.API.Controls.FromObject(objectMesh); + + apiMesh.renderer = objectMesh.renderer; + apiMesh.raycaster = objectMesh.raycaster; + + return new GameLib.D3.Controls.Editor( + graphics, + apiMesh + ); + +}; \ No newline at end of file diff --git a/src/game-lib-d3-custom-code.js b/src/game-lib-d3-custom-code.js index 1cf5b60..e8f9e0e 100644 --- a/src/game-lib-d3-custom-code.js +++ b/src/game-lib-d3-custom-code.js @@ -19,36 +19,24 @@ GameLib.D3.CustomCode = function( this, apiCustomCode.id, apiCustomCode.name, - apiCustomCode.parentEntity, + apiCustomCode.eventId, apiCustomCode.code, - apiCustomCode.domElementId, - apiCustomCode.args + apiCustomCode.parentEntity ); + this.codeMirror = null; + GameLib.Component.call( this, - GameLib.Component.COMPONENT_CUSTOM_CODE, - { - 'args' : [GameLib.Component] - } + GameLib.Component.COMPONENT_CUSTOM_CODE ); }; GameLib.D3.CustomCode.prototype = Object.create(GameLib.D3.API.CustomCode.prototype); GameLib.D3.CustomCode.prototype.constructor = GameLib.D3.CustomCode; -/** - * Creates a camera instance of 'graphics' type (only THREE for now) - * @returns {THREE.CustomCode} - */ -GameLib.D3.CustomCode.prototype.createInstance = function(update) { - - var instance = function(deltaTime) { - this.args['deltaTime'] = deltaTime; - var f = new Function(this.code).apply(this.parentEntity, this.args); - f(); - }; - +GameLib.D3.CustomCode.prototype.createInstance = function() { + var instance = new Function('data', this.code); return instance; }; @@ -56,7 +44,7 @@ GameLib.D3.CustomCode.prototype.createInstance = function(update) { * Updates the instance with the current state */ GameLib.D3.CustomCode.prototype.updateInstance = function() { - this.instance = this.createInstance(true); + this.instance = new Function('data', this.code); }; /** @@ -65,19 +53,12 @@ GameLib.D3.CustomCode.prototype.updateInstance = function() { */ GameLib.D3.CustomCode.prototype.toApiObject = function() { - var apiArgs = this.args.map( - function(arg) { - return GameLib.Utils.IdOrNull(arg); - } - ); - return new GameLib.D3.API.CustomCode( this.id, this.name, - GameLib.Utils.IdOrNull(this.parentEntity), + this.eventId, this.code, - this.domElementId, - apiArgs + GameLib.Utils.IdOrNull(this.parentEntity) ); }; @@ -89,16 +70,19 @@ GameLib.D3.CustomCode.prototype.toApiObject = function() { * @constructor */ GameLib.D3.CustomCode.FromObject = function(objectCustomCode) { - var apiCustomCode = GameLib.D3.API.CustomCode.FromObject(objectCustomCode); - return new GameLib.D3.CustomCode( apiCustomCode ); - }; - -GameLib.D3.CustomCode.prototype.update = function(deltaTime) { - this.instance(deltaTime); +GameLib.D3.CustomCode.prototype.launchEditor = function(){ + this.codeMirror = CodeMirror( + document.body, + { + value : this.code, + mode : 'javascript', + lineNumbers : true + } + ); }; \ No newline at end of file diff --git a/src/game-lib-d3-helper.js b/src/game-lib-d3-helper.js index b587af9..b295011 100644 --- a/src/game-lib-d3-helper.js +++ b/src/game-lib-d3-helper.js @@ -131,4 +131,7 @@ GameLib.D3.Helper.prototype.createInstance = function() { * Updates the instance with the current state */ GameLib.D3.Helper.prototype.updateInstance = function() { + this.instance.position.copy(this.object.instance.position); + this.instance.scale.copy(this.object.instance.scale); + this.instance.quaternion.copy(this.object.instance.quaternion); }; diff --git a/src/game-lib-d3-input-editor.js b/src/game-lib-d3-input-editor.js deleted file mode 100644 index 9e27064..0000000 --- a/src/game-lib-d3-input-editor.js +++ /dev/null @@ -1,646 +0,0 @@ -/** - * Input parent class - * @param graphics GameLib.D3.Graphics - * @param apiInputEditor GameLib.D3.API.Input.Editor - * @constructor - */ -GameLib.D3.Input.Editor = function ( - graphics, - apiInputEditor -) { - - this.graphics = graphics; - this.graphics.isNotThreeThrow(); - - if (GameLib.Utils.UndefinedOrNull(apiInputEditor)) { - apiInputEditor = {}; - } - - if (apiInputEditor instanceof GameLib.D3.Input.Editor) { - return apiInputEditor; - } - - GameLib.D3.API.Input.Editor.call( - this, - apiInputEditor.id, - apiInputEditor.name, - apiInputEditor.domElement, - apiInputEditor.camera, - apiInputEditor.parentEntity - ); - - if (this.domElement instanceof GameLib.API.DomElement) { - this.domElement = new GameLib.DomElement( - this.domElement - ) - } - - if (this.camera instanceof GameLib.D3.API.Camera) { - this.camera = new GameLib.D3.Camera( - this.graphics, - this.camera - ) - } - - this.meshMoveMode = false; - this.meshMoveXMode = false; - this.meshMoveYMode = false; - this.meshMoveZMode = false; - - /** - * We need new function pointers with scope bound to this so we can remove the - * window event handlers when we need to - * @type {function()} - */ - this.mouseMove = null; - this.mouseDown = null; - this.keyDown = null; - this.mouseUp = null; - this.mouseWheel = null; - - this.selectAll = false; - - this.controlLeft = false; - - this.raycaster = new GameLib.D3.Raycaster( - this.graphics - ); - - this.mouse = new GameLib.Mouse( - this.graphics - ); - - GameLib.Component.call( - this, - GameLib.Component.COMPONENT_INPUT_EDITOR, - { - 'camera' : GameLib.D3.Camera - } - ); -}; - -GameLib.D3.Input.Editor.prototype = Object.create(GameLib.D3.API.Input.Editor.prototype); -GameLib.D3.Input.Editor.prototype.constructor = GameLib.D3.Input.Editor; - -GameLib.D3.Input.Editor.prototype.createInstance = function() { - return true; -}; - -GameLib.D3.Input.Editor.prototype.updateInstance = function() { -}; - -/** - * GameLib.D3.Input.Editor to GameLib.D3.API.Input.Editor - * @returns {GameLib.D3.API.Input.Editor} - */ -GameLib.D3.Input.Editor.prototype.toApiObject = function() { - - var apiInputEditor = new GameLib.D3.API.Input.Editor( - this.id, - this.name, - this.domElementId, - GameLib.Utils.IdOrNull(this.camera), - GameLib.Utils.IdOrNull(this.parentEntity) - ); - - return apiInputEditor; -}; - -GameLib.D3.Input.Editor.FromObject = function(graphics, objectComponent) { - - var apiInputEditor = GameLib.D3.API.Input.Editor.FromObject(objectComponent); - - return new GameLib.D3.Input.Editor( - graphics, - apiInputEditor - ); -}; - -/** - * Keypress events - * @param entity - * @param entityManager - * @returns {Function} - */ -GameLib.D3.Input.Editor.prototype.onKeyDown = function(entity, entityManager) { - - return function(event) { - - console.log('entity ' + entity.name + ' emitted keypress ' + event.code); - - var meshes = null; - - if (event.code === 'Delete') { - - meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]); - - var deletedMeshes = []; - - meshes.map( - function(mesh) { - if (mesh.selected) { - - deletedMeshes.push(mesh); - - this.removeHelper(mesh, entity); - entity.removeComponent(mesh); - entity.buildIdToObject(); - - var scene = mesh.parentScene; - scene.removeObject(mesh); - scene.buildIdToObject(); - } - }.bind(this) - ); - - GameLib.Event.Emit( - GameLib.Event.MESH_DELETED, - { - meshes : deletedMeshes - } - ); - - } - - if (event.code === 'ControlLeft') { - this.controlLeft = true; - } - - if (event.code === 'KeyA') { - - this.selectAll = !this.selectAll; - - meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]); - - meshes.map(function(mesh){ - if (this.selectAll) { - this.selectMesh(mesh); - } else { - this.deSelectMesh(mesh); - } - }.bind(this)); - - GameLib.Event.Emit( - GameLib.Event.BUILD_GUI, - null - ) - - } - } - -}; - -GameLib.D3.Input.Editor.prototype.onKeyUp = function(entity, entityManager) { - - return function(event) { - console.log('entity ' + entity.name + 'emitted keypress ' + event.code); - - if (event.code === 'ControlLeft') { - this.controlLeft = false; - } - } - -}; - -/** - * MouseMove events - * @param entity - * @returns {Function} - */ -GameLib.D3.Input.Editor.prototype.onMouseMove = function(entity) { - return function(event) { - } -}; - -/** - * - * @param entity - * @returns {Function} - */ -GameLib.D3.Input.Editor.prototype.onMouseUp = function(entity) { - return function(event) { - }; -}; - -/** - * - * @param entity - * @returns {Function} - */ -GameLib.D3.Input.Editor.prototype.onMouseWheel = function(entity) { - return function(event) { - }; -}; - -GameLib.D3.Input.Editor.prototype.removeHelper = function(mesh) { - - var components = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Helper); - - var helper = components.reduce( - function (result, component) { - if (component.object === mesh) { - result = component; - } - return result; - }, - null - ); - - if (helper) { - - mesh.parentScene.instance.remove(helper.instance); - - /** - * Restore the polygonOffset value - */ - mesh.instance.material.polygonOffset = mesh.polygonOffset; - - } else { - console.warn('failed to locate helper object which should exist for ' + mesh.name); - } - - return helper; -}; - -GameLib.D3.Input.Editor.prototype.selectMesh = function(mesh) { - - /** - * If mesh is already selected, do nothing - */ - if (mesh.selected === true) { - return; - } - - /** - * Notify our component as being 'selected' - * @type {boolean} - */ - mesh.selected = true; - - /** - * Add a helper to the scene - * @type GameLib.D3.Helper - */ - - var helper = new GameLib.D3.Helper( - this.graphics, - null, - mesh.name + ' Helper', - mesh, - GameLib.D3.Helper.HELPER_TYPE_EDGES - ); - - /** - * Backup the polygonOffset value, then set it to 'true' - helps for clear nice outlines - */ - mesh.polygonOffset = mesh.instance.material.polygonOffset; - - mesh.instance.material.polygonOffset = true; - - mesh.parentScene.instance.add(helper.instance); - - GameLib.Event.Emit( - GameLib.Event.MESH_SELECTED, - { - mesh : mesh - } - ); -}; - -GameLib.D3.Input.Editor.prototype.deSelectMesh = function(mesh) { - - mesh.selected = false; - - this.removeHelper(mesh); - - GameLib.Event.Emit( - GameLib.Event.MESH_DESELECTED, - { - mesh : mesh - } - ); -}; - -/** - * MouseDown events - * @param entity GameLib.Entity - * @returns {Function} - */ -GameLib.D3.Input.Editor.prototype.onMouseDown = function(entity) { - - return function(event) { - - if (event.button === 2) { - - if (this.controlLeft) { - return; - } - - var renderer = entity.getFirstComponent(GameLib.D3.Renderer); - - this.mouse.x = (event.offsetX / renderer.instance.domElement.width) * 2 - 1; - this.mouse.y = -(event.offsetY / renderer.instance.domElement.height) * 2 + 1; - - var scenes = entity.getComponents(GameLib.D3.Scene); - - var intersects = scenes.reduce( - function(result, scene) { - if (!scene.activeCamera) { - console.warn('scene ' + scene.name + ' (' + scene.id + ') has no active cameras associated with it'); - return result; - } - - this.raycaster.instance.setFromCamera( - this.mouse, - scene.activeCamera.instance - ); - - intersects = this.raycaster.getIntersectedObjects(scene.meshes); - - intersects.map(function(intersect){ - result.push(intersect); - }); - - return result; - }.bind(this), - [] - ); - - intersects.sort( - function(a, b) { - if (a.distance < b.distance) { - return -1; - } - - if (a.distance > b.distance) { - return 1; - } - - return 0; - } - ); - - var meshes = intersects.map(function(intersect){ - return intersect.mesh; - }); - - var mesh = meshes[0]; - - if (mesh) { - - /** - * Prevent default action (like context menu or whatever) - */ - event.preventDefault(); - - /** - * Prevent other event listeners for 'mousedown' from executing their actions - */ - event.stopImmediatePropagation(); - - if (mesh.selected) { - this.deSelectMesh(mesh); - } else { - this.selectMesh(mesh); - } - - /** - * Notify our GUI system to build a GUI - */ - GameLib.Event.Emit( - GameLib.Event.BUILD_GUI, - null - ) - } - } - } -}; - - -// -// console.log('keypressed ' + event.code); -// -// if (event.code === 'KeyV') { -// //todo - change view -// } -// -// if (event.code == "KeyQ") { -// -// this.editor.allSelected = !this.editor.allSelected; -// -// this.editor.selectedObjects = []; -// -// if (this.editor.allSelected) { -// for (var property in this.editor.idToObject) { -// if (this.editor.idToObject.hasOwnProperty(property)) { -// this.editor.selectedObjects.push( -// new GameLib.D3.SelectedObject( -// this.graphics, -// this.editor.idToObject(property) -// ) -// ) -// } -// } -// } -// -// if (this.editor.onSelectionChanged) { -// this.editor.onSelectionChanged(this.editor); -// } -// } -// -// if (event.code == 'KeyG') { -// if (!this.meshMoveMode) { -// console.log('move mode'); -// this.meshMoveMode = true; -// } -// } -// -// if (event.code == 'KeyX') { -// if (this.meshMoveMode) { -// console.log('move along x'); -// this.meshMoveXMode = true; -// this.meshMoveYMode = false; -// this.meshMoveZMode = false; -// } -// } -// -// if (event.code == 'KeyY') { -// if (this.meshMoveMode) { -// console.log('move along y'); -// this.meshMoveXMode = false; -// this.meshMoveYMode = true; -// this.meshMoveZMode = false; -// } -// } -// -// if (event.code == 'KeyZ') { -// if (this.meshMoveMode) { -// console.log('move along z'); -// this.meshMoveXMode = false; -// this.meshMoveYMode = false; -// this.meshMoveZMode = true; -// } -// } -// -// if (event.code == 'Escape') { -// if (this.meshMoveMode) { -// this.meshMoveMode = false; -// console.log('TODO: implement restore positions'); -// } -// } -// -// if (event.code == 'Enter') { -// if (this.meshMoveMode) { -// this.meshMoveMode = false; -// console.log('TODO: implement apply positions'); -// } -// } -// }; - -// GameLib.D3.Input.Editor.prototype.onMouseDown = function(entity) { -// -// return function(event) { -// -// if (event.button === 2) { -// event.cancelBubble = true; -// -// event.preventDefault(); -// -// if (event.stopPropagation) { -// event.stopPropagation(); -// } -// -// var meshes = entity.queryComponents(GameLib.D3.Mesh); -// -// var intersects = this.raycaster.getIntersectedObjects(meshes); -// -// if (intersects.length > 0) { -// -// console.log('object(s) instersected'); -// -// // var index = -1; -// // -// // for (var s = 0; s < this.editor.selectedObjects.length; s++) { -// // if (this.editor.selectedObjects[s].object == intersects[0]) { -// // index = s; -// // break; -// // } -// // } -// // -// // if (index == -1) { -// // /** -// // * The object is not selected, select it -// // */ -// // this.selectObject(intersects[0]); -// // -// // } else { -// // /** -// // * De-select the objec -// // */ -// // var delta = Date.now() - this.editor.selectedObjects[index].lastUpdate; -// // if (delta > this.selectDelayMs) { -// // this.unselectObject(intersects[0]); -// // } -// // } -// // -// // if (this.editor.onSelectionChanged) { -// // this.editor.onSelectionChanged(this.editor); -// // } -// } -// -// return false; -// } -// } -// }; - -// /** -// * Mouse click events -// * @param event -// * @returns {boolean} -// */ -// GameLib.D3.Input.Editor.prototype.onMouseDown = function(event) { -// -// if (event.button === 2) { -// -// -// -// -// -// } -// -// if (event.button == 0) { -// if (this.meshMoveMode) { -// this.meshMoveMode = false; -// this.meshMoveXMode = false; -// this.meshMoveYMode = false; -// this.meshMoveZMode = false; -// } -// } -// }; - -// /** -// * Mouse move events -// * @param event -// */ -// GameLib.D3.Input.Editor.prototype.onMouseMove = function(event) { -// -// // var clientX = event.clientX - this.widthOffset; -// // this.mouse.x = ((clientX / (window.innerWidth - this.widthOffset))) * 2 - 1; -// // this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; -// -// this.mouse.x = event.clientX; -// this.mouse.y = event.clientY; -// -// console.log("mouse (" + this.mouse.x + ", " + this.mouse.y + ")"); -// -// this.raycaster.instance.setFromCamera( -// this.mouse, -// this.camera.instance -// ); -// -// if (this.meshMoveMode) { -// -// var units = event.movementY; -// -// if (this.meshMoveXMode) { -// this.moveSelectedObjects('x', units); -// } -// -// if (this.meshMoveYMode) { -// this.moveSelectedObjects('y', units); -// } -// -// if (this.meshMoveZMode) { -// this.moveSelectedObjects('z', units); -// } -// } -// }; - -// /** -// * Moves selected objects along an axis -// * @param alongAxis -// * @param units -// */ -// GameLib.D3.Input.Editor.prototype.moveSelectedObjects = function(alongAxis, units) { -// -// for (var s = 0; s < this.editor.selectedObjects.length; s++) { -// -// var object = this.editor.selectedObjects[s].object; -// -// if (object.position) { -// if (alongAxis == 'x') { -// object.position.x += units; -// } -// if (alongAxis == 'y') { -// object.position.y += units; -// } -// if (alongAxis == 'z') { -// object.position.z += units; -// } -// -// if (object.updateInstance) { -// object.updateInstance(); -// } -// } -// } -// }; diff --git a/src/game-lib-d3-mesh-0.js b/src/game-lib-d3-mesh-0.js index 3b350c7..2386e20 100644 --- a/src/game-lib-d3-mesh-0.js +++ b/src/game-lib-d3-mesh-0.js @@ -132,6 +132,12 @@ GameLib.D3.Mesh = function ( componentType = GameLib.Component.COMPONENT_MESH_SPHERE } + /** + * Runtime meshes have helpers too + * @type {null} + */ + this.helper = null; + GameLib.Component.call( this, componentType, @@ -626,6 +632,10 @@ GameLib.D3.Mesh.prototype.updateInstance = function() { this.instance.renderOrder = this.renderOrder; + if (this.helper) { + this.helper.updateInstance(); + } + }; GameLib.D3.Mesh.prototype.getBoundingBox = function() { @@ -790,6 +800,10 @@ GameLib.D3.Mesh.prototype.applyLocalPositionRotationScale = function() { this.updateInstance(); }; +/** + * Gets all children components of this Mesh + * @returns {Array} + */ GameLib.D3.Mesh.prototype.getChildrenComponents = function() { var components = []; @@ -824,4 +838,68 @@ GameLib.D3.Mesh.prototype.getChildrenComponents = function() { ); return components; -}; \ No newline at end of file +}; + +/** + * Convenience function for creating a helper for this Mesh - should be called from Systems only + */ +GameLib.D3.Mesh.prototype.createHelper = function() { + + if (GameLib.Utils.UndefinedOrNull(this.parentScene) || + GameLib.Utils.UndefinedOrNull(this.parentScene.instance)) { + console.warn('this mesh has no parent scene - cannot create helper'); + return; + } + + if (this.helper) { + this.removeHelper(); + } + + this.helper = new GameLib.D3.Helper( + this.graphics, + null, + this.name + ' Helper', + this, + GameLib.D3.Helper.HELPER_TYPE_EDGES + ); + + this.helper.updateInstance(); + + /** + * Backup the polygonOffset value, then set it to 'true' - helps for clear nice outlines + */ + this.polygonOffset = this.instance.material.polygonOffset; + + this.instance.material.polygonOffset = true; + + this.parentScene.instance.add(this.helper.instance); + +}; + +/** + * Convenience function for removing a helper for this Mesh - should be called from Systems only + */ +GameLib.D3.Mesh.prototype.removeHelper = function() { + + if (GameLib.Utils.UndefinedOrNull(this.parentScene) || + GameLib.Utils.UndefinedOrNull(this.parentScene.instance)) { + console.warn('this mesh has no parent scene - cannot remove helper'); + return; + } + + if (this.helper && this.helper.instance) { + this.parentScene.instance.remove(this.helper.instance); + delete this.helper.instance; + } + + this.instance.material.polygonOffset = this.polygonOffset; + + GameLib.Event.Emit( + GameLib.Event.COMPONENT_REMOVE, + { + component : this.helper + } + ); + + this.helper = null; +}; diff --git a/src/game-lib-d3-mesh-plane.js b/src/game-lib-d3-mesh-plane.js index 4924326..ad91104 100644 --- a/src/game-lib-d3-mesh-plane.js +++ b/src/game-lib-d3-mesh-plane.js @@ -106,6 +106,11 @@ GameLib.D3.Mesh.Plane.prototype.updateInstance = function() { this.instance.geometry = geometry; this.updateVerticesFromGeometryInstance(geometry); + + if (this.helper) { + this.removeHelper(); + this.createHelper(); + } } GameLib.D3.Mesh.prototype.updateInstance.call(this); diff --git a/src/game-lib-d3-renderer.js b/src/game-lib-d3-renderer.js index 0b90c73..0c2fcd4 100644 --- a/src/game-lib-d3-renderer.js +++ b/src/game-lib-d3-renderer.js @@ -2,11 +2,13 @@ * Renders a scene with a camera * @param graphics GameLib.D3.Graphics * @param apiRenderer GameLib.D3.API.Renderer + * @param statistics GameLib.D3.Stats * @constructor */ GameLib.D3.Renderer = function ( graphics, - apiRenderer + apiRenderer, + statistics ) { this.graphics = graphics; @@ -31,6 +33,9 @@ GameLib.D3.Renderer = function ( apiRenderer.preserveDrawingBuffer, apiRenderer.domElement, apiRenderer.clearColor, + apiRenderer.camera, + apiRenderer.scenes, + apiRenderer.viewports, apiRenderer.parentEntity ); @@ -46,11 +51,55 @@ GameLib.D3.Renderer = function ( ); } + if (this.camera instanceof GameLib.D3.API.Camera) { + this.camera = new GameLib.D3.Camera( + this.graphics, + this.camera + ) + } + + this.scenes = this.scenes.map(function(scene){ + if (scene instanceof GameLib.D3.API.Scene) { + return new GameLib.D3.Scene( + this.graphics, + scene + ); + } else { + return scene; + } + }.bind(this)); + + this.viewports = this.viewports.map(function(viewport){ + if (viewport instanceof GameLib.D3.API.Viewport) { + return new GameLib.D3.Viewport( + this.graphics, + viewport + ); + } else { + return viewport; + } + }.bind(this)); + + /** + * Only runtime Renderer Components have runtime statistics + */ + if (GameLib.Utils.UndefinedOrNull(statistics)) { + statistics = null; + } + this.statistics = statistics; + + this.mouse = new GameLib.Mouse( + this.graphics + ); + GameLib.Component.call( this, GameLib.Component.COMPONENT_RENDERER, { - 'domElement' : GameLib.DomElement + 'domElement' : GameLib.DomElement, + 'camera' : GameLib.D3.Camera, + 'scenes' : [GameLib.D3.Scene], + 'viewports' : [GameLib.D3.Viewport] } ); @@ -94,7 +143,11 @@ GameLib.D3.Renderer.prototype.createInstance = function() { return instance; }; +/** + * + */ GameLib.D3.Renderer.prototype.updateInstance = function() { + this.instance.localClippingEnabled = this.localClipping; this.instance.setSize( @@ -118,6 +171,10 @@ GameLib.D3.Renderer.prototype.updateInstance = function() { this.instance.preserveDrawingBuffer = this.preserveDrawingBuffer; }; +/** + * + * @returns {GameLib.D3.API.Renderer} + */ GameLib.D3.Renderer.prototype.toApiObject = function() { var apiRenderer = new GameLib.D3.API.Renderer( @@ -129,6 +186,14 @@ GameLib.D3.Renderer.prototype.toApiObject = function() { this.height, this.preserveDrawingBuffer, this.domElement.toApiObject(), + this.clearColor.toApiObject(), + GameLib.Utils.IdOrNull(this.camera), + this.scenes.map(function(scene){ + return GameLib.Utils.IdOrNull(scene); + }), + this.viewports.map(function(viewport){ + return GameLib.Utils.IdOrNull(viewport); + }), GameLib.Utils.IdOrNull(this.parentEntity) ); @@ -152,8 +217,63 @@ GameLib.D3.Renderer.FromObject = function(graphics, objectComponent) { ); }; -GameLib.D3.Renderer.prototype.render = function() { - this.instance.render(this.scene.instance, this.camera.instance); +/** + * Convenience render function + */ +GameLib.D3.Renderer.prototype.render = function(delta) { + + if (this.statistics) { + this.statistics.start(); + } + + if (!this.instance) { + return; + } + + if (this.viewports.length > 1) { + this.instance.autoClear = false; + } + + if (this.scenes.length > 1) { + this.instance.autoClear = false; + } + + this.instance.clear(); + + this.viewports.map( + + function(viewport) { + + this.instance.setViewport( + viewport.x * this.width, + viewport.y * this.height, + viewport.width * this.width, + viewport.height * this.height + ); + + this.scenes.map(function(scene) { + + if (!scene.instance) { + return; + } + + if (!this.camera.instance) { + return; + } + + this.instance.render( + scene.instance, + this.camera.instance + ) + + }.bind(this)); + + }.bind(this) + ); + + if (this.statistics) { + this.statistics.end(); + } }; GameLib.D3.Renderer.prototype.setSize = function(width, height) { diff --git a/src/game-lib-d3-scene.js b/src/game-lib-d3-scene.js index d948375..2fc19ba 100644 --- a/src/game-lib-d3-scene.js +++ b/src/game-lib-d3-scene.js @@ -153,6 +153,12 @@ GameLib.D3.Scene = function ( ); } + /** + * Runtime scenes have helpers (just used to store which helper belongs to which scene) + * @type {Array} + */ + this.helpers = []; + GameLib.Component.call( this, GameLib.Component.COMPONENT_SCENE, diff --git a/src/game-lib-d3-stats.js b/src/game-lib-d3-stats.js index 3746265..a440da5 100644 --- a/src/game-lib-d3-stats.js +++ b/src/game-lib-d3-stats.js @@ -69,3 +69,11 @@ GameLib.D3.Stats.prototype.createInstance = function() { GameLib.D3.Stats.prototype.updateInstance = function() { this.instance = new this.stats(); }; + +GameLib.D3.Stats.prototype.start = function() { + this.instance.begin(); +}; + +GameLib.D3.Stats.prototype.end = function() { + this.instance.end(); +}; diff --git a/src/game-lib-d3-viewport.js b/src/game-lib-d3-viewport.js index c040700..c89768d 100644 --- a/src/game-lib-d3-viewport.js +++ b/src/game-lib-d3-viewport.js @@ -28,28 +28,21 @@ GameLib.D3.Viewport = function ( apiViewport.height, apiViewport.x, apiViewport.y, - apiViewport.scenes, apiViewport.parentEntity ); GameLib.Component.call( this, - GameLib.Component.COMPONENT_VIEWPORT, - { - 'scenes' : [GameLib.D3.Scene] - } + GameLib.Component.COMPONENT_VIEWPORT ); }; GameLib.D3.Viewport.prototype = Object.create(GameLib.D3.API.Viewport.prototype); GameLib.D3.Viewport.prototype.constructor = GameLib.D3.Viewport; -//GameLib.D3.Viewport.VIEWPORT_TYPE_GAME = 0x1; - /** * - * @param update - * @returns {*} + * @returns {boolean} */ GameLib.D3.Viewport.prototype.createInstance = function() { return true; @@ -75,9 +68,6 @@ GameLib.D3.Viewport.prototype.toApiObject = function() { this.height, this.x, this.y, - this.scenes.map(function(scene){ - return GameLib.Utils.IdOrNull(scene); - }), GameLib.Utils.IdOrNull(this.parentEntity) ); diff --git a/src/game-lib-entity-manager.js b/src/game-lib-entity-manager.js index c45bc01..c980307 100644 --- a/src/game-lib-entity-manager.js +++ b/src/game-lib-entity-manager.js @@ -44,17 +44,27 @@ GameLib.EntityManager.prototype.createInstance = function() { }; GameLib.EntityManager.prototype.registerComponent = function(data) { - this.register.push(data.component); - GameLib.Event.Emit( - GameLib.Event.REGISTER_UPDATE, - { - register : this.register - } - ); + + var length = this.register.length; + + GameLib.Utils.PushUnique(this.register, data.component); + + if (length !== this.register.length) { + GameLib.Event.Emit( + GameLib.Event.REGISTER_UPDATE, + { + register : this.register + } + ); + } }; GameLib.EntityManager.prototype.removeComponent = function(data) { + if (data.component.parentEntity) { + data.component.parentEntity.removeComponent(data.component); + } + var index = this.register.indexOf(data.component); if (index !== -1) { @@ -134,33 +144,39 @@ GameLib.EntityManager.prototype.findComponentById = function(id) { }; GameLib.EntityManager.prototype.findHelperByObject = function(object) { - - return this.entities.reduce( - function(result, entity) { - var helpers = entity.getComponents(GameLib.D3.Helper); - var helper = helpers.reduce( - function(helperResult, tmpHelper) { - - if (tmpHelper.object === object) { - helperResult = tmpHelper; - } - - return helperResult; - }, - null - ); - - if (helper) { - result = helper; + return this.register.reduce( + function(result, component) { + if (component instanceof GameLib.D3.Helper) { + if (component.object === object) { + result = component; + } } - return result; }, null ); - }; +GameLib.EntityManager.prototype.findSceneByObject = function(object) { + return this.register.reduce( + function(result, component) { + if (component instanceof GameLib.D3.Scene) { + + if (component.meshes.indexOf(object) !== -1) { + result = component; + } + + if (component.lights.indexOf(object) !== -1) { + result = component; + } + } + return result; + }, + null + ); +}; + + /** * Adds an entity to this manager * @param entity GameLib.Entity diff --git a/src/game-lib-system-0.js b/src/game-lib-system-0.js index 8e48f70..f2bbe36 100644 --- a/src/game-lib-system-0.js +++ b/src/game-lib-system-0.js @@ -42,6 +42,7 @@ GameLib.System.SYSTEM_TYPE_STORAGE = 0x8; GameLib.System.SYSTEM_TYPE_GUI = 0x10; GameLib.System.SYSTEM_TYPE_PHYSICS = 0x20; GameLib.System.SYSTEM_TYPE_LINKING = 0x40; +GameLib.System.SYSTEM_TYPE_CUSTOM = 0x80; GameLib.System.SYSTEM_TYPE_ALL = 0xFFFF; GameLib.System.prototype.createInstance = function() { diff --git a/src/game-lib-system-custom-code.js b/src/game-lib-system-custom-code.js new file mode 100644 index 0000000..76d2676 --- /dev/null +++ b/src/game-lib-system-custom-code.js @@ -0,0 +1,54 @@ +/** + * System takes care of updating all the entities (based on their component data) + * @param apiSystem GameLib.API.System + * @constructor + */ +GameLib.System.CustomCode = function( + apiSystem +) { + + GameLib.System.call( + this, + apiSystem + ); + + this.customCodeComponents = null; + + this.subscriptions = []; + +}; + +GameLib.System.CustomCode.prototype = Object.create(GameLib.System.prototype); +GameLib.System.CustomCode.prototype.constructor = GameLib.System.CustomCode; + +/** + * Start the rendering system + */ +GameLib.System.CustomCode.prototype.start = function() { + + this.customCodeComponents = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.CustomCode); + + this.customCodeComponents.map(function(customCodeComponent){ + + this.subscriptions.push( + this.subscribe( + customCodeComponent.eventId, + customCodeComponent.instance + ) + ); + + }.bind(this)); + +}; + +/** + * Stop the rendering system + */ +GameLib.System.CustomCode.prototype.stop = function() { + + this.subscriptions.map(function(subscription){ + subscription.remove(); + }); + +}; + diff --git a/src/game-lib-system-gui.js b/src/game-lib-system-gui.js index 9f021d6..ef5b785 100644 --- a/src/game-lib-system-gui.js +++ b/src/game-lib-system-gui.js @@ -20,7 +20,7 @@ GameLib.System.GUI = function( * later when we are done. * @type {null} */ - this.backupComponents = null; + this.backupComponents = []; this.exclusiveMode = false; @@ -325,9 +325,38 @@ GameLib.System.GUI.prototype.buildArrayManagerControl = function( }; -GameLib.System.GUI.prototype.buildSelectControl = function(folder, object, property, entityManager, constructor) { +GameLib.System.GUI.prototype.buildColorControl = function(folder, componentTemplate, property) { - var objects = entityManager.queryComponents(constructor); + var object = componentTemplate.template; + + folder.addColor( + { + hexColor : object[property].toHex() + }, + 'hexColor' + ).name(property).listen().onChange( + function(value) { + componentTemplate.affected.map( + function(component) { + component[property].fromHex(value); + component[property].updateInstance(); + } + ) + } + ); + +}; + +GameLib.System.GUI.prototype.buildSelectControl = function(folder, componentTemplate, property) { + + /** + * We need to discover the constructor for this component + */ + var constructor = componentTemplate.template[property].constructor; + + var object = componentTemplate.template; + + var objects = GameLib.EntityManager.Instance.queryComponents(constructor); var idToObject = {}; @@ -348,47 +377,36 @@ GameLib.System.GUI.prototype.buildSelectControl = function(folder, object, prope options ).name(property).listen().onChange( - function(gui) { + function (value) { - return function (value) { + var newComponent = null; - if (value !== 'null') { - object[property] = idToObject[value]; - } else { - object[property] = null; + var originalComponent = this.initialValue; + + if (value !== 'null') { + newComponent = idToObject[value]; + } + + componentTemplate.affected.map( + function(component) { + component[property] = newComponent; + component.updateInstance(); + + if (property === 'parentScene') { + GameLib.Event.Emit( + GameLib.Event.PARENT_SCENE_CHANGE, + { + originalScene: originalComponent, + newScene: newComponent, + object: component + } + ); + } } + ); - if (property === 'parentScene') { - /** - * New way of doing things - */ - GameLib.Event.Emit( - GameLib.Event.PARENT_SCENE_CHANGE, - { - originalScene: this.initialValue, - newScene: object[property], - object: object, - entityManager: entityManager - } - ); - - } - else { - /** - * Old way of doing things - */ - object.updateInstance(); - } - - - /** - * Properties changed - rebuild GUI - */ - //gui.build(entityManager); - - }; - - }(this) + this.initialValue = newComponent; + } ); }; @@ -396,6 +414,17 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, var object = componentTemplate.template; + var listen = false; + + if (componentTemplate.affected.length === 1) { + /** + * If the template only affects a single object - put the handle on this so we can listen for changes + */ + //object = componentTemplate.affected[0]; + + listen = true; + } + var componentType = componentTemplate.componentType; var handles = []; @@ -404,7 +433,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, GameLib.Utils.isString(object[property]) || GameLib.Utils.isBoolean(object[property]) ) { - handles.push(folder.add(object, property).name(property).listen()); + handles.push(folder.add(object, property)); } if (GameLib.Utils.isNumber(object[property])) { @@ -429,7 +458,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'linking' : GameLib.System.SYSTEM_TYPE_LINKING, 'physics' : GameLib.System.SYSTEM_TYPE_PHYSICS } - ).listen() + ) ); } else if (property === 'broadphaseType') { handles.push( @@ -441,7 +470,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'grid': GameLib.D3.Image.BROADPHASE_TYPE_GRID, 'sap': GameLib.D3.Image.BROADPHASE_TYPE_SAP } - ).listen() + ) ); } else if (property === 'meshType') { handles.push( @@ -455,7 +484,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'plane' : GameLib.D3.Mesh.MESH_TYPE_PLANE, 'sphere' : GameLib.D3.Mesh.MESH_TYPE_SPHERE } - ).listen() + ) ); } else if (property === 'materialType') { handles.push( @@ -468,7 +497,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'phong': GameLib.D3.Material.MATERIAL_TYPE_PHONG, 'points': GameLib.D3.Material.MATERIAL_TYPE_POINTS } - ).listen() + ) ); } else if (property === 'side') { handles.push( @@ -480,7 +509,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'front': GameLib.D3.Material.TYPE_FRONT_SIDE, 'back': GameLib.D3.Material.TYPE_BACK_SIDE } - ).listen() + ) ); } else if (property === 'combine') { handles.push( @@ -492,7 +521,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'mix': GameLib.D3.Material.TYPE_MIX_OPERATION, 'add': GameLib.D3.Material.TYPE_ADD_OPERATION } - ).listen() + ) ); } else if (property === 'vertexColors') { handles.push( @@ -504,7 +533,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'face': GameLib.D3.Material.TYPE_FACE_COLORS, 'vertex': GameLib.D3.Material.TYPE_VERTEX_COLORS } - ).listen() + ) ); } else if (property === 'blending') { handles.push( @@ -517,27 +546,27 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'subtractive': GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING, 'multiply': GameLib.D3.Material.TYPE_MULTIPLY_BLENDING } - ).listen() + ) ); } else if (property === 'blendSrc') { handles.push( folder.add( object, - property,- - { - 'zero': GameLib.D3.Material.TYPE_ZERO_FACTOR, - 'one': GameLib.D3.Material.TYPE_ONE_FACTOR, - 'source color': GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR, - 'one minus source color': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR, - 'source alpha': GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR, - 'one minus source alpha': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR, - 'destination alpha': GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR, - 'one minus destination alpha': GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR, - 'destination color': GameLib.D3.Material.TYPE_DST_COLOR_FACTOR, - 'one minus destination color': GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR, - 'source alpha saturate': GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR - } - ).listen() + property, + { + 'zero': GameLib.D3.Material.TYPE_ZERO_FACTOR, + 'one': GameLib.D3.Material.TYPE_ONE_FACTOR, + 'source color': GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR, + 'one minus source color': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR, + 'source alpha': GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR, + 'one minus source alpha': GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR, + 'destination alpha': GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR, + 'one minus destination alpha': GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR, + 'destination color': GameLib.D3.Material.TYPE_DST_COLOR_FACTOR, + 'one minus destination color': GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR, + 'source alpha saturate': GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR + } + ) ); } else if (property === 'blendDst') { handles.push( @@ -557,7 +586,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'one minus destination color': GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR, 'source alpha saturate': GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR } - ).listen() + ) ); } else if (property === 'blendEquation') { handles.push( @@ -571,7 +600,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'min': GameLib.D3.Material.TYPE_MIN_EQUATION, 'max': GameLib.D3.Material.TYPE_MAX_EQUATION } - ).listen() + ) ); } else if (property === 'depthFunc') { handles.push( @@ -588,7 +617,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'greated depth': GameLib.D3.Material.TYPE_GREATER_DEPTH, 'not equal depth': GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH } - ).listen() + ) ); } else if (property === 'wrapS') { handles.push( @@ -600,7 +629,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'clamp': GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING, 'mirrored repeat': GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING } - ).listen() + ) ); } else if (property === 'wrapT') { handles.push( @@ -612,7 +641,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'clamp': GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING, 'mirrored repeat': GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING } - ).listen() + ) ); } else if (property === 'format') { handles.push( @@ -627,7 +656,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'luminance alpha': GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT, 'depth': GameLib.D3.Texture.TYPE_DEPTH_FORMAT } - ).listen() + ) ); } else if (property === 'mapping') { handles.push( @@ -644,7 +673,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'cube uv reflection': GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING, 'cube uv refraction': GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING } - ).listen() + ) ); } else if (property === 'magFilter') { handles.push( @@ -659,21 +688,22 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'linear mipmap nearest': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER, 'linear mipmap linear': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER } - ).listen() + ) ); } else if (property === 'minFilter') { - handles.push(folder.add( - object, - property, - { - 'nearest': GameLib.D3.Texture.TYPE_NEAREST_FILTER, - 'nearest mipmap nearest': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER, - 'nearest mipmap linear': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER, - 'linear': GameLib.D3.Texture.TYPE_LINEAR_FILTER, - 'linear mipmap nearest': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER, - 'linear mipmap linear': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER - } - ).listen() + handles.push( + folder.add( + object, + property, + { + 'nearest': GameLib.D3.Texture.TYPE_NEAREST_FILTER, + 'nearest mipmap nearest': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER, + 'nearest mipmap linear': GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER, + 'linear': GameLib.D3.Texture.TYPE_LINEAR_FILTER, + 'linear mipmap nearest': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER, + 'linear mipmap linear': GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER + } + ) ); } else if (componentType === GameLib.Component.COMPONENT_TEXTURE && property === 'typeId') { handles.push( @@ -684,7 +714,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'normal': GameLib.D3.Texture.TEXTURE_TYPE_NORMAL, 'cube': GameLib.D3.Texture.TEXTURE_TYPE_CUBE } - ).listen() + ) ); } else if (property === 'textureType') { handles.push( @@ -701,7 +731,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'float': GameLib.D3.Texture.TYPE_FLOAT, 'half float': GameLib.D3.Texture.TYPE_HALF_FLOAT } - ).listen() + ) ); } else if (property === 'encoding') { handles.push( @@ -718,7 +748,7 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'rgbm16': GameLib.D3.Texture.TYPE_RGBM16_ENCODING, 'rgbd': GameLib.D3.Texture.TYPE_RGBD_ENCODING } - ).listen() + ) ); } else if (property === 'lightType') { handles.push( @@ -731,7 +761,26 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, 'spot': GameLib.D3.Light.LIGHT_TYPE_SPOT, 'point': GameLib.D3.Light.LIGHT_TYPE_POINT } - ).listen() + ) + ); + } else if (property === 'eventId') { + + var options = {}; + + for (var i = 0; i < 200; i++) { + try { + options[GameLib.Event.GetEventName(i)] = i; + } catch (error) { + + } + } + + handles.push( + folder.add( + object, + property, + options + ) ); } else { @@ -743,60 +792,65 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, property === 'metalness' || property === 'roughness' ) { - handles.push(folder.add(object, property, 0, 1.0, 0.001).listen()); + handles.push(folder.add(object, property, 0, 1.0, 0.001)); } else if ( property === 'shininess' || property === 'fov' ) { - handles.push(folder.add(object, property, -255, 255, 1).listen()); + handles.push(folder.add(object, property, -255, 255, 1)); } else if ( property === 'aspect' ) { - handles.push(folder.add(object, property, 0, 5, 0.001).listen()); + handles.push(folder.add(object, property, 0, 5, 0.001)); } else if ( property === 'widthSegments' || property === 'heightSegments' ) { - handles.push(folder.add(object, property, 1, 1000, 1).listen()); + handles.push(folder.add(object, property, 1, 1000, 1)); } else if ( property === 'angle' || property === 'width' || property === 'height' || property === 'depth' ) { - handles.push(folder.add(object, property, -1000, 1000, 1).listen()); + handles.push(folder.add(object, property, -1000, 1000, 1)); } else if ( property === 'near' || property === 'distanceGrain' || property === 'bumpScale' || property === 'envMapIntensity' ) { - handles.push(folder.add(object, property, -10, 100, 0.001).listen()); + handles.push(folder.add(object, property, -10, 100, 0.001)); } else if ( property === 'heightOffset' || property === 'rotationFactor' ) { - handles.push(folder.add(object, property, -100, 100, 0.001).step(0.001).listen()); + handles.push(folder.add(object, property, -100, 100, 0.001)); } else { - handles.push(folder.add(object, property, -10000, 10000, grain).listen()); + handles.push(folder.add(object, property, -10000, 10000, grain)); } } } handles.map( function(handle) { + if (property === 'name') { handle.onFinishChange( - function(__handle) { + function(__handle, __folder) { return function(value) { + componentTemplate.affected.map( function(component){ component[property] = value; component.updateInstance(); } ); + + var li = __folder.domElement.getElementsByClassName('title')[0]; + li.innerHTML = value; } - }(handle) + }(handle, folder) ); } else { handle.onChange( @@ -815,6 +869,11 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, } ); } + + if (listen) { + handle.listen(); + } + } ); @@ -1195,10 +1254,19 @@ GameLib.System.GUI.prototype.buildGUI = function(data) { continue; } + if (componentTemplate.template[templateProperty] instanceof GameLib.Color) { + this.buildColorControl(folder, componentTemplate, templateProperty); + continue; + } + if (typeof componentTemplate.template[templateProperty] === 'object') { - /** - * ignore objects for now - */ + + if (componentTemplate.template[templateProperty] instanceof GameLib.Component) { + this.buildSelectControl(folder, componentTemplate, templateProperty) + } else { + //TODO: maybe start including some other types of objects + //console.log('ignored : ' + templateProperty); + } continue; } diff --git a/src/game-lib-system-input.js b/src/game-lib-system-input.js index 745899e..3a1944c 100644 --- a/src/game-lib-system-input.js +++ b/src/game-lib-system-input.js @@ -10,98 +10,649 @@ GameLib.System.Input = function( this, apiSystem ); + + this.meshMoveMode = false; + this.meshMoveXMode = false; + this.meshMoveYMode = false; + this.meshMoveZMode = false; + + /** + * We need new function pointers with scope bound to this so we can remove the + * window event handlers when we need to + * @type {function()} + */ + this.mouseMove = null; + this.mouseDown = null; + this.keyDown = null; + this.mouseUp = null; + this.mouseWheel = null; + + this.selectAll = false; + + this.controlLeft = false; + + this.renderers = []; + }; GameLib.System.Input.prototype = Object.create(GameLib.System.prototype); GameLib.System.Input.prototype.constructor = GameLib.System.Input; +/** + * + */ GameLib.System.Input.prototype.start = function() { - /** - * Hookup all editor input capabilities - */ - var entities = GameLib.EntityManager.Instance.query([GameLib.D3.Input.Editor]); + this.renderers = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Renderer); - entities.map(function(entity){ + this.renderers.map( + function(renderer) { - var component = entity.getFirstComponent(GameLib.D3.Input.Editor); + var editorControls = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Controls.Editor); - component.mouseDown = component.onMouseDown(entity).bind(component); - component.mouseMove = component.onMouseMove(entity).bind(component); - component.keyDown = component.onKeyDown(entity, GameLib.EntityManager.Instance).bind(component); - component.keyUp = component.onKeyUp(entity, GameLib.EntityManager.Instance).bind(component); + renderer.controls = editorControls.reduce( + function(result, editorControls) { + if (editorControls.renderer === renderer) { + result = editorControls; + } + return result; + }, + null + ); - component.domElement.instance.addEventListener('mousedown', component.mouseDown, false); - component.domElement.instance.addEventListener('mousemove', component.mouseMove, false); - component.domElement.instance.addEventListener('keydown', component.keyDown, false); - component.domElement.instance.addEventListener('keyup', component.keyUp, false); + renderer.mouseDown = this.onMouseDown(renderer, renderer.controls).bind(this); + renderer.domElement.instance.addEventListener( + 'mousedown', + renderer.mouseDown, + false + ); - component.controls = new THREE.EditorControls( - component.camera.instance, - component.domElement.instance + renderer.mouseMove = this.onMouseMove.bind(this); + renderer.domElement.instance.addEventListener( + 'mousemove', + renderer.mouseMove, + false + ); + + renderer.keyDown = this.onKeyDown.bind(this); + renderer.domElement.instance.addEventListener( + 'keydown', + renderer.keyDown, + false + ); + + renderer.keyUp = this.onKeyUp.bind(this); + renderer.domElement.instance.addEventListener( + 'keyup', + renderer.keyUp, + false + ); + + if (renderer.controls) { + /** + * Create the delayed instance here - it affects the order of event listeners attached to DOM + */ + renderer.controls.instance = renderer.controls.delayedInstance(); + } else { + console.warn('no third party controls for renderer : ' + renderer.name); + } + + renderer.mouseWheel = this.onMouseWheel(renderer.camera).bind(this); + renderer.domElement.instance.addEventListener( + 'mousewheel', + renderer.mouseWheel, + false + ); + + renderer.mouseUp = this.onMouseUp(renderer.camera, renderer.controls).bind(this); + renderer.domElement.instance.addEventListener( + 'mouseup', + renderer.mouseUp, + false + ); + }.bind(this) + ); +}; + + +GameLib.System.Input.prototype.onKeyDown = function(event) { + + console.log('input system emitted keypress ' + event.code); + + GameLib.Event.Emit( + GameLib.Event.KEY_DOWN, + { + code : event.code + } + ); + + var meshes = null; + + if (event.code === 'Delete') { + + meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]); + + var deletedMeshes = []; + + meshes.map( + function(mesh) { + if (mesh.selected) { + + deletedMeshes.push(mesh); + + mesh.removeHelper(); + + var scene = mesh.parentScene; + scene.removeObject(mesh); + scene.buildIdToObject(); + } + }.bind(this) ); - /** - * After our mouse 'up' editor controls would have updated our camera - * instance, so we need to update our game-lib camera to reflect these - * changes - we override - */ - component.mouseUp = function(center) { - return function() { - var camera = entity.getFirstComponent(GameLib.D3.Camera); - camera.position.x = camera.instance.position.x; - camera.position.y = camera.instance.position.y; - camera.position.z = camera.instance.position.z; + GameLib.Event.Emit( + GameLib.Event.MESH_DELETED, + { + meshes : deletedMeshes + } + ); - camera.quaternion.x = camera.instance.quaternion.x; - camera.quaternion.y = camera.instance.quaternion.y; - camera.quaternion.z = camera.instance.quaternion.z; - camera.quaternion.w = camera.instance.quaternion.w; + } - camera.lookAt.x = center.x; - camera.lookAt.y = center.y; - camera.lookAt.z = center.z; + if (event.code === 'ControlLeft') { + this.controlLeft = true; + } - camera.lookAt.instance.copy(center); - }; - }(component.controls.center).bind(component); + if (event.code === 'KeyA') { - /** - * Same applies to our mouse 'scroll' event - */ - component.mouseWheel = function() { - return function() { - var camera = entity.getFirstComponent(GameLib.D3.Camera); - camera.position.x = camera.instance.position.x; - camera.position.y = camera.instance.position.y; - camera.position.z = camera.instance.position.z; - }; - }.bind(component); + this.selectAll = !this.selectAll; - component.domElement.instance.addEventListener('mousewheel', component.mouseWheel, false); - component.domElement.instance.addEventListener('mouseup', component.mouseUp, false); + meshes = GameLib.EntityManager.Instance.queryComponents([GameLib.D3.Mesh]); - }.bind(this)) + meshes.map(function(mesh){ + if (this.selectAll) { + this.selectMesh(mesh); + } else { + this.deSelectMesh(mesh); + } + }.bind(this)); + + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI, + null + ) + + } +}; + +GameLib.System.Input.prototype.onKeyUp = function(event) { + + GameLib.Event.Emit( + GameLib.Event.KEY_UP, + { + code : event.code + } + ); + + if (event.code === 'ControlLeft') { + this.controlLeft = false; + } +}; + +GameLib.System.Input.prototype.onMouseDown = function(renderer, controls) { + + return function(event) { + + if (event.button === 2) { + + if (this.controlLeft) { + return; + } + + renderer.mouse.x = (event.offsetX / renderer.instance.domElement.width) * 2 - 1; + renderer.mouse.y = -(event.offsetY / renderer.instance.domElement.height) * 2 + 1; + + var scenes = renderer.scenes; + + var intersects = scenes.reduce( + + function(result, scene) { + + controls.raycaster.instance.setFromCamera( + renderer.mouse, + renderer.camera.instance + ); + + intersects = controls.raycaster.getIntersectedObjects(scene.meshes); + + intersects.map(function(intersect){ + result.push(intersect); + }); + + return result; + }.bind(this), + [] + ); + + intersects.sort( + function(a, b) { + if (a.distance < b.distance) { + return -1; + } + + if (a.distance > b.distance) { + return 1; + } + + return 0; + } + ); + + var meshes = intersects.map(function(intersect){ + return intersect.mesh; + }); + + var mesh = meshes[0]; + + if (mesh) { + + /** + * Prevent default action (like context menu or whatever) + */ + event.preventDefault(); + + /** + * Prevent other event listeners for 'mousedown' from executing their actions + */ + event.stopImmediatePropagation(); + + if (mesh.selected) { + this.deSelectMesh(mesh); + } else { + this.selectMesh(mesh); + } + + /** + * Notify our GUI system to build a GUI + */ + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI, + null + ) + } + } + }.bind(this); +}; + +/** + * + * @param event + */ +GameLib.System.Input.prototype.onMouseMove = function(event) { }; +/** + * Update the camera position etc. after mouse up + * @param __camera + * @param __controls + * @returns {Function} + */ +GameLib.System.Input.prototype.onMouseUp = function(__camera, __controls) { + return function(event) { + + __camera.position.x = __camera.instance.position.x; + __camera.position.y = __camera.instance.position.y; + __camera.position.z = __camera.instance.position.z; + + __camera.quaternion.x = __camera.instance.quaternion.x; + __camera.quaternion.y = __camera.instance.quaternion.y; + __camera.quaternion.z = __camera.instance.quaternion.z; + __camera.quaternion.w = __camera.instance.quaternion.w; + + __camera.lookAt.x = __controls.instance.center.x; + __camera.lookAt.y = __controls.instance.center.y; + __camera.lookAt.z = __controls.instance.center.z; + + __camera.lookAt.instance.copy(__controls.instance.center); + }; +}; + +/** + * Update our camera position after moving the mouse wheel + * @param __camera + * @returns {Function} + */ +GameLib.System.Input.prototype.onMouseWheel = function(__camera) { + return function(event) { + __camera.position.x = __camera.instance.position.x; + __camera.position.y = __camera.instance.position.y; + __camera.position.z = __camera.instance.position.z; + } +}; + +GameLib.System.Input.prototype.selectMesh = function(mesh) { + + /** + * If mesh is already selected, do nothing + */ + if (mesh.selected === true) { + return; + } + + /** + * Notify our component as being 'selected' + * @type {boolean} + */ + mesh.selected = true; + + mesh.createHelper(); + + GameLib.Event.Emit( + GameLib.Event.MESH_SELECTED, + { + mesh : mesh + } + ); +}; + +GameLib.System.Input.prototype.deSelectMesh = function(mesh) { + + mesh.selected = false; + + mesh.removeHelper(); + + GameLib.Event.Emit( + GameLib.Event.MESH_DESELECTED, + { + mesh : mesh + } + ); +}; + +/** + * + */ GameLib.System.Input.prototype.stop = function() { /** - * Now remove all editor input capabilities + * Now remove all input capabilities */ - var entities = GameLib.EntityManager.Instance.query([GameLib.D3.Input.Editor]); + this.renderers.map( + function(renderer) { - entities.map(function(entity){ - var component = entity.getFirstComponent(GameLib.D3.Input.Editor); - component.domElement.instance.removeEventListener('mousedown', component.mouseDown, false); - component.domElement.instance.removeEventListener('mousemove', component.mouseMove, false); - component.domElement.instance.removeEventListener('keydown', component.keyDown, false); - component.domElement.instance.removeEventListener('keyup', component.keyUp, false); - component.controls.dispose(); - component.domElement.instance.removeEventListener('mouseup', component.mouseUp, false); - component.domElement.instance.removeEventListener('mousewheel', component.mouseWheel, false); - }); + renderer.domElement.instance.removeEventListener( + 'mousedown', + renderer.mouseDown, + false + ); + renderer.domElement.instance.removeEventListener( + 'mousemove', + renderer.mouseMove, + false + ); + + renderer.domElement.instance.removeEventListener( + 'keydown', + renderer.keyDown, + false + ); + + renderer.domElement.instance.removeEventListener( + 'keyup', + renderer.keyUp, + false + ); + + if (renderer.controls) { + renderer.controls.dispose(); + } else { + console.warn('no third party controls to stop for renderer : ' + renderer.name); + } + + renderer.domElement.instance.removeEventListener( + 'mousewheel', + renderer.mouseWheel, + false + ); + + renderer.domElement.instance.removeEventListener( + 'mouseup', + renderer.mouseUp, + false + ); + }.bind(this) + ); }; + + + +// +// console.log('keypressed ' + event.code); +// +// if (event.code === 'KeyV') { +// //todo - change view +// } +// +// if (event.code == "KeyQ") { +// +// this.editor.allSelected = !this.editor.allSelected; +// +// this.editor.selectedObjects = []; +// +// if (this.editor.allSelected) { +// for (var property in this.editor.idToObject) { +// if (this.editor.idToObject.hasOwnProperty(property)) { +// this.editor.selectedObjects.push( +// new GameLib.D3.SelectedObject( +// this.graphics, +// this.editor.idToObject(property) +// ) +// ) +// } +// } +// } +// +// if (this.editor.onSelectionChanged) { +// this.editor.onSelectionChanged(this.editor); +// } +// } +// +// if (event.code == 'KeyG') { +// if (!this.meshMoveMode) { +// console.log('move mode'); +// this.meshMoveMode = true; +// } +// } +// +// if (event.code == 'KeyX') { +// if (this.meshMoveMode) { +// console.log('move along x'); +// this.meshMoveXMode = true; +// this.meshMoveYMode = false; +// this.meshMoveZMode = false; +// } +// } +// +// if (event.code == 'KeyY') { +// if (this.meshMoveMode) { +// console.log('move along y'); +// this.meshMoveXMode = false; +// this.meshMoveYMode = true; +// this.meshMoveZMode = false; +// } +// } +// +// if (event.code == 'KeyZ') { +// if (this.meshMoveMode) { +// console.log('move along z'); +// this.meshMoveXMode = false; +// this.meshMoveYMode = false; +// this.meshMoveZMode = true; +// } +// } +// +// if (event.code == 'Escape') { +// if (this.meshMoveMode) { +// this.meshMoveMode = false; +// console.log('TODO: implement restore positions'); +// } +// } +// +// if (event.code == 'Enter') { +// if (this.meshMoveMode) { +// this.meshMoveMode = false; +// console.log('TODO: implement apply positions'); +// } +// } +// }; + +// GameLib.D3.Input.Editor.prototype.onMouseDown = function(entity) { +// +// return function(event) { +// +// if (event.button === 2) { +// event.cancelBubble = true; +// +// event.preventDefault(); +// +// if (event.stopPropagation) { +// event.stopPropagation(); +// } +// +// var meshes = entity.queryComponents(GameLib.D3.Mesh); +// +// var intersects = this.raycaster.getIntersectedObjects(meshes); +// +// if (intersects.length > 0) { +// +// console.log('object(s) instersected'); +// +// // var index = -1; +// // +// // for (var s = 0; s < this.editor.selectedObjects.length; s++) { +// // if (this.editor.selectedObjects[s].object == intersects[0]) { +// // index = s; +// // break; +// // } +// // } +// // +// // if (index == -1) { +// // /** +// // * The object is not selected, select it +// // */ +// // this.selectObject(intersects[0]); +// // +// // } else { +// // /** +// // * De-select the objec +// // */ +// // var delta = Date.now() - this.editor.selectedObjects[index].lastUpdate; +// // if (delta > this.selectDelayMs) { +// // this.unselectObject(intersects[0]); +// // } +// // } +// // +// // if (this.editor.onSelectionChanged) { +// // this.editor.onSelectionChanged(this.editor); +// // } +// } +// +// return false; +// } +// } +// }; + +// /** +// * Mouse click events +// * @param event +// * @returns {boolean} +// */ +// GameLib.D3.Input.Editor.prototype.onMouseDown = function(event) { +// +// if (event.button === 2) { +// +// +// +// +// +// } +// +// if (event.button == 0) { +// if (this.meshMoveMode) { +// this.meshMoveMode = false; +// this.meshMoveXMode = false; +// this.meshMoveYMode = false; +// this.meshMoveZMode = false; +// } +// } +// }; + +// /** +// * Mouse move events +// * @param event +// */ +// GameLib.D3.Input.Editor.prototype.onMouseMove = function(event) { +// +// // var clientX = event.clientX - this.widthOffset; +// // this.mouse.x = ((clientX / (window.innerWidth - this.widthOffset))) * 2 - 1; +// // this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; +// +// this.mouse.x = event.clientX; +// this.mouse.y = event.clientY; +// +// console.log("mouse (" + this.mouse.x + ", " + this.mouse.y + ")"); +// +// this.raycaster.instance.setFromCamera( +// this.mouse, +// this.camera.instance +// ); +// +// if (this.meshMoveMode) { +// +// var units = event.movementY; +// +// if (this.meshMoveXMode) { +// this.moveSelectedObjects('x', units); +// } +// +// if (this.meshMoveYMode) { +// this.moveSelectedObjects('y', units); +// } +// +// if (this.meshMoveZMode) { +// this.moveSelectedObjects('z', units); +// } +// } +// }; + +// /** +// * Moves selected objects along an axis +// * @param alongAxis +// * @param units +// */ +// GameLib.D3.Input.Editor.prototype.moveSelectedObjects = function(alongAxis, units) { +// +// for (var s = 0; s < this.editor.selectedObjects.length; s++) { +// +// var object = this.editor.selectedObjects[s].object; +// +// if (object.position) { +// if (alongAxis == 'x') { +// object.position.x += units; +// } +// if (alongAxis == 'y') { +// object.position.y += units; +// } +// if (alongAxis == 'z') { +// object.position.z += units; +// } +// +// if (object.updateInstance) { +// object.updateInstance(); +// } +// } +// } +// }; + diff --git a/src/game-lib-system-render.js b/src/game-lib-system-render.js index 36ba435..a0640aa 100644 --- a/src/game-lib-system-render.js +++ b/src/game-lib-system-render.js @@ -12,127 +12,63 @@ GameLib.System.Render = function( apiSystem ); + this.renderSubscription = null; + }; GameLib.System.Render.prototype = Object.create(GameLib.System.prototype); GameLib.System.Render.prototype.constructor = GameLib.System.Render; +/** + * Start the rendering system + */ GameLib.System.Render.prototype.start = function() { - this.renderEntities = GameLib.EntityManager.Instance.query( - [ - GameLib.D3.Viewport, - GameLib.D3.Scene, - GameLib.D3.Renderer, - GameLib.D3.Camera - ] + this.renderers = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Renderer); + + this.renderers.map( + function(renderer) { + if (renderer.statistics) { + renderer.statistics.resize(); + renderer.domElement.instance.parentElement.appendChild(renderer.statistics.instance.dom); + } + } + ); + + this.renderSubscription = this.subscribe( + GameLib.Event.RENDER, + this.render ); - this.renderEntities.map( - function(entity) { - var stats = entity.getFirstComponent(GameLib.D3.Stats); - stats.resize(); - stats.domElement.instance.parentElement.appendChild(stats.instance.dom); - } - ) }; /** - * Update script + * Render subscription script */ -GameLib.System.Render.prototype.update = function() { - - this.renderEntities.map( - - function (renderEntity) { - - var stats = renderEntity.getFirstComponent(GameLib.D3.Stats); - - if (!stats.instance) { - return; - } - - var renderer = renderEntity.getFirstComponent(GameLib.D3.Renderer); - var camera = renderEntity.getFirstComponent(GameLib.D3.Camera); - var viewports = renderEntity.getComponents(GameLib.D3.Viewport); - var scenes = renderEntity.getComponents(GameLib.D3.Scene); - - if (!renderer.instance) { - return; - } - - if (viewports.length > 1) { - renderer.instance.autoClear = false; - } - - if (scenes.length > 1) { - renderer.instance.autoClear = false; - } - - renderer.instance.clear(); - - viewports.map( - function (viewport) { - - renderer.instance.setViewport( - viewport.x * renderer.width, - viewport.y * renderer.height, - viewport.width * renderer.width, - viewport.height * renderer.height - ); - - function renderScene(scene) { - - if (!scene.instance) { - return; - } - - if (scene.activeCamera) { - - if (!scene.activeCamera.instance) { - return; - } - - renderer.instance.render( - scene.instance, - scene.activeCamera.instance - ); - } else { - - if (!camera.instance) { - return; - } - - renderer.instance.render( - scene.instance, - camera.instance - ); - } - } - - if (viewport.scenes && viewport.scenes.length > 0) { - viewport.scenes.map(renderScene); - } else { - scenes.map(renderScene); - } - } - ); - - stats.instance.end(); +GameLib.System.Render.prototype.render = function(data) { + this.renderers.map( + function (renderer) { + renderer.render(data.delta); } ); - }; +/** + * Stop the rendering system + */ GameLib.System.Render.prototype.stop = function() { - this.renderEntities.map( - function(entity) { - var stats = entity.getFirstComponent(GameLib.D3.Stats); - stats.domElement.instance.parentElement.removeChild(stats.instance.dom); + this.renderers.map( + function(renderer) { + if (renderer.statistics) { + renderer.statistics.resize(); + renderer.domElement.instance.parentElement.removeChild(renderer.statistics.instance.dom); + } } ); - this.renderEntities = []; + this.renderers = []; + + this.renderSubscription.stop(); };