diff --git a/src/game-lib-a-1-event.js b/src/game-lib-a-1-event.js index 22cddee..8227cef 100644 --- a/src/game-lib-a-1-event.js +++ b/src/game-lib-a-1-event.js @@ -61,6 +61,7 @@ GameLib.Event.RENDER = 0x2b; GameLib.Event.EVENT_LIST = 0x2c; GameLib.Event.COMPILE_SUCCESS = 0x2d; GameLib.Event.COMPILE_FAILED = 0x2e; +GameLib.Event.IMAGE_CHANGED = 0x2f; /** * Returns string name of event ID @@ -117,6 +118,7 @@ GameLib.Event.GetEventName = function(number) { case 0x2c : return 'event_list'; case 0x2d : return 'compile_success'; case 0x2e : return 'compile_failed'; + case 0x2f : return 'image_changed'; break; } diff --git a/src/game-lib-a-2-utils.js b/src/game-lib-a-2-utils.js index 9098bd1..9e22539 100644 --- a/src/game-lib-a-2-utils.js +++ b/src/game-lib-a-2-utils.js @@ -660,15 +660,26 @@ GameLib.Utils.isNumber = function(member) { }; GameLib.Utils.isVector2 = function(member) { - return (member instanceof GameLib.Vector2); + return ( + member instanceof GameLib.API.Vector2 || + member instanceof GameLib.Vector2 + ); }; GameLib.Utils.isVector3 = function(member) { - return (member instanceof GameLib.Vector3); + return ( + member instanceof GameLib.API.Vector3 || + member instanceof GameLib.Vector3 + ); }; GameLib.Utils.isVector4 = function(member) { - return (member instanceof GameLib.Vector4); + return ( + member instanceof GameLib.API.Vector4 || + member instanceof GameLib.Vector4 || + member instanceof GameLib.API.Quaternion || + member instanceof GameLib.Quaternion + ); }; /** diff --git a/src/game-lib-d3-material.js b/src/game-lib-d3-material.js index f4423ab..320aeef 100644 --- a/src/game-lib-d3-material.js +++ b/src/game-lib-d3-material.js @@ -490,6 +490,7 @@ GameLib.D3.Material.prototype.createMeshBasicMaterialInstance = function() { * updates textures */ GameLib.D3.Material.prototype.updateTextures = function() { + if (this.alphaMap && this.alphaMap.instance) { this.instance.alphaMap = this.alphaMap.instance; } else { @@ -972,6 +973,61 @@ GameLib.D3.Material.prototype.toApiObject = function(save) { return apiMaterial; }; +GameLib.D3.Material.prototype.getTextures = function() { + + var textures = []; + + if (this.alphaMap) { + textures.push(this.alphaMap); + } + + if (this.aoMap) { + textures.push(this.aoMap); + } + + if (this.bumpMap) { + textures.push(this.bumpMap); + } + + if (this.diffuseMap) { + textures.push(this.diffuseMap); + } + + if (this.displacementMap) { + textures.push(this.displacementMap); + } + + if (this.emissiveMap) { + textures.push(this.emissiveMap); + } + + if (this.environmentMap) { + textures.push(this.environmentMap); + } + + if (this.lightMap) { + textures.push(this.lightMap); + } + + if (this.metalnessMap) { + textures.push(this.metalnessMap); + } + + if (this.normalMap) { + textures.push(this.normalMap); + } + + if (this.roughnessMap) { + textures.push(this.roughnessMap); + } + + if (this.specularMap) { + textures.push(this.specularMap); + } + + return textures; +}; + /** * Creates a GameLib.D3.Material from a material Object * @param graphics GameLib.D3.Graphics diff --git a/src/game-lib-d3-mesh-0.js b/src/game-lib-d3-mesh-0.js index 2386e20..b659154 100644 --- a/src/game-lib-d3-mesh-0.js +++ b/src/game-lib-d3-mesh-0.js @@ -163,9 +163,258 @@ 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() { + /** + * Setup face indexes - first we sort according to the material index, because later we will create + * groups for each vertice group + */ + this.faces.sort(function(a, b){ + + if (a.materialIndex < b.materialIndex) { + return -1; + } + + if (a.materialIndex > b.materialIndex) { + return 1; + } + + return 0; + }); + + /** + * Setup mesh vertices positions + * @type {Float32Array} + */ + var vertices = new Float32Array( + + this.faces.reduce( + function(result, face){ + result.push(this.vertices[face.v0].position.x); + result.push(this.vertices[face.v0].position.y); + result.push(this.vertices[face.v0].position.z); + result.push(this.vertices[face.v1].position.x); + result.push(this.vertices[face.v1].position.y); + result.push(this.vertices[face.v1].position.z); + result.push(this.vertices[face.v2].position.x); + result.push(this.vertices[face.v2].position.y); + result.push(this.vertices[face.v2].position.z); + return result; + }.bind(this), + [] + ) + + ); + + var geometry = new THREE.BufferGeometry(); + + geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3)); + + /** + * Setyp mesh vertices colors + */ + var colors = Float32Array.from( + this.faces.reduce( + function(result, face){ + result.push(1,1,1,1,1,1,1,1,1); + // result.push(face.color.r); + // result.push(face.color.g); + // result.push(face.color.b); + // result.push(face.color.r); + // result.push(face.color.g); + // result.push(face.color.b); + // result.push(face.color.r); + // result.push(face.color.g); + // result.push(face.color.b); + return result; + }.bind(this), + [] + ) + ); + geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3, true)); + + /** + * Setup face UVs + */ + var uvs = Float32Array.from( + this.faceVertexUvs[0].reduce( + function(result, uv) { + result.push(uv[0].x); + result.push(uv[0].y); + result.push(uv[1].x); + result.push(uv[1].y); + result.push(uv[2].x); + result.push(uv[2].y); + return result; + }, + [] + ) + ); + geometry.addAttribute('uv', new THREE.BufferAttribute(uvs, 2)); + + /** + * Setup material groups - this means creating a new group for each material index change + * We know faces are sorted according to material index + */ + var groupIndexCounts = this.faces.reduce( + function(result, face) { + + var currentGroup = result.pop(); + + if (currentGroup.index !== face.materialIndex) { + /** + * We have a new group + */ + result.push(currentGroup); + result.push({ + index: face.materialIndex, + count: 3 + }) + } else { + currentGroup.count += 3; + result.push(currentGroup); + } + + return result; + }, + [ + { + index : 0, + count : 0 + } + ] + ); + + groupIndexCounts.reduce( + function(start, group) { + geometry.addGroup(start, group.count, group.index); + return start + group.count; + }, + 0 + ); + + + /** + * Apply skin indices + */ + // this.applyBones(geometry); + + /** + * Re-compute normals + */ + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); + + return geometry; + +}; + /** - * Apply geometry data to our game-lib object from the geometry instance (revere of applyVertexData) + * Creates a mesh instance or updates it + */ +GameLib.D3.Mesh.prototype.createInstance = function() { + + console.log('mesh create instance'); + + var geometry = this.createInstanceGeometry(); + + var instance = null; + + var instanceMaterials = function(result, material){ + result.push(material.instance); + return result; + }; + + if (this.skeleton) { + instance = new THREE.SkinnedMesh( + geometry, + this.materials.reduce( + instanceMaterials, + [] + ) + ); + instance.add(this.skeleton.rootBoneInstance); + instance.bind(this.skeleton.instance); + } else { + instance = new THREE.Mesh( + geometry, + this.materials.reduce( + instanceMaterials, + [] + ) + ); + } + + this.createInstanceDefaults(instance); + + return instance; +}; + +/** + * Updates the mesh instance + */ +GameLib.D3.Mesh.prototype.updateInstance = function() { + + console.log('mesh update instance'); + + if (this.parentMesh && this.parentMesh.loaded) { + + if (this.instance.parent !== this.parentMesh.instance) { + this.instance.parent = this.parentMesh.instance; + } + + this.instance.position.x = this.localPosition.x; + this.instance.position.y = this.localPosition.y; + this.instance.position.z = this.localPosition.z; + + this.instance.rotation.x = this.localRotation.x; + this.instance.rotation.y = this.localRotation.y; + this.instance.rotation.z = this.localRotation.z; + + this.instance.scale.x = this.localScale.x; + this.instance.scale.y = this.localScale.y; + this.instance.scale.z = this.localScale.z; + + } else { + + this.instance.quaternion.x = this.quaternion.x; + this.instance.quaternion.y = this.quaternion.y; + this.instance.quaternion.z = this.quaternion.z; + this.instance.quaternion.w = this.quaternion.w; + + this.instance.position.x = this.position.x + this.localPosition.x; + this.instance.position.y = this.position.y + this.localPosition.y; + this.instance.position.z = this.position.z + this.localPosition.z; + + this.instance.scale.x = this.scale.x * this.localScale.x; + this.instance.scale.y = this.scale.y * this.localScale.y; + this.instance.scale.z = this.scale.z * this.localScale.z; + + this.instance.up.x = this.up.x; + this.instance.up.y = this.up.y; + this.instance.up.z = this.up.z; + + this.instance.rotateX(this.localRotation.x); + this.instance.rotateY(this.localRotation.y); + this.instance.rotateZ(this.localRotation.z); + } + + this.instance.name = this.name; + + if (this.materials.length === 1 && this.materials[0].instance) { + this.instance.material = this.materials[0].instance; + } + + this.instance.renderOrder = this.renderOrder; + + if (this.helper) { + this.helper.updateInstance(); + } + +}; + +/** + * Apply geometry data to our game-lib object from the geometry instance (reverse of applyVertexData) * @param geometryInstance */ GameLib.D3.Mesh.prototype.updateVerticesFromGeometryInstance = function(geometryInstance) { @@ -175,23 +424,151 @@ GameLib.D3.Mesh.prototype.updateVerticesFromGeometryInstance = function(geometry this.vertices = []; - geometryInstance.vertices.map(function(vertex){ - this.vertices.push( - new GameLib.D3.Vertex( - this.graphics, - new GameLib.D3.API.Vertex( - new GameLib.Vector3( - this.graphics, - new GameLib.API.Vector3( - vertex.x, - vertex.y, - vertex.z - ) - ) - ) - ) - ) - }.bind(this)); + this.faces = []; + + this.faceVertexUvs = [[]]; + + if (geometryInstance instanceof THREE.BufferGeometry) { + + var vertices = this.instance.geometry.getAttribute('position').array; + + var uvs = this.instance.geometry.getAttribute('uv').array; + + this.instance.geometry.groups.map(function(group){ + + var materialIndex = group.materialIndex; + + var start = group.start; + + var count = group.count; + + var faceIndexes = []; + + var indexedUvs = []; + + for (var i = start; i < count; i ++) { + + var vertex = new GameLib.D3.Vertex( + this.graphics, + new GameLib.D3.API.Vertex( + new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + vertices[i*3], + vertices[i*3 + 1], + vertices[i*3 + 2] + ) + ) + ) + ); + + var uv = new GameLib.Vector2( + this.graphics, + new GameLib.API.Vector2( + uvs[i*2], + uvs[i*2 + 1] + ) + ); + + indexedUvs.push(uv); + + var vertexIndex = this.vertices.reduce( + function(result, indexedVertex, currentIndex){ + if (indexedVertex.position.equals(vertex.position)) { + result = currentIndex; + } + return result; + }, + -1 + ); + + var faceIndex = vertexIndex; + + if (vertexIndex === -1) { + this.vertices.push(vertex); + faceIndex = this.vertices.length - 1; + } + + faceIndexes.push(faceIndex); + + if (faceIndexes.length === 3) { + + this.faces.push(new GameLib.D3.TriangleFace( + faceIndexes[0], + faceIndexes[1], + faceIndexes[2], + materialIndex + )); + + this.faceVertexUvs[0].push([indexedUvs[0], indexedUvs[1], indexedUvs[2]]); + + indexedUvs = []; + faceIndexes = []; + } + } + + }.bind(this)); + + + + console.log('todo : update vertices from buffer geometry'); + } else { + + geometryInstance.faces.map(function(face){ + this.faces.push( + new GameLib.D3.TriangleFace( + face.a, + face.b, + face.c, + face.materialIndex + ) + ) + }.bind(this)); + + geometryInstance.vertices.map(function(vertex){ + this.vertices.push( + new GameLib.D3.Vertex( + this.graphics, + new GameLib.D3.API.Vertex( + new GameLib.Vector3( + this.graphics, + new GameLib.API.Vector3( + vertex.x, + vertex.y, + vertex.z + ) + ) + ) + ) + ) + }.bind(this)); + + geometryInstance.faceVertexUvs[0].map(function(uvs){ + this.faceVertexUvs[0].push([ + new GameLib.Vector2( + this.graphics, + new GameLib.API.Vector2( + uvs[0].x, + uvs[0].y + ) + ), + new GameLib.Vector2( + this.graphics, + new GameLib.API.Vector2( + uvs[1].x, + uvs[1].y + ) + ), + new GameLib.Vector2( + this.graphics, + new GameLib.API.Vector2( + uvs[2].x, + uvs[2].y + ) + ) + ]) + }.bind(this)) + } }; @@ -290,353 +667,9 @@ GameLib.D3.Mesh.prototype.createInstanceDefaults = function(instance) { instance.rotateZ(this.localRotation.z); } - - instance.renderOrder = this.renderOrder; - - this.subscribe( - GameLib.Event.MATERIAL_TYPE_CHANGED, - function (data) { - - /** - * Check if this material is in use by the mesh - */ - - var inUse = this.materials.reduce( - function(result, material) { - if (material === data.material) { - result = true; - } - return result; - }, - false - ); - - /** - * If the material is in use, assign all the new material instances to the mesh instance, and update - * geometry uvs - */ - if (inUse) { - - this.instance.material = this.materials.map( - function(material){ - return material.instance; - } - ); - - this.instance.geometry.uvsNeedUpdate = true; - } - - - // if (this.materials[0] === data.material) { - // this.instance.material = data.material.instance; - // this.instance.geometry.uvsNeedUpdate = true; - // } - } - ); }; -/** - * Creates a mesh instance or updates it - */ -GameLib.D3.Mesh.prototype.createInstance = function() { - - console.log('mesh create instance'); - - function disposeArray() { - // this.array = null; - } - - var geometry = new THREE.BufferGeometry(); - - /** - * Setup face indexes - first we sort according to the material index, because later we will create - * groups for each vertice group - */ - this.faces.sort(function(a, b){ - - if (a.materialIndex < b.materialIndex) { - return -1; - } - - if (a.materialIndex > b.materialIndex) { - return 1; - } - - return 0; - }); - - /** - * Setup mesh vertices positions - * @type {Float32Array} - */ - var vertices = new Float32Array( - - this.faces.reduce( - function(result, face){ - result.push(this.vertices[face.v0].position.x); - result.push(this.vertices[face.v0].position.y); - result.push(this.vertices[face.v0].position.z); - result.push(this.vertices[face.v1].position.x); - result.push(this.vertices[face.v1].position.y); - result.push(this.vertices[face.v1].position.z); - result.push(this.vertices[face.v2].position.x); - result.push(this.vertices[face.v2].position.y); - result.push(this.vertices[face.v2].position.z); - return result; - }.bind(this), - [] - ) - - // this.vertices.reduce( - // function(result, vertex) { - // result.push(vertex.position.x); - // result.push(vertex.position.y); - // result.push(vertex.position.z); - // return result; - // }, - // [] - // ) - ); - geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3).onUpload( disposeArray )); - - /** - * Setyp mesh vertices colors - */ - var colors = Float32Array.from( - this.faces.reduce( - function(result, face){ - result.push(1,1,1,1,1,1,1,1,1); - // result.push(face.color.r); - // result.push(face.color.g); - // result.push(face.color.b); - // result.push(face.color.r); - // result.push(face.color.g); - // result.push(face.color.b); - // result.push(face.color.r); - // result.push(face.color.g); - // result.push(face.color.b); - return result; - }.bind(this), - [] - ) - ); - geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3, true).onUpload( disposeArray )); - - /** - * Setup face UVs - */ - var uvs = Float32Array.from( - this.faceVertexUvs[0].reduce( - function(result, uv) { - result.push(uv[0].x); - result.push(uv[0].y); - result.push(uv[1].x); - result.push(uv[1].y); - result.push(uv[2].x); - result.push(uv[2].y); - return result; - }, - [] - ) - ); - geometry.addAttribute('uv', new THREE.BufferAttribute(uvs, 2).onUpload( disposeArray )); - - - // geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).onUpload( disposeArray ) ); - // geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ).onUpload( disposeArray ) ); - // geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).onUpload( disposeArray ) ); - - - /** - * Now we create the face indices - */ - // var faceIndices = Uint32Array.from( - // this.faces.reduce( - // function(result, face) { - // result.push(face.v0); - // result.push(face.v1); - // result.push(face.v2); - // return result; - // }, - // [] - // ) - // ); - // geometry.setIndex(new THREE.BufferAttribute(faceIndices, 1)); - - /** - * Setup material groups - this means creating a new group for each material index change - * We know faces are sorted according to material index - */ - var groupIndexCounts = this.faces.reduce( - function(result, face) { - - var currentGroup = result.pop(); - - if (currentGroup.index !== face.materialIndex) { - /** - * We have a new group - */ - result.push(currentGroup); - result.push({ - index: face.materialIndex, - count: 3 - }) - } else { - currentGroup.count += 3; - result.push(currentGroup); - } - - return result; - }, - [ - { - index : 0, - count : 0 - } - ] - ); - - groupIndexCounts.reduce( - function(start, group) { - geometry.addGroup(start, group.count, group.index); - return start + group.count; - }, - 0 - ); - - //geometry.addGroup(0, vertices.length, this.materials.length - 1); - // - // 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 - // ) - // ); - // } - // } - - /** - * Apply skin indices - */ - // this.applyBones(geometry); - - /** - * Re-compute normals - */ - geometry.computeFaceNormals(); - geometry.computeVertexNormals(); - - var instance = null; - - var instanceMaterials = function(result, material){ - result.push(material.instance); - return result; - }; - - if (this.skeleton) { - instance = new THREE.SkinnedMesh( - geometry, - this.materials.reduce( - instanceMaterials, - [] - ) - ); - instance.add(this.skeleton.rootBoneInstance); - instance.bind(this.skeleton.instance); - } else { - instance = new THREE.Mesh( - geometry, - this.materials.reduce( - instanceMaterials, - [] - ) - ); - } - - //this.createInstanceDefaults(instance); - - return instance; -}; - -/** - * Updates the mesh instance - */ -GameLib.D3.Mesh.prototype.updateInstance = function() { - - console.log('mesh update instance'); - - if (this.parentMesh && this.parentMesh.loaded) { - - if (this.instance.parent !== this.parentMesh.instance) { - this.instance.parent = this.parentMesh.instance; - } - - this.instance.position.x = this.localPosition.x; - this.instance.position.y = this.localPosition.y; - this.instance.position.z = this.localPosition.z; - - this.instance.rotation.x = this.localRotation.x; - this.instance.rotation.y = this.localRotation.y; - this.instance.rotation.z = this.localRotation.z; - - this.instance.scale.x = this.localScale.x; - this.instance.scale.y = this.localScale.y; - this.instance.scale.z = this.localScale.z; - - } else { - - this.instance.quaternion.x = this.quaternion.x; - this.instance.quaternion.y = this.quaternion.y; - this.instance.quaternion.z = this.quaternion.z; - this.instance.quaternion.w = this.quaternion.w; - - this.instance.position.x = this.position.x + this.localPosition.x; - this.instance.position.y = this.position.y + this.localPosition.y; - this.instance.position.z = this.position.z + this.localPosition.z; - - this.instance.scale.x = this.scale.x * this.localScale.x; - this.instance.scale.y = this.scale.y * this.localScale.y; - this.instance.scale.z = this.scale.z * this.localScale.z; - - this.instance.up.x = this.up.x; - this.instance.up.y = this.up.y; - this.instance.up.z = this.up.z; - - this.instance.rotateX(this.localRotation.x); - this.instance.rotateY(this.localRotation.y); - this.instance.rotateZ(this.localRotation.z); - } - - this.instance.name = this.name; - - if (this.materials.length === 1 && this.materials[0].instance) { - this.instance.material = this.materials[0].instance; - } - - this.instance.renderOrder = this.renderOrder; - - if (this.helper) { - this.helper.updateInstance(); - } - -}; GameLib.D3.Mesh.prototype.getBoundingBox = function() { @@ -775,31 +808,52 @@ GameLib.D3.Mesh.prototype.applyLocalPositionRotationScale = function() { this.instance.updateMatrix(); - this.localPosition.x = this.instance.position.x; - this.localPosition.y = this.instance.position.y; - this.localPosition.z = this.instance.position.z; + this.updateVerticesFromGeometryInstance(this.instance.geometry); - this.localScale.x = this.instance.scale.x; - this.localScale.y = this.instance.scale.y; - this.localScale.z = this.instance.scale.z; + var geometry = this.createInstanceGeometry(); - this.localRotation.x = this.instance.rotation.x; - this.localRotation.y = this.instance.rotation.y; - this.localRotation.z = this.instance.rotation.z; + this.instance.geometry = geometry; - console.log('TODO: update vertices from vertex array - we store them indexed but they live non-indexed'); - // var vertices = this.instance.geometry.getAttribute('position').array; - // - // for (var v = 0; v < vertices.length; v+=3) { - // - // this.vertices[v/3].position.x = vertices[v+0]; - // this.vertices[v/3].position.y = vertices[v+1]; - // this.vertices[v/3].position.z = vertices[v+2]; - // } + this.localPosition.x = 0; + this.localPosition.y = 0; + this.localPosition.z = 0; + + this.localRotation.x = 0; + this.localRotation.y = 0; + this.localRotation.z = 0; + + this.localScale.x = 1; + this.localScale.y = 1; + this.localScale.z = 1; this.updateInstance(); + // + // this.localPosition.x = this.instance.position.x; + // this.localPosition.y = this.instance.position.y; + // this.localPosition.z = this.instance.position.z; + // + // this.localScale.x = this.instance.scale.x; + // this.localScale.y = this.instance.scale.y; + // this.localScale.z = this.instance.scale.z; + // + // this.rotation.x = this.instance.rotation.x; + // this.rotation.y = this.instance.rotation.y; + // this.rotation.z = this.instance.rotation.z; + // + // console.log('TODO: update vertices from vertex array - we store them indexed but they live non-indexed'); + // // ; + // // + // // for (var v = 0; v < vertices.length; v+=3) { + // // + // // this.vertices[v/3].position.x = vertices[v+0]; + // // this.vertices[v/3].position.y = vertices[v+1]; + // // this.vertices[v/3].position.z = vertices[v+2]; + // // } + // + // this.updateInstance(); }; + /** * Gets all children components of this Mesh * @returns {Array} diff --git a/src/game-lib-d3-mesh-plane.js b/src/game-lib-d3-mesh-plane.js index ad91104..0fd5c1b 100644 --- a/src/game-lib-d3-mesh-plane.js +++ b/src/game-lib-d3-mesh-plane.js @@ -52,20 +52,27 @@ GameLib.D3.Mesh.Plane.prototype.constructor = GameLib.D3.Mesh.Plane; GameLib.D3.Mesh.Plane.prototype.createInstance = function() { - var geometry = new THREE.PlaneGeometry( - this.width, - this.height, - this.widthSegments, - this.heightSegments - ); + var geometry = null; /** * If this geometry is coming from the database, apply the vertex data */ if (this.vertices.length > 0) { - this.applyVertexDataToInstance(geometry); + + geometry = this.createInstanceGeometry(); + } else { + + geometry = new THREE.PlaneGeometry( + this.width, + this.height, + this.widthSegments, + this.heightSegments + ); + this.updateVerticesFromGeometryInstance(geometry); + + geometry = this.createInstanceGeometry(); } var materialInstances = this.materials.reduce( @@ -96,17 +103,22 @@ GameLib.D3.Mesh.Plane.prototype.updateInstance = function() { this.instance.userData.widthSegments !== this.widthSegments || this.instance.userData.heightSegments !== this.heightSegments ) { - var geometry = new THREE.PlaneGeometry( + this.instance.userData.width = this.width; + this.instance.userData.height = this.height; + this.instance.userData.widthSegments = this.widthSegments; + this.instance.userData.heightSegments = this.heightSegments; + + var geometry = new THREE.PlaneGeometry( this.width, this.height, this.widthSegments, this.heightSegments ); - this.instance.geometry = geometry; - this.updateVerticesFromGeometryInstance(geometry); + this.instance.geometry = this.createInstanceGeometry(); + if (this.helper) { this.removeHelper(); this.createHelper(); @@ -196,15 +208,29 @@ GameLib.D3.Mesh.Plane.prototype.getHeightData = function(img,scale) { * @returns {THREE.PlaneGeometry} */ GameLib.D3.Mesh.Plane.prototype.generateHeightMapFromBumpMap = function() { + var data = this.getHeightData(); - for ( var i = 0; i < this.instance.geometry.vertices.length; i++ ) { - this.instance.geometry.vertices[i].z = data[i]; - } + this.vertices.map( + function(vertex, index) { + vertex.position.z = data[index]; + } + ); - this.instance.geometry.verticesNeedUpdate = true; + var geometry = this.createInstanceGeometry(); - this.updateVerticesFromGeometryInstance(this.instance.geometry); + this.instance.geometry = geometry; + + // + // var vertices = this.instance.geometry.attributes.position.array; + // + // for ( var i = 0; i < vertices.length; i += 3 ) { + // vertices[i+2] = data[i]; + // } + // + // this.instance.geometry.attributes.position.needsUpdate = true; + + //this.updateVerticesFromGeometryInstance(this.instance.geometry); // this.updateInstance(); }; diff --git a/src/game-lib-d3-texture.js b/src/game-lib-d3-texture.js index 857bd71..4947e96 100644 --- a/src/game-lib-d3-texture.js +++ b/src/game-lib-d3-texture.js @@ -161,7 +161,7 @@ GameLib.D3.Texture.prototype.createInstance = function() { if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_CUBE) { - if (this.image.instance) { + if (this.image && this.image.instance) { instance = new THREE.CubeTexture( [ @@ -186,7 +186,7 @@ GameLib.D3.Texture.prototype.createInstance = function() { } else { - if (this.image.instance) { + if (this.image && this.image.instance) { instance = new THREE.Texture( this.image.instance ); @@ -200,17 +200,17 @@ GameLib.D3.Texture.prototype.createInstance = function() { } } // - // instance.name = this.name; - // instance.flipY = this.flipY; + instance.name = this.name; + instance.flipY = this.flipY; // instance.encoding = this.encoding; - // instance.offset.x = this.offset.x; - // instance.offset.y = this.offset.y; - // instance.repeat.x = this.repeat.x; - // instance.repeat.y = this.repeat.y; - // instance.mapping = this.mapping; + instance.offset.x = this.offset.x; + instance.offset.y = this.offset.y; + instance.repeat.x = this.repeat.x; + instance.repeat.y = this.repeat.y; + //instance.mapping = this.mapping; // instance.format = this.format; - // instance.wrapS = this.wrapS; - // instance.wrapT = this.wrapT; + instance.wrapS = this.wrapS; + instance.wrapT = this.wrapT; return instance; }; @@ -222,51 +222,64 @@ GameLib.D3.Texture.prototype.updateInstance = function() { console.log('texture update instance'); + var imageChanged = false; + if (!this.instance) { console.error('no texture instance'); return; } - if (!this.image.instance) { - console.error('no image instance'); - return; - } + if (this.image && this.image.instance) { - if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_NORMAL) { - if (this.instance.image !== this.image.instance) { - this.instance = new THREE.Texture( - this.image.instance - ); - this.mapping = this.instance.mapping; - } - } else if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_CUBE) { - if (this.instance.image[0] !== this.image.instance) { - this.instance = new THREE.CubeTexture( - [ - this.image.instance, - this.image.instance, - this.image.instance, - this.image.instance, - this.image.instance, - this.image.instance - ] - ); - this.mapping = this.instance.mapping; - } - } + if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_NORMAL) { + if (this.instance.image !== this.image.instance) { + this.instance = new THREE.Texture( + this.image.instance + ); + this.mapping = this.instance.mapping; - // this.instance.name = this.name; - // this.instance.flipY = this.flipY; + imageChanged = true; + } + } else if (this.typeId === GameLib.D3.Texture.TEXTURE_TYPE_CUBE) { + if (this.instance.image[0] !== this.image.instance) { + this.instance = new THREE.CubeTexture( + [ + this.image.instance, + this.image.instance, + this.image.instance, + this.image.instance, + this.image.instance, + this.image.instance + ] + ); + this.mapping = this.instance.mapping; + + imageChanged = true; + } + } + } + + this.instance.name = this.name; + this.instance.flipY = this.flipY; // this.instance.encoding = this.encoding; - // this.instance.offset.x = this.offset.x; - // this.instance.offset.y = this.offset.y; - // this.instance.repeat.x = this.repeat.x; - // this.instance.repeat.y = this.repeat.y; - // this.instance.mapping = this.mapping; - // this.instance.format = this.format; - // this.instance.wrapS = this.wrapS; - // this.instance.wrapT = this.wrapT; + this.instance.offset.x = this.offset.x; + this.instance.offset.y = this.offset.y; + this.instance.repeat.x = this.repeat.x; + this.instance.repeat.y = this.repeat.y; + this.instance.mapping = this.mapping; + //this.instance.format = this.format; + this.instance.wrapS = this.wrapS; + this.instance.wrapT = this.wrapT; this.instance.needsUpdate = true; + + if (imageChanged) { + this.publish( + GameLib.Event.IMAGE_CHANGED, + { + texture : this + } + ) + } }; /** diff --git a/src/game-lib-system-gui.js b/src/game-lib-system-gui.js index 7c3a884..fb2b896 100644 --- a/src/game-lib-system-gui.js +++ b/src/game-lib-system-gui.js @@ -113,7 +113,77 @@ GameLib.System.GUI.prototype.start = function() { ) }; -GameLib.System.GUI.prototype.buildVectorControl = function(folder, componentTemplate, property, dimension) { +GameLib.System.GUI.prototype.onChange = function(property, subProperty, affected) { + return function(value) { + affected.map(function(component){ + component[property][subProperty] = value; + component.updateInstance(); + }); + } +}; + +GameLib.System.GUI.prototype.controller = function(folder, object, property, subProperty, step, listen, affected) { + + var min = -100; + var max = 100; + + if (property === 'localRotation') { + min = -Math.PI; + max = Math.PI; + } + + var handle = folder.add( + object[property], + subProperty, + min, + max, + step + ).name(property + '.' + subProperty); + + handle.onChange(this.onChange(property, subProperty, affected)); + + if (listen) { + handle.listen(); + } + + return handle; +}; + +GameLib.System.GUI.prototype.buildQuaternionControl = function(folder, componentTemplate, property) { + + var step = 0.1; + + 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 affected = componentTemplate.affected; + + this.controller(folder, object, property, 'x', step, listen, affected); + this.controller(folder, object, property, 'y', step, listen, affected); + this.controller(folder, object, property, 'z', step, listen, affected); + this.controller(folder, object, property, 'w', step, listen, affected); + this.controller(folder, object, property, 'angle', step, listen, affected); + + + object = object[property]; + property = 'axis'; + + this.controller(folder, object, property, 'x', step, listen, affected); + this.controller(folder, object, property, 'y', step, listen, affected); + this.controller(folder, object, property, 'z', step, listen, affected); +}; + +GameLib.System.GUI.prototype.buildVectorControl = function(folder, componentTemplate, property) { var step = 0.1; @@ -141,75 +211,21 @@ GameLib.System.GUI.prototype.buildVectorControl = function(folder, componentTemp step = 0.001; } - controllers.push(); - if (dimension === 4) { - - folder.add( - object[property], - 'w', - -100, - 100, - step - ).name(property + '.w').listen().onChange( - function(value) { - affected.map(function(component){ - component[property].w = value; - component.updateInstance(); - }.bind(this)); - } - ); + if (GameLib.Utils.isVector4(object[property])) { + controllers.push(this.controller(folder, object, property, 'w', step, listen, affected)); } - folder.add( - object[property], - 'x', - -100, - 100, - step - ).listen().name(property + '.x').onChange( - function(value) { - affected.map(function(component){ - component[property].x = value; - component.updateInstance(); - }.bind(this)); - } - ); - - folder.add( - object[property], - 'y', - -100, - 100, - step - ).name(property + '.y').listen().onChange( - function(value) { - affected.map(function(component){ - component[property].y = value; - component.updateInstance(); - }.bind(this)); - } - ); + controllers.push(this.controller(folder, object, property, 'x', step, listen, affected)); + controllers.push(this.controller(folder, object, property, 'y', step, listen, affected)); if ( - dimension === 3 || - dimension === 4 + GameLib.Utils.isVector3(object[property]) || + GameLib.Utils.isVector4(object[property]) ) { - folder.add( - object[property], - 'z', - -100, - 100, - step - ).name(property + '.z').listen().onChange( - function(value) { - affected.map(function(component){ - component[property].z = value; - component.updateInstance(); - }.bind(this)); - } - ); + controllers.push(this.controller(folder, object, property, 'z', step, listen, affected)); } + }; /** @@ -378,7 +394,15 @@ GameLib.System.GUI.prototype.buildSelectControl = function(folder, componentTemp /** * We need to discover the constructor for this component */ - var constructor = componentTemplate.template[property].constructor; + var constructor = null; + + if (componentTemplate.template[property]) { + constructor = componentTemplate.template[property].constructor; + } else { + if (componentTemplate.template.linkedObjects[property]) { + constructor = componentTemplate.template.linkedObjects[property]; + } + } var object = componentTemplate.template; @@ -1256,19 +1280,20 @@ GameLib.System.GUI.prototype.buildGUI = function(data) { continue; } - if (componentTemplate.template[templateProperty] instanceof GameLib.Vector2) { - this.buildVectorControl(folder, componentTemplate, templateProperty, 2); + /** + * We only want to affect runtime vectors because their onchange will execute updateInstance() + */ + if ( + componentTemplate.template[templateProperty] instanceof GameLib.Vector2 || + componentTemplate.template[templateProperty] instanceof GameLib.Vector3 || + componentTemplate.template[templateProperty] instanceof GameLib.Vector4 + ) { + this.buildVectorControl(folder, componentTemplate, templateProperty); continue; } - if (componentTemplate.template[templateProperty] instanceof GameLib.Vector3) { - this.buildVectorControl(folder, componentTemplate, templateProperty, 3); - continue; - } - - if (componentTemplate.template[templateProperty] instanceof GameLib.Vector4) { - this.buildVectorControl(folder, componentTemplate, templateProperty, 4); - continue; + if (componentTemplate.template[templateProperty] instanceof GameLib.Quaternion) { + this.buildQuaternionControl(folder, componentTemplate, templateProperty); } if (templateProperty === 'parentEntity') { @@ -1277,6 +1302,14 @@ GameLib.System.GUI.prototype.buildGUI = function(data) { } if (componentTemplate.template[templateProperty] instanceof Array) { + + if ( + templateProperty === 'vertices' || + templateProperty === 'faces' + ) { + continue; + } + this.buildArrayManagerControl(folder, componentTemplate, templateProperty); continue; } @@ -1288,7 +1321,13 @@ GameLib.System.GUI.prototype.buildGUI = function(data) { if (typeof componentTemplate.template[templateProperty] === 'object') { - if (componentTemplate.template[templateProperty] instanceof GameLib.Component) { + if ( + componentTemplate.template[templateProperty] instanceof GameLib.Component || + ( + componentTemplate.template.linkedObjects && + componentTemplate.template.linkedObjects[templateProperty] + ) + ) { this.buildSelectControl(folder, componentTemplate, templateProperty) } else { //TODO: maybe start including some other types of objects diff --git a/src/game-lib-system-linking.js b/src/game-lib-system-linking.js index 2e0554c..0f0fbf1 100644 --- a/src/game-lib-system-linking.js +++ b/src/game-lib-system-linking.js @@ -35,6 +35,8 @@ GameLib.System.Linking = function( this.textureInstanceCreatedSubscription = null; this.materialInstanceCreatedSubscription = null; this.meshDeletedSubscription = null; + this.imageChangedSubscription = null; + this.materialTypeChangedSubscription = null; }; GameLib.System.Linking.prototype = Object.create(GameLib.System.prototype); @@ -96,6 +98,16 @@ GameLib.System.Linking.prototype.start = function() { GameLib.Event.MESH_DELETED, this.meshDeleted ); + + this.imageChangedSubscription = this.subscribe( + GameLib.Event.IMAGE_CHANGED, + this.imageChanged + ); + + this.materialTypeChangedSubscription = this.subscribe( + GameLib.Event.MATERIAL_TYPE_CHANGED, + this.materialTypeChanged + ) }; GameLib.System.Linking.prototype.link = function(component, data) { @@ -381,6 +393,22 @@ GameLib.System.Linking.prototype.imageNotFound = function(data) { }; +GameLib.System.Linking.prototype.imageChanged = function(data) { + + var materials = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Material); + + materials.map(function(material){ + + var textures = material.getTextures(); + + if (textures.indexOf(data.texture) !== -1) { + material.updateInstance(); + } + + }); + +}; + GameLib.System.Linking.prototype.meshInstanceCreated = function(data) { this.resolveDependencies(data.mesh); @@ -498,6 +526,37 @@ GameLib.System.Linking.prototype.materialInstanceCreated = function(data) { this.resolveDependencies(data.material); }; +GameLib.System.Linking.prototype.materialTypeChanged = function(data) { + + var meshes = GameLib.EntityManager.Instance.queryComponents(GameLib.D3.Mesh); + + meshes.map( + function(mesh){ + var inUse = mesh.materials.reduce( + function(result, material) { + if (material === data.material) { + result = true; + } + return result; + }, + false + ); + + if (inUse) { + + mesh.instance.material = mesh.materials.map(function(material){ + return material.instance; + }); + + mesh.instance.geometry.uvsNeedUpdate = true; + + } + + } + ); + +}; + /** * Defines what should happen when a parent scene changes * @param data @@ -640,5 +699,7 @@ GameLib.System.Linking.prototype.stop = function() { this.textureInstanceCreatedSubscription.remove(); this.materialInstanceCreatedSubscription.remove(); this.meshDeletedSubscription.remove(); + this.imageChangedSubscription.remove(); + this.materialTypeChangedSubscription.remove(); }; diff --git a/src/game-lib-system-storage.js b/src/game-lib-system-storage.js index b568183..4591224 100644 --- a/src/game-lib-system-storage.js +++ b/src/game-lib-system-storage.js @@ -536,13 +536,12 @@ GameLib.System.Storage.prototype.imageUploadComplete = function(data) { image = GameLib.D3.Image.FromObject(this.graphics, imageData); } - /** - * Finally, load the image - */ + GameLib.Event.Emit( GameLib.Event.LOAD_IMAGE, { - image : image + image : image, + createTexture : true } ); @@ -719,7 +718,7 @@ GameLib.System.Storage.prototype.loadImage = function(data) { ); if (onLoaded) { - onLoaded(image); + onLoaded(image, data.createTexture); } };