521 lines
14 KiB
JavaScript
521 lines
14 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
|
||
|
* @param imageFactory GameLib.D3.ImageFactory
|
||
|
* @param computeNormals Boolean
|
||
|
* @constructor
|
||
|
*/
|
||
|
GameLib.D3.Mesh = function (
|
||
|
graphics,
|
||
|
apiMesh,
|
||
|
imageFactory,
|
||
|
computeNormals
|
||
|
) {
|
||
|
this.graphics = graphics;
|
||
|
this.graphics.isNotThreeThrow();
|
||
|
|
||
|
if (GameLib.Utils.UndefinedOrNull(apiMesh)) {
|
||
|
apiMesh = {};
|
||
|
}
|
||
|
|
||
|
if (apiMesh instanceof GameLib.D3.Mesh) {
|
||
|
return apiMesh;
|
||
|
}
|
||
|
|
||
|
if (GameLib.Utils.UndefinedOrNull(computeNormals)) {
|
||
|
computeNormals = true;
|
||
|
}
|
||
|
this.computeNormals = computeNormals;
|
||
|
|
||
|
if (GameLib.Utils.UndefinedOrNull(imageFactory)) {
|
||
|
console.warn('Cannot create Meshes fully without specifying an ImageFactory for downloading Textures');
|
||
|
imageFactory = null;
|
||
|
}
|
||
|
this.imageFactory = imageFactory;
|
||
|
|
||
|
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 (apiMaterial) {
|
||
|
|
||
|
if (apiMaterial instanceof GameLib.D3.API.Material) {
|
||
|
return new GameLib.D3.Material(
|
||
|
this.graphics,
|
||
|
apiMaterial,
|
||
|
this.imageFactory
|
||
|
)
|
||
|
} else {
|
||
|
console.warn('API material not of instance API.Material - should be linked at runtime');
|
||
|
return apiMaterial;
|
||
|
// throw new Error('API material not of instance API.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
|
||
|
);
|
||
|
|
||
|
this.buildIdToObject();
|
||
|
|
||
|
this.instance = this.createInstance(false);
|
||
|
|
||
|
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;
|
||
|
|
||
|
};
|
||
|
|
||
|
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) {
|
||
|
|
||
|
var instance = null;
|
||
|
|
||
|
if (update) {
|
||
|
instance = this.instance;
|
||
|
}
|
||
|
|
||
|
if (!update) {
|
||
|
|
||
|
var geometry = null;
|
||
|
|
||
|
if (this instanceof GameLib.D3.Mesh.Sphere) {
|
||
|
geometry = this.sphereGeometry();
|
||
|
} else {
|
||
|
geometry = this.customGeometry();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Re-calculate normals (if we have to)
|
||
|
* @type {Array}
|
||
|
*/
|
||
|
if (this.computeNormals) {
|
||
|
geometry.computeFaceNormals();
|
||
|
geometry.computeVertexNormals();
|
||
|
this.computeNormals = false;
|
||
|
}
|
||
|
|
||
|
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(geometry);
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
if (instance === null) {
|
||
|
console.log('cannot handle meshes of type ' + this.meshType + ' yet.');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
instance.name = this.name;
|
||
|
|
||
|
instance.gameLibObject = this;
|
||
|
|
||
|
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;
|
||
|
|
||
|
// this.position.x = this.parentMesh.position.x;
|
||
|
// this.position.y = this.parentMesh.position.y;
|
||
|
// this.position.z = this.parentMesh.position.z;
|
||
|
|
||
|
// var euler = new THREE.Euler();
|
||
|
//
|
||
|
// var worldRotation = this.parentMesh.instance.getWorldRotation();
|
||
|
//
|
||
|
// this.instance.setRotationFromEuler(euler);
|
||
|
|
||
|
// this.quaternion.x = this.parentMesh.quaternion.x;
|
||
|
// this.quaternion.y = this.parentMesh.quaternion.y;
|
||
|
// this.quaternion.z = this.parentMesh.quaternion.z;
|
||
|
// this.quaternion.w = this.parentMesh.quaternion.w;
|
||
|
} 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;
|
||
|
|
||
|
return instance;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Updates the mesh instance
|
||
|
*/
|
||
|
GameLib.D3.Mesh.prototype.updateInstance = function() {
|
||
|
this.instance = this.createInstance(true);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Clones a mesh
|
||
|
* @returns {*}
|
||
|
*/
|
||
|
GameLib.D3.Mesh.prototype.clone = function() {
|
||
|
return _.cloneDeep(this);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Converts a GameLib.D3.Mesh to a GameLib.D3.API.Mesh
|
||
|
* @returns {GameLib.D3.API.Mesh}
|
||
|
*/
|
||
|
GameLib.D3.Mesh.prototype.toApiObject = function() {
|
||
|
|
||
|
var apiSkeleton = null;
|
||
|
|
||
|
if (this.skeleton) {
|
||
|
apiSkeleton = this.skeleton.toApiObject();
|
||
|
}
|
||
|
|
||
|
return new GameLib.D3.API.Mesh(
|
||
|
this.id,
|
||
|
this.meshType,
|
||
|
this.name,
|
||
|
this.vertices.map(
|
||
|
function (vertex) {
|
||
|
return vertex.toApiObject();
|
||
|
}
|
||
|
),
|
||
|
this.faces,
|
||
|
this.faceVertexUvs,
|
||
|
this.materials.map(function(material){return material.id}),
|
||
|
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
|
||
|
);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* 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.FromObjectMesh = function(graphics, objectMesh, computeNormals, imageFactory) {
|
||
|
|
||
|
var apiMesh = GameLib.D3.API.Mesh.FromObjectMesh(objectMesh);
|
||
|
|
||
|
return new GameLib.D3.Mesh(
|
||
|
graphics,
|
||
|
apiMesh,
|
||
|
computeNormals,
|
||
|
imageFactory
|
||
|
);
|
||
|
|
||
|
};
|