/** * System takes care of updating all the entities (based on their component data) * @param apiSystem GameLib.API.System * @constructor */ GameLib.System.GUI = function( apiSystem ) { GameLib.System.call( this, apiSystem ); this.guis = []; this.selected = []; this.buildGUISubscription = null; this.meshDeletedSubscription = null; this.meshSelectedSubscription = null; this.meshDeselectedSubscription = null; this.newEntitySubscription = null; this.meshSelectionObjects = {}; }; GameLib.System.GUI.prototype = Object.create(GameLib.System.prototype); GameLib.System.GUI.prototype.constructor = GameLib.System.GUI; GameLib.System.GUI.prototype.start = function() { this.guis = GameLib.EntityManager.Instance.queryComponents(GameLib.GUI); /** * Add some GUI behaviour */ dat.GUI.prototype.removeEmtpyFolders = function() { for (var property in this.__folders) { if (this.__folders.hasOwnProperty(property)){ var folder = this.__folders[property]; if (folder.__listening.length === 0) { folder.close(); this.__ul.removeChild(folder.domElement.parentNode); delete this.__folders[property]; this.onResize(); } } } }; dat.GUI.prototype.removeAllFolders = function() { for (var property in this.__folders) { if (this.__folders.hasOwnProperty(property)){ var folder = this.__folders[property]; folder.close(); this.__ul.removeChild(folder.domElement.parentNode); delete this.__folders[property]; this.onResize(); } } }; this.guis.map(function(gui){ gui.domElement.instance.parentElement.appendChild(gui.instance.domElement); }); this.buildGUISubscription = this.subscribe( GameLib.Event.BUILD_GUI, this.buildGUI ); this.meshDeletedSubscription = this.subscribe( GameLib.Event.MESH_DELETED, this.meshDeleted ); this.meshSelectedSubscription = this.subscribe( GameLib.Event.MESH_SELECTED, this.meshSelectionChange ); this.meshDeselectedSubscription = this.subscribe( GameLib.Event.MESH_DESELECTED, this.meshSelectionChange ); this.newEntitySubscription = this.subscribe( GameLib.Event.NEW_ENTITY, this.newEntity ) }; GameLib.System.GUI.prototype.buildGUI = function(data) { this.guis.map(function(gui){ /** * Check if we have data */ if (GameLib.Utils.UndefinedOrNull(data.components)) { console.log('no data components'); return; } if (GameLib.Utils.UndefinedOrNull(data.components.length) || data.components.length === 0) { console.log('no components selected'); return; } /** * First, start fresh - remove all folders */ gui.removeAllFolders(); /** * Sort the components by component type */ data.components.sort( function(a, b) { if (a.componentType > b.componentType) { return 1; } if (a.componentType < b.componentType) { return -1; } return 0; } ); /** * Split the components into groups of componentType */ var componentGroups = data.components.reduce( function(result, component) { var componentData = result.pop(); if (component.componentType === componentData.componentType) { /** * This is the first component */ componentData.components.push(component); result.push(componentData); return result; } if (component.componentType !== componentData.componentType) { result.push(componentData); result.push({ componentType : component.componentType, components:[component] }); return result; } }, [ { componentType : data.components[0].componentType, components : [] } ] ); componentGroups.map( function(componentGroup){ if (componentGroup.components.length < 1) { console.warn('invalid number of components'); } var templateObject = { template : { /** * Doing this here is just to put parentEntity at the top of the gui */ 'parentEntity' : componentGroup.components[0].parentEntity }, affected : [componentGroup.components[0]], componentType : componentGroup.componentType }; for (var property in componentGroup.components[0]) { if ( componentGroup.components[0].hasOwnProperty(property) || typeof componentGroup.components[0][property] === 'function' ) { if (typeof componentGroup.components[0][property] === 'function') { templateObject.template[property] = function(__property) { return function() { this.affected.map( function(component) { component[__property].bind(component)(); } ) }.bind(templateObject); }(property); } else { templateObject.template[property] = componentGroup.components[0][property]; } } } var componentTemplate = componentGroup.components.reduce( function(result, component) { if (component === componentGroup.components[0]) { /** * This is the first component, just return */ return result; } /** * Now start to filter out the properties */ for (var property in component) { if ( component.hasOwnProperty(property) ) { if (!result.template.hasOwnProperty(property)) { continue; } if ( result.template[property] instanceof GameLib.Vector2 || result.template[property] instanceof GameLib.Vector3 || result.template[property] instanceof GameLib.Vector4 ) { if (!result.template[property].equals(component[property])) { delete result.template[property]; } continue; } if (result.template[property] !== component[property]) { delete result.template[property]; } } } /** * Store the affected component */ result.affected.push(component); return result; }, templateObject ); /** * componentTemplate now contains for this particular component type group - all * the properties which are modifiable, and also the objects affected by this property changes */ var name; if (GameLib.Utils.UndefinedOrNull(componentTemplate.template.name)) { name = GameLib.Component.GetComponentName(componentTemplate.componentType); } else { name = componentTemplate.template.name; } var folder = gui.addFolder(name); if (!folder) { throw new Error('Could not create folder'); } for (var templateProperty in componentTemplate.template) { if ( componentTemplate.template.hasOwnProperty(templateProperty) || typeof (componentTemplate.template[templateProperty]) === 'function' ) { if (typeof (componentTemplate.template[templateProperty]) === 'function') { folder.add(componentTemplate.template, templateProperty); continue; } if (componentTemplate.template[templateProperty] instanceof GameLib.Vector2) { gui.buildVectorControl(folder, componentTemplate, templateProperty, 2); continue; } if (componentTemplate.template[templateProperty] instanceof GameLib.Vector3) { gui.buildVectorControl(folder, componentTemplate, templateProperty, 3); continue; } if (componentTemplate.template[templateProperty] instanceof GameLib.Vector4) { gui.buildVectorControl(folder, componentTemplate, templateProperty, 4); continue; } // if ( // component.linkedObjects && // component.linkedObjects[property] // ) { // if (property === 'parentEntity') { // this.buildEntitySelectionControlFromArray( // folder, // component, // property, // entityManager // ) // } else if (component.linkedObjects[property] instanceof Array) { // this.buildArrayManager( // folder, // component, // property, // component.linkedObjects[property], // entityManager // ) // } else { // this.buildSelectControl(folder, component, property, entityManager, component.linkedObjects[property]); // } // // } else if (typeof (component[property]) === 'object') { // // if (this.isColor(component[property])) { // this.buildControl(folder, component, property); // } else { // //console.log('ignored: ' + property); // } // } else { // this.buildControl(folder, component, property, entityManager); // } } } } ); }); }; GameLib.System.GUI.prototype.meshDeleted = function(data) { }; GameLib.System.GUI.prototype.meshSelectionChange = function(data) { var meshes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh); var components = []; meshes.map(function(mesh){ if (!mesh.selected) { return; } if (mesh.parentEntity) { GameLib.Utils.PushUnique(components, mesh.parentEntity); } components.push(mesh); mesh.materials.map( function(material){ GameLib.Utils.PushUnique(components, material); } ); mesh.materials.map( function(material){ for (var property in material.linkedObjects) { if ( material.linkedObjects.hasOwnProperty(property) && material.hasOwnProperty(property) && material[property] && property !== 'parentEntity' ) { GameLib.Utils.PushUnique(components, material[property]); for (var tProperty in material[property].linkedObjects) { if ( material[property].linkedObjects.hasOwnProperty(tProperty) && material[property].hasOwnProperty(tProperty) && material[property][tProperty] && tProperty !== 'parentEntity' ) { GameLib.Utils.PushUnique(components, material[property][tProperty]); } } } } } ); }); GameLib.Event.Emit( GameLib.Event.BUILD_GUI, { components : components } ); }; GameLib.System.GUI.prototype.meshSelected = function(data) { }; GameLib.System.GUI.prototype.meshDeslected = function(data) { }; GameLib.System.GUI.prototype.newEntity = function(data) { }; GameLib.System.GUI.prototype.stop = function() { this.guis.map(function(gui){ gui.domElement.instance.parentElement.removeChild(gui.instance.domElement); }); delete dat.GUI.removeEmtpyFolders; delete dat.GUI.removeAllFolders; this.buildGUISubscription.remove(); this.meshDeletedSubscription.remove(); this.meshSelectedSubscription.remove(); this.meshDeselectedSubscription.remove(); this.newEntitySubscription.remove(); this.guis = []; };