/** * R3.D3.Scene * @param graphics * @param apiScene R3.D3.API.Scene * @constructor */ R3.D3.Scene = function( graphics, apiScene ) { this.graphics = graphics; this.graphics.isNotThreeThrow(); if (R3.Utils.UndefinedOrNull(apiScene)) { apiScene = {}; } R3.D3.API.Scene.call( this, apiScene.id, apiScene.name, apiScene.meshes, apiScene.lights, apiScene.textures, apiScene.materials, apiScene.images, apiScene.fog, apiScene.showGrid, apiScene.showAxis, apiScene.gridSize, apiScene.gridColor, apiScene.parent ); this.textures = this.textures.map( function(apiTexture) { if (typeof apiTexture === 'string') { return apiTexture; } return new R3.D3.Texture( this.graphics, apiTexture ); }.bind(this) ); this.materials = this.materials.map( function(apiMaterial) { if (typeof apiMaterial === 'string') { return apiMaterial; } return new R3.D3.Material( this.graphics, apiMaterial ); }.bind(this) ); this.images = this.images.map( function(apiImage) { if (typeof apiImage === 'string') { return apiImage; } return new R3.Image( this.graphics, apiImage ); }.bind(this) ); if (this.fog instanceof R3.D3.API.Fog) { this.fog = new R3.D3.Fog( this.graphics, this.fog ) } this.gridColor = new R3.Color( this.graphics, this.gridColor, this ); /** * Runtime scenes have helpers (just used to store which helper belongs to which scene) * @type {Array} */ this.helpers = []; this.clones = []; this.grid = []; this.axis = []; this.storeClones = false; this.instance = instance; R3.Component.call( this, { 'meshes' : [R3.D3.Mesh], 'lights' : [R3.D3.Light], 'textures' : [R3.D3.Texture], 'materials' : [R3.D3.Material], 'images' : [R3.Image], 'fog' : R3.D3.Fog } ); }; R3.D3.Scene.prototype = Object.create(R3.Component.prototype); R3.D3.Scene.prototype.constructor = R3.D3.Scene; R3.D3.Scene.prototype.constructFromInstance = function() { this.loaded = true; console.log('todo: - setup scene from instance'); }; /** * Creates an instance scene * @returns {THREE.Scene} */ R3.D3.Scene.prototype.createInstance = function() { if (R3.Utils.UndefinedOrNull(this.instance)) { this.instance = new THREE.Scene(); } else { this.constructFromInstance(); return; } this.instance.name = this.name; if (this.fog && this.fog.instance) { this.instance.fog = this.fog.instance; } this.meshes.map( function(mesh) { if (R3.Utils.UndefinedOrNull(mesh)) { throw new Error('no mesh'); } if (R3.Utils.UndefinedOrNull(mesh.instance)) { throw new Error('no mesh instance'); } this.instance.add(mesh.instance); mesh.parentScene = this; }.bind(this) ); this.lights.map( function(light) { if (R3.Utils.UndefinedOrNull(light)) { throw new Error('no light'); } if (R3.Utils.UndefinedOrNull(light.instance)) { throw new Error('no light instance'); } this.instance.add(light.instance); light.parentScene = this; }.bind(this) ); if (this.showGrid) { this.drawGrid(); } if (this.showAxis) { this.drawAxis(); } R3.Component.prototype.createInstance.call(this); }; R3.D3.Scene.prototype.updateInstance = function(property) { if (property === 'name') { this.instance.name = this.name; return; } if (property === 'fog') { if (this.fog && this.fog.instance !== this.instance.fog) { this.instance.fog = this.fog.instance; } } if (property === 'meshes') { /** * Add missing meshes */ this.meshes.map( function(mesh) { if (this.instance.children.indexOf(mesh.instance === -1)) { this.instance.add(mesh.instance); } }.bind(this) ); } if (property === 'lights') { /** * Add missing lights */ this.lights.map( function(light) { if (this.instance.children.indexOf(light.instance) === -1) { this.instance.add(light.instance); } }.bind(this) ); } if ( property === 'meshes' || property === 'lights' ) { /** * Remove extra meshes and lights */ this.instance.children.map( function(instanceObject) { var instanceMeshes = this.meshes.map( function(mesh) { return mesh.instance; } ); var instanceLights = this.lights.map( function(light) { return light.instance; } ); if ( ( instanceObject instanceof THREE.Mesh || instanceObject instanceof THREE.Light ) && ( instanceLights.indexOf(instanceObject) === -1 && instanceMeshes.indexOf(instanceObject) === -1 ) ) { this.instance.remove(instanceObject); } }.bind(this) ); return; } if ( property === 'showGrid' || property === 'gridSize' || property === 'gridColor' ) { if (this.showGrid) { this.drawGrid(); } else { this.removeGrid(); } } if (property === 'showAxis') { if (this.showAxis) { this.drawAxis(); } else { this.removeAxis(); } } R3.Component.prototype.updateInstance.call(this, property); }; /** * Converts a R3.D3.Scene to a R3.D3.API.Scene * @returns {R3.D3.API.Scene} */ R3.D3.Scene.prototype.toApiObject = function() { var apiMeshes = []; if (this.storeClones) { this.clones.map( function(clone) { R3.Utils.PushUnique( apiMeshes, R3.Utils.IdOrNull(clone) ); } ); } this.meshes.map( function(mesh) { R3.Utils.PushUnique( apiMeshes, R3.Utils.IdOrNull(mesh) ); } ); return new R3.D3.API.Scene( this.id, this.name, apiMeshes, this.lights.map( function(light) { return R3.Utils.IdOrNull(light); } ), this.textures.map( function(texture) { return R3.Utils.IdOrNull(texture); } ), this.materials.map( function(material) { return R3.Utils.IdOrNull(material); } ), this.images.map( function(image) { return R3.Utils.IdOrNull(image); } ), R3.Utils.IdOrNull(this.fog), this.showGrid, this.showAxis, this.gridSize, this.gridColor.toApiObject(), R3.Utils.IdOrNull(this.parent) ); }; /** * Adds a mesh to the scene * @param object R3.D3.Mesh */ R3.D3.Scene.prototype.addObject = function(object) { if (object instanceof R3.D3.Mesh) { if (this.meshes.indexOf(object.id) === -1) { R3.Utils.PushUnique(this.meshes, object); } } if (object instanceof R3.D3.Light) { if (this.lights.indexOf(object.id) === -1) { R3.Utils.PushUnique(this.lights, object); } } object.parentScene = this; if ( this.instance && object.instance ) { if (this.instance.children.indexOf(object.instance) === -1) { this.instance.add(object.instance); } } else { // console.warn('either scene or mesh instance not ready'); } // if (this.parent) { // this.parent.addComponent(object); // } }; R3.D3.Scene.prototype.addClone = function(component) { if (component instanceof R3.D3.Mesh || component instanceof R3.D3.Light ) { if (this.instance && component.instance) { if (this.instance.children.indexOf(component.instance) === -1) { this.instance.add(component.instance); } } component.isClone = true; R3.Utils.PushUnique(this.clones, component); var index = this.meshes.indexOf(component); if (index !== -1) { this.meshes.splice(index, 1); } component.parentScene = this; } }; /** * * @param object */ R3.D3.Scene.prototype.removeObject = function(object) { var index = -1; if (object instanceof R3.D3.Mesh) { index = this.meshes.indexOf(object); if (index !== -1) { this.meshes.splice(index, 1); } index = this.clones.indexOf(object); if (index !== -1) { this.clones.splice(index, 1); } } else if (object instanceof R3.D3.Light) { index = this.lights.indexOf(object); if (index !== -1) { this.lights.splice(index, 1); } index = this.clones.indexOf(object); if (index !== -1) { this.clones.splice(index, 1); } } else { console.warn('Cannot remove this object - what is this ?' + object.toString()); return; } if (this.instance.children.indexOf(object.instance) !== -1) { this.instance.remove(object.instance); } else { console.warn('no scene instance'); } if (object.parentScene === this) { object.parentScene = null; } // // if (this.parent) { // this.parent.removeComponent(object); // } // this.buildIdToObject(); }; R3.D3.Scene.prototype.drawGrid = function() { this.removeGrid(); var lineMaterial = new THREE.LineBasicMaterial({ color: this.gridColor.toHex(), linewidth: 1 }); for (var y = -this.gridSize; y <= this.gridSize; y += 1) { var Xgeometry = new THREE.Geometry(); Xgeometry.vertices.push( new THREE.Vector3( y, 0, this.gridSize * -1 ), new THREE.Vector3( y, 0, this.gridSize ) ); var lineX = new THREE.Line(Xgeometry, lineMaterial); this.instance.add(lineX); this.grid.push(lineX); var Ygeometry = new THREE.Geometry(); Ygeometry.vertices.push( new THREE.Vector3( this.gridSize * -1 , 0, y ), new THREE.Vector3( this.gridSize, 0, y ) ); var lineY = new THREE.Line(Ygeometry, lineMaterial); this.instance.add(lineY); this.grid.push(lineY); } }; R3.D3.Scene.prototype.removeGrid = function() { this.grid.map( function(object) { this.instance.remove(object); }.bind(this) ); }; R3.D3.Scene.prototype.drawAxis = function() { this.removeAxis(); var Xmaterial = new THREE.LineBasicMaterial({ color: 0xff0000, linewidth: 2 }); var Xgeometry = new THREE.Geometry(); Xgeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 100, 0, 0 ) ); var lineX = new THREE.Line(Xgeometry, Xmaterial); this.instance.add(lineX); this.axis.push(lineX); var Ymaterial = new THREE.LineBasicMaterial({ color: 0x00ff00, linewidth: 2 }); var Ygeometry = new THREE.Geometry(); Ygeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 100, 0 ) ); var lineY = new THREE.Line(Ygeometry, Ymaterial); this.instance.add(lineY); this.axis.push(lineY); var Zmaterial = new THREE.LineBasicMaterial({ color: 0x0000ff, linewidth: 2 }); var Zgeometry = new THREE.Geometry(); Zgeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 100 ) ); var lineZ = new THREE.Line(Zgeometry, Zmaterial); this.instance.add(lineZ); this.axis.push(lineZ); }; R3.D3.Scene.prototype.removeAxis = function() { this.axis.map( function(object) { this.instance.remove(object); }.bind(this) ); };