From f9c18837e668d591f9ea37d4ce5ebf573d593196 Mon Sep 17 00:00:00 2001 From: "Theunis J. Botha" Date: Fri, 2 Jun 2017 13:52:29 +0200 Subject: [PATCH] sphere meshes --- src/game-lib-a-1-event.js | 3 +- src/game-lib-a-component-a.js | 2 +- src/game-lib-d3-input-editor.js | 33 ++- ...e-lib-d3-mesh.js => game-lib-d3-mesh-0.js} | 270 ++++++++++-------- src/game-lib-d3-mesh-sphere.js | 92 ++++++ src/game-lib-d3-scene.js | 53 ++++ src/game-lib-entity.js | 18 +- src/game-lib-gui.js | 135 ++++++++- src/game-lib-system.js | 1 - 9 files changed, 456 insertions(+), 151 deletions(-) rename src/{game-lib-d3-mesh.js => game-lib-d3-mesh-0.js} (69%) create mode 100644 src/game-lib-d3-mesh-sphere.js diff --git a/src/game-lib-a-1-event.js b/src/game-lib-a-1-event.js index 4b66a6f..6cc2a7f 100644 --- a/src/game-lib-a-1-event.js +++ b/src/game-lib-a-1-event.js @@ -14,7 +14,8 @@ GameLib.Event.Subscriptions = {}; /** * Events we can subscribe to and publish */ -GameLib.Event.WINDOW_RESIZE = 0x1; +GameLib.Event.WINDOW_RESIZE = 0x1; +GameLib.Event.PARENT_SCENE_CHANGE = 0x2; /** * Subscribe to some events diff --git a/src/game-lib-a-component-a.js b/src/game-lib-a-component-a.js index 6d95aa8..fd9c7fd 100644 --- a/src/game-lib-a-component-a.js +++ b/src/game-lib-a-component-a.js @@ -31,7 +31,7 @@ GameLib.Component = function( this.built = true; - //this.linkedObjects.parentEntity = GameLib.Entity; + this.linkedObjects.parentEntity = GameLib.Entity; if (GameLib.Utils.UndefinedOrNull(guiProperties)) { guiProperties = {}; diff --git a/src/game-lib-d3-input-editor.js b/src/game-lib-d3-input-editor.js index 4de54e7..96f572d 100644 --- a/src/game-lib-d3-input-editor.js +++ b/src/game-lib-d3-input-editor.js @@ -189,14 +189,29 @@ GameLib.D3.Input.Editor.prototype.onMouseDown = function(entity, entityManager) this.mouse.x = (event.offsetX / renderer.instance.domElement.width) * 2 - 1; this.mouse.y = -(event.offsetY / renderer.instance.domElement.height) * 2 + 1; - this.raycaster.instance.setFromCamera( - this.mouse, - this.camera.instance - ); + var cameras = entity.getComponents(GameLib.D3.Camera); - var meshes = entity.getComponents(GameLib.D3.Mesh); + var meshes = entity.getComponents(GameLib.D3.Mesh); - var intersects = this.raycaster.getIntersectedObjects(meshes); + var intersects = cameras.reduce( + + function(result, camera){ + + this.raycaster.instance.setFromCamera( + this.mouse, + camera.instance + ); + + intersects = this.raycaster.getIntersectedObjects(meshes); + + intersects.map(function(intersect){ + result.push(intersect); + }) + + return result; + }.bind(this), + [] + ); if (intersects.length > 0) { @@ -252,6 +267,12 @@ GameLib.D3.Input.Editor.prototype.onMouseDown = function(entity, entityManager) scene.instance.add(helper.instance); + scene.subscribe(GameLib.Event.PARENT_SCENE_CHANGE, function(data) { + if (data.old === scene) { + scene.instance.remove(helper.instance); + } + }); + gui.addObject(intersects[0]); } else { diff --git a/src/game-lib-d3-mesh.js b/src/game-lib-d3-mesh-0.js similarity index 69% rename from src/game-lib-d3-mesh.js rename to src/game-lib-d3-mesh-0.js index ce3f842..e0f2d92 100644 --- a/src/game-lib-d3-mesh.js +++ b/src/game-lib-d3-mesh-0.js @@ -161,9 +161,138 @@ GameLib.D3.Mesh.prototype.constructor = GameLib.D3.Mesh; * Mesh Type * @type {number} */ -GameLib.D3.Mesh.TYPE_NORMAL = 0; -GameLib.D3.Mesh.TYPE_SKINNED = 1; -GameLib.D3.Mesh.TYPE_CURVE = 2; +GameLib.D3.Mesh.TYPE_NORMAL = 0x0; +GameLib.D3.Mesh.TYPE_SKINNED = 0x1; +GameLib.D3.Mesh.TYPE_CURVE = 0x2; + +/** + * Mesh Shape (predefined or custom) + * @type {number} + */ +GameLib.D3.Mesh.SHAPE_CUSTOM = 0x1; +GameLib.D3.Mesh.SHAPE_SPHERE = 0x2; + +/** + * Creates custom geometry + * @returns {THREE.Geometry} + */ +GameLib.D3.Mesh.prototype.customGeometry = function(){ + + var geometry = new THREE.Geometry(); + + /** + * Setup vertices + */ + for (var v = 0; v < this.vertices.length; v++) { + geometry.vertices.push( + new this.graphics.instance.Vector3( + this.vertices[v].position.x, + this.vertices[v].position.y, + this.vertices[v].position.z + ) + ) + } + + /** + * Setup faces + */ + for (var f = 0; f < this.faces.length; f++) { + + var face = new this.graphics.instance.Face3( + this.faces[f].v0, + this.faces[f].v1, + this.faces[f].v2, + new this.graphics.instance.Vector3( + this.faces[f].normal.x, + this.faces[f].normal.y, + this.faces[f].normal.z + ), + new this.graphics.instance.Color( + this.faces[f].color.r, + this.faces[f].color.g, + this.faces[f].color.b + ), + this.faces[f].materialIndex + ); + + face.vertexColors = [ + new this.graphics.instance.Color( + this.faces[f].vertexColors[0].r, + this.faces[f].vertexColors[0].g, + this.faces[f].vertexColors[0].b + ), + new this.graphics.instance.Color( + this.faces[f].vertexColors[1].r, + this.faces[f].vertexColors[1].g, + this.faces[f].vertexColors[1].b + ), + new this.graphics.instance.Color( + this.faces[f].vertexColors[2].r, + this.faces[f].vertexColors[2].g, + this.faces[f].vertexColors[2].b + ) + ]; + + face.normal = new this.graphics.instance.Vector3( + this.faces[f].normal.x, + this.faces[f].normal.y, + this.faces[f].normal.z + ); + + face.vertexNormals = [ + new this.graphics.instance.Vector3( + this.faces[f].vertexNormals[0].x, + this.faces[f].vertexNormals[0].y, + this.faces[f].vertexNormals[0].z + ), + new this.graphics.instance.Vector3( + this.faces[f].vertexNormals[1].x, + this.faces[f].vertexNormals[1].y, + this.faces[f].vertexNormals[1].z + ), + new this.graphics.instance.Vector3( + this.faces[f].vertexNormals[2].x, + this.faces[f].vertexNormals[2].y, + this.faces[f].vertexNormals[2].z + ) + ]; + + geometry.faces.push(face); + } + + geometry.faceVertexUvs = []; + + /** + * Setup face UVs + */ + for (var fm = 0; fm < this.faceVertexUvs.length; fm++) { + + var faceMaterialVertexUvs = this.faceVertexUvs[fm]; + + geometry.faceVertexUvs[fm] = []; + + for (var fuv = 0; fuv < faceMaterialVertexUvs.length; fuv++) { + geometry.faceVertexUvs[fm][fuv] = []; + geometry.faceVertexUvs[fm][fuv].push( + new this.graphics.instance.Vector2( + faceMaterialVertexUvs[fuv][0].x, + faceMaterialVertexUvs[fuv][0].y + ), + new this.graphics.instance.Vector2( + faceMaterialVertexUvs[fuv][1].x, + faceMaterialVertexUvs[fuv][1].y + ), + new this.graphics.instance.Vector2( + faceMaterialVertexUvs[fuv][2].x, + faceMaterialVertexUvs[fuv][2].y + ) + ); + } + } + + return geometry; + +}; /** * Creates a mesh instance or updates it @@ -177,116 +306,13 @@ GameLib.D3.Mesh.prototype.createInstance = function(update) { } if (!update) { - var instanceGeometry = new this.graphics.instance.Geometry(); - /** - * Setup vertices - */ - for (var v = 0; v < this.vertices.length; v++) { - instanceGeometry.vertices.push( - new this.graphics.instance.Vector3( - this.vertices[v].position.x, - this.vertices[v].position.y, - this.vertices[v].position.z - ) - ) - } + var geometry = null; - /** - * Setup faces - */ - for (var f = 0; f < this.faces.length; f++) { - - var face = new this.graphics.instance.Face3( - this.faces[f].v0, - this.faces[f].v1, - this.faces[f].v2, - new this.graphics.instance.Vector3( - this.faces[f].normal.x, - this.faces[f].normal.y, - this.faces[f].normal.z - ), - new this.graphics.instance.Color( - this.faces[f].color.r, - this.faces[f].color.g, - this.faces[f].color.b - ), - this.faces[f].materialIndex - ); - - face.vertexColors = [ - new this.graphics.instance.Color( - this.faces[f].vertexColors[0].r, - this.faces[f].vertexColors[0].g, - this.faces[f].vertexColors[0].b - ), - new this.graphics.instance.Color( - this.faces[f].vertexColors[1].r, - this.faces[f].vertexColors[1].g, - this.faces[f].vertexColors[1].b - ), - new this.graphics.instance.Color( - this.faces[f].vertexColors[2].r, - this.faces[f].vertexColors[2].g, - this.faces[f].vertexColors[2].b - ) - ]; - - face.normal = new this.graphics.instance.Vector3( - this.faces[f].normal.x, - this.faces[f].normal.y, - this.faces[f].normal.z - ); - - face.vertexNormals = [ - new this.graphics.instance.Vector3( - this.faces[f].vertexNormals[0].x, - this.faces[f].vertexNormals[0].y, - this.faces[f].vertexNormals[0].z - ), - new this.graphics.instance.Vector3( - this.faces[f].vertexNormals[1].x, - this.faces[f].vertexNormals[1].y, - this.faces[f].vertexNormals[1].z - ), - new this.graphics.instance.Vector3( - this.faces[f].vertexNormals[2].x, - this.faces[f].vertexNormals[2].y, - this.faces[f].vertexNormals[2].z - ) - ]; - - instanceGeometry.faces.push(face); - } - - instanceGeometry.faceVertexUvs = []; - - /** - * Setup face UVs - */ - for (var fm = 0; fm < this.faceVertexUvs.length; fm++) { - - var faceMaterialVertexUvs = this.faceVertexUvs[fm]; - - instanceGeometry.faceVertexUvs[fm] = []; - - for (var fuv = 0; fuv < faceMaterialVertexUvs.length; fuv++) { - instanceGeometry.faceVertexUvs[fm][fuv] = []; - instanceGeometry.faceVertexUvs[fm][fuv].push( - new this.graphics.instance.Vector2( - faceMaterialVertexUvs[fuv][0].x, - faceMaterialVertexUvs[fuv][0].y - ), - new this.graphics.instance.Vector2( - faceMaterialVertexUvs[fuv][1].x, - faceMaterialVertexUvs[fuv][1].y - ), - new this.graphics.instance.Vector2( - faceMaterialVertexUvs[fuv][2].x, - faceMaterialVertexUvs[fuv][2].y - ) - ); - } + if (this instanceof GameLib.D3.Mesh.Sphere) { + geometry = this.sphereGeometry(); + } else { + geometry = this.customGeometry(); } /** @@ -294,26 +320,26 @@ GameLib.D3.Mesh.prototype.createInstance = function(update) { * @type {Array} */ if (this.computeNormals) { - instanceGeometry.computeFaceNormals(); - instanceGeometry.computeVertexNormals(); + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); this.computeNormals = false; } - if (this.meshType == GameLib.D3.Mesh.TYPE_NORMAL) { - instance = new THREE.Mesh(instanceGeometry); + if (this.meshType === GameLib.D3.Mesh.TYPE_NORMAL) { + instance = new THREE.Mesh(geometry); } - if (this.meshType == GameLib.D3.Mesh.TYPE_CURVE) { - instance = new THREE.Points(instanceGeometry); + if (this.meshType === GameLib.D3.Mesh.TYPE_CURVE) { + instance = new THREE.Points(geometry); } - if (this.meshType == GameLib.D3.Mesh.TYPE_SKINNED) { + if (this.meshType === GameLib.D3.Mesh.TYPE_SKINNED) { /** * Setup bones (indexes) */ for (var si = 0; si < this.skinIndices.length; si++) { - instanceGeometry.skinIndices.push( + geometry.skinIndices.push( new THREE.Vector4( this.skinIndices[si].x, this.skinIndices[si].y, @@ -327,7 +353,7 @@ GameLib.D3.Mesh.prototype.createInstance = function(update) { * Setup bones (weights) */ for (var sw = 0; sw < this.skinWeights.length; sw++) { - instanceGeometry.skinWeights.push( + geometry.skinWeights.push( new THREE.Vector4( this.skinWeights[sw].x, this.skinWeights[sw].y, @@ -337,14 +363,14 @@ GameLib.D3.Mesh.prototype.createInstance = function(update) { ); } - instance = new THREE.SkinnedMesh(instanceGeometry); + instance = new THREE.SkinnedMesh(geometry); instance.add(this.skeleton.rootBoneInstance); instance.bind(this.skeleton.instance); } - if (instance == null) { + if (instance === null) { console.log('cannot handle meshes of type ' + this.meshType + ' yet.'); } } diff --git a/src/game-lib-d3-mesh-sphere.js b/src/game-lib-d3-mesh-sphere.js new file mode 100644 index 0000000..97a634c --- /dev/null +++ b/src/game-lib-d3-mesh-sphere.js @@ -0,0 +1,92 @@ +/** + * Mesh Superset - The apiMesh properties get moved into the Mesh object itself, and then the instance is created + * @param graphics GameLib.D3.Graphics + * @param apiMesh GameLib.D3.API.Mesh + * @param radius + * @param widthSegments + * @param heightSegments + * @constructor + */ +GameLib.D3.Mesh.Sphere = function ( + graphics, + apiMesh, + radius, + widthSegments, + heightSegments +) { + this.graphics = graphics; + this.graphics.isNotThreeThrow(); + + if (GameLib.Utils.UndefinedOrNull(radius)) { + radius = 1; + } + this.radius = radius; + + if (GameLib.Utils.UndefinedOrNull(widthSegments)) { + widthSegments = 5; + } + this.widthSegments = widthSegments; + + if (GameLib.Utils.UndefinedOrNull(heightSegments)) { + heightSegments = 5; + } + this.heightSegments = heightSegments; + + GameLib.D3.Mesh.call( + this, + this.graphics, + apiMesh, + null, + true + ); +}; + +GameLib.D3.Mesh.Sphere.prototype = Object.create(GameLib.D3.Mesh.prototype); +GameLib.D3.Mesh.Sphere.prototype.constructor = GameLib.D3.Mesh.Sphere; + + +GameLib.D3.Mesh.Sphere.prototype.sphereGeometry = function() { + return new THREE.SphereGeometry( + this.radius, + this.widthSegments, + this.heightSegments + ); +}; + +/** + * Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh + * @returns {GameLib.D3.API.Mesh} + */ +GameLib.D3.Mesh.Sphere.prototype.toApiObject = function() { + + var apiMesh = GameLib.D3.Mesh.prototype.toApiObject.call(this); + + apiMesh.radius = this.radius; + apiMesh.widthSegments = this.widthSegments; + apiMesh.heightSegments = this.heightSegments; + + return apiMesh; +}; + +/** + * TODO fix all this weird loading shit + * Converts a standard object mesh to a GameLib.D3.Mesh + * @param graphics GameLib.D3.Graphics + * @param objectMesh {Object} + * @param computeNormals boolean to indicate whether or not to recalculate normals + * @param imageFactory GameLib.D3.ImageFactory + * @constructor + */ +GameLib.D3.Mesh.Sphere.FromObjectMesh = function(graphics, objectMesh, computeNormals, imageFactory) { + + var apiMesh = GameLib.D3.API.Mesh.FromObjectMesh(objectMesh); + + return new GameLib.D3.Mesh.Sphere( + graphics, + apiMesh, + objectMesh.radius, + objectMesh.widthSegments, + objectMesh.heightSegments + ); + +}; diff --git a/src/game-lib-d3-scene.js b/src/game-lib-d3-scene.js index 4a99c07..f86b05a 100644 --- a/src/game-lib-d3-scene.js +++ b/src/game-lib-d3-scene.js @@ -283,3 +283,56 @@ GameLib.D3.Scene.FromObjectScene = function( computeNormals ); }; + + +/** + * Adds a mesh to the scene + * @param mesh GameLib.D3.Mesh + */ +GameLib.D3.Scene.prototype.addMesh = function(mesh) { + + if (mesh instanceof GameLib.D3.Mesh) { + this.meshes.push(mesh); + } else if (mesh instanceof GameLib.D3.API.Mesh) { + mesh = new GameLib.D3.Mesh( + this.graphics, + mesh, + mesh.imageFactory, + mesh.computeNormals + ) + } + + mesh.parentScene = this; + + this.instance.add(mesh.instance); + + this.buildIdToObject(); +}; + +/** + * + * @param mesh + */ +GameLib.D3.Scene.prototype.removeMesh = function(mesh) { + + var index = -1; + + if (mesh instanceof GameLib.D3.Mesh) { + index = this.meshes.indexOf(mesh); + } else { + console.warn('Cannot remove this mesh - what is this ?' + mesh.toString()); + throw new Error('Cannot remove this mesh - what is this ?' + mesh.toString()) + } + + this.instance.remove(mesh.instance); + + if (index !== -1) { + this.meshes.splice(index, 1); + } + + if (mesh.parentScene === this) { + mesh.parentScene = null; + } + + this.buildIdToObject(); +}; \ No newline at end of file diff --git a/src/game-lib-entity.js b/src/game-lib-entity.js index b81f498..7bb2b25 100644 --- a/src/game-lib-entity.js +++ b/src/game-lib-entity.js @@ -196,18 +196,24 @@ GameLib.Entity.prototype.updateInstance = function() { */ GameLib.Entity.prototype.toApiObject = function() { - var apiComponents = this.components.map( - function(component) { - return component.toApiObject(); - } + var apiComponents = this.components.reduce( + function(result, component) { + if (typeof component.toApiObject === 'function') { + result.push(component.toApiObject()); + } else { + console.log('ignored runtime component : ' + component.name); + } + return result; + }, + [] ); return new GameLib.API.Entity( this.id, this.name, apiComponents, - this.parentEntity.id, - this.parentEntityManager.id + GameLib.Utils.IdOrNull(this.parentEntity), + GameLib.Utils.IdOrNull(this.parentEntityManager) ); }; diff --git a/src/game-lib-gui.js b/src/game-lib-gui.js index 2c4b549..aaab240 100644 --- a/src/game-lib-gui.js +++ b/src/game-lib-gui.js @@ -745,16 +745,109 @@ GameLib.GUI.prototype.buildSelectControl = function(folder, object, property, en object, property, options - ).name(property).listen().onChange(function(value){ - if (value !== 'null') { - object[property] = idToObject[value]; - } else { - object[property] = null; - } - parentObject.buildIdToObject(); - object.updateInstance(); - this.build(entityManager); - }.bind(this)); + ).name(property).listen().onChange( + + function(gui) { + + return function (value) { + + if (value !== 'null') { + object[property] = idToObject[value]; + } else { + object[property] = null; + } + + if (property === 'parentScene') { + /** + * New way of doing things + */ + GameLib.Event.Emit( + GameLib.Event.PARENT_SCENE_CHANGE, + { + old: this.initialValue, + current: object[property], + object: object, + property: property + } + ); + } else { + /** + * Old way of doing things + */ + parentObject.buildIdToObject(); + object.updateInstance(); + } + + /** + * Properties changed - rebuild GUI + */ + gui.build(entityManager); + }; + + }(this) + ); +}; + +/** + * + */ +GameLib.GUI.prototype.buildCurrentSelectionControlFromArray = function( + folder, + object, + property, + name +) { + + name = name || 'current ' + property; + + object['current' + property] = null; + + var options = object[property].reduce( + function(result, obj){ + if (obj instanceof Object) { + result[obj.name] = obj; + } else { + console.log('not an object'); + } + return result; + }, + { + 'none' : null + } + ); + + folder.add(object, 'current' + property, options).name(name).listen() +}; + +GameLib.GUI.prototype.buildEntitySelectionControlFromArray = function( + folder, + object, + property, + entityManager +) { + + var options = entityManager.entities.reduce( + function(result, obj){ + if (obj instanceof Object) { + result[obj.name] = obj; + } else { + console.log('not an object'); + } + return result; + }, + { + 'none' : null + } + ); + + folder.add(object, property, options).name(property).listen().onChange( + function(value) { + GameLib.Event.Emit( + GameLib.Event.PARENT_ENTITY_CHANGE, + {} + ); + } + ); }; /** @@ -775,7 +868,6 @@ GameLib.GUI.prototype.build = function(entityManager) { if (object.idToObject) { for (var property in object.idToObject) { if (object.idToObject.hasOwnProperty(property)) { - if (discoveredObjects.indexOf(object.idToObject[property]) === -1) { discoveredObjects.push(object.idToObject[property]); } @@ -792,7 +884,11 @@ GameLib.GUI.prototype.build = function(entityManager) { var apiObject = object.toApiObject(); - var folder = this.instance.addFolder(apiObject.name); + try { + var folder = this.instance.addFolder(apiObject.name); + } catch (e) { + //todo increase name count + } var property; @@ -805,9 +901,20 @@ GameLib.GUI.prototype.build = function(entityManager) { object.linkedObjects && object.linkedObjects[property] ) { - - if (object.linkedObjects[property] instanceof Array) { + if (property === 'parentEntity') { + this.buildEntitySelectionControlFromArray( + folder, + object, + property, + entityManager + ) + } else if (object.linkedObjects[property] instanceof Array) { console.log('ignored array : ' + property); + this.buildCurrentSelectionControlFromArray( + folder, + object, + property + ) } else { this.buildSelectControl(folder, object, property, entityManager, object.linkedObjects[property], parentObject); } diff --git a/src/game-lib-system.js b/src/game-lib-system.js index c0977c3..2f0fd08 100644 --- a/src/game-lib-system.js +++ b/src/game-lib-system.js @@ -147,7 +147,6 @@ GameLib.System.prototype.start = function() { var guis = this.entityManager.queryComponents(GameLib.GUI); guis.map(function(gui){ - gui.resize(); gui.domElement.instance.parentElement.appendChild(gui.instance.domElement); })