diff --git a/src/game-lib-a-1-event.js b/src/game-lib-a-1-event.js index 3ec714f..d58f8ed 100644 --- a/src/game-lib-a-1-event.js +++ b/src/game-lib-a-1-event.js @@ -64,6 +64,9 @@ GameLib.Event.COMPILE_FAILED = 0x2e; GameLib.Event.IMAGE_CHANGED = 0x2f; GameLib.Event.PARENT_ENTITY_CHANGED = 0x30; GameLib.Event.MATERIAL_TEXTURES_UPDATED = 0x31; +GameLib.Event.DELETE_COMPONENT_ERROR = 0x32; +GameLib.Event.COMPONENT_DELETED = 0x33; +GameLib.Event.COMPONENT_TYPES_UPDATED = 0x34; /** * Returns string name of event ID @@ -123,6 +126,9 @@ GameLib.Event.GetEventName = function(number) { case 0x2f : return 'image_changed'; case 0x30 : return 'parent_entity_changed'; case 0x31 : return 'material_textures_updated'; + case 0x32 : return 'delete_component_error'; + case 0x33 : return 'component_deleted'; + case 0x34 : return 'component_types_updated'; break; } diff --git a/src/game-lib-d3-mesh-0.js b/src/game-lib-d3-mesh-0.js index d4eed50..f199b4f 100644 --- a/src/game-lib-d3-mesh-0.js +++ b/src/game-lib-d3-mesh-0.js @@ -178,7 +178,13 @@ GameLib.D3.Mesh.MESH_TYPE_CURVE = 0x2; GameLib.D3.Mesh.MESH_TYPE_SPHERE = 0x3; GameLib.D3.Mesh.MESH_TYPE_PLANE = 0x4; -GameLib.D3.Mesh.prototype.createInstanceGeometry = function() { +GameLib.D3.Mesh.prototype.createInstanceGeometry = function(instanceGeometry) { + + if (instanceGeometry instanceof THREE.Geometry) { + if (this.isBufferMesh) { + return new THREE.BufferGeometry().fromGeometry(instanceGeometry); + } + } /** * Setup face indexes - first we sort according to the material index, because later we will create @@ -453,6 +459,15 @@ GameLib.D3.Mesh.prototype.updateInstance = function() { console.log('mesh update instance'); + if (( this.isBufferMesh && !(this.instance.geometry instanceof THREE.BufferGeometry)) || + ( !this.isBufferMesh && (this.instance.geometry instanceof THREE.BufferGeometry))) + { + /** + * The buffer geometry needs updating + */ + this.instance.geometry = this.createInstanceGeometry(this.instance.geometry); + } + if (this.parentMesh && this.parentMesh.loaded) { if (this.instance.parent !== this.parentMesh.instance) { @@ -635,9 +650,6 @@ GameLib.D3.Mesh.prototype.updateVerticesFromGeometryInstance = function(geometry face.c, face.materialIndex, [[ - // new GameLib.Vector2( - // this.graphics, - // new GameLib.API.Vector2( { x: geometryInstance.faceVertexUvs[0][faceIndex][0].x, y: geometryInstance.faceVertexUvs[0][faceIndex][0].y @@ -650,22 +662,6 @@ GameLib.D3.Mesh.prototype.updateVerticesFromGeometryInstance = function(geometry x: geometryInstance.faceVertexUvs[0][faceIndex][2].x, y: geometryInstance.faceVertexUvs[0][faceIndex][2].y } - // ) - // ), - // new GameLib.Vector2( - // this.graphics, - // new GameLib.API.Vector2( - // geometryInstance.faceVertexUvs[0][faceIndex][1].x, - // geometryInstance.faceVertexUvs[0][faceIndex][1].y - // ) - // ), - // new GameLib.Vector2( - // this.graphics, - // new GameLib.API.Vector2( - // geometryInstance.faceVertexUvs[0][faceIndex][2].x, - // geometryInstance.faceVertexUvs[0][faceIndex][2].y - // ) - // ) ]] // new GameLib.Color( // this.graphics, diff --git a/src/game-lib-d3-rigid-body.js b/src/game-lib-d3-rigid-body.js index e6b0758..7f8a1a1 100644 --- a/src/game-lib-d3-rigid-body.js +++ b/src/game-lib-d3-rigid-body.js @@ -47,7 +47,7 @@ GameLib.D3.RigidBody = function ( this, GameLib.Component.COMPONENT_RIGID_BODY, { - 'shapes' : [GameLib.D3.Shape] + 'shapes' : [GameLib.D3.Shape, GameLib.D3.Shape.Box] } ); }; diff --git a/src/game-lib-d3-shape-0.js b/src/game-lib-d3-shape-0.js index d26e633..b87d2ed 100644 --- a/src/game-lib-d3-shape-0.js +++ b/src/game-lib-d3-shape-0.js @@ -28,8 +28,11 @@ GameLib.D3.Shape = function ( var componentType = GameLib.Component.COMPONENT_SHAPE; + var linkedObjects = {}; + if (this instanceof GameLib.D3.Shape.Box) { componentType = GameLib.Component.COMPONENT_SHAPE_BOX; + linkedObjects.activeMesh = GameLib.D3.Mesh; } if (this instanceof GameLib.D3.Shape.Sphere) { @@ -58,7 +61,8 @@ GameLib.D3.Shape = function ( GameLib.Component.call( this, - componentType + componentType, + linkedObjects ); }; @@ -79,6 +83,10 @@ GameLib.D3.Shape.prototype.updateInstance = function() { throw new Error('Do not instantiate this class directly - use a child class instead'); }; +GameLib.D3.Shape.prototype.visualize = function() { + +}; + /** * Converts a GameLib.D3.Shape to a GameLib.D3.API.Shape * @returns {GameLib.D3.API.Shape} diff --git a/src/game-lib-d3-shape-box.js b/src/game-lib-d3-shape-box.js index 5e79c06..9a539b0 100644 --- a/src/game-lib-d3-shape-box.js +++ b/src/game-lib-d3-shape-box.js @@ -35,7 +35,6 @@ GameLib.D3.Shape.Box = function ( activeMesh = null; } this.activeMesh = activeMesh; - this.linkedObjects.activeMesh = GameLib.D3.Mesh; GameLib.D3.Shape.call( this, @@ -68,6 +67,10 @@ GameLib.D3.Shape.Box.prototype.updateInstance = function() { this.instance.updateConvexPolyhedronRepresentation(); }; +GameLib.D3.Shape.prototype.visualize = function() { + +}; + GameLib.D3.Shape.Box.prototype.toApiObject = function() { var apiShape = GameLib.D3.Shape.prototype.toApiObject.call(this); diff --git a/src/game-lib-system-gui.js b/src/game-lib-system-gui.js index 14bd688..5098df5 100644 --- a/src/game-lib-system-gui.js +++ b/src/game-lib-system-gui.js @@ -64,13 +64,85 @@ GameLib.System.GUI.prototype.start = function() { } }; + dat.GUI.prototype.listen = function(controller) { + const init = this.__listening.length === 0; + this.__listening.push(controller); + + delete this.closed; + + Object.defineProperty(this, 'closed', { + get: function() { + return this.params.closed; + }, + set: function(v) { + console.log('override here too'); + + this.params.closed = v; + if (this.params.closed) { + this.dom.addClass(this.__ul, 'closed'); + + cancelAnimationFrame(this.animationId); + + } else { + this.dom.removeClass(this.__ul, 'closed'); + + this.updateDisplaysCallback = function() { + + /** + * We store the animationFrameId so we can remove this callback later + */ + this.animationId = requestAnimationFrame(this.updateDisplaysCallback.bind(this)); + + this.__listening.map(function(controller){ + controller.updateDisplay(); + }); + + }.bind(this); + + this.animationId = requestAnimationFrame(this.updateDisplaysCallback); + } + // For browsers that aren't going to respect the CSS transition, + // Lets just check our height against the window height right off + // the bat. + this.onResize(); + + if (this.__closeButton) { + this.__closeButton.innerHTML = v ? 'Open Controls' : 'Close Controls'; + } + }, + configurable: true + }); + + }; + dat.GUI.prototype.removeAllFolders = function() { for (var property in this.__folders) { if (this.__folders.hasOwnProperty(property)){ var folder = this.__folders[property]; + /** + * Theres a big 'TODO' in the controller remove() function to actually remove the listener + * That's what we are going to do now.. - because it really fucks with the framerate eventually + */ + cancelAnimationFrame(folder.animationId); + + folder.__controllers.map( + function(controller) { + controller.remove(); + + } + ); + + folder.__controllers = []; + + folder.__listening = []; + + /** + * Call UpdateDisplays with + */ folder.close(); + this.__ul.removeChild(folder.domElement.parentNode); delete this.__folders[property]; this.onResize(); @@ -281,6 +353,11 @@ GameLib.System.GUI.prototype.buildEntitySelectionControl = function(folder, comp }.bind(this) ); + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI, + null + ); + this.initialValue = newEntity; } ).onFinishChange( @@ -301,7 +378,19 @@ GameLib.System.GUI.prototype.buildArrayManagerControl = function( property ) { - var constructor = componentTemplate.template[property].constructor; + var constructors = componentTemplate.template.linkedObjects[property]; + + if (constructors instanceof Array) { + /** + * All good + */ + } else { + /** + * There is a data mismatch + */ + console.error('data mismatch - something not an array'); + return; + } var object = componentTemplate.template; @@ -309,25 +398,32 @@ GameLib.System.GUI.prototype.buildArrayManagerControl = function( var addArrayItem = function(item, index){ + var name = 'invalid item'; + + if (item && item.name) { + name = item.name; + } + var controller = folder.add( { 'remove' : function() { componentTemplate.affected.map(function(component){ - component[property].splice(component[property].indexOf(item), 1); + component[property].splice(index, 1); folder.remove(controller); }); } }, 'remove' - ).name('remove ' + property + '[' + index + '] - ' + item.name); - }; + ).name('remove ' + property + '[' + index + '] - ' + name); + folder.updateDisplay(); + }; array.map(addArrayItem); var idToObject = {}; - var selectionObject = GameLib.EntityManager.Instance.queryComponents(constructor).reduce( + var selectionObject = GameLib.EntityManager.Instance.queryComponents(constructors).reduce( function(result, component) { result[component.name] = component; idToObject[component.id] = component; @@ -338,26 +434,22 @@ GameLib.System.GUI.prototype.buildArrayManagerControl = function( } ); - var activeSelection = function(__object, __property) { -//TODO: fix this again - var object = __object; - var property = __property; + var activeSelection = { + component: null, + add: function () { - return { - component : null, - add : function() { - - componentTemplate.affected.map(function(component){ - if (component[property].indexOf(activeSelection.component) === -1) { - component[property].push(activeSelection.component); - addArrayItem(activeSelection.component, component[property].length - 1) - } - }); - } - }; - - }(object, property); + componentTemplate.affected.map(function (component) { + if (component[property].indexOf(activeSelection.component) === -1) { + component[property].push(activeSelection.component); + addArrayItem(activeSelection.component, component[property].length - 1); + } + }); + GameLib.Event.Emit( + GameLib.Event.BUILD_GUI + ); + } + }; folder.add(activeSelection, 'component', selectionObject).name('select ' + property).onChange( function(value){ @@ -974,7 +1066,15 @@ GameLib.System.GUI.prototype.meshDeslected = function(data) { }; /** - * This function responds to the BUILD_GUI event, data contains the components to build a GUI for + * This function responds to the BUILD_GUI event, data contains the components to build a GUI for data. + * + * If we send data with components - go into exclusive mode, backup the currently selected components and rebuild the gui + * + * If we send data without components - go out of exclusive mode, restore the backup of the currently selected components + * and rebuild based on the meshes + * + * If we don't send any data (null or undefined) - some parameters changed and just rebuild the gui. + * * @param data */ GameLib.System.GUI.prototype.buildGUI = function(data) { @@ -984,40 +1084,58 @@ GameLib.System.GUI.prototype.buildGUI = function(data) { /** * First, start fresh - remove all folders */ + gui.instance.destroy(); + gui.removeAllFolders(); + // gui.domElement.instance.parentElement.appendChild(gui.instance.domElement); + if (data) { if (data.components) { - this.exclusiveMode = true; /** - * Backup the current selection + * Check if we are not already in exclusive mode, because we only want to make a backup if + * it does not already exist */ - this.backupComponents = this.components.map( - function(component) { - return component; - } - ); + if (!this.exclusiveMode) { + + this.exclusiveMode = true; + + /** + * Backup the current selection + */ + this.backupComponents = this.components.map( + function(component) { + return component; + } + ); + + } this.components = data.components.map( function(component) { return component; } ); + } else { - this.exclusiveMode = false; + if (this.exclusiveMode) { + this.exclusiveMode = false; - /** - * Time to restore the backup - */ - this.components = this.backupComponents.map( - function(component) { - return component; - } - ) + /** + * Time to restore the backup + */ + this.components = this.backupComponents.map( + function(component) { + return component; + } + ) + } else { + console.log('we are already not in mesh select mode - not doing anything with the backup'); + } } } @@ -1316,7 +1434,10 @@ GameLib.System.GUI.prototype.buildGUI = function(data) { continue; } - this.buildArrayManagerControl(folder, componentTemplate, templateProperty); + if (componentTemplate.template.linkedObjects[templateProperty] instanceof Array) { + this.buildArrayManagerControl(folder, componentTemplate, templateProperty); + } + continue; } diff --git a/src/game-lib-system-linking.js b/src/game-lib-system-linking.js index c94477f..6672b80 100644 --- a/src/game-lib-system-linking.js +++ b/src/game-lib-system-linking.js @@ -603,7 +603,7 @@ GameLib.System.Linking.prototype.onParentEntityChange = function(data) { data.newEntity.addComponent(data.object); - GameLib.Event.Emit( + GameLib.Event.Emit( GameLib.Event.PARENT_ENTITY_CHANGED, { originalEntity : data.originalEntity, @@ -611,7 +611,6 @@ GameLib.System.Linking.prototype.onParentEntityChange = function(data) { component : data.object } ) - }; /** diff --git a/src/game-lib-system-render.js b/src/game-lib-system-render.js index a0640aa..e58d9c9 100644 --- a/src/game-lib-system-render.js +++ b/src/game-lib-system-render.js @@ -69,6 +69,6 @@ GameLib.System.Render.prototype.stop = function() { this.renderers = []; - this.renderSubscription.stop(); + this.renderSubscription.remove(); }; diff --git a/src/game-lib-system-storage.js b/src/game-lib-system-storage.js index 4591224..1903dc2 100644 --- a/src/game-lib-system-storage.js +++ b/src/game-lib-system-storage.js @@ -121,6 +121,11 @@ GameLib.System.Storage.prototype.start = function() { this.load ); + this.deleteSubscription = this.subscribe( + GameLib.Event.DELETE_COMPONENT, + this.delete + ); + this.loadImageSubscription = this.subscribe( GameLib.Event.LOAD_IMAGE, this.loadImage @@ -137,6 +142,62 @@ GameLib.System.Storage.prototype.start = function() { ); }; +GameLib.System.Storage.prototype.delete = function(data) { + + if (typeof XMLHttpRequest === 'undefined') { + console.log('Implement server side delete here'); + return; + } + + data.ids.map(function(id){ + var xhr = new XMLHttpRequest(); + + xhr.open( + 'POST', + this.apiUrl + '/component/delete/' + id + ); + + xhr.setRequestHeader("Accept", "application/json"); + xhr.setRequestHeader("Content-Type", "application/json"); + + xhr.onreadystatechange = function () { + if (this.readyState === 4) { + try { + var response = JSON.parse(this.responseText) + } catch (error) { + GameLib.Event.Emit( + GameLib.Event.DELETE_COMPONENT_ERROR, + { + message: this.responseText + } + ) + } + + if (response.result === 'success') { + GameLib.Event.Emit( + GameLib.Event.COMPONENT_DELETED, + { + message: response.message || 'Successfully saved the component' + } + ) + } else { + GameLib.Event.Emit( + GameLib.Event.DELETE_COMPONENT_ERROR, + { + message: response.message || 'The server responded but failed to save the component' + } + ) + } + } + }; + + xhr.send(JSON.stringify({ + session : this.token + })); + }.bind(this)); +}; + + /** * 'Saves' data to baseURL */ @@ -768,5 +829,6 @@ GameLib.System.Storage.prototype.stop = function() { this.loadImageSubscription.remove(); this.blenderDataSubscription.remove(); this.imageUploadCompleteSubscription.remove(); + this.deleteSubscription.remove(); };