593 lines
17 KiB
JavaScript
593 lines
17 KiB
JavaScript
/**
|
|
* 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
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Mesh = function (
|
|
graphics,
|
|
apiMesh
|
|
) {
|
|
this.graphics = graphics;
|
|
this.graphics.isNotThreeThrow();
|
|
|
|
if (GameLib.Utils.UndefinedOrNull(apiMesh)) {
|
|
apiMesh = {};
|
|
}
|
|
|
|
if (apiMesh instanceof GameLib.D3.Mesh) {
|
|
return apiMesh;
|
|
}
|
|
|
|
GameLib.D3.API.Mesh.call(
|
|
this,
|
|
apiMesh.id,
|
|
apiMesh.meshType,
|
|
apiMesh.name,
|
|
apiMesh.vertices,
|
|
apiMesh.faces,
|
|
apiMesh.faceVertexUvs,
|
|
apiMesh.materials,
|
|
apiMesh.parentMesh,
|
|
apiMesh.parentScene,
|
|
apiMesh.skeleton,
|
|
apiMesh.skinIndices,
|
|
apiMesh.skinWeights,
|
|
apiMesh.position,
|
|
apiMesh.quaternion,
|
|
apiMesh.scale,
|
|
apiMesh.localPosition,
|
|
apiMesh.localRotation,
|
|
apiMesh.localScale,
|
|
apiMesh.up,
|
|
apiMesh.modelMatrix,
|
|
apiMesh.parentEntity,
|
|
apiMesh.renderOrder
|
|
);
|
|
|
|
this.materials = this.materials.map(
|
|
function(material) {
|
|
if (material instanceof GameLib.D3.API.Material) {
|
|
return new GameLib.D3.Material(
|
|
this.graphics,
|
|
material
|
|
)
|
|
} else {
|
|
return material;
|
|
}
|
|
}.bind(this)
|
|
);
|
|
|
|
if (this.skeleton) {
|
|
this.skeleton = new GameLib.D3.Skeleton(
|
|
this.graphics,
|
|
this.skeleton
|
|
);
|
|
}
|
|
|
|
this.vertices = this.vertices.map(
|
|
function (apiVertex) {
|
|
return new GameLib.D3.Vertex(
|
|
this.graphics,
|
|
apiVertex
|
|
);
|
|
}.bind(this)
|
|
);
|
|
|
|
this.position = new GameLib.Vector3(
|
|
this.graphics,
|
|
this.position,
|
|
this
|
|
);
|
|
|
|
this.scale = new GameLib.Vector3(
|
|
this.graphics,
|
|
this.scale,
|
|
this
|
|
);
|
|
|
|
this.up = new GameLib.Vector3(
|
|
this.graphics,
|
|
this.up,
|
|
this
|
|
);
|
|
|
|
this.quaternion = new GameLib.Quaternion(
|
|
this.graphics,
|
|
this.quaternion,
|
|
this
|
|
);
|
|
|
|
this.localPosition = new GameLib.Vector3(
|
|
this.graphics,
|
|
this.localPosition,
|
|
this
|
|
);
|
|
|
|
this.localRotation = new GameLib.Vector3(
|
|
this.graphics,
|
|
this.localRotation,
|
|
this
|
|
);
|
|
|
|
this.localScale = new GameLib.Vector3(
|
|
this.graphics,
|
|
this.localScale,
|
|
this
|
|
);
|
|
|
|
this.modelMatrix = new GameLib.Matrix4(
|
|
this.graphics,
|
|
this.modelMatrix,
|
|
this
|
|
);
|
|
|
|
GameLib.Component.call(
|
|
this,
|
|
GameLib.Component.COMPONENT_MESH,
|
|
{
|
|
'parentMesh' : GameLib.D3.Mesh,
|
|
'parentScene' : GameLib.D3.Scene,
|
|
'materials' : [GameLib.D3.Material],
|
|
'skeleton' : GameLib.D3.Skeleton
|
|
}
|
|
);
|
|
};
|
|
|
|
GameLib.D3.Mesh.prototype = Object.create(GameLib.D3.API.Mesh.prototype);
|
|
GameLib.D3.Mesh.prototype.constructor = GameLib.D3.Mesh;
|
|
|
|
/**
|
|
* Mesh Type
|
|
* @type {number}
|
|
*/
|
|
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
|
|
*/
|
|
GameLib.D3.Mesh.prototype.createInstance = function(update) {
|
|
|
|
if (!this.loaded) {
|
|
console.log('Attempted to create an instance but the runtime object is not fully loaded : ' + this.name);
|
|
return null;
|
|
}
|
|
|
|
if (update) {
|
|
|
|
if (this.parentMesh && this.parentMesh.loaded) {
|
|
|
|
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;
|
|
|
|
this.instance.geometry.computeBoundingBox();
|
|
|
|
this.width = this.instance.geometry.boundingBox.max.x - this.instance.geometry.boundingBox.min.x;
|
|
this.height = this.instance.geometry.boundingBox.max.y - this.instance.geometry.boundingBox.min.y;
|
|
this.depth = this.instance.geometry.boundingBox.max.z - this.instance.geometry.boundingBox.min.z;
|
|
|
|
} else {
|
|
|
|
var instance = null;
|
|
var geometry = null;
|
|
|
|
if (this instanceof GameLib.D3.Mesh.Sphere) {
|
|
geometry = this.sphereGeometry();
|
|
} else {
|
|
geometry = this.customGeometry();
|
|
}
|
|
|
|
geometry.computeFaceNormals();
|
|
geometry.computeVertexNormals();
|
|
|
|
if (this.meshType === GameLib.D3.Mesh.TYPE_NORMAL) {
|
|
instance = new THREE.Mesh(geometry);
|
|
} else if (this.meshType === GameLib.D3.Mesh.TYPE_CURVE) {
|
|
instance = new THREE.Points(geometry);
|
|
} else if (this.meshType === GameLib.D3.Mesh.TYPE_SKINNED) {
|
|
|
|
/**
|
|
* Setup bones (indexes)
|
|
*/
|
|
for (var si = 0; si < this.skinIndices.length; si++) {
|
|
geometry.skinIndices.push(
|
|
new THREE.Vector4(
|
|
this.skinIndices[si].x,
|
|
this.skinIndices[si].y,
|
|
this.skinIndices[si].z,
|
|
this.skinIndices[si].w
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Setup bones (weights)
|
|
*/
|
|
for (var sw = 0; sw < this.skinWeights.length; sw++) {
|
|
geometry.skinWeights.push(
|
|
new THREE.Vector4(
|
|
this.skinWeights[sw].x,
|
|
this.skinWeights[sw].y,
|
|
this.skinWeights[sw].z,
|
|
this.skinWeights[sw].w
|
|
)
|
|
);
|
|
}
|
|
|
|
instance = new THREE.SkinnedMesh(geometry);
|
|
|
|
instance.add(this.skeleton.rootBoneInstance);
|
|
|
|
instance.bind(this.skeleton.instance);
|
|
} else {
|
|
console.log('cannot handle meshes of type ' + this.meshType + ' yet.');
|
|
}
|
|
|
|
instance.name = this.name;
|
|
|
|
if (this.parentMesh && this.parentMesh.loaded) {
|
|
|
|
instance.parent = this.parentMesh.instance;
|
|
|
|
instance.position.x = this.localPosition.x;
|
|
instance.position.y = this.localPosition.y;
|
|
instance.position.z = this.localPosition.z;
|
|
|
|
instance.rotation.x = this.localRotation.x;
|
|
instance.rotation.y = this.localRotation.y;
|
|
instance.rotation.z = this.localRotation.z;
|
|
|
|
instance.scale.x = this.localScale.x;
|
|
instance.scale.y = this.localScale.y;
|
|
instance.scale.z = this.localScale.z;
|
|
|
|
} else {
|
|
instance.quaternion.x = this.quaternion.x;
|
|
instance.quaternion.y = this.quaternion.y;
|
|
instance.quaternion.z = this.quaternion.z;
|
|
instance.quaternion.w = this.quaternion.w;
|
|
|
|
instance.position.x = this.position.x + this.localPosition.x;
|
|
instance.position.y = this.position.y + this.localPosition.y;
|
|
instance.position.z = this.position.z + this.localPosition.z;
|
|
|
|
instance.scale.x = this.scale.x * this.localScale.x;
|
|
instance.scale.y = this.scale.y * this.localScale.y;
|
|
instance.scale.z = this.scale.z * this.localScale.z;
|
|
|
|
instance.up.x = this.up.x;
|
|
instance.up.y = this.up.y;
|
|
instance.up.z = this.up.z;
|
|
|
|
instance.rotateX(this.localRotation.x);
|
|
instance.rotateY(this.localRotation.y);
|
|
instance.rotateZ(this.localRotation.z);
|
|
}
|
|
|
|
if (this.materials.length === 1 && this.materials[0].instance) {
|
|
instance.material = this.materials[0].instance;
|
|
}
|
|
|
|
instance.renderOrder = this.renderOrder;
|
|
|
|
instance.geometry.computeBoundingBox();
|
|
|
|
this.width = instance.geometry.boundingBox.max.x - instance.geometry.boundingBox.min.x;
|
|
this.height = instance.geometry.boundingBox.max.y - instance.geometry.boundingBox.min.y;
|
|
this.depth = instance.geometry.boundingBox.max.z - instance.geometry.boundingBox.min.z;
|
|
|
|
this.subscribe(
|
|
GameLib.Event.MATERIAL_LOADED,
|
|
function(data) {
|
|
|
|
if (this.instance.material === data.material.instance) {
|
|
return;
|
|
}
|
|
|
|
if (this.materials[0] === data.material) {
|
|
this.instance.material = data.material.instance;
|
|
this.instance.geometry.uvsNeedUpdate = true;
|
|
}
|
|
}
|
|
);
|
|
|
|
this.subscribe(
|
|
GameLib.Event.MATERIAL_TYPE_CHANGED,
|
|
function(data) {
|
|
if (this.materials[0].id === data.material.id) {
|
|
this.instance.material = data.material.instance;
|
|
this.instance.geometry.uvsNeedUpdate = true;
|
|
}
|
|
}
|
|
);
|
|
|
|
return instance;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Updates the mesh instance
|
|
*/
|
|
GameLib.D3.Mesh.prototype.updateInstance = function() {
|
|
this.createInstance(true);
|
|
};
|
|
|
|
/**
|
|
* Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh
|
|
* @returns {GameLib.D3.API.Mesh}
|
|
*/
|
|
GameLib.D3.Mesh.prototype.toApiObject = function(save) {
|
|
|
|
if (GameLib.Utils.UndefinedOrNull(save)) {
|
|
save = false;
|
|
}
|
|
|
|
var apiSkeleton = null;
|
|
if (this.skeleton) {
|
|
if (save) {
|
|
this.skeleton.save();
|
|
}
|
|
apiSkeleton = this.skeleton.id;
|
|
}
|
|
|
|
var apiMaterials = null;
|
|
if (this.materials) {
|
|
apiMaterials = this.materials.map(
|
|
function(material) {
|
|
if (save) {
|
|
material.save();
|
|
}
|
|
return material.id;
|
|
}
|
|
)
|
|
}
|
|
|
|
var apiMesh = new GameLib.D3.API.Mesh(
|
|
this.id,
|
|
this.meshType,
|
|
this.name,
|
|
this.vertices.map(
|
|
function (vertex) {
|
|
return vertex.toApiObject();
|
|
}
|
|
),
|
|
this.faces,
|
|
this.faceVertexUvs,
|
|
apiMaterials,
|
|
GameLib.Utils.IdOrNull(this.parentMesh),
|
|
GameLib.Utils.IdOrNull(this.parentScene),
|
|
apiSkeleton,
|
|
this.skinIndices,
|
|
this.skinWeights,
|
|
this.position.toApiObject(),
|
|
this.quaternion.toApiObject(),
|
|
this.scale.toApiObject(),
|
|
this.localPosition.toApiObject(),
|
|
this.localRotation.toApiObject(),
|
|
this.localScale.toApiObject(),
|
|
this.up.toApiObject(),
|
|
this.modelMatrix.toApiObject(),
|
|
GameLib.Utils.IdOrNull(this.parentEntity),
|
|
this.renderOrder
|
|
);
|
|
|
|
return apiMesh;
|
|
};
|
|
|
|
/**
|
|
* Converts a standard object mesh to a GameLib.D3.Mesh
|
|
* @param graphics GameLib.D3.Graphics
|
|
* @param objectMesh {Object}
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Mesh.FromObject = function(graphics, objectMesh) {
|
|
|
|
var apiMesh = GameLib.D3.API.Mesh.FromObject(objectMesh);
|
|
|
|
return new GameLib.D3.Mesh(
|
|
graphics,
|
|
apiMesh
|
|
);
|
|
|
|
};
|
|
|
|
/**
|
|
* Centers the mesh around origin
|
|
*/
|
|
GameLib.D3.Mesh.prototype.centerAroundOrigin = function() {
|
|
|
|
var localPosition = this.instance.geometry.center();
|
|
|
|
this.instance.position.set(0,0,0);
|
|
|
|
this.instance.updateMatrix();
|
|
|
|
this.position.x = this.instance.position.x;
|
|
this.position.y = this.instance.position.y;
|
|
this.position.z = this.instance.position.z;
|
|
|
|
for (var v = 0; v < this.instance.geometry.vertices.length; v++) {
|
|
this.vertices[v].position.x = this.instance.geometry.vertices[v].x;
|
|
this.vertices[v].position.y = this.instance.geometry.vertices[v].y;
|
|
this.vertices[v].position.z = this.instance.geometry.vertices[v].z;
|
|
}
|
|
|
|
this.localPosition.x = -localPosition.x;
|
|
this.localPosition.y = -localPosition.y;
|
|
this.localPosition.z = -localPosition.z;
|
|
|
|
this.updateInstance();
|
|
}; |