4668 lines
125 KiB
JavaScript
4668 lines
125 KiB
JavaScript
if (typeof GameLib == 'undefined') {
|
|
function GameLib() {}
|
|
}
|
|
|
|
if (typeof GameLib.D3 == 'undefined') {
|
|
GameLib.D3 = function(){};
|
|
}
|
|
/**
|
|
* BoneWeight object - associates a vertex to a bone with some weight
|
|
* @param boneIndex int
|
|
* @param weight float
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.BoneWeight = function(
|
|
boneIndex,
|
|
weight
|
|
) {
|
|
this.boneIndex = boneIndex;
|
|
this.weight = weight;
|
|
};
|
|
/**
|
|
* Bone Superset
|
|
* @param id
|
|
* @param name string
|
|
* @param boneId
|
|
* @param childBoneIds
|
|
* @param parentBoneId
|
|
* @param quaternion
|
|
* @param position
|
|
* @param rotation
|
|
* @param scale GameLib.D3.Vector3
|
|
* @param up
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Bone = function(
|
|
id,
|
|
boneId,
|
|
name,
|
|
childBoneIds,
|
|
parentBoneId,
|
|
quaternion,
|
|
position,
|
|
rotation,
|
|
scale,
|
|
up
|
|
) {
|
|
this.id = id;
|
|
this.name = name;
|
|
this.boneId = boneId;
|
|
|
|
if (typeof childBoneIds == 'undefined') {
|
|
childBoneIds = [];
|
|
}
|
|
this.childBoneIds = childBoneIds;
|
|
|
|
if (typeof parentBoneId == 'undefined') {
|
|
parentBoneId = null;
|
|
}
|
|
this.parentBoneId = parentBoneId;
|
|
|
|
if (typeof quaternion == 'undefined') {
|
|
quaternion = new GameLib.D3.Vector4();
|
|
}
|
|
this.quaternion = quaternion;
|
|
|
|
if (typeof position == 'undefined') {
|
|
position = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.position = position;
|
|
|
|
if (typeof rotation == 'undefined') {
|
|
rotation = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.rotation = rotation;
|
|
|
|
if (typeof scale == 'undefined') {
|
|
scale = new GameLib.D3.Vector3(1,1,1);
|
|
}
|
|
this.scale = scale;
|
|
|
|
if (typeof up == 'undefined') {
|
|
up = new GameLib.D3.Vector3(0,1,0);
|
|
}
|
|
this.up = up;
|
|
};
|
|
/**
|
|
* Physics Broadphase Superset
|
|
* @param id
|
|
* @param name String
|
|
* @param broadphaseType Number
|
|
* @param engine GameLib.D3.Engine
|
|
* @param createInstance Boolean
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Broadphase = function(
|
|
id,
|
|
name,
|
|
broadphaseType,
|
|
engine,
|
|
createInstance
|
|
) {
|
|
this.id = id;
|
|
|
|
if (typeof name == 'undefined') {
|
|
name = 'broadphase-' + broadphaseType;
|
|
}
|
|
this.name = name;
|
|
|
|
if (typeof broadphaseType == 'undefined') {
|
|
broadphaseType = GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE;
|
|
}
|
|
this.broadphaseType = broadphaseType;
|
|
|
|
if (typeof engine == 'undefined') {
|
|
engine = null;
|
|
}
|
|
this.engine = engine;
|
|
|
|
this.instance = null;
|
|
|
|
if (createInstance) {
|
|
this.createInstance();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a custom Broadphase instance based on the engine type
|
|
*/
|
|
GameLib.D3.Broadphase.prototype.createInstance = function() {
|
|
|
|
if (!(this.engine instanceof GameLib.D3.Engine)) {
|
|
console.warn('No Engine');
|
|
throw new Error('No Engine');
|
|
}
|
|
|
|
this.engine.isNotCannonThrow();
|
|
|
|
var instance = null;
|
|
|
|
if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) {
|
|
instance = new this.engine.instance.NaiveBroadphase();
|
|
} else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) {
|
|
instance = new this.engine.instance.GridBroadphase();
|
|
} else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) {
|
|
instance = new this.engine.instance.SAPBroardphase();
|
|
} else {
|
|
console.warn('Unsupported broadphase type: ' + this.broadphaseType);
|
|
throw new Error('Unsupported broadphase type: ' + this.broadphaseType);
|
|
}
|
|
|
|
this.instance = instance;
|
|
|
|
return instance;
|
|
};
|
|
|
|
/**
|
|
* Broadphase Types
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE = 0x1;
|
|
GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID = 0x2;
|
|
GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP = 0x3;
|
|
/**
|
|
* Color Superset
|
|
* @param r
|
|
* @param g
|
|
* @param b
|
|
* @param a
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Color = function(r, g, b, a) {
|
|
this.r = r;
|
|
this.g = g;
|
|
this.b = b;
|
|
this.a = a;
|
|
};
|
|
/**
|
|
* Engine Superset
|
|
* @param engineType
|
|
* @param instance {CANNON | Ammo | Goblin}
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Engine = function(
|
|
engineType,
|
|
instance
|
|
) {
|
|
this.engineType = engineType;
|
|
this.instance = instance;
|
|
};
|
|
|
|
/**
|
|
* True if CANNON physics
|
|
* @returns {boolean}
|
|
*/
|
|
GameLib.D3.Engine.prototype.isCannon = function() {
|
|
return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_CANNON)
|
|
};
|
|
|
|
/**
|
|
* Logs a warning and throws an error if not cannon
|
|
*/
|
|
GameLib.D3.Engine.prototype.isNotCannonThrow = function() {
|
|
if (this.engineType != GameLib.D3.Engine.ENGINE_TYPE_CANNON) {
|
|
console.warn('Only CANNON supported for this function');
|
|
throw new Error('Only CANNON supported for this function');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* True if Ammo physics
|
|
* @returns {boolean}
|
|
*/
|
|
GameLib.D3.Engine.prototype.isAmmo = function() {
|
|
return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_AMMO)
|
|
};
|
|
|
|
/**
|
|
* True if Goblin physics
|
|
* @returns {boolean}
|
|
*/
|
|
GameLib.D3.Engine.prototype.isGoblin = function() {
|
|
return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_GOBLIN)
|
|
};
|
|
|
|
/**
|
|
* Physics GameLib.D3.Engine Types
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Engine.ENGINE_TYPE_CANNON = 0x1;
|
|
GameLib.D3.Engine.ENGINE_TYPE_AMMO = 0x2;
|
|
GameLib.D3.Engine.ENGINE_TYPE_GOBLIN = 0x3;
|
|
/**
|
|
* Fly Controls
|
|
* @param camera
|
|
* @param THREE
|
|
* @param canvas
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.FlyControls = function(
|
|
camera,
|
|
THREE,
|
|
canvas
|
|
) {
|
|
this.flySpeed = 100;
|
|
|
|
this.canvas = canvas;
|
|
|
|
this.THREE = THREE;
|
|
|
|
this.yaw = 0;
|
|
this.pitch = 0;
|
|
this.canRotate = false;
|
|
|
|
this.moveForward = false;
|
|
this.moveBackward = false;
|
|
this.moveLeft = false;
|
|
this.moveRight = false;
|
|
this.moveUp = false;
|
|
this.moveDown = false;
|
|
|
|
this.mouseUpCallback = this.onMouseUp.bind(this);
|
|
this.mouseDownCallback = this.onMouseDown.bind(this);
|
|
this.mouseMoveCallback = this.onMouseMove.bind(this);
|
|
this.mouseWheelCallback = this.onMouseWheel.bind(this);
|
|
this.keyDownCallback = this.onKeyDown.bind(this);
|
|
this.keyUpCallback = this.onKeyUp.bind(this);
|
|
|
|
this.camera = camera;
|
|
|
|
this.canvas.addEventListener('keydown', this.keyDownCallback, false);
|
|
this.canvas.addEventListener('keyup', this.keyUpCallback, false);
|
|
this.canvas.addEventListener('mousedown', this.mouseDownCallback, false);
|
|
this.canvas.addEventListener('mouseup', this.mouseUpCallback, false);
|
|
this.canvas.addEventListener('mousewheel', this.mouseWheelCallback, false);
|
|
|
|
this.havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
|
|
this.element = document.body;
|
|
|
|
if (this.havePointerLock) {
|
|
this.element.requestPointerLock = this.element.requestPointerLock || this.element.mozRequestPointerLock || this.element.webkitRequestPointerLock;
|
|
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock || document.webkitExitPointerLock;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Go forward / backward on mouse wheel
|
|
* @param event
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.onMouseWheel = function(event) {
|
|
this.moveForward = true;
|
|
this.applyTranslation(event.wheelDelta * 0.001);
|
|
event.preventDefault();
|
|
this.moveForward = false;
|
|
};
|
|
|
|
/**
|
|
* Start rotating the camera on mouse middle button down
|
|
* @param event
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.onMouseDown = function(event) {
|
|
if (event.button == 1) {
|
|
this.canRotate = true;
|
|
this.canvas.addEventListener('mousemove', this.mouseMoveCallback, false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Stop rotating on middle mouse button down
|
|
* @param event
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.onMouseUp = function(event) {
|
|
if (event.button == 1) {
|
|
this.canRotate = false;
|
|
this.canvas.removeEventListener('mousemove', this.mouseMoveCallback);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Apply current yaw and pitch to camera
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.applyRotation = function() {
|
|
this.camera.rotation.set(this.pitch, this.yaw, 0, "YXZ");
|
|
};
|
|
|
|
/**
|
|
* Apply current position to camera
|
|
* @param deltaTime
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.applyTranslation = function(deltaTime) {
|
|
var direction = new this.THREE.Vector3(0, 0, -1);
|
|
var rotation = new this.THREE.Euler(0, 0, 0, "YXZ");
|
|
rotation.set(this.pitch, this.yaw, 0, "YXZ");
|
|
|
|
direction = direction.applyEuler(rotation);
|
|
|
|
var forward = direction.normalize();
|
|
var right = forward.cross(new this.THREE.Vector3(0, 1, 0));
|
|
|
|
if(this.moveForward) {
|
|
|
|
this.camera.position.x += forward.x * (deltaTime * this.flySpeed);
|
|
this.camera.position.y += forward.y * (deltaTime * this.flySpeed);
|
|
this.camera.position.z += forward.z * (deltaTime * this.flySpeed);
|
|
|
|
} else if(this.moveBackward) {
|
|
|
|
this.camera.position.x -= forward.x * (deltaTime * this.flySpeed);
|
|
this.camera.position.y -= forward.y * (deltaTime * this.flySpeed);
|
|
this.camera.position.z -= forward.z * (deltaTime * this.flySpeed);
|
|
}
|
|
|
|
if(this.moveLeft) {
|
|
|
|
this.camera.position.x -= right.x * (deltaTime * this.flySpeed);
|
|
this.camera.position.y -= right.y * (deltaTime * this.flySpeed);
|
|
this.camera.position.z -= right.z * (deltaTime * this.flySpeed);
|
|
|
|
} else if(this.moveRight) {
|
|
|
|
this.camera.position.x += right.x * (deltaTime * this.flySpeed);
|
|
this.camera.position.y += right.y * (deltaTime * this.flySpeed);
|
|
this.camera.position.z += right.z * (deltaTime * this.flySpeed);
|
|
}
|
|
|
|
if(this.moveUp) {
|
|
|
|
this.camera.position.y += (deltaTime * this.flySpeed);
|
|
|
|
} else if(this.moveDown) {
|
|
|
|
this.camera.position.y -= (deltaTime * this.flySpeed);
|
|
|
|
}
|
|
};
|
|
|
|
/**
|
|
* This update function should be called from the animation function in order to apply the 'frame rate independent'
|
|
* movement to the camera
|
|
* @param deltaTime
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.update = function(deltaTime) {
|
|
this.applyRotation();
|
|
this.applyTranslation(deltaTime);
|
|
};
|
|
|
|
/**
|
|
* Rotate on mouse move
|
|
* @param event
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.onMouseMove = function ( event ) {
|
|
if (this.canRotate) {
|
|
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
|
|
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
|
|
|
|
this.yaw -= movementX * 0.002;
|
|
this.pitch -= movementY * 0.002;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Keyboard controls
|
|
* @param event
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.onKeyDown = function ( event ) {
|
|
switch ( event.keyCode ) {
|
|
|
|
case 87: // w
|
|
this.moveForward = true;
|
|
break;
|
|
|
|
case 65: // a
|
|
this.moveLeft = true;
|
|
break;
|
|
|
|
case 83: // s
|
|
this.moveBackward = true;
|
|
break;
|
|
|
|
case 68: // d
|
|
this.moveRight = true;
|
|
break;
|
|
|
|
case 104: // keypad up arrow
|
|
this.moveUp = true;
|
|
break;
|
|
|
|
case 98: // keypad down arrow
|
|
this.moveDown = true;
|
|
break;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Keyboard controls
|
|
* @param event
|
|
*/
|
|
GameLib.D3.FlyControls.prototype.onKeyUp = function ( event ) {
|
|
switch ( event.keyCode ) {
|
|
|
|
case 38: // up
|
|
case 87: // w
|
|
this.moveForward = false;
|
|
break;
|
|
|
|
case 37: // left
|
|
case 65: // a
|
|
this.moveLeft = false;
|
|
break;
|
|
|
|
case 40: // down
|
|
case 83: // s
|
|
this.moveBackward = false;
|
|
break;
|
|
|
|
case 39: // right
|
|
case 68: // d
|
|
this.moveRight = false;
|
|
break;
|
|
|
|
case 104: // keypad up arrow
|
|
this.moveUp = false;
|
|
break;
|
|
|
|
case 98: // keypad down arrow
|
|
this.moveDown = false;
|
|
break;
|
|
}
|
|
};
|
|
GameLib.D3.Game = function (
|
|
|
|
) {
|
|
this.scenes = {};
|
|
this.physicsWorlds = [];
|
|
this.sceneToPhysicsWorldsMap = {};
|
|
};
|
|
|
|
GameLib.D3.Game.prototype.AddScene = function(
|
|
scene
|
|
) {
|
|
this.scenes[scene.name] = scene;
|
|
};
|
|
|
|
GameLib.D3.Game.prototype.AddPhysicsWorld = function(
|
|
physicsWorld
|
|
) {
|
|
this.physicsWorlds.push(physicsWorld);
|
|
};
|
|
|
|
GameLib.D3.Game.prototype.LinkPhysicsWorldToScene = function(
|
|
physicsWorld,
|
|
scene
|
|
) {
|
|
this.sceneToPhysicsWorldsMap[scene.name] = this.sceneToPhysicsWorldsMap[scene.name] || [];
|
|
this.sceneToPhysicsWorldsMap[scene.name].push(physicsWorld);
|
|
};
|
|
|
|
GameLib.D3.Game.prototype.GetPhysicsWorldsForScene = function (
|
|
scene
|
|
) {
|
|
return this.sceneToPhysicsWorldsMap[scene.name];
|
|
};
|
|
|
|
GameLib.D3.Game.prototype.ProcessPhysics = function (
|
|
timestep
|
|
) {
|
|
for(var s in this.sceneToPhysicsWorldsMap) {
|
|
|
|
var physicsWorldArray = this.sceneToPhysicsWorldsMap[s];
|
|
var scene = this.scenes[s];
|
|
|
|
if(scene && physicsWorldArray) {
|
|
|
|
for(var i = 0, l = physicsWorldArray.length; i < l; i++) {
|
|
|
|
var physicsWorld = physicsWorldArray[i];
|
|
physicsWorld.Step(timestep);
|
|
|
|
for(var p in physicsWorld.linkedPairs) {
|
|
var pair = physicsWorld.linkedPairs[p];
|
|
var mesh = pair.threeMesh;
|
|
var body = pair.physicsBody;
|
|
|
|
if(mesh) {
|
|
if(physicsWorld.engineType === GameLib.D3.Physics.TYPE_CANNON) {
|
|
|
|
var quaternion = new THREE.Quaternion();
|
|
quaternion.copy(body.rigidBodyInstance.quaternion);
|
|
|
|
var quaternionCopy = quaternion.clone();
|
|
|
|
var position = new THREE.Vector3();
|
|
position.copy(body.rigidBodyInstance.position);
|
|
|
|
if(mesh.permutate) {
|
|
|
|
if(mesh.permutate.offset) {
|
|
if(mesh.permutate.offset.quaternion) {
|
|
var offsetQuaternion = new THREE.Quaternion();
|
|
offsetQuaternion.copy(mesh.permutate.offset.quaternion);
|
|
quaternion = quaternion.multiply(offsetQuaternion).normalize();
|
|
}
|
|
|
|
if(mesh.permutate.offset.position) {
|
|
var offsetPosition = new THREE.Vector3();
|
|
offsetPosition.copy(mesh.permutate.offset.position);
|
|
//position = position.add(offsetPosition);
|
|
position = position.add(offsetPosition.applyQuaternion(quaternionCopy));
|
|
}
|
|
}
|
|
}
|
|
|
|
mesh.position.copy(position);
|
|
mesh.quaternion.copy(quaternion);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
};
|
|
|
|
GameLib.D3.Game.prototype.LinkPair = function (
|
|
threeMesh,
|
|
physicsBody,
|
|
physicsWorld
|
|
) {
|
|
physicsWorld.linkedPairs = physicsWorld.linkedPairs || [];
|
|
|
|
physicsWorld.linkedPairs.push({
|
|
threeMesh : threeMesh,
|
|
physicsBody : physicsBody
|
|
});
|
|
};
|
|
/**
|
|
*
|
|
* @param sizeX Number
|
|
* @param sizeY Number
|
|
* @param matrix matrix 2D Array with height data (Column Major)
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Heightmap = function(
|
|
sizeX,
|
|
sizeY,
|
|
matrix
|
|
) {
|
|
if (typeof sizeX == 'undefined') {
|
|
sizeX = 0;
|
|
}
|
|
this.sizeX = sizeX;
|
|
|
|
if (typeof sizeY == 'undefined') {
|
|
sizeY = 0;
|
|
}
|
|
this.sizeY = sizeY;
|
|
|
|
if (typeof matrix == 'undefined') {
|
|
matrix = [];
|
|
}
|
|
this.matrix = matrix;
|
|
};
|
|
|
|
GameLib.D3.Heightmap.prototype.generateThreeMeshFromHeightField = function(
|
|
THREE,
|
|
heightFieldShape,
|
|
engine
|
|
) {
|
|
var geometry = new THREE.Geometry();
|
|
|
|
var v0 = new this.physics.CANNON.Vec3();
|
|
var v1 = new this.physics.CANNON.Vec3();
|
|
var v2 = new this.physics.CANNON.Vec3();
|
|
|
|
var shape = heightFieldShape;
|
|
for (var xi = 0; xi < shape.data.length - 1; xi++) {
|
|
for (var yi = 0; yi < shape.data[xi].length - 1; yi++) {
|
|
for (var k = 0; k < 2; k++) {
|
|
shape.getConvexTrianglePillar(xi, yi, k===0);
|
|
v0.copy(shape.pillarConvex.vertices[0]);
|
|
v1.copy(shape.pillarConvex.vertices[1]);
|
|
v2.copy(shape.pillarConvex.vertices[2]);
|
|
v0.vadd(shape.pillarOffset, v0);
|
|
v1.vadd(shape.pillarOffset, v1);
|
|
v2.vadd(shape.pillarOffset, v2);
|
|
geometry.vertices.push(
|
|
new THREE.Vector3(v0.x, v0.y, v0.z),
|
|
new THREE.Vector3(v1.x, v1.y, v1.z),
|
|
new THREE.Vector3(v2.x, v2.y, v2.z)
|
|
);
|
|
var i = geometry.vertices.length - 3;
|
|
geometry.faces.push(new THREE.Face3(i, i+1, i+2));
|
|
}
|
|
}
|
|
}
|
|
geometry.computeBoundingSphere();
|
|
geometry.computeFaceNormals();
|
|
|
|
return new THREE.Mesh(geometry, new THREE.MeshNormalMaterial({ wireframe : false, shading : THREE.SmoothShading }));
|
|
};
|
|
|
|
|
|
GameLib.D3.Heightmap.prototype.generateHeightmapDataFromImage = function (
|
|
imagePath,
|
|
callback // receives HeightmapData instance as the first argument
|
|
) {
|
|
var img = new Image();
|
|
|
|
img.onload = function () {
|
|
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = img.width;
|
|
canvas.height = img.height;
|
|
|
|
var context = canvas.getContext('2d');
|
|
context.drawImage(img, 0, 0);
|
|
|
|
var imgd = context.getImageData(0, 0, img.width, img.height);
|
|
var pixels = imgd.data;
|
|
|
|
var heightList = [];
|
|
for (var i = 0, n = pixels.length; i < n; i += (4)) {
|
|
heightList.push(pixels[i]);
|
|
}
|
|
|
|
var matrix = [];
|
|
var sizeX = img.width,
|
|
sizeY = img.height;
|
|
|
|
for (var i = 0; i < sizeX; i++) {
|
|
matrix.push([]);
|
|
for (var j = 0; j < sizeY; j++) {
|
|
var height = (heightList[(sizeX - i) + j * sizeY] / 255) * 15;
|
|
matrix[i].push(height);
|
|
}
|
|
}
|
|
|
|
|
|
// todo: delete canvas here
|
|
|
|
callback(new GameLib.D3.HeightmapData(sizeX, sizeY, matrix));
|
|
};
|
|
|
|
img.src = imagePath;
|
|
};
|
|
/**
|
|
* Image
|
|
* @param id
|
|
* @param textureLink
|
|
* @param filename
|
|
* @param size
|
|
* @param contentType
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Image = function(
|
|
id,
|
|
textureLink,
|
|
filename,
|
|
size,
|
|
contentType
|
|
) {
|
|
this.id = id;
|
|
|
|
this.filename = filename;
|
|
|
|
this.textureLink = textureLink;
|
|
|
|
if (typeof size == 'undefined') {
|
|
size = 0;
|
|
}
|
|
this.size = size;
|
|
|
|
if (typeof contentType == 'undefined') {
|
|
|
|
contentType = 'application/octet-stream';
|
|
|
|
if (this.filename.match(/(png)$/i)) {
|
|
contentType = 'image/png';
|
|
}
|
|
|
|
if (this.filename.match(/(jpg|jpeg)$/i)) {
|
|
contentType = 'image/jpeg';
|
|
}
|
|
|
|
if (this.filename.match(/(gif)$/i)) {
|
|
contentType = 'image/gif';
|
|
}
|
|
}
|
|
this.contentType = contentType;
|
|
};
|
|
/**
|
|
* Light Superset
|
|
* @param id
|
|
* @param lightType
|
|
* @param name
|
|
* @param color
|
|
* @param intensity
|
|
* @param position
|
|
* @param targetPosition
|
|
* @param quaternion
|
|
* @param rotation
|
|
* @param scale
|
|
* @param distance
|
|
* @param decay
|
|
* @param power
|
|
* @param angle
|
|
* @param penumbra
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Light = function(
|
|
id,
|
|
lightType,
|
|
name,
|
|
color,
|
|
intensity,
|
|
position,
|
|
targetPosition,
|
|
quaternion,
|
|
rotation,
|
|
scale,
|
|
distance,
|
|
decay,
|
|
power,
|
|
angle,
|
|
penumbra
|
|
) {
|
|
this.id = id;
|
|
this.lightType = lightType;
|
|
this.name = name;
|
|
this.color = color;
|
|
this.intensity = intensity;
|
|
|
|
if (typeof position == 'undefined') {
|
|
position = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.position = position;
|
|
|
|
if (typeof targetPosition == 'undefined') {
|
|
targetPosition = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.targetPosition = targetPosition;
|
|
|
|
if (typeof quaternion == 'undefined'){
|
|
quaternion = new GameLib.D3.Vector4();
|
|
}
|
|
this.quaternion = quaternion;
|
|
|
|
if (typeof rotation == 'undefined'){
|
|
rotation = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.rotation = rotation;
|
|
|
|
if (typeof scale == 'undefined'){
|
|
scale = new GameLib.D3.Vector3(1,1,1);
|
|
}
|
|
this.scale = scale;
|
|
|
|
if (typeof distance == 'undefined'){
|
|
distance = 0;
|
|
}
|
|
this.distance = distance;
|
|
|
|
if (typeof decay == 'undefined'){
|
|
decay = 1;
|
|
}
|
|
this.decay = decay;
|
|
|
|
if (typeof power == 'undefined'){
|
|
power = 4 * Math.PI;
|
|
}
|
|
this.power = power;
|
|
|
|
if (typeof angle == 'undefined'){
|
|
angle = Math.PI / 3;
|
|
}
|
|
this.angle = angle;
|
|
|
|
if (typeof penumbra == 'undefined'){
|
|
penumbra = 0;
|
|
}
|
|
this.penumbra = penumbra;
|
|
};
|
|
/**
|
|
* Material Superset
|
|
* @param id
|
|
* @param name
|
|
* @param materialType
|
|
* @param opacity
|
|
* @param side
|
|
* @param transparent
|
|
* @param maps
|
|
* @param specular
|
|
* @param lightMapIntensity
|
|
* @param aoMapIntensity
|
|
* @param color
|
|
* @param emissive
|
|
* @param emissiveIntensity
|
|
* @param combine
|
|
* @param shininess
|
|
* @param reflectivity
|
|
* @param refractionRatio
|
|
* @param fog
|
|
* @param wireframe
|
|
* @param wireframeLineWidth
|
|
* @param wireframeLineCap
|
|
* @param wireframeLineJoin
|
|
* @param vertexColors
|
|
* @param skinning
|
|
* @param morphTargets
|
|
* @param morphNormals
|
|
* @param lineWidth
|
|
* @param lineCap
|
|
* @param lineJoin
|
|
* @param dashSize
|
|
* @param gapWidth
|
|
* @param blending
|
|
* @param blendSrc
|
|
* @param blendDst
|
|
* @param blendEquation
|
|
* @param depthTest
|
|
* @param depthFunc
|
|
* @param depthWrite
|
|
* @param polygonOffset
|
|
* @param polygonOffsetFactor
|
|
* @param polygonOffsetUnits
|
|
* @param alphaTest
|
|
* @param clippingPlanes
|
|
* @param clipShadows
|
|
* @param visible
|
|
* @param overdraw
|
|
* @param shading
|
|
* @param bumpScale
|
|
* @param normalScale
|
|
* @param displacementScale
|
|
* @param displacementBias
|
|
* @param roughness
|
|
* @param metalness
|
|
* @param pointSize
|
|
* @param pointSizeAttenuation
|
|
* @param spriteRotation
|
|
* @param envMapIntensity
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Material = function(
|
|
id,
|
|
name,
|
|
materialType,
|
|
opacity,
|
|
side,
|
|
transparent,
|
|
maps,
|
|
specular,
|
|
lightMapIntensity,
|
|
aoMapIntensity,
|
|
color,
|
|
emissive,
|
|
emissiveIntensity,
|
|
combine,
|
|
shininess,
|
|
reflectivity,
|
|
refractionRatio,
|
|
fog,
|
|
wireframe,
|
|
wireframeLineWidth,
|
|
wireframeLineCap,
|
|
wireframeLineJoin,
|
|
vertexColors,
|
|
skinning,
|
|
morphTargets,
|
|
morphNormals,
|
|
lineWidth,
|
|
lineCap,
|
|
lineJoin,
|
|
dashSize,
|
|
gapWidth,
|
|
blending,
|
|
blendSrc,
|
|
blendDst,
|
|
blendEquation,
|
|
depthTest,
|
|
depthFunc,
|
|
depthWrite,
|
|
polygonOffset,
|
|
polygonOffsetFactor,
|
|
polygonOffsetUnits,
|
|
alphaTest,
|
|
clippingPlanes,
|
|
clipShadows,
|
|
visible,
|
|
overdraw,
|
|
shading,
|
|
bumpScale,
|
|
normalScale,
|
|
displacementScale,
|
|
displacementBias,
|
|
roughness,
|
|
metalness,
|
|
pointSize,
|
|
pointSizeAttenuation,
|
|
spriteRotation,
|
|
envMapIntensity
|
|
) {
|
|
this.id = id;
|
|
this.name = name;
|
|
if (typeof materialType == 'undefined') {
|
|
materialType = GameLib.D3.Material.TYPE_MESH_STANDARD;
|
|
}
|
|
this.materialType = materialType;
|
|
|
|
if (typeof opacity == 'undefined') {
|
|
opacity = 1.0;
|
|
}
|
|
this.opacity = opacity;
|
|
|
|
if (typeof side == 'undefined') {
|
|
side = GameLib.D3.Material.TYPE_FRONT_SIDE;
|
|
}
|
|
this.side = side;
|
|
|
|
if (typeof transparent == 'undefined') {
|
|
transparent = false;
|
|
}
|
|
this.transparent = transparent;
|
|
|
|
if (typeof maps == 'undefined') {
|
|
maps = {
|
|
alpha: null,
|
|
ao: null,
|
|
bump: null,
|
|
diffuse: null,
|
|
displacement: null,
|
|
emissive: null,
|
|
environment: null,
|
|
light: null,
|
|
metalness: null,
|
|
normal: null,
|
|
roughness: null,
|
|
specular: null
|
|
};
|
|
}
|
|
this.maps = maps;
|
|
|
|
if (typeof specular == 'undefined') {
|
|
specular = new GameLib.D3.Color(0.06, 0.06, 0.06, 0.06);
|
|
}
|
|
this.specular = specular;
|
|
|
|
if (typeof lightMapIntensity == 'undefined') {
|
|
lightMapIntensity = 1;
|
|
}
|
|
this.lightMapIntensity = lightMapIntensity;
|
|
|
|
if (typeof aoMapIntensity == 'undefined') {
|
|
aoMapIntensity = 1;
|
|
}
|
|
this.aoMapIntensity = aoMapIntensity;
|
|
|
|
if (typeof color == 'undefined') {
|
|
color = new GameLib.D3.Color(1, 1, 1, 1)
|
|
}
|
|
this.color = color;
|
|
|
|
if (typeof emissive == 'undefined') {
|
|
emissive = new GameLib.D3.Color(0, 0, 0, 0);
|
|
}
|
|
this.emissive = emissive;
|
|
|
|
if (typeof emissiveIntensity == 'undefined') {
|
|
emissiveIntensity = 1;
|
|
}
|
|
this.emissiveIntensity = emissiveIntensity;
|
|
|
|
if (typeof combine == 'undefined') {
|
|
combine = GameLib.D3.Material.TYPE_MULTIPLY_OPERATION;
|
|
}
|
|
this.combine = combine;
|
|
|
|
if (typeof shininess == 'undefined') {
|
|
shininess = 30;
|
|
}
|
|
this.shininess = shininess;
|
|
|
|
if (typeof reflectivity == 'undefined') {
|
|
reflectivity = 1;
|
|
}
|
|
this.reflectivity = reflectivity;
|
|
|
|
if (typeof refractionRatio == 'undefined') {
|
|
refractionRatio = 0.98;
|
|
}
|
|
this.refractionRatio = refractionRatio;
|
|
|
|
if (typeof fog == 'undefined') {
|
|
fog = true;
|
|
}
|
|
this.fog = fog;
|
|
|
|
if (typeof wireframe == 'undefined') {
|
|
wireframe = false;
|
|
}
|
|
this.wireframe = wireframe;
|
|
|
|
if (typeof wireframeLineWidth == 'undefined') {
|
|
wireframeLineWidth = 1;
|
|
}
|
|
this.wireframeLineWidth = wireframeLineWidth;
|
|
|
|
if (typeof wireframeLineCap == 'undefined') {
|
|
wireframeLineCap = 'round';
|
|
}
|
|
this.wireframeLineCap = wireframeLineCap;
|
|
|
|
if (typeof wireframeLineJoin == 'undefined') {
|
|
wireframeLineJoin = 'round';
|
|
}
|
|
this.wireframeLineJoin = wireframeLineJoin;
|
|
|
|
if (typeof vertexColors == 'undefined') {
|
|
vertexColors = GameLib.D3.Material.TYPE_NO_COLORS;
|
|
}
|
|
this.vertexColors = vertexColors;
|
|
|
|
if (typeof skinning == 'undefined') {
|
|
skinning = false;
|
|
}
|
|
this.skinning = skinning;
|
|
|
|
if (typeof morphTargets == 'undefined') {
|
|
morphTargets = false;
|
|
}
|
|
this.morphTargets = morphTargets;
|
|
|
|
if (typeof morphNormals == 'undefined') {
|
|
morphNormals = false;
|
|
}
|
|
this.morphNormals = morphNormals;
|
|
|
|
if (typeof overdraw == 'undefined') {
|
|
overdraw = 0;
|
|
}
|
|
this.overdraw = overdraw;
|
|
|
|
if (typeof lineWidth == 'undefined') {
|
|
lineWidth = 1;
|
|
}
|
|
this.lineWidth = lineWidth;
|
|
|
|
if (typeof lineCap == 'undefined') {
|
|
lineCap = 'round';
|
|
}
|
|
this.lineCap = lineCap;
|
|
|
|
if (typeof lineJoin == 'undefined') {
|
|
lineJoin = 'round';
|
|
}
|
|
this.lineJoin = lineJoin;
|
|
|
|
if (typeof dashSize == 'undefined') {
|
|
dashSize = 3;
|
|
}
|
|
this.dashSize = dashSize;
|
|
|
|
if (typeof gapWidth == 'undefined') {
|
|
gapWidth = 1;
|
|
}
|
|
this.gapWidth = gapWidth;
|
|
|
|
if (typeof blending == 'undefined') {
|
|
blending = GameLib.D3.Material.TYPE_NORMAL_BLENDING;
|
|
}
|
|
this.blending = blending;
|
|
|
|
if (typeof blendSrc == 'undefined') {
|
|
blendSrc = GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR;
|
|
}
|
|
this.blendSrc = blendSrc;
|
|
|
|
if (typeof blendDst == 'undefined') {
|
|
blendDst = GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR;
|
|
}
|
|
this.blendDst = blendDst;
|
|
|
|
if (typeof blendEquation == 'undefined') {
|
|
blendEquation = GameLib.D3.Material.TYPE_ADD_EQUATION;
|
|
}
|
|
this.blendEquation = blendEquation;
|
|
|
|
if (typeof depthTest == 'undefined') {
|
|
depthTest = true;
|
|
}
|
|
this.depthTest = depthTest;
|
|
|
|
if (typeof depthFunc == 'undefined') {
|
|
depthFunc = GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH;
|
|
}
|
|
this.depthFunc = depthFunc;
|
|
|
|
if (typeof depthWrite == 'undefined') {
|
|
depthWrite = true;
|
|
}
|
|
this.depthWrite = depthWrite;
|
|
|
|
if (typeof polygonOffset == 'undefined') {
|
|
polygonOffset = false;
|
|
}
|
|
this.polygonOffset = polygonOffset;
|
|
|
|
if (typeof polygonOffsetFactor == 'undefined') {
|
|
polygonOffsetFactor = 1;
|
|
}
|
|
this.polygonOffsetFactor = polygonOffsetFactor;
|
|
|
|
if (typeof polygonOffsetUnits == 'undefined') {
|
|
polygonOffsetUnits = 1;
|
|
}
|
|
this.polygonOffsetUnits = polygonOffsetUnits;
|
|
|
|
if (typeof alphaTest == 'undefined') {
|
|
alphaTest = 0;
|
|
}
|
|
this.alphaTest = alphaTest;
|
|
|
|
if (typeof clippingPlanes == 'undefined') {
|
|
clippingPlanes = [];
|
|
}
|
|
this.clippingPlanes = clippingPlanes;
|
|
|
|
if (typeof clipShadows == 'undefined') {
|
|
clipShadows = false;
|
|
}
|
|
this.clipShadows = clipShadows;
|
|
|
|
if (typeof visible == 'undefined') {
|
|
visible = true;
|
|
}
|
|
this.visible = visible;
|
|
|
|
if (typeof shading == 'undefined') {
|
|
shading = GameLib.D3.Material.TYPE_FLAT_SHADING;
|
|
}
|
|
this.shading = shading;
|
|
|
|
if (typeof bumpScale == 'undefined') {
|
|
bumpScale = 1;
|
|
}
|
|
this.bumpScale = bumpScale;
|
|
|
|
if (typeof normalScale == 'undefined') {
|
|
normalScale = 1;
|
|
}
|
|
this.normalScale = normalScale;
|
|
|
|
if (typeof displacementScale == 'undefined') {
|
|
displacementScale = 1;
|
|
}
|
|
this.displacementScale = displacementScale;
|
|
|
|
if (typeof displacementBias == 'undefined') {
|
|
displacementBias = 0;
|
|
}
|
|
this.displacementBias = displacementBias;
|
|
|
|
if (typeof roughness == 'undefined') {
|
|
roughness = 0.5;
|
|
}
|
|
this.roughness = roughness;
|
|
|
|
if (typeof metalness == 'undefined') {
|
|
metalness = 0.5;
|
|
}
|
|
this.metalness = metalness;
|
|
|
|
if (typeof pointSize == 'undefined') {
|
|
pointSize = 1;
|
|
}
|
|
this.pointSize = pointSize;
|
|
|
|
if (typeof pointSizeAttenuation == 'undefined') {
|
|
pointSizeAttenuation = true;
|
|
}
|
|
this.pointSizeAttenuation = pointSizeAttenuation;
|
|
|
|
if (typeof spriteRotation == 'undefined') {
|
|
spriteRotation = 0;
|
|
}
|
|
this.spriteRotation = spriteRotation;
|
|
|
|
if (typeof envMapIntensity == 'undefined') {
|
|
envMapIntensity = 1.0;
|
|
}
|
|
this.envMapIntensity = envMapIntensity;
|
|
|
|
};
|
|
|
|
/**
|
|
* Combine Method
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_MULTIPLY_OPERATION = 0;
|
|
GameLib.D3.Material.TYPE_MIX_OPERATION = 1;
|
|
GameLib.D3.Material.TYPE_ADD_OPERATION = 2;
|
|
|
|
/**
|
|
* Vertex Color Mode
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_NO_COLORS = 0;
|
|
GameLib.D3.Material.TYPE_FACE_COLORS = 1;
|
|
GameLib.D3.Material.TYPE_VERTEX_COLORS = 2;
|
|
|
|
/**
|
|
* Blending Mode
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_NORMAL_BLENDING = 1;
|
|
GameLib.D3.Material.TYPE_ADDITIVE_BLENDING = 2;
|
|
GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING = 3;
|
|
GameLib.D3.Material.TYPE_MULTIPLY_BLENDING = 4;
|
|
GameLib.D3.Material.TYPE_CUSTOM_BLENDING = 5;
|
|
|
|
/**
|
|
* Blend Source and Destination
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_ZERO_FACTOR = 200;
|
|
GameLib.D3.Material.TYPE_ONE_FACTOR = 201;
|
|
GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR = 202;
|
|
GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR = 203;
|
|
GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR = 204;
|
|
GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR = 205;
|
|
GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR = 206;
|
|
GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR = 207;
|
|
GameLib.D3.Material.TYPE_DST_COLOR_FACTOR = 208;
|
|
GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR = 209;
|
|
GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR = 210;
|
|
|
|
/**
|
|
* Blend Operation
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_ADD_EQUATION = 100;
|
|
GameLib.D3.Material.TYPE_SUBTRACT_EQUATION = 101;
|
|
GameLib.D3.Material.TYPE_REVERSE_SUBTRACT_EQUATION = 102;
|
|
GameLib.D3.Material.TYPE_MIN_EQUATION = 103;
|
|
GameLib.D3.Material.TYPE_MAX_EQUATION = 104;
|
|
|
|
/**
|
|
* Depth Function
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_NEVER_DEPTH = 0;
|
|
GameLib.D3.Material.TYPE_ALWAYS_DEPTH = 1;
|
|
GameLib.D3.Material.TYPE_LESS_DEPTH = 2;
|
|
GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH = 3;
|
|
GameLib.D3.Material.TYPE_EQUAL_DEPTH = 4;
|
|
GameLib.D3.Material.TYPE_GREATER_EQUAL_DEPTH = 5;
|
|
GameLib.D3.Material.TYPE_GREATER_DEPTH = 6;
|
|
GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH = 7;
|
|
|
|
/**
|
|
* Culling Mode
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_FRONT_SIDE = 0;
|
|
GameLib.D3.Material.TYPE_BACK_SIDE = 1;
|
|
GameLib.D3.Material.TYPE_DOUBLE_SIDE = 2;
|
|
|
|
/**
|
|
* Shading Type
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Material.TYPE_FLAT_SHADING = 1;
|
|
GameLib.D3.Material.TYPE_SMOOTH_SHADING = 2;
|
|
|
|
/**
|
|
* Material Type
|
|
* @type {string}
|
|
*/
|
|
GameLib.D3.Material.TYPE_LINE_BASIC = "LineBasicMaterial";
|
|
GameLib.D3.Material.TYPE_LINE_DASHED = "LineDashedMaterial";
|
|
GameLib.D3.Material.TYPE_MESH_BASIC = "MeshBasicMaterial";
|
|
GameLib.D3.Material.TYPE_MESH_DEPTH = "MeshDepthMaterial";
|
|
GameLib.D3.Material.TYPE_MESH_LAMBERT = "MeshLambertMaterial";
|
|
GameLib.D3.Material.TYPE_MESH_NORMAL = "MeshNormalMaterial";
|
|
GameLib.D3.Material.TYPE_MESH_PHONG = "MeshPhongMaterial";
|
|
GameLib.D3.Material.TYPE_MESH_STANDARD = "MeshStandardMaterial";
|
|
GameLib.D3.Material.TYPE_POINTS = "PointsMaterial";
|
|
GameLib.D3.Material.TYPE_SPRITE = "SpriteMaterial";
|
|
GameLib.D3.Material.TYPE_MULTI_MATERIAL= "MultiMaterial";
|
|
|
|
/**
|
|
* Creates a THREE.Material from a GameLib.D3.Material
|
|
* @param blenderMaterial GameLib.D3.Material
|
|
* @param THREE THREE.js
|
|
*/
|
|
GameLib.D3.prototype.createThreeMaterial = function(blenderMaterial, THREE) {
|
|
|
|
var defer = this.Q.defer();
|
|
|
|
var threeMaterial = null;
|
|
|
|
var blenderMaps = [];
|
|
|
|
if (blenderMaterial.materialType == GameLib.D3.Material.TYPE_MESH_STANDARD) {
|
|
|
|
threeMaterial = new THREE.MeshStandardMaterial({
|
|
name: blenderMaterial.name,
|
|
opacity: blenderMaterial.opacity,
|
|
transparent: blenderMaterial.transparent,
|
|
blending: blenderMaterial.blending,
|
|
blendSrc: blenderMaterial.blendSrc,
|
|
blendDst: blenderMaterial.blendDst,
|
|
blendEquation: blenderMaterial.blendEquation,
|
|
depthTest: blenderMaterial.depthTest,
|
|
depthFunc: blenderMaterial.depthFunc,
|
|
depthWrite: blenderMaterial.depthWrite,
|
|
polygonOffset: blenderMaterial.polygonOffset,
|
|
polygonOffsetFactor: blenderMaterial.polygonOffsetFactor,
|
|
polygonOffsetUnits: blenderMaterial.polygonOffsetUnits,
|
|
alphaTest: blenderMaterial.alphaTest,
|
|
clippingPlanes: blenderMaterial.clippingPlanes,
|
|
clipShadows: blenderMaterial.clipShadows,
|
|
overdraw: blenderMaterial.overdraw,
|
|
visible: blenderMaterial.visible,
|
|
side: blenderMaterial.side,
|
|
color: new THREE.Color(
|
|
blenderMaterial.color.r,
|
|
blenderMaterial.color.g,
|
|
blenderMaterial.color.b
|
|
),
|
|
roughness: blenderMaterial.roughness,
|
|
metalness: blenderMaterial.metalness,
|
|
lightMapIntensity: blenderMaterial.lightMapIntensity,
|
|
aoMapIntensity: blenderMaterial.aoMapIntensity,
|
|
emissive: new THREE.Color(
|
|
blenderMaterial.emissive.r,
|
|
blenderMaterial.emissive.g,
|
|
blenderMaterial.emissive.b
|
|
),
|
|
emissiveIntensity: blenderMaterial.emissiveIntensity,
|
|
bumpScale: blenderMaterial.bumpScale,
|
|
normalScale: blenderMaterial.normalScale,
|
|
displacementScale: blenderMaterial.displacementScale,
|
|
refractionRatio: blenderMaterial.refractionRatio,
|
|
fog: blenderMaterial.fog,
|
|
shading: blenderMaterial.shading,
|
|
wireframe: blenderMaterial.wireframe,
|
|
wireframeLinewidth: blenderMaterial.wireframeLineWidth,
|
|
wireframeLinecap: blenderMaterial.wireframeLineCap,
|
|
wireframeLinejoin: blenderMaterial.wireframeLineJoin,
|
|
vertexColors: blenderMaterial.vertexColors,
|
|
skinning: blenderMaterial.skinning,
|
|
morphTargets: blenderMaterial.morphTargets,
|
|
morphNormals: blenderMaterial.morphNormals
|
|
});
|
|
|
|
blenderMaps.push(
|
|
'diffuse',
|
|
'light',
|
|
'ao',
|
|
'emissive',
|
|
'bump',
|
|
'normal',
|
|
'displacement',
|
|
'roughness',
|
|
'metalness',
|
|
'alpha',
|
|
'environment'
|
|
);
|
|
} else if (blenderMaterial.materialType == GameLib.D3.Material.TYPE_MESH_PHONG) {
|
|
|
|
threeMaterial = new THREE.MeshPhongMaterial({
|
|
name: blenderMaterial.name,
|
|
opacity: blenderMaterial.opacity,
|
|
transparent: blenderMaterial.transparent,
|
|
blending: blenderMaterial.blending,
|
|
blendSrc: blenderMaterial.blendSrc,
|
|
blendDst: blenderMaterial.blendDst,
|
|
blendEquation: blenderMaterial.blendEquation,
|
|
depthTest: blenderMaterial.depthTest,
|
|
depthFunc: blenderMaterial.depthFunc,
|
|
depthWrite: blenderMaterial.depthWrite,
|
|
polygonOffset: blenderMaterial.polygonOffset,
|
|
polygonOffsetFactor: blenderMaterial.polygonOffsetFactor,
|
|
polygonOffsetUnits: blenderMaterial.polygonOffsetUnits,
|
|
alphaTest: blenderMaterial.alphaTest,
|
|
clippingPlanes: blenderMaterial.clippingPlanes,
|
|
clipShadows: blenderMaterial.clipShadows,
|
|
overdraw: blenderMaterial.overdraw,
|
|
visible: blenderMaterial.visible,
|
|
side: blenderMaterial.side,
|
|
color: new THREE.Color(
|
|
blenderMaterial.color.r,
|
|
blenderMaterial.color.g,
|
|
blenderMaterial.color.b
|
|
),
|
|
specular: new THREE.Color(
|
|
blenderMaterial.specular.r,
|
|
blenderMaterial.specular.g,
|
|
blenderMaterial.specular.b
|
|
),
|
|
shininess: blenderMaterial.shininess,
|
|
lightMapIntensity: blenderMaterial.lightMapIntensity,
|
|
aoMapIntensity: blenderMaterial.aoMapIntensity,
|
|
emissive: new THREE.Color(
|
|
blenderMaterial.emissive.r,
|
|
blenderMaterial.emissive.g,
|
|
blenderMaterial.emissive.b
|
|
),
|
|
emissiveIntensity: blenderMaterial.emissiveIntensity,
|
|
bumpScale: blenderMaterial.bumpScale,
|
|
normalScale: blenderMaterial.normalScale,
|
|
displacementScale: blenderMaterial.displacementScale,
|
|
combine: blenderMaterial.combine,
|
|
refractionRatio: blenderMaterial.refractionRatio,
|
|
fog: blenderMaterial.fog,
|
|
shading: blenderMaterial.shading,
|
|
wireframe: blenderMaterial.wireframe,
|
|
wireframeLinewidth: blenderMaterial.wireframeLineWidth,
|
|
wireframeLinecap: blenderMaterial.wireframeLineCap,
|
|
wireframeLinejoin: blenderMaterial.wireframeLineJoin,
|
|
vertexColors: blenderMaterial.vertexColors,
|
|
skinning: blenderMaterial.skinning,
|
|
morphTargets: blenderMaterial.morphTargets,
|
|
morphNormals: blenderMaterial.morphNormals
|
|
});
|
|
|
|
blenderMaps.push(
|
|
'diffuse',
|
|
'light',
|
|
'ao',
|
|
'emissive',
|
|
'bump',
|
|
'normal',
|
|
'displacement',
|
|
'specular',
|
|
'alpha',
|
|
'environment'
|
|
);
|
|
|
|
} else {
|
|
console.log("material type is not implemented yet: " + blenderMaterial.materialType + " - material indexes could be screwed up");
|
|
}
|
|
|
|
if (blenderMaps.length > 0) {
|
|
var textureMaps = this.loadMaps(blenderMaterial, blenderMaps, threeMaterial);
|
|
Q.all(textureMaps).then(
|
|
function(){
|
|
defer.resolve(threeMaterial);
|
|
}
|
|
).catch(
|
|
function(error){
|
|
console.log(error);
|
|
defer.reject(error);
|
|
}
|
|
)
|
|
} else {
|
|
defer.resolve(threeMaterial);
|
|
}
|
|
|
|
return defer.promise;
|
|
};
|
|
/**
|
|
* Matrix 3 Maths
|
|
* @param row0 GameLib.D3.Vector3
|
|
* @param row1 GameLib.D3.Vector3
|
|
* @param row2 GameLib.D3.Vector3
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Matrix3 = function(
|
|
row0,
|
|
row1,
|
|
row2
|
|
) {
|
|
this.identity();
|
|
|
|
if (row0) {
|
|
this.rows[0] = row0;
|
|
}
|
|
|
|
if (row1) {
|
|
this.rows[1] = row1;
|
|
}
|
|
|
|
if (row2) {
|
|
this.rows[2] = row2;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Set matrix to identity
|
|
*/
|
|
GameLib.D3.Matrix3.prototype.identity = function () {
|
|
this.rows = [
|
|
new GameLib.D3.Vector4(1, 0, 0),
|
|
new GameLib.D3.Vector4(0, 1, 0),
|
|
new GameLib.D3.Vector4(0, 0, 1)
|
|
];
|
|
};
|
|
GameLib.D3.Matrix4 = function(
|
|
row0,
|
|
row1,
|
|
row2,
|
|
row3
|
|
) {
|
|
|
|
this.identity();
|
|
|
|
if (row0) {
|
|
this.rows[0] = row0;
|
|
}
|
|
|
|
if (row1) {
|
|
this.rows[1] = row1;
|
|
}
|
|
|
|
if (row2) {
|
|
this.rows[2] = row2;
|
|
}
|
|
|
|
if (row3) {
|
|
this.rows[3] = row3;
|
|
}
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.rotationMatrixX = function (radians) {
|
|
this.identity();
|
|
this.rows[1] = new GameLib.D3.Vector4(0, Math.cos(radians), -1 * Math.sin(radians), 0);
|
|
this.rows[2] = new GameLib.D3.Vector4(0, Math.sin(radians), Math.cos(radians), 0);
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.rotationMatrixY = function (radians) {
|
|
this.identity();
|
|
this.rows[0] = new GameLib.D3.Vector4(
|
|
Math.cos(radians),
|
|
0,
|
|
Math.sin(radians),
|
|
0
|
|
);
|
|
this.rows[2] = new GameLib.D3.Vector4(
|
|
-1 * Math.sin(radians),
|
|
0,
|
|
Math.cos(radians),
|
|
0
|
|
);
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.rotationMatrixZ = function (radians) {
|
|
this.identity();
|
|
this.rows[0] = new GameLib.D3.Vector4(Math.cos(radians), -1 * Math.sin(radians), 0, 0);
|
|
this.rows[1] = new GameLib.D3.Vector4(Math.sin(radians), Math.cos(radians), 0, 0);
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.rotateX = function (radians, point) {
|
|
this.identity();
|
|
this.rotationMatrixX(radians);
|
|
return this.multiply(point);
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.rotateY = function (radians, point) {
|
|
this.identity();
|
|
this.rotationMatrixY(radians);
|
|
return this.multiply(point);
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.rotateZ = function (radians, point) {
|
|
this.identity();
|
|
this.rotationMatrixZ(radians);
|
|
return this.multiply(point);
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.multiply = function (mvp) {
|
|
if (mvp instanceof GameLib.D3.Vector4) {
|
|
return new GameLib.D3.Vector4(
|
|
this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z + this.rows[0].w * mvp.w,
|
|
this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z + this.rows[1].w * mvp.w,
|
|
this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z + this.rows[2].w * mvp.w,
|
|
this.rows[3].x * mvp.x + this.rows[3].y * mvp.y + this.rows[3].z * mvp.z + this.rows[3].w * mvp.w
|
|
);
|
|
} else if (mvp instanceof GameLib.D3.Vector3) {
|
|
return new GameLib.D3.Vector3(
|
|
this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z,
|
|
this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z,
|
|
this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z
|
|
);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.identity = function () {
|
|
this.rows = [
|
|
new GameLib.D3.Vector4(1, 0, 0, 0),
|
|
new GameLib.D3.Vector4(0, 1, 0, 0),
|
|
new GameLib.D3.Vector4(0, 0, 1, 0),
|
|
new GameLib.D3.Vector4(0, 0, 0, 1)
|
|
];
|
|
};
|
|
|
|
GameLib.D3.Matrix4.prototype.lookAt = function (position, target, up) {
|
|
|
|
var pv = new GameLib.D3.Vector3(position.x, position.y, position.z);
|
|
|
|
var z = pv.subtract(target).normalize();
|
|
|
|
if (z.squared() === 0) {
|
|
z.z = 1;
|
|
}
|
|
|
|
var x = up.cross(z).normalize();
|
|
|
|
if (x.squared() === 0) {
|
|
z.x += 0.0001;
|
|
x = up.cross(z).normalize();
|
|
}
|
|
|
|
var y = z.cross(x);
|
|
|
|
this.rows[0].x = x.x;
|
|
this.rows[0].y = x.y;
|
|
this.rows[0].z = x.z;
|
|
|
|
this.rows[1].x = y.x;
|
|
this.rows[1].y = y.y;
|
|
this.rows[1].z = y.z;
|
|
|
|
this.rows[2].x = z.x;
|
|
this.rows[2].y = z.y;
|
|
this.rows[2].z = z.z;
|
|
|
|
return this;
|
|
|
|
// te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
|
|
// te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
|
|
// te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
|
|
|
|
|
|
// var matrix4 = new Matrix4();
|
|
//
|
|
// matrix4.rows[0] = side.negative();
|
|
// matrix4.rows[1] = _up;
|
|
// matrix4.rows[2] = forward;
|
|
|
|
//
|
|
// matrix4.setColumn(0, side.negative());
|
|
// matrix4.setColumn(1, _up);
|
|
// matrix4.setColumn(2, forward);
|
|
|
|
//return matrix4;
|
|
|
|
// return new Matrix4(
|
|
// new Vector4(
|
|
// side.x,
|
|
// side.y,
|
|
// side.z,
|
|
// side.negative().dot(position)
|
|
// ),
|
|
// new Vector4(
|
|
// _up.x,
|
|
// _up.y,
|
|
// _up.z,
|
|
// _up.negative().dot(position)
|
|
// ),
|
|
// new Vector4(
|
|
// forward.negative().x,
|
|
// forward.negative().y,
|
|
// forward.negative().z,
|
|
// forward.dot(position)
|
|
// )
|
|
// )
|
|
};
|
|
|
|
/**
|
|
* Mesh Superset
|
|
* @param id
|
|
* @param path
|
|
* @param name
|
|
* @param meshType
|
|
* @param vertices
|
|
* @param faces
|
|
* @param skeleton
|
|
* @param faceVertexUvs
|
|
* @param skinIndices
|
|
* @param skinWeights
|
|
* @param materials
|
|
* @param position
|
|
* @param quaternion
|
|
* @param rotation
|
|
* @param scale
|
|
* @param up
|
|
* @param physics
|
|
* @param parentMeshId
|
|
* @param parentSceneId
|
|
* @param rawData
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Mesh = function(
|
|
id,
|
|
path,
|
|
name,
|
|
meshType,
|
|
vertices,
|
|
faces,
|
|
skeleton,
|
|
faceVertexUvs,
|
|
skinIndices,
|
|
skinWeights,
|
|
materials,
|
|
position,
|
|
quaternion,
|
|
rotation,
|
|
scale,
|
|
up,
|
|
physics,
|
|
parentMeshId,
|
|
parentSceneId,
|
|
rawData
|
|
) {
|
|
this.id = id;
|
|
this.path = path;
|
|
this.name = name;
|
|
this.meshType = meshType;
|
|
this.vertices = vertices;
|
|
this.faces = faces;
|
|
|
|
if (typeof skeleton == 'undefined') {
|
|
skeleton = null;
|
|
}
|
|
this.skeleton = skeleton;
|
|
|
|
if (typeof faceVertexUvs == 'undefined') {
|
|
faceVertexUvs = [];
|
|
}
|
|
this.faceVertexUvs = faceVertexUvs;
|
|
|
|
if (typeof skinIndices == 'undefined') {
|
|
skinIndices = [];
|
|
}
|
|
this.skinIndices = skinIndices;
|
|
|
|
if (typeof skinWeights == 'undefined') {
|
|
skinWeights = [];
|
|
}
|
|
this.skinWeights = skinWeights;
|
|
|
|
if (typeof materials == 'undefined') {
|
|
materials = [];
|
|
}
|
|
this.materials = materials;
|
|
|
|
if (typeof position == 'undefined') {
|
|
position = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.position = position;
|
|
|
|
if (typeof quaternion == 'undefined') {
|
|
new GameLib.D3.Vector4();
|
|
}
|
|
this.quaternion = quaternion;
|
|
|
|
if (typeof rotation == 'undefined') {
|
|
rotation = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.rotation = rotation;
|
|
|
|
if (typeof scale == 'undefined') {
|
|
scale = new GameLib.D3.Vector3(1,1,1);
|
|
}
|
|
this.scale = scale;
|
|
|
|
if (typeof up == 'undefined') {
|
|
up = new GameLib.D3.Vector3(0,1,0);
|
|
}
|
|
this.up = up;
|
|
|
|
this.physics = physics;
|
|
|
|
this.parentMeshId = parentMeshId;
|
|
|
|
this.parentSceneId = parentSceneId;
|
|
|
|
this.rawData = null;// rawData;
|
|
};
|
|
|
|
|
|
/**
|
|
* Mesh Type
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Mesh.TYPE_NORMAL = 0;
|
|
GameLib.D3.Mesh.TYPE_SKINNED = 1;
|
|
|
|
|
|
/**
|
|
* Creates a THREE Mesh from GameLib.D3.Mesh
|
|
* @param gameLibMesh
|
|
* @param threeGeometry
|
|
* @param threeMaterial
|
|
* @returns {*}
|
|
*/
|
|
GameLib.D3.prototype.createThreeMesh = function(gameLibMesh, threeGeometry, threeMaterial) {
|
|
|
|
var threeMesh = null;
|
|
|
|
if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_NORMAL) {
|
|
threeMesh = new this.THREE.Mesh(threeGeometry, threeMaterial);
|
|
}
|
|
|
|
if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_SKINNED) {
|
|
|
|
var bones = gameLibMesh.skeleton.bones;
|
|
|
|
var skinIndices = gameLibMesh.skinIndices;
|
|
|
|
var skinWeights = gameLibMesh.skinWeights;
|
|
|
|
var threeBones = [];
|
|
|
|
for (var bi = 0; bi < bones.length; bi++) {
|
|
|
|
var bone = new this.THREE.Bone();
|
|
|
|
bone.name = bones[bi].name;
|
|
|
|
bone.position.x = bones[bi].position.x;
|
|
bone.position.y = bones[bi].position.y;
|
|
bone.position.z = bones[bi].position.z;
|
|
|
|
bone.rotation.x = bones[bi].rotation.x;
|
|
bone.rotation.y = bones[bi].rotation.y;
|
|
bone.rotation.z = bones[bi].rotation.z;
|
|
|
|
bone.quaternion.x = bones[bi].quaternion.x;
|
|
bone.quaternion.y = bones[bi].quaternion.y;
|
|
bone.quaternion.z = bones[bi].quaternion.z;
|
|
bone.quaternion.w = bones[bi].quaternion.w;
|
|
|
|
bone.scale.x = bones[bi].scale.x;
|
|
bone.scale.y = bones[bi].scale.y;
|
|
bone.scale.z = bones[bi].scale.z;
|
|
|
|
bone.up.x = bones[bi].up.x;
|
|
bone.up.y = bones[bi].up.y;
|
|
bone.up.z = bones[bi].up.z;
|
|
|
|
threeBones.push(bone);
|
|
}
|
|
|
|
/**
|
|
* Setup the bone relationships
|
|
*/
|
|
for (var br = 0; br < bones.length; br++) {
|
|
for (var cbi = 0; cbi < bones[br].childBoneIds.length; cbi++) {
|
|
threeBones[br].add(threeBones[bones[br].childBoneIds[cbi]]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setup bones (indexes)
|
|
*/
|
|
for (var si = 0; si < skinIndices.length; si++) {
|
|
threeGeometry.skinIndices.push(
|
|
new this.THREE.Vector4(
|
|
skinIndices[si].x,
|
|
skinIndices[si].y,
|
|
skinIndices[si].z,
|
|
skinIndices[si].w
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Setup bones (weights)
|
|
*/
|
|
for (var sw = 0; sw < skinWeights.length; sw++) {
|
|
threeGeometry.skinWeights.push(
|
|
new this.THREE.Vector4(
|
|
skinWeights[sw].x,
|
|
skinWeights[sw].y,
|
|
skinWeights[sw].z,
|
|
skinWeights[sw].w
|
|
)
|
|
);
|
|
}
|
|
|
|
threeMesh = new this.THREE.SkinnedMesh(threeGeometry, threeMaterial);
|
|
|
|
var skeleton = new this.THREE.Skeleton(threeBones);
|
|
|
|
skeleton.useVertexTexture = gameLibMesh.skeleton.useVertexTexture;
|
|
|
|
for (var i = 0; i < bones.length; i++) {
|
|
if (bones[i].parentBoneId === null) {
|
|
threeMesh.add(threeBones[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
threeMesh.bind(skeleton);
|
|
|
|
threeMesh.pose();
|
|
|
|
threeMesh.skeleton.skeletonHelper = new this.THREE.SkeletonHelper(threeMesh);
|
|
threeMesh.skeleton.skeletonHelper.material.linewidth = 5;
|
|
}
|
|
|
|
if (threeMesh == null) {
|
|
console.log('cannot handle meshes of type ' + gameLibMesh.meshType + ' yet.');
|
|
}
|
|
|
|
gameLibMesh.threeMeshId = threeMesh.id;
|
|
|
|
return threeMesh;
|
|
};
|
|
|
|
GameLib.D3.prototype.invertWindingOrder = function(triangles) {
|
|
|
|
for (var i = 0; i < triangles.length; i++) {
|
|
var v1 = triangles[i].v1;
|
|
triangles[i].v1 = triangles[i].v2;
|
|
triangles[i].v2 = v1;
|
|
|
|
var backupUV = triangles[i].triangle.v1uv;
|
|
triangles[i].triangle.v1uv = triangles[i].triangle.v2uv;
|
|
triangles[i].triangle.v2uv = backupUV;
|
|
}
|
|
|
|
return triangles;
|
|
};
|
|
|
|
/**
|
|
* This function resets a the winding order of a mesh from a reference point V (the average center of the mesh)
|
|
*/
|
|
GameLib.D3.prototype.resetWindingOrder = function(faces, vertices) {
|
|
|
|
var vertexList = new GameLib.D3.Vector3.Points();
|
|
|
|
for (var v = 0; v < vertices.length; v++) {
|
|
vertexList.add(new GameLib.D3.Vector3(
|
|
vertices[v].position.x,
|
|
vertices[v].position.y,
|
|
vertices[v].position.z
|
|
));
|
|
}
|
|
|
|
var V = vertexList.average();
|
|
|
|
var triangles = [];
|
|
|
|
for (var s = 0; s < faces.length; s += 3) {
|
|
|
|
var v0 = faces[s];
|
|
var v1 = faces[s+1];
|
|
var v2 = faces[s+2];
|
|
|
|
triangles.push(
|
|
{
|
|
v0 : v0,
|
|
v1 : v1,
|
|
v2 : v2,
|
|
edges : [
|
|
{v0: v0, v1: v1},
|
|
{v0: v1, v1: v2},
|
|
{v0: v2, v1: v0}
|
|
],
|
|
winding : 0,
|
|
edgeIndex : -1,
|
|
processed : false
|
|
}
|
|
);
|
|
}
|
|
|
|
for (var i = 0; i < triangles.length; i++) {
|
|
if (
|
|
GameLib.D3.Vector3.clockwise(
|
|
vertices[triangles[i].v0].position,
|
|
vertices[triangles[i].v1].position,
|
|
vertices[triangles[i].v2].position,
|
|
V
|
|
)
|
|
) {
|
|
console.log('clockwise');
|
|
var bv1 = triangles[i].v1;
|
|
triangles[i].v1 = triangles[i].v2;
|
|
triangles[i].v2 = bv1;
|
|
} else {
|
|
console.log('not clockwise');
|
|
}
|
|
}
|
|
|
|
return triangles;
|
|
};
|
|
|
|
/**
|
|
* This function resets the winding order for triangles in faces, given an initial triangle and orientation edge
|
|
* used pseudocode from
|
|
* http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh
|
|
* We need to use a graph traversal algorithm,
|
|
* lets assume we have method that returns neighbor of triangle on given edge
|
|
*
|
|
* neighbor_on_egde( next_tria, edge )
|
|
*
|
|
* to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it
|
|
* processed = set of processed triangles; initial empty
|
|
*
|
|
* while to_process is not empty:
|
|
* next_tria, orientation_edge = to_process.pop()
|
|
* add next_tria in processed
|
|
* if next_tria is not opposite oriented than orientation_edge:
|
|
* change next_tria (ABC) orientation (B<->C)
|
|
* for each edge (AB) in next_tria:
|
|
* neighbor_tria = neighbor_on_egde( next_tria, edge )
|
|
* if neighbor_tria exists and neighbor_tria not in processed:
|
|
* to_process add (neighbor_tria, edge opposite oriented (BA))
|
|
* @param faces GameLib.D3.TriangleFace[]
|
|
* @param orientationEdge GameLib.D3.Vector2
|
|
* @returns {Array}
|
|
*/
|
|
GameLib.D3.fixWindingOrder = function(faces, orientationEdge) {
|
|
|
|
/**
|
|
* Checks if a TriangleFace belonging to a TriangleEdge has already been processed
|
|
* @param processed TriangleEdge[]
|
|
* @param triangle TriangleFace
|
|
* @returns {boolean}
|
|
*/
|
|
function inProcessed(processed, triangle) {
|
|
|
|
for (var i = 0; i < processed.length; i++) {
|
|
if (processed[i].triangle.equals(triangle)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns a neighbouring triangle on a specific edge - preserving the edge orientation
|
|
* @param edge GameLib.D3.Vector2
|
|
* @param faces GameLib.D3.TriangleFace[]
|
|
* @param currentTriangle
|
|
* @returns {*}
|
|
*/
|
|
function neighbourOnEdge(edge, faces, currentTriangle) {
|
|
|
|
for (var i = 0; i < faces.length; i++) {
|
|
if (
|
|
(faces[i].v0 == edge.x && faces[i].v1 == edge.y) ||
|
|
(faces[i].v1 == edge.x && faces[i].v2 == edge.y) ||
|
|
(faces[i].v2 == edge.x && faces[i].v0 == edge.y) ||
|
|
(faces[i].v0 == edge.y && faces[i].v1 == edge.x) ||
|
|
(faces[i].v1 == edge.y && faces[i].v2 == edge.x) ||
|
|
(faces[i].v2 == edge.y && faces[i].v0 == edge.x)
|
|
) {
|
|
|
|
var triangle = new GameLib.D3.TriangleFace(
|
|
faces[i].v0,
|
|
faces[i].v1,
|
|
faces[i].v2,
|
|
faces[i].materialIndex,
|
|
faces[i].v0uv,
|
|
faces[i].v1uv,
|
|
faces[i].v2uv
|
|
);
|
|
|
|
if (triangle.equals(currentTriangle)) {
|
|
continue;
|
|
}
|
|
|
|
return new GameLib.D3.TriangleEdge(
|
|
triangle,
|
|
edge
|
|
);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
var toProcess = [
|
|
new GameLib.D3.TriangleEdge(
|
|
new GameLib.D3.TriangleFace(
|
|
faces[0].v0,
|
|
faces[0].v1,
|
|
faces[0].v2,
|
|
faces[0].materialIndex,
|
|
faces[0].v0uv,
|
|
faces[0].v1uv,
|
|
faces[0].v2uv
|
|
),
|
|
orientationEdge
|
|
)
|
|
];
|
|
|
|
var processed = [];
|
|
|
|
while (toProcess.length > 0) {
|
|
|
|
var triangleEdge = toProcess.pop();
|
|
|
|
/**
|
|
* If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed
|
|
* to have the same winding order)
|
|
*/
|
|
if (
|
|
(triangleEdge.triangle.v0 == triangleEdge.edge.x &&
|
|
triangleEdge.triangle.v1 == triangleEdge.edge.y) ||
|
|
(triangleEdge.triangle.v1 == triangleEdge.edge.x &&
|
|
triangleEdge.triangle.v2 == triangleEdge.edge.y) ||
|
|
(triangleEdge.triangle.v2 == triangleEdge.edge.x &&
|
|
triangleEdge.triangle.v0 == triangleEdge.edge.y)
|
|
) {
|
|
var backupV = triangleEdge.triangle.v1;
|
|
triangleEdge.triangle.v1 = triangleEdge.triangle.v2;
|
|
triangleEdge.triangle.v2 = backupV;
|
|
|
|
var backupUV = triangleEdge.triangle.v1uv;
|
|
triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv;
|
|
triangleEdge.triangle.v2uv = backupUV;
|
|
}
|
|
|
|
processed.push(triangleEdge);
|
|
|
|
var edges = [
|
|
new GameLib.D3.Vector2(
|
|
triangleEdge.triangle.v0,
|
|
triangleEdge.triangle.v1
|
|
),
|
|
new GameLib.D3.Vector2(
|
|
triangleEdge.triangle.v1,
|
|
triangleEdge.triangle.v2
|
|
),
|
|
new GameLib.D3.Vector2(
|
|
triangleEdge.triangle.v2,
|
|
triangleEdge.triangle.v0
|
|
)
|
|
];
|
|
|
|
for (var j = 0; j < edges.length; j++) {
|
|
var neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle);
|
|
if (neighbour && !inProcessed(processed, neighbour.triangle)) {
|
|
toProcess.push(neighbour);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* In processed - we will have some duplicates - only add the unique ones
|
|
* @type {Array}
|
|
*/
|
|
var triangles = [];
|
|
for (var i = 0; i < processed.length; i++) {
|
|
var found = false;
|
|
for (var k = 0; k < triangles.length; k++) {
|
|
if (triangles[k].equals(processed[i].triangle)){
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
triangles.push(processed[i].triangle);
|
|
}
|
|
}
|
|
|
|
return triangles;
|
|
};
|
|
|
|
/**
|
|
* This is a work-around function to fix polys which don't triangulate because
|
|
* they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around
|
|
* Z then Y axis
|
|
* @param verticesFlat []
|
|
* @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY
|
|
* @return []
|
|
*/
|
|
GameLib.D3.fixPolyZPlane = function(verticesFlat, grain) {
|
|
|
|
if ((verticesFlat.length % 3) != 0 && !(verticesFlat.length > 9)) {
|
|
console.log("The vertices are not in the right length : " + verticesFlat.length);
|
|
}
|
|
|
|
var vertices = [];
|
|
|
|
var points = new GameLib.D3.Vector4.Points();
|
|
|
|
for (var i = 0; i < verticesFlat.length; i += 3) {
|
|
points.add(new GameLib.D3.Vector3(
|
|
verticesFlat[i],
|
|
verticesFlat[i + 1],
|
|
verticesFlat[i + 2]
|
|
));
|
|
}
|
|
|
|
points.toOrigin();
|
|
|
|
points.maximizeXDistance(grain);
|
|
|
|
points.maximizeYDistance(grain);
|
|
|
|
for (i = 0; i < points.vectors.length; i++) {
|
|
vertices.push(
|
|
[
|
|
points.vectors[i].x,
|
|
points.vectors[i].y
|
|
]
|
|
);
|
|
}
|
|
|
|
return vertices;
|
|
};
|
|
/**
|
|
* Physics SuperSet Namespace Object
|
|
* @param id
|
|
* @param name
|
|
* @param engine GameLib.D3.Engine
|
|
* @param worlds
|
|
* @returns {{World: World}}
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Physics = function(
|
|
id,
|
|
name,
|
|
engine,
|
|
worlds
|
|
) {
|
|
this.id = id;
|
|
this.name = name;
|
|
this.engine = engine;
|
|
|
|
if (typeof worlds == 'undefined') {
|
|
worlds = [];
|
|
}
|
|
this.worlds = worlds;
|
|
};
|
|
|
|
|
|
/**
|
|
* Solver Types
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Physics.SPLIT_SOLVER = 0x1;
|
|
GameLib.D3.Physics.GS_SOLVER = 0x2;
|
|
/**
|
|
* Contains a Poly vertex data structure
|
|
* @param localIndex
|
|
* @param mvertIndex
|
|
* @param uv GameLib.D3.Vector2
|
|
* @param materialIndex
|
|
* @param edgeIndex
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.PolyVertex = function(
|
|
localIndex,
|
|
mvertIndex,
|
|
uv,
|
|
materialIndex,
|
|
edgeIndex
|
|
) {
|
|
this.localIndex = localIndex;
|
|
this.mvertIndex = mvertIndex;
|
|
this.uv = uv;
|
|
this.materialIndex = materialIndex;
|
|
this.edgeIndex = edgeIndex;
|
|
};
|
|
|
|
/**
|
|
* Clone a PolyVertex
|
|
* @returns {GameLib.D3.PolyVertex}
|
|
*/
|
|
GameLib.D3.PolyVertex.prototype.clone = function() {
|
|
return new GameLib.D3.PolyVertex(
|
|
this.localIndex,
|
|
this.mvertIndex,
|
|
this.uv.copy(),
|
|
this.materialIndex,
|
|
this.edgeIndex
|
|
)
|
|
};
|
|
/**
|
|
* Physics Raycast Vehicle Superset
|
|
* TODO: body + wheels[]
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.RaycastVehicle = function(
|
|
) {
|
|
this.vehicleObject = null;
|
|
};
|
|
|
|
GameLib.D3.RaycastVehicle.prototype.GetWheelInfo = function(
|
|
|
|
) {
|
|
// note: need a way to determine which engine we are currently using
|
|
return this.vehicleObject.wheelInfos;
|
|
};
|
|
|
|
/**
|
|
* Physics Rigid Body Vehicle Superset
|
|
* TODO: body + wheels[]
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.RigidVehicle = function(
|
|
) {
|
|
this.vehicleObject = null;
|
|
};
|
|
|
|
GameLib.D3.RigidVehicle.prototype.GetWheelInfo = function(
|
|
|
|
) {
|
|
// note: need a way to determine which engine we are currently using
|
|
return this.vehicleObject.wheelBodies;
|
|
};
|
|
|
|
/**
|
|
* RigidBody Superset
|
|
* @param mass
|
|
* @param friction
|
|
* @param position
|
|
* @param quaternion
|
|
* @param velocity
|
|
* @param angularVelocity
|
|
* @param linearDamping
|
|
* @param angularDamping
|
|
* @param allowSleep
|
|
* @param sleepSpeedLimit
|
|
* @param sleepTimeLimit
|
|
* @param collisionFilterGroup
|
|
* @param collisionFilterMask
|
|
* @param fixedRotation
|
|
* @param shape
|
|
* @returns {GameLib.D3.Physics.RigidBody}
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.RigidBody = function(
|
|
mass,
|
|
friction,
|
|
position,
|
|
quaternion,
|
|
velocity,
|
|
angularVelocity,
|
|
linearDamping,
|
|
angularDamping,
|
|
allowSleep,
|
|
sleepSpeedLimit,
|
|
sleepTimeLimit,
|
|
collisionFilterGroup,
|
|
collisionFilterMask,
|
|
fixedRotation,
|
|
shape
|
|
) {
|
|
|
|
this.position = position || new GameLib.D3.Vector3();
|
|
this.velocity = velocity || new GameLib.D3.Vector3();
|
|
this.angularVelocity = angularVelocity || new GameLib.D3.Vector3();
|
|
this.quaternion = quaternion || new GameLib.D3.Vector4(0, 0, 0, 1);
|
|
this.mass = typeof mass == "undefined" ? 0 : mass;
|
|
this.friction = typeof friction == "undefined" ? 5 : friction;
|
|
this.linearDamping = typeof linearDamping == "undefined" ? 0.01 : linearDamping;
|
|
this.angularDamping = typeof angularDamping == "undefined" ? 0.01 : angularDamping;
|
|
this.allowSleep = typeof allowSleep == "undefined" ? true : allowSleep;
|
|
this.sleepSpeedLimit = typeof sleepSpeedLimit == "undefined" ? 0.1 : sleepSpeedLimit;
|
|
this.sleepTimeLimit = typeof sleepTimeLimit == "undefined" ? 1.0 : sleepTimeLimit;
|
|
this.collisionFilterGroup = typeof collisionFilterGroup == "undefined" ? 1 : collisionFilterGroup;
|
|
this.collisionFilterMask = typeof collisionFilterMask == "undefined" ? 1 : collisionFilterMask;
|
|
this.fixedRotation = typeof fixedRotation == "undefined" ? false : fixedRotation;
|
|
this.shape = typeof shape == "undefined" ? null : shape;
|
|
|
|
this.rigidBodyInstance = this.createRigidBodyInstance();
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @returns {*}
|
|
*/
|
|
GameLib.D3.RigidBody.prototype.createRigidBodyInstance = function() {
|
|
|
|
var rigidBody = null;
|
|
|
|
// Create the bodyObject
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
rigidBody = new this.physics.CANNON.Body(
|
|
{
|
|
mass: mass,
|
|
friction: friction,
|
|
position: new this.physics.CANNON.Vec3(position.x, position.y, position.z),
|
|
velocity: new this.physics.CANNON.Vec3(velocity.x, velocity.y, velocity.z),
|
|
quaternion: new this.physics.CANNON.Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w),
|
|
angularVelocity: new this.physics.CANNON.Vec3(angularVelocity.x, angularVelocity.y, angularVelocity.z),
|
|
linearDamping: linearDamping,
|
|
angularDamping: angularDamping,
|
|
allowSleep: allowSleep,
|
|
sleepSpeedLimit: sleepSpeedLimit,
|
|
sleepTimeLimit: sleepTimeLimit,
|
|
collisionFilterGroup: collisionFilterGroup,
|
|
collisionFilterMask: collisionFilterMask,
|
|
fixedRotation: fixedRotation,
|
|
shape: shape
|
|
}
|
|
);
|
|
|
|
}
|
|
|
|
return rigidBody;
|
|
};
|
|
|
|
|
|
/**
|
|
* Scenes are objects putting meshes into 'world space'
|
|
* @param id
|
|
* @param path String
|
|
* @param name String
|
|
* @param meshes GameLib.D3.Mesh[]
|
|
* @param quaternion
|
|
* @param position
|
|
* @param rotation
|
|
* @param scale
|
|
* @param parentSceneId
|
|
* @param lights
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Scene = function(
|
|
id,
|
|
path,
|
|
name,
|
|
meshes,
|
|
quaternion,
|
|
position,
|
|
rotation,
|
|
scale,
|
|
parentSceneId,
|
|
lights,
|
|
physics
|
|
) {
|
|
this.id = id;
|
|
this.path = path;
|
|
this.name = name;
|
|
if (this.name.trim() == "") {
|
|
this.name = 'unnamed';
|
|
}
|
|
this.meshes = meshes;
|
|
|
|
if (typeof quaternion == 'undefined') {
|
|
quaternion = new GameLib.D3.Vector4();
|
|
}
|
|
this.quaternion = quaternion;
|
|
|
|
if (typeof position == 'undefined') {
|
|
position = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.position = position;
|
|
|
|
if (typeof rotation == 'undefined') {
|
|
rotation = new GameLib.D3.Vector3(0,0,0);
|
|
}
|
|
this.rotation = rotation;
|
|
|
|
if (typeof scale == 'undefined') {
|
|
scale = new GameLib.D3.Vector3(1,1,1);
|
|
}
|
|
this.scale = scale;
|
|
|
|
if (typeof parentSceneId == 'undefined') {
|
|
parentSceneId = null;
|
|
}
|
|
this.parentSceneId = parentSceneId;
|
|
|
|
if (typeof lights == 'undefined') {
|
|
lights = [];
|
|
}
|
|
this.lights = lights;
|
|
|
|
if (typeof physics == 'undefined') {
|
|
physics = [];
|
|
}
|
|
this.physics = physics;
|
|
};
|
|
|
|
/**
|
|
* Loads a scene directly from the API
|
|
* @param sceneName
|
|
* @param onLoaded callback
|
|
*/
|
|
GameLib.D3.prototype.loadSceneFromApi = function(scene, onLoaded) {
|
|
|
|
/**
|
|
* First check if this is a client or server side request
|
|
*/
|
|
if (typeof XMLHttpRequest == 'undefined') {
|
|
console.warn('implement server side loading from API here');
|
|
return onLoaded(null, new Error('not implemented'));
|
|
}
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open(
|
|
'GET',
|
|
this.apiUrl + '/scene/load' + scene.path + '/' + scene.name
|
|
);
|
|
|
|
xhr.onreadystatechange = function(xhr, gameLibD3) {
|
|
return function() {
|
|
if (xhr.readyState == 4) {
|
|
|
|
var response = JSON.parse(xhr.responseText);
|
|
|
|
if (!response.scene || response.scene.length == 0) {
|
|
return onLoaded(null, null, new Error('Could not load scene'));
|
|
}
|
|
|
|
var scene = response.scene[0];
|
|
|
|
var physics3ds = [];
|
|
|
|
if (scene.physics && scene.physics.length > 0) {
|
|
|
|
for (var p = 0; p < scene.physics.length; p++) {
|
|
|
|
var physics = scene.physics[p];
|
|
|
|
var physics3d = new GameLib.D3.Physics(
|
|
physics.id,
|
|
physics.name,
|
|
physics.engineType,
|
|
gameLibD3.CANNON,
|
|
null,
|
|
null
|
|
);
|
|
|
|
var worlds3d = [];
|
|
|
|
for (var w = 0; w < physics.worlds.length; w++) {
|
|
|
|
var world = physics.worlds[w];
|
|
|
|
var broadphase = world.broadphase;
|
|
|
|
var broadphase3d = new GameLib.D3.Physics.Broadphase(
|
|
broadphase.id,
|
|
broadphase.name,
|
|
broadphase.broadphaseType
|
|
);
|
|
|
|
var solver = world.solver;
|
|
|
|
var solver3d = new GameLib.D3.Physics.Solver(
|
|
solver.id,
|
|
solver.name,
|
|
solver.solverType,
|
|
solver.iterations,
|
|
solver.tolerance
|
|
);
|
|
|
|
var bodies = world.rigidBodies;
|
|
|
|
var bodies3d = [];
|
|
|
|
for (var b = 0; b < bodies.length; b++) {
|
|
|
|
var body = bodies[b];
|
|
|
|
//TODO: add all body properties here
|
|
var body3d = new GameLib.D3.Physics.RigidBody(
|
|
body.id,
|
|
body.name
|
|
);
|
|
|
|
bodies3d.push(body3d);
|
|
}
|
|
|
|
var world3d = new GameLib.D3.Physics.World(
|
|
null,
|
|
world.name,
|
|
physics3d,
|
|
new GameLib.D3.Vector3(
|
|
world.gravity.x,
|
|
world.gravity.y,
|
|
world.gravity.z
|
|
),
|
|
broadphase3d,
|
|
solver3d,
|
|
bodies3d
|
|
);
|
|
|
|
worlds3d.push(world3d);
|
|
}
|
|
|
|
physics3ds.push(physics3d);
|
|
}
|
|
}
|
|
|
|
var lights3d = [];
|
|
|
|
for (var l = 0; l < scene.lights.length; l++) {
|
|
|
|
var light = scene.lights[l];
|
|
|
|
var light3d = new GameLib.D3.Light(
|
|
light.id,
|
|
light.lightType,
|
|
light.name,
|
|
new GameLib.D3.Color(
|
|
light.color.r,
|
|
light.color.g,
|
|
light.color.b,
|
|
light.color.a
|
|
),
|
|
light.intensity,
|
|
new GameLib.D3.Vector3(
|
|
light.position.x,
|
|
light.position.y,
|
|
light.position.z
|
|
),
|
|
new GameLib.D3.Vector3(
|
|
light.targetPosition.x,
|
|
light.targetPosition.y,
|
|
light.targetPosition.z
|
|
),
|
|
new GameLib.D3.Vector4(
|
|
light.quaternion.x,
|
|
light.quaternion.y,
|
|
light.quaternion.z,
|
|
light.quaternion.w
|
|
),
|
|
new GameLib.D3.Vector3(
|
|
light.rotation.x,
|
|
light.rotation.y,
|
|
light.rotation.z
|
|
),
|
|
new GameLib.D3.Vector3(
|
|
light.scale.x,
|
|
light.scale.y,
|
|
light.scale.z
|
|
),
|
|
light.distance,
|
|
light.decay,
|
|
light.power,
|
|
light.angle,
|
|
light.penumbra
|
|
);
|
|
|
|
lights3d.push(light3d);
|
|
};
|
|
|
|
var scene3d = new GameLib.D3.Scene(
|
|
scene._id || scene.id,
|
|
scene.path,
|
|
scene.name,
|
|
scene.meshes,
|
|
new GameLib.D3.Vector4(
|
|
scene.quaternion.x,
|
|
scene.quaternion.y,
|
|
scene.quaternion.z,
|
|
scene.quaternion.w
|
|
),
|
|
new GameLib.D3.Vector3(
|
|
scene.position.x,
|
|
scene.position.y,
|
|
scene.position.z
|
|
),
|
|
new GameLib.D3.Vector3(
|
|
scene.rotation.x,
|
|
scene.rotation.y,
|
|
scene.rotation.z
|
|
),
|
|
new GameLib.D3.Vector3(
|
|
scene.scale.x,
|
|
scene.scale.y,
|
|
scene.scale.z
|
|
),
|
|
scene.parentSceneId,
|
|
lights3d,
|
|
physics3ds
|
|
);
|
|
|
|
gameLibD3.loadScene(scene3d, onLoaded, false);
|
|
}
|
|
}
|
|
}(xhr, this);
|
|
|
|
xhr.send();
|
|
};
|
|
|
|
|
|
/**
|
|
* Loads a GameLib.D3.Scene object into a ThreeJS Scene object
|
|
* @param gameLibScene GameLib.D3.Scene
|
|
* @param onLoaded callback when all meshes have loaded
|
|
* @param computeNormals set to true to compute new face and vertex normals during load
|
|
*/
|
|
GameLib.D3.prototype.loadScene = function(gameLibScene, onLoaded, computeNormals) {
|
|
|
|
console.log("loading scene " + gameLibScene.name);
|
|
|
|
this.path = gameLibScene.path;
|
|
|
|
var meshQ = [];
|
|
|
|
for (var m = 0; m < gameLibScene.meshes.length; m++) {
|
|
|
|
var mesh = gameLibScene.meshes[m];
|
|
|
|
console.log("loading mesh " + mesh.name);
|
|
|
|
var geometry = new this.THREE.Geometry();
|
|
|
|
var vertices = mesh.vertices;
|
|
|
|
var faces = mesh.faces;
|
|
|
|
var faceVertexUvs = mesh.faceVertexUvs;
|
|
|
|
var materials = mesh.materials;
|
|
|
|
/**
|
|
* Setup vertices
|
|
*/
|
|
for (var v = 0; v < vertices.length; v++) {
|
|
geometry.vertices.push(
|
|
new this.THREE.Vector3(
|
|
vertices[v].position.x,
|
|
vertices[v].position.y,
|
|
vertices[v].position.z
|
|
)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Setup faces
|
|
*/
|
|
for (var f = 0; f < faces.length; f++) {
|
|
|
|
var face = new this.THREE.Face3(
|
|
faces[f].v0,
|
|
faces[f].v1,
|
|
faces[f].v2,
|
|
new this.THREE.Vector3(
|
|
faces[f].normal.x,
|
|
faces[f].normal.y,
|
|
faces[f].normal.z
|
|
),
|
|
new this.THREE.Color(
|
|
faces[f].color.r,
|
|
faces[f].color.g,
|
|
faces[f].color.b
|
|
),
|
|
faces[f].materialIndex
|
|
);
|
|
|
|
face.vertexColors = [
|
|
new this.THREE.Color(
|
|
faces[f].vertexColors[0].r,
|
|
faces[f].vertexColors[0].g,
|
|
faces[f].vertexColors[0].b
|
|
),
|
|
new this.THREE.Color(
|
|
faces[f].vertexColors[1].r,
|
|
faces[f].vertexColors[1].g,
|
|
faces[f].vertexColors[1].b
|
|
),
|
|
new this.THREE.Color(
|
|
faces[f].vertexColors[2].r,
|
|
faces[f].vertexColors[2].g,
|
|
faces[f].vertexColors[2].b
|
|
)
|
|
];
|
|
|
|
face.normal = new this.THREE.Vector3(
|
|
faces[f].normal.x,
|
|
faces[f].normal.y,
|
|
faces[f].normal.z
|
|
);
|
|
|
|
face.vertexNormals = [
|
|
new this.THREE.Vector3(
|
|
faces[f].vertexNormals[0].x,
|
|
faces[f].vertexNormals[0].y,
|
|
faces[f].vertexNormals[0].z
|
|
),
|
|
new this.THREE.Vector3(
|
|
faces[f].vertexNormals[1].x,
|
|
faces[f].vertexNormals[1].y,
|
|
faces[f].vertexNormals[1].z
|
|
),
|
|
new this.THREE.Vector3(
|
|
faces[f].vertexNormals[2].x,
|
|
faces[f].vertexNormals[2].y,
|
|
faces[f].vertexNormals[2].z
|
|
)
|
|
];
|
|
|
|
geometry.faces.push(face);
|
|
}
|
|
|
|
geometry.faceVertexUvs = [];
|
|
|
|
/**
|
|
* Setup face UVs
|
|
*/
|
|
for (var fm = 0; fm < faceVertexUvs.length; fm++) {
|
|
|
|
var faceMaterialVertexUvs = faceVertexUvs[fm];
|
|
|
|
geometry.faceVertexUvs[fm] = [];
|
|
|
|
for (var fuv = 0; fuv < faceMaterialVertexUvs.length; fuv++) {
|
|
geometry.faceVertexUvs[fm][fuv] = [];
|
|
geometry.faceVertexUvs[fm][fuv].push(
|
|
new this.THREE.Vector2(
|
|
faceMaterialVertexUvs[fuv][0].x,
|
|
faceMaterialVertexUvs[fuv][0].y
|
|
),
|
|
new this.THREE.Vector2(
|
|
faceMaterialVertexUvs[fuv][1].x,
|
|
faceMaterialVertexUvs[fuv][1].y
|
|
),
|
|
new this.THREE.Vector2(
|
|
faceMaterialVertexUvs[fuv][2].x,
|
|
faceMaterialVertexUvs[fuv][2].y
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Re-calculate normals (if we have to)
|
|
* @type {Array}
|
|
*/
|
|
if (computeNormals) {
|
|
geometry.computeFaceNormals();
|
|
geometry.computeVertexNormals();
|
|
}
|
|
|
|
var threeMaterialLoaders = [];
|
|
|
|
/**
|
|
* Setup materials
|
|
*/
|
|
for (var mi = 0; mi < materials.length; mi++) {
|
|
threeMaterialLoaders.push(this.createThreeMaterial(materials[mi]));
|
|
}
|
|
|
|
var result = this.Q.all(threeMaterialLoaders).then(
|
|
function(gl3d, mesh, geometry) {
|
|
return function(materials) {
|
|
|
|
console.log("loaded material : " + materials[0].name);
|
|
|
|
/**
|
|
* We don't support MultiMaterial atm - it doesn't work with raycasting
|
|
*/
|
|
var material = materials[0];
|
|
|
|
var threeMesh = gl3d.createThreeMesh(mesh, geometry, material);
|
|
threeMesh.name = mesh.name;
|
|
|
|
threeMesh.position.x = mesh.position.x;
|
|
threeMesh.position.y = mesh.position.y;
|
|
threeMesh.position.z = mesh.position.z;
|
|
|
|
threeMesh.rotation.x = mesh.rotation.x;
|
|
threeMesh.rotation.y = mesh.rotation.y;
|
|
threeMesh.rotation.z = mesh.rotation.z;
|
|
|
|
threeMesh.scale.x = mesh.scale.x;
|
|
threeMesh.scale.y = mesh.scale.y;
|
|
threeMesh.scale.z = mesh.scale.z;
|
|
|
|
threeMesh.quaternion.x = mesh.quaternion.x;
|
|
threeMesh.quaternion.y = mesh.quaternion.y;
|
|
threeMesh.quaternion.z = mesh.quaternion.z;
|
|
threeMesh.quaternion.w = mesh.quaternion.w;
|
|
|
|
return threeMesh;
|
|
};
|
|
}(this, mesh, geometry)
|
|
).catch(function(error){
|
|
console.log(error);
|
|
});
|
|
|
|
meshQ.push(result);
|
|
}
|
|
|
|
this.Q.all(meshQ).then(function(threeMeshes){
|
|
console.log("all meshes have loaded");
|
|
if (typeof onLoaded != 'undefined') {
|
|
|
|
var threeLights = [];
|
|
|
|
for (var sli = 0; sli < gameLibScene.lights.length; sli++) {
|
|
|
|
var blenderLight = gameLibScene.lights[sli];
|
|
|
|
var light = null;
|
|
|
|
if (blenderLight.lightType == 'AmbientLight') {
|
|
light = new this.THREE.AmbientLight(blenderLight.color, blenderLight.intensity);
|
|
}
|
|
|
|
if (blenderLight.lightType == 'DirectionalLight') {
|
|
light = new this.THREE.DirectionalLight(blenderLight.color, blenderLight.intensity);
|
|
}
|
|
|
|
if (blenderLight.lightType == 'PointLight') {
|
|
light = new this.THREE.PointLight(blenderLight.color, blenderLight.intensity);
|
|
light.distance = blenderLight.distance;
|
|
light.decay = blenderLight.decay;
|
|
}
|
|
|
|
if (blenderLight.lightType == 'SpotLight') {
|
|
light = new this.THREE.SpotLight(blenderLight.color, blenderLight.intensity);
|
|
light.distance = blenderLight.distance;
|
|
light.angle = blenderLight.angle;
|
|
light.penumbra = blenderLight.penumbra;
|
|
light.decay = blenderLight.decay;
|
|
}
|
|
|
|
light.position.x = blenderLight.position.x;
|
|
light.position.y = blenderLight.position.y;
|
|
light.position.z = blenderLight.position.z;
|
|
|
|
light.rotation.x = blenderLight.rotation.x;
|
|
light.rotation.y = blenderLight.rotation.y;
|
|
light.rotation.z = blenderLight.rotation.z;
|
|
|
|
// light.scale.x = blenderLight.scale.x;
|
|
// light.scale.y = blenderLight.scale.y;
|
|
// light.scale.z = blenderLight.scale.z;
|
|
|
|
if (light == null) {
|
|
console.warn('Does not support lights of type :' + blenderLight.lightType + ', not imported');
|
|
} else {
|
|
light.name = blenderLight.name;
|
|
threeLights.push(light);
|
|
}
|
|
}
|
|
|
|
var threeScene = new this.THREE.Scene();
|
|
|
|
threeScene.name = gameLibScene.name;
|
|
|
|
threeScene.position.x = gameLibScene.position.x;
|
|
threeScene.position.y = gameLibScene.position.y;
|
|
threeScene.position.z = gameLibScene.position.z;
|
|
|
|
threeScene.rotation.x = gameLibScene.rotation.x;
|
|
threeScene.rotation.y = gameLibScene.rotation.y;
|
|
threeScene.rotation.z = gameLibScene.rotation.z;
|
|
|
|
threeScene.scale.x = gameLibScene.scale.x;
|
|
threeScene.scale.y = gameLibScene.scale.y;
|
|
threeScene.scale.z = gameLibScene.scale.z;
|
|
|
|
threeScene.quaternion.x = gameLibScene.quaternion.x;
|
|
threeScene.quaternion.y = gameLibScene.quaternion.y;
|
|
threeScene.quaternion.z = gameLibScene.quaternion.z;
|
|
threeScene.quaternion.w = gameLibScene.quaternion.w;
|
|
|
|
for (var m = 0; m < threeMeshes.length; m++) {
|
|
threeScene.add(threeMeshes[m]);
|
|
}
|
|
|
|
for (var l = 0; l < threeLights.length; l++) {
|
|
threeScene.add(threeLights[l]);
|
|
}
|
|
|
|
onLoaded(
|
|
gameLibScene,
|
|
{
|
|
scene: threeScene,
|
|
lights: threeLights,
|
|
meshes: threeMeshes
|
|
}
|
|
);
|
|
}
|
|
}.bind(this)).catch(function(error){
|
|
console.log(error);
|
|
});
|
|
};
|
|
/**
|
|
* Physics Shape Superset
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Physics.Shape = function(
|
|
shapeObject, // Physics engine specific
|
|
shapeType
|
|
) {
|
|
this.shapeObject = shapeObject;
|
|
this.shapeType = shapeType;
|
|
this.scale = new GameLib.D3.Vector3(1, 1, 1);
|
|
};
|
|
|
|
GameLib.D3.Physics.SHAPE_TYPE_SPHERE = 1;
|
|
GameLib.D3.Physics.SHAPE_TYPE_BOX = 2;
|
|
GameLib.D3.Physics.SHAPE_TYPE_TRIMESH = 3;
|
|
GameLib.D3.Physics.SHAPE_TYPE_CYLINDER = 4;
|
|
|
|
|
|
GameLib.D3.Physics.Shape.prototype.Update = function() {
|
|
if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
|
|
if(this.shapeType === GameLib.D3.Physics.SHAPE_TYPE_TRIMESH) {
|
|
this.shapeObject.setScale(
|
|
new this.physics.CANNON.Vec3(
|
|
this.scale.x,
|
|
this.scale.y,
|
|
this.scale.z
|
|
)
|
|
);
|
|
this.shapeObject.updateAABB();
|
|
this.shapeObject.updateNormals();
|
|
this.shapeObject.updateEdges();
|
|
this.shapeObject.updateBoundingSphereRadius();
|
|
this.shapeObject.updateTree();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Skeleton Superset
|
|
* @param id
|
|
* @param bones GameLib.D3.Bone
|
|
* @param boneInverses
|
|
* @param useVertexTexture
|
|
* @param boneTextureWidth
|
|
* @param boneTextureHeight
|
|
* @param boneMatrices
|
|
* @param boneTexture
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Skeleton = function(
|
|
id,
|
|
bones,
|
|
boneInverses,
|
|
useVertexTexture,
|
|
boneTextureWidth,
|
|
boneTextureHeight,
|
|
boneMatrices,
|
|
boneTexture
|
|
) {
|
|
this.id = id;
|
|
|
|
this.bones = bones;
|
|
|
|
/**
|
|
* An array of Matrix4s that represent the inverse of the matrixWorld of the individual bones.
|
|
* @type GameLib.D3.Matrix4[]
|
|
*/
|
|
if (typeof boneInverses == 'undefined') {
|
|
boneInverses = [];
|
|
}
|
|
this.boneInverses = boneInverses;
|
|
|
|
/**
|
|
* Use a vertex texture in the shader - allows for more than 4 bones per vertex, not supported by all devices
|
|
* @type {boolean}
|
|
*/
|
|
if (typeof useVertexTexture == 'undefined') {
|
|
useVertexTexture = false;
|
|
}
|
|
this.useVertexTexture = useVertexTexture;
|
|
|
|
if (this.useVertexTexture == true) {
|
|
console.warn('support for vertex texture bones is not supported yet - something could break somewhere');
|
|
}
|
|
|
|
if (typeof boneTextureWidth == 'undefined') {
|
|
boneTextureWidth = 0;
|
|
}
|
|
this.boneTextureWidth = boneTextureWidth;
|
|
|
|
if (typeof boneTextureHeight == 'undefined') {
|
|
boneTextureHeight = 0;
|
|
}
|
|
this.boneTextureHeight = boneTextureHeight;
|
|
|
|
if (typeof boneMatrices == 'undefined') {
|
|
boneMatrices = [];
|
|
}
|
|
this.boneMatrices = boneMatrices;
|
|
|
|
if (typeof boneTexture == 'undefined') {
|
|
boneTexture = [];
|
|
}
|
|
this.boneTexture = boneTexture;
|
|
};
|
|
|
|
|
|
GameLib.D3.SkyBox = function (
|
|
|
|
) {
|
|
this.id = null;
|
|
this.texturesFolder = null;
|
|
};
|
|
|
|
GameLib.D3.SkyBox.prototype.Load = function (
|
|
texturesFolder
|
|
) {
|
|
this.texturesFolder = texturesFolder;
|
|
this.textures = [];
|
|
this.materials = [];
|
|
this.mesh = {};
|
|
this.scene = new THREE.Scene();
|
|
this.textureCube = null;
|
|
|
|
var textureLoader = new THREE.TextureLoader();
|
|
|
|
// this textures are used to display the skybox
|
|
this.textures.push(textureLoader.load(this.texturesFolder + "px.png"));
|
|
this.textures.push(textureLoader.load(this.texturesFolder + "nx.png"));
|
|
this.textures.push(textureLoader.load(this.texturesFolder + "py.png"));
|
|
this.textures.push(textureLoader.load(this.texturesFolder + "ny.png"));
|
|
this.textures.push(textureLoader.load(this.texturesFolder + "pz.png"));
|
|
this.textures.push(textureLoader.load(this.texturesFolder + "nz.png"));
|
|
|
|
// assign textures to each cube face
|
|
for (var i = 0; i < 6; i ++) {
|
|
this.materials.push(new THREE.MeshBasicMaterial({ map: this.textures[i] }));
|
|
}
|
|
|
|
// create cube geometry
|
|
this.mesh = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE.MeshFaceMaterial(this.materials));
|
|
this.mesh.applyMatrix(new THREE.Matrix4().makeScale(1, 1, -1));
|
|
this.scene.add(this.mesh);
|
|
|
|
// Load env textureCube
|
|
// this is used for reflections on meshes
|
|
// mesh.material.envMap = this.textureCube;
|
|
this.textureCube = new THREE.CubeTextureLoader().load([
|
|
this.texturesFolder + "px.png", this.texturesFolder + "nx.png",
|
|
this.texturesFolder + "py.png", this.texturesFolder + "ny.png",
|
|
this.texturesFolder + "pz.png", this.texturesFolder + "nz.png"
|
|
]);
|
|
};
|
|
|
|
GameLib.D3.SkyBox.prototype.Render = function (
|
|
threeRenderer,
|
|
threeCamera
|
|
) {
|
|
var cameraPosition = new THREE.Vector3(threeCamera.position.x, threeCamera.position.y, threeCamera.position.z);
|
|
|
|
threeCamera.position.set(0, 0, 0);
|
|
|
|
var gl = threeRenderer.context;
|
|
|
|
gl.disable(gl.DEPTH_TEST);
|
|
|
|
threeRenderer.render(this.scene, threeCamera);
|
|
|
|
gl.enable(gl.DEPTH_TEST);
|
|
|
|
threeCamera.position.copy(cameraPosition);
|
|
};
|
|
|
|
/**
|
|
* Physics Solver Superset
|
|
* @param id
|
|
* @param name
|
|
* @param solverType
|
|
* @param iterations
|
|
* @param tolerance
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Physics.Solver = function(
|
|
id,
|
|
name,
|
|
solverType,
|
|
iterations,
|
|
tolerance
|
|
) {
|
|
this.id = id;
|
|
if (typeof name == 'undefined') {
|
|
if (solverType == GameLib.D3.Physics.SPLIT_SOLVER) {
|
|
name = 'split solver';
|
|
} else if (solverType == GameLib.D3.Physics.GS_SOLVER) {
|
|
name = 'gs solver';
|
|
} else {
|
|
name = 'unknown solver';
|
|
}
|
|
}
|
|
this.name = name;
|
|
this.solverType = solverType;
|
|
this.iterations = iterations;
|
|
this.tolerance = tolerance;
|
|
};
|
|
|
|
/**
|
|
* Solver Types
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Physics.SPLIT_SOLVER = 0x1;
|
|
GameLib.D3.Physics.GS_SOLVER = 0x2;
|
|
|
|
/**
|
|
* Texture Superset
|
|
* @param id
|
|
* @param name
|
|
* @param image
|
|
* @param wrapS
|
|
* @param wrapT
|
|
* @param repeat
|
|
* @param data
|
|
* @param format
|
|
* @param mapping
|
|
* @param magFilter
|
|
* @param minFilter
|
|
* @param textureType
|
|
* @param anisotropy
|
|
* @param offset
|
|
* @param generateMipmaps
|
|
* @param flipY
|
|
* @param mipmaps
|
|
* @param unpackAlignment
|
|
* @param premultiplyAlpha
|
|
* @param encoding
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Texture = function(
|
|
id,
|
|
name,
|
|
image,
|
|
wrapS,
|
|
wrapT,
|
|
repeat,
|
|
data,
|
|
format,
|
|
mapping,
|
|
magFilter,
|
|
minFilter,
|
|
textureType,
|
|
anisotropy,
|
|
offset,
|
|
generateMipmaps,
|
|
flipY,
|
|
mipmaps,
|
|
unpackAlignment,
|
|
premultiplyAlpha,
|
|
encoding
|
|
) {
|
|
this.id = id;
|
|
this.name = name;
|
|
this.image = image;
|
|
|
|
if (typeof wrapS == 'undefined') {
|
|
wrapS = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING;
|
|
}
|
|
this.wrapS = wrapS;
|
|
|
|
if (typeof wrapT == 'undefined') {
|
|
wrapT = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING;
|
|
}
|
|
this.wrapT = wrapT;
|
|
|
|
if (typeof repeat == 'undefined') {
|
|
repeat = new GameLib.D3.Vector2(1, 1);
|
|
}
|
|
this.repeat = repeat;
|
|
|
|
if (typeof data == 'undefined') {
|
|
data = null;
|
|
}
|
|
this.data = data;
|
|
|
|
if (typeof format == 'undefined') {
|
|
format = GameLib.D3.Texture.TYPE_RGBA_FORMAT;
|
|
}
|
|
this.format = format;
|
|
|
|
if (typeof mapping == 'undefined') {
|
|
mapping = GameLib.D3.Texture.TYPE_UV_MAPPING;
|
|
}
|
|
this.mapping = mapping;
|
|
|
|
if (typeof magFilter == 'undefined') {
|
|
magFilter = GameLib.D3.Texture.TYPE_LINEAR_FILTER;
|
|
}
|
|
this.magFilter = magFilter;
|
|
|
|
if (typeof minFilter == 'undefined') {
|
|
minFilter = GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER;
|
|
}
|
|
this.minFilter = minFilter;
|
|
|
|
if (typeof textureType == 'undefined') {
|
|
textureType = GameLib.D3.Texture.TYPE_UNSIGNED_BYTE;
|
|
}
|
|
this.textureType = textureType;
|
|
|
|
if (typeof anisotropy == 'undefined') {
|
|
anisotropy = 1;
|
|
}
|
|
this.anisotropy = anisotropy;
|
|
|
|
if (typeof offset == 'undefined') {
|
|
offset = new GameLib.D3.Vector2(0, 0);
|
|
}
|
|
this.offset = offset;
|
|
|
|
if (typeof generateMipmaps == 'undefined') {
|
|
generateMipmaps = true;
|
|
}
|
|
this.generateMipmaps = generateMipmaps;
|
|
|
|
if (typeof flipY == 'undefined') {
|
|
flipY = true;
|
|
}
|
|
this.flipY = flipY;
|
|
|
|
if (typeof mipmaps == 'undefined') {
|
|
mipmaps = [];
|
|
}
|
|
this.mipmaps = mipmaps;
|
|
|
|
if (typeof unpackAlignment == 'undefined') {
|
|
unpackAlignment = 4;
|
|
}
|
|
this.unpackAlignment = unpackAlignment;
|
|
|
|
if (typeof premultiplyAlpha == 'undefined') {
|
|
premultiplyAlpha = false;
|
|
}
|
|
this.premultiplyAlpha = premultiplyAlpha;
|
|
|
|
if (typeof encoding == 'undefined') {
|
|
encoding = GameLib.D3.Texture.TYPE_LINEAR_ENCODING;
|
|
}
|
|
this.encoding = encoding;
|
|
};
|
|
|
|
/**
|
|
* Texture Formats
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Texture.TYPE_ALPHA_FORMAT = 1019;
|
|
GameLib.D3.Texture.TYPE_RGB_FORMAT = 1020;
|
|
GameLib.D3.Texture.TYPE_RGBA_FORMAT = 1021;
|
|
GameLib.D3.Texture.TYPE_LUMINANCE_FORMAT = 1022;
|
|
GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT = 1023;
|
|
GameLib.D3.Texture.TYPE_DEPTH_FORMAT = 1026;
|
|
|
|
/**
|
|
* Mapping modes
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Texture.TYPE_UV_MAPPING = 300;
|
|
GameLib.D3.Texture.TYPE_CUBE_REFLECTION_MAPPING = 301;
|
|
GameLib.D3.Texture.TYPE_CUBE_REFRACTION_MAPPING = 302;
|
|
GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING = 303;
|
|
GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING = 304;
|
|
GameLib.D3.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING = 305;
|
|
GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING = 306;
|
|
GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING = 307;
|
|
|
|
/**
|
|
* Wrapping Modes
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Texture.TYPE_REPEAT_WRAPPING = 1000;
|
|
GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING = 1001;
|
|
GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING = 1002;
|
|
|
|
/**
|
|
* Mipmap Filters
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Texture.TYPE_NEAREST_FILTER = 1003;
|
|
GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER = 1004;
|
|
GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER = 1005;
|
|
GameLib.D3.Texture.TYPE_LINEAR_FILTER = 1006;
|
|
GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER = 1007;
|
|
GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER = 1008;
|
|
|
|
/**
|
|
* Texture Data Types
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Texture.TYPE_UNSIGNED_BYTE = 1009;
|
|
GameLib.D3.Texture.TYPE_BYTE = 1010;
|
|
GameLib.D3.Texture.TYPE_SHORT = 1011;
|
|
GameLib.D3.Texture.TYPE_UNSIGNED_SHORT = 1012;
|
|
GameLib.D3.Texture.TYPE_INT = 1013;
|
|
GameLib.D3.Texture.TYPE_UNSIGNED_INT = 1014;
|
|
GameLib.D3.Texture.TYPE_FLOAT = 1015;
|
|
GameLib.D3.Texture.TYPE_HALF_FLOAT = 1025;
|
|
|
|
/**
|
|
* Encoding Modes
|
|
* @type {number}
|
|
*/
|
|
GameLib.D3.Texture.TYPE_LINEAR_ENCODING = 3000; // NO ENCODING AT ALL.
|
|
GameLib.D3.Texture.TYPE_SRGB_ENCODING = 3001;
|
|
GameLib.D3.Texture.TYPE_GAMMA_ENCODING = 3007; // USES GAMMA_FACTOR, FOR BACKWARDS COMPATIBILITY WITH WEBGLRENDERER.GAMMAINPUT/GAMMAOUTPUT
|
|
GameLib.D3.Texture.TYPE_RGBE_ENCODING = 3002; // AKA RADIANCE.
|
|
GameLib.D3.Texture.TYPE_LOG_LUV_ENCODING = 3003;
|
|
GameLib.D3.Texture.TYPE_RGBM7_ENCODING = 3004;
|
|
GameLib.D3.Texture.TYPE_RGBM16_ENCODING = 3005;
|
|
GameLib.D3.Texture.TYPE_RGBD_ENCODING = 3006; // MAXRANGE IS 256.
|
|
|
|
|
|
|
|
/**
|
|
* Defers loading of an image and resolves once image is loaded
|
|
* @param gameLibTexture
|
|
* @param threeMaterial
|
|
* @param threeMaterialMapType
|
|
* @returns {Promise}
|
|
*/
|
|
GameLib.D3.prototype.loadMap = function(gameLibTexture, threeMaterial, threeMaterialMapType) {
|
|
|
|
var q = this.Q.defer();
|
|
|
|
var imagePath = null;
|
|
|
|
if (gameLibTexture && gameLibTexture.image && gameLibTexture.image.filename) {
|
|
/**
|
|
* Else, load from upload source
|
|
*/
|
|
imagePath = this.editorUrl + '/uploads' + this.path + '/' + gameLibTexture.image.filename;
|
|
}
|
|
|
|
if (imagePath) {
|
|
|
|
this.textureLoader.crossOrigin = '';
|
|
|
|
this.textureLoader.load(
|
|
imagePath,
|
|
function(texture) {
|
|
/**
|
|
* onLoad
|
|
*/
|
|
threeMaterial[threeMaterialMapType] = texture;
|
|
threeMaterial[threeMaterialMapType].name = gameLibTexture.name;
|
|
threeMaterial[threeMaterialMapType].anisotropy = gameLibTexture.anisotropy;
|
|
threeMaterial[threeMaterialMapType].encoding = gameLibTexture.encoding;
|
|
threeMaterial[threeMaterialMapType].flipY = gameLibTexture.flipY;
|
|
/**
|
|
* We don't restore the format since this changing from OS to OS and breaks the implementation sometimes
|
|
*/
|
|
threeMaterial[threeMaterialMapType].generateMipmaps = gameLibTexture.generateMipmaps;
|
|
threeMaterial[threeMaterialMapType].magFilter = gameLibTexture.magFilter;
|
|
threeMaterial[threeMaterialMapType].minFilter = gameLibTexture.minFilter;
|
|
threeMaterial[threeMaterialMapType].mapping = gameLibTexture.mapping;
|
|
threeMaterial[threeMaterialMapType].mipmaps = gameLibTexture.mipmaps;
|
|
threeMaterial[threeMaterialMapType].offset = new this.THREE.Vector2(
|
|
gameLibTexture.offset.x,
|
|
gameLibTexture.offset.y
|
|
);
|
|
threeMaterial[threeMaterialMapType].premultiplyAlpha = gameLibTexture.premultiplyAlpha;
|
|
threeMaterial[threeMaterialMapType].textureType = gameLibTexture.textureType;
|
|
threeMaterial[threeMaterialMapType].wrapS = gameLibTexture.wrapS;
|
|
threeMaterial[threeMaterialMapType].wrapT = gameLibTexture.wrapT;
|
|
threeMaterial[threeMaterialMapType].unpackAlignment = gameLibTexture.unpackAlignment;
|
|
threeMaterial.needsUpdate = true;
|
|
q.resolve(true);
|
|
},
|
|
function(xhr) {
|
|
/**
|
|
* onProgress
|
|
*/
|
|
if (this.editor) {
|
|
this.editor.setServerStatus(Math.round(xhr.loaded / xhr.total * 100) + '% complete', 'success');
|
|
}
|
|
},
|
|
function(error) {
|
|
/**
|
|
* onError
|
|
*/
|
|
console.log("an error occurred while trying to load the image : " + imagePath);
|
|
q.resolve(null);
|
|
}
|
|
);
|
|
|
|
} else {
|
|
q.resolve(null);
|
|
}
|
|
|
|
return q.promise;
|
|
};
|
|
|
|
|
|
/**
|
|
* Returns an array of image loading Promises
|
|
* @param blenderMaterial
|
|
* @param blenderMaps
|
|
* @param threeMaterial
|
|
* @returns Q[]
|
|
*/
|
|
GameLib.D3.prototype.loadMaps = function(blenderMaterial, blenderMaps, threeMaterial) {
|
|
|
|
var textureMaps = [];
|
|
|
|
for (var ti = 0; ti < blenderMaps.length; ti++) {
|
|
|
|
var map = blenderMaps[ti];
|
|
|
|
if (blenderMaterial.maps.hasOwnProperty(map)) {
|
|
|
|
var blenderTexture = blenderMaterial.maps[map];
|
|
|
|
if (
|
|
blenderTexture &&
|
|
blenderTexture.image &&
|
|
blenderTexture.image.filename
|
|
) {
|
|
|
|
var threeMap = null;
|
|
|
|
if (map == 'alpha') {
|
|
threeMap = 'alhpaMap';
|
|
}
|
|
|
|
if (map == 'ao') {
|
|
threeMap = 'aoMap';
|
|
}
|
|
|
|
if (map == 'bump') {
|
|
threeMap = 'bumpMap';
|
|
}
|
|
|
|
if (map == 'displacement') {
|
|
threeMap = 'displacementMap';
|
|
}
|
|
|
|
if (map == 'emissive') {
|
|
threeMap = 'emissiveMap';
|
|
}
|
|
|
|
if (map == 'environment') {
|
|
threeMap = 'envMap';
|
|
}
|
|
|
|
if (map == 'light') {
|
|
threeMap = 'lightMap';
|
|
}
|
|
|
|
if (map == 'specular') {
|
|
threeMap = 'specularMap';
|
|
}
|
|
|
|
if (map == 'diffuse') {
|
|
threeMap = 'map';
|
|
}
|
|
|
|
if (map == 'roughness') {
|
|
threeMap = 'roughnessMap';
|
|
}
|
|
|
|
if (map == 'metalness') {
|
|
threeMap = 'metalnessMap';
|
|
}
|
|
|
|
if (threeMap == null) {
|
|
console.warn("unsupported map type : " + map);
|
|
}
|
|
|
|
textureMaps.push(this.loadMap(blenderMaterial.maps[map], threeMaterial, threeMap));
|
|
}
|
|
}
|
|
}
|
|
|
|
return textureMaps;
|
|
};
|
|
|
|
/**
|
|
* TriangleEdge
|
|
* @param triangle
|
|
* @param edge
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.TriangleEdge = function(
|
|
triangle,
|
|
edge
|
|
) {
|
|
this.triangle = triangle;
|
|
this.edge = edge;
|
|
};
|
|
/**
|
|
* TriangleFace
|
|
* @param v0
|
|
* @param v1
|
|
* @param v2
|
|
* @param materialIndex
|
|
* @param v0uv
|
|
* @param v1uv
|
|
* @param v2uv
|
|
* @param color
|
|
* @param vertexColors
|
|
* @param vertexNormals
|
|
* @param normal
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.TriangleFace = function(
|
|
v0,
|
|
v1,
|
|
v2,
|
|
materialIndex,
|
|
v0uv,
|
|
v1uv,
|
|
v2uv,
|
|
color,
|
|
vertexColors,
|
|
vertexNormals,
|
|
normal
|
|
) {
|
|
this.v0 = v0;
|
|
this.v1 = v1;
|
|
this.v2 = v2;
|
|
this.materialIndex = materialIndex;
|
|
this.v0uv = v0uv;
|
|
this.v1uv = v1uv;
|
|
this.v2uv = v2uv;
|
|
if (!color) {
|
|
color = new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff);
|
|
}
|
|
this.color = color;
|
|
|
|
if (!vertexColors) {
|
|
vertexColors = [
|
|
new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff),
|
|
new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff),
|
|
new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff)
|
|
];
|
|
}
|
|
this.vertexColors = vertexColors;
|
|
|
|
if (!vertexNormals) {
|
|
vertexNormals = [
|
|
new GameLib.D3.Vector3(),
|
|
new GameLib.D3.Vector3(),
|
|
new GameLib.D3.Vector3()
|
|
]
|
|
}
|
|
this.vertexNormals = vertexNormals;
|
|
|
|
if (!normal) {
|
|
normal = new GameLib.D3.Vector3(0);
|
|
}
|
|
|
|
this.normal = normal;
|
|
};
|
|
|
|
/**
|
|
* Clone a TriangleFace
|
|
* @returns {GameLib.D3.TriangleFace}
|
|
*/
|
|
GameLib.D3.TriangleFace.prototype.clone = function(){
|
|
return new GameLib.D3.TriangleFace(
|
|
this.v0,
|
|
this.v1,
|
|
this.v2,
|
|
this.materialIndex,
|
|
this.v0uv.copy(),
|
|
this.v1uv.copy(),
|
|
this.v2uv.copy()
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Returns true if two triangles are equal (their vertex indices match in some order)
|
|
* @param triangle
|
|
* @returns {boolean}
|
|
*/
|
|
GameLib.D3.TriangleFace.prototype.equals = function(triangle) {
|
|
return !!(
|
|
(
|
|
(this.v0 == triangle.v0) &&
|
|
(this.v1 == triangle.v1) &&
|
|
(this.v2 == triangle.v2)
|
|
)
|
|
||
|
|
(
|
|
(this.v0 == triangle.v0) &&
|
|
(this.v1 == triangle.v2) &&
|
|
(this.v2 == triangle.v1)
|
|
)
|
|
||
|
|
(
|
|
(this.v0 == triangle.v1) &&
|
|
(this.v1 == triangle.v0) &&
|
|
(this.v2 == triangle.v2)
|
|
)
|
|
||
|
|
(
|
|
(this.v0 == triangle.v1) &&
|
|
(this.v1 == triangle.v2) &&
|
|
(this.v2 == triangle.v0)
|
|
)
|
|
||
|
|
(
|
|
(this.v0 == triangle.v2) &&
|
|
(this.v1 == triangle.v0) &&
|
|
(this.v2 == triangle.v1)
|
|
)
|
|
||
|
|
(
|
|
(this.v0 == triangle.v2) &&
|
|
(this.v1 == triangle.v1) &&
|
|
(this.v2 == triangle.v0)
|
|
));
|
|
};
|
|
|
|
|
|
GameLib.D3.Vector2 = function(x, y) {
|
|
|
|
this.x = 0;
|
|
this.y = 0;
|
|
|
|
if (x) {
|
|
this.x = x;
|
|
}
|
|
|
|
if (y) {
|
|
this.y = y;
|
|
}
|
|
};
|
|
|
|
GameLib.D3.Vector2.prototype.copy = function() {
|
|
return new GameLib.D3.Vector2(
|
|
this.x,
|
|
this.y
|
|
);
|
|
};
|
|
|
|
GameLib.D3.Vector2.prototype.equals = function(v) {
|
|
return !!(((this.x == v.x) &&
|
|
(this.y == v.y)) ||
|
|
((this.y == v.x) &&
|
|
(this.x == v.y)));
|
|
};
|
|
|
|
GameLib.D3.Vector3 = function(x, y, z) {
|
|
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.z = 0;
|
|
|
|
if (x) {
|
|
this.x = x;
|
|
}
|
|
|
|
if (y) {
|
|
this.y = y;
|
|
}
|
|
|
|
if (z) {
|
|
this.z = z;
|
|
}
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.subtract = function (v) {
|
|
|
|
if (v instanceof GameLib.D3.Vector3) {
|
|
this.x -= v.x;
|
|
this.y -= v.y;
|
|
this.z -= v.z;
|
|
}
|
|
|
|
if (v instanceof GameLib.D3.Vector4) {
|
|
console.warn("trying to subtract vector of bigger length (4 vs 3))");
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.cross = function (v) {
|
|
return new GameLib.D3.Vector3(
|
|
this.y * v.z - this.z * v.y,
|
|
this.z * v.x - this.x * v.z,
|
|
this.x * v.y - this.y * v.x
|
|
);
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.negative = function () {
|
|
this.x *= -1;
|
|
this.y *= -1;
|
|
this.z *= -1;
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector3.clockwise = function (u, v, w, viewPoint) {
|
|
|
|
var normal = GameLib.D3.Vector3.normal(u, v, w);
|
|
|
|
var uv = u.copy();
|
|
|
|
var winding = normal.dot(uv.subtract(viewPoint));
|
|
|
|
return (winding > 0);
|
|
};
|
|
|
|
GameLib.D3.Vector3.normal = function (u, v, w) {
|
|
var vv = v.copy();
|
|
var wv = w.copy();
|
|
return vv.subtract(u).cross(wv.subtract(u));
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.lookAt = function (at, up) {
|
|
|
|
var lookAtMatrix = GameLib.D3.Matrix4.lookAt(this, at, up);
|
|
|
|
this.multiply(lookAtMatrix);
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.translate = function (v) {
|
|
this.x += v.x;
|
|
this.y += v.y;
|
|
this.z += v.z;
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.squared = function () {
|
|
return this.x * this.x + this.y * this.y + this.z * this.z;
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.copy = function () {
|
|
return new GameLib.D3.Vector3(
|
|
this.x,
|
|
this.y,
|
|
this.z
|
|
);
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.multiply = function (s) {
|
|
if (s instanceof GameLib.D3.Vector3) {
|
|
this.x *= s.x;
|
|
this.y *= s.y;
|
|
this.z *= s.z;
|
|
} else if (s instanceof GameLib.D3.Matrix4) {
|
|
var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z;
|
|
var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z;
|
|
var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z;
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
} else {
|
|
console.log("functionality not implemented - please do this");
|
|
throw new Error("not implemented");
|
|
}
|
|
return this;
|
|
};
|
|
|
|
|
|
GameLib.D3.Vector3.prototype.dot = function (v) {
|
|
return (this.x * v.x) + (this.y * v.y) + (this.z * v.z);
|
|
};
|
|
|
|
GameLib.D3.Vector3.prototype.normalize = function () {
|
|
|
|
var EPSILON = 0.000001;
|
|
|
|
var v2 = this.squared();
|
|
|
|
if (v2 < EPSILON) {
|
|
return this; //do nothing for zero vector
|
|
}
|
|
|
|
var invLength = 1 / Math.sqrt(v2);
|
|
|
|
this.x *= invLength;
|
|
this.y *= invLength;
|
|
this.z *= invLength;
|
|
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector4 = function(x, y, z, w) {
|
|
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.z = 0;
|
|
this.w = 0;
|
|
|
|
if (x) {
|
|
this.x = x;
|
|
}
|
|
|
|
if (y) {
|
|
this.y = y;
|
|
}
|
|
|
|
if (z) {
|
|
this.z = z;
|
|
}
|
|
|
|
if (w) {
|
|
this.w = w;
|
|
}
|
|
};
|
|
|
|
GameLib.D3.Vector4.prototype.translate = function (v) {
|
|
this.x += v.x;
|
|
this.y += v.y;
|
|
this.z += v.z;
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector4.prototype.copy = function () {
|
|
return new GameLib.D3.Vector4(
|
|
this.x,
|
|
this.y,
|
|
this.z,
|
|
this.w
|
|
);
|
|
};
|
|
|
|
GameLib.D3.Vector4.prototype.multiply = function (s) {
|
|
if (s instanceof GameLib.D3.Vector3) {
|
|
this.x *= s.x;
|
|
this.y *= s.y;
|
|
this.z *= s.z;
|
|
} else if (s instanceof GameLib.D3.Matrix4) {
|
|
var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z + s.rows[0].w * this.w;
|
|
var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z + s.rows[1].w * this.w;
|
|
var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z + s.rows[2].w * this.w;
|
|
var w = s.rows[3].x * this.x + s.rows[3].y * this.y + s.rows[3].z * this.z + s.rows[3].w * this.w;
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
this.w = w;
|
|
} else {
|
|
console.log("functionality not implemented - please do this");
|
|
throw new Error("not implemented");
|
|
}
|
|
};
|
|
|
|
|
|
GameLib.D3.Vector4.prototype.normalize = function () {
|
|
|
|
// note - leave w untouched
|
|
var EPSILON = 0.000001;
|
|
|
|
var v2 = this.x * this.x + this.y * this.y + this.z * this.z;
|
|
|
|
if (v2 < EPSILON) {
|
|
return this; //do nothing for zero vector
|
|
}
|
|
|
|
var invLength = 1 / Math.sqrt(v2);
|
|
|
|
this.x *= invLength;
|
|
this.y *= invLength;
|
|
this.z *= invLength;
|
|
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector4.prototype.subtract = function (v) {
|
|
|
|
if (v instanceof GameLib.D3.Vector3) {
|
|
this.x -= v.x;
|
|
this.y -= v.y;
|
|
this.z -= v.z;
|
|
}
|
|
|
|
if (v instanceof GameLib.D3.Vector4) {
|
|
this.x -= v.x;
|
|
this.y -= v.y;
|
|
this.z -= v.z;
|
|
this.w -= v.w;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points = function () {
|
|
this.vectors = [];
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points.prototype.add = function (vector) {
|
|
|
|
if (vector instanceof GameLib.D3.Vector3) {
|
|
vector = new GameLib.D3.Vector4(
|
|
vector.x,
|
|
vector.y,
|
|
vector.z,
|
|
1
|
|
)
|
|
}
|
|
|
|
if (!vector instanceof GameLib.D3.Vector4) {
|
|
console.warn("Vector needs to be of type Vector4");
|
|
throw new Error("Vector needs to be of type Vector4");
|
|
}
|
|
|
|
this.vectors.push(vector);
|
|
|
|
return this;
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points.prototype.copy = function () {
|
|
|
|
var vectors = [];
|
|
|
|
for (var i = 0; i < this.vectors.length; i++) {
|
|
vectors.push(this.vectors[i].copy());
|
|
}
|
|
|
|
return vectors;
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points.prototype.maximizeXDistance = function (grain) {
|
|
|
|
// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
|
|
|
|
var multiplier = 0;
|
|
|
|
var rotationMatrixY = new GameLib.D3.Matrix4().rotationMatrixY(grain);
|
|
|
|
var totalRadians = 0;
|
|
|
|
var backupVectors = this.copy();
|
|
|
|
var maxXDistance = 0;
|
|
|
|
for (var i = 0; i < Math.PI * 2; i += grain) {
|
|
|
|
multiplier++;
|
|
|
|
for (var j = 0; j < this.vectors.length; j++) {
|
|
this.vectors[j] = rotationMatrixY.multiply(this.vectors[j]);
|
|
}
|
|
|
|
var distances = this.distances();
|
|
|
|
if (distances.x > maxXDistance) {
|
|
|
|
maxXDistance = distances.x;
|
|
totalRadians = multiplier * grain;
|
|
}
|
|
}
|
|
|
|
this.vectors = backupVectors;
|
|
|
|
// console.log("distance: " + maxXDistance + " radians : " + totalRadians);
|
|
|
|
var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixY(totalRadians);
|
|
|
|
for (var k = 0; k < this.vectors.length; k++) {
|
|
this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
|
|
}
|
|
|
|
// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
|
|
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points.prototype.maximizeYDistance = function (grain) {
|
|
|
|
// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
|
|
|
|
var multiplier = 0;
|
|
|
|
var rotationMatrixX = new GameLib.D3.Matrix4().rotationMatrixX(grain);
|
|
|
|
var totalRadians = 0;
|
|
|
|
var backupVectors = this.copy();
|
|
|
|
var maxYDistance = 0;
|
|
|
|
for (var i = 0; i < Math.PI * 2; i += grain) {
|
|
|
|
multiplier++;
|
|
|
|
for (var j = 0; j < this.vectors.length; j++) {
|
|
this.vectors[j] = rotationMatrixX.multiply(this.vectors[j]);
|
|
}
|
|
|
|
var distances = this.distances();
|
|
|
|
if (distances.y > maxYDistance) {
|
|
maxYDistance = distances.y;
|
|
totalRadians = multiplier * grain;
|
|
}
|
|
}
|
|
|
|
this.vectors = backupVectors;
|
|
|
|
// console.log("distance: " + maxYDistance + " radians : " + totalRadians);
|
|
|
|
var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixX(totalRadians);
|
|
|
|
for (var k = 0; k < this.vectors.length; k++) {
|
|
this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
|
|
}
|
|
|
|
// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
|
|
|
|
};
|
|
|
|
|
|
GameLib.D3.Vector4.Points.prototype.lookAt = function (at, up) {
|
|
|
|
var polyCenter = this.average();
|
|
|
|
console.log("poly center : " + JSON.stringify(polyCenter));
|
|
|
|
var lookAtMatrix = new GameLib.D3.Matrix4().lookAt(polyCenter, at, up);
|
|
|
|
lookAtMatrix.rows[0] = new GameLib.D3.Vector4(1, 0, 0, 0);
|
|
lookAtMatrix.rows[1] = new GameLib.D3.Vector4(0, 0, 1, 0);
|
|
lookAtMatrix.rows[2] = new GameLib.D3.Vector4(0, 1, 0, 0);
|
|
|
|
console.log("look at matrix : " + JSON.stringify(lookAtMatrix, null, 2));
|
|
|
|
for (var i = 0; i < this.vectors.length; i++) {
|
|
console.log("vector " + i + " (before): " + JSON.stringify(this.vectors[i]));
|
|
this.vectors[i] = lookAtMatrix.multiply(this.vectors[i]);
|
|
console.log("vector " + i + " (after) : " + JSON.stringify(this.vectors[i]));
|
|
}
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points.prototype.distances = function () {
|
|
|
|
var minX = this.vectors[0].x;
|
|
var minY = this.vectors[0].y;
|
|
var minZ = this.vectors[0].z;
|
|
|
|
var maxX = this.vectors[0].x;
|
|
var maxY = this.vectors[0].y;
|
|
var maxZ = this.vectors[0].z;
|
|
|
|
for (var i = 0; i < this.vectors.length; i++) {
|
|
if (this.vectors[i].x < minX) {
|
|
minX = this.vectors[i].x;
|
|
}
|
|
if (this.vectors[i].y < minY) {
|
|
minY = this.vectors[i].y;
|
|
}
|
|
if (this.vectors[i].z < minZ) {
|
|
minZ = this.vectors[i].z;
|
|
}
|
|
|
|
if (this.vectors[i].x > maxX) {
|
|
maxX = this.vectors[i].x;
|
|
}
|
|
if (this.vectors[i].y > maxY) {
|
|
maxY = this.vectors[i].y;
|
|
}
|
|
if (this.vectors[i].z > maxZ) {
|
|
maxZ = this.vectors[i].z;
|
|
}
|
|
}
|
|
|
|
return new GameLib.D3.Vector3(
|
|
Math.abs(maxX - minX),
|
|
Math.abs(maxY - minY),
|
|
Math.abs(maxY - minZ)
|
|
)
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points.prototype.average = function () {
|
|
var averageX = 0;
|
|
var averageY = 0;
|
|
var averageZ = 0;
|
|
|
|
for (var i = 0; i < this.vectors.length; i++) {
|
|
averageX += this.vectors[i].x;
|
|
averageY += this.vectors[i].y;
|
|
averageZ += this.vectors[i].z;
|
|
}
|
|
|
|
return new GameLib.D3.Vector3(
|
|
averageX / this.vectors.length,
|
|
averageY / this.vectors.length,
|
|
averageZ / this.vectors.length
|
|
);
|
|
};
|
|
|
|
GameLib.D3.Vector4.Points.prototype.negative = function () {
|
|
|
|
for (var i = 0; i < this.vectors.length; i++) {
|
|
this.vectors[i].x *= -1;
|
|
this.vectors[i].y *= -1;
|
|
this.vectors[i].z *= -1;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
|
|
GameLib.D3.Vector4.Points.prototype.toOrigin = function () {
|
|
|
|
var distanceFromOrigin = this.average().negative();
|
|
|
|
for (var i = 0; i < this.vectors.length; i++) {
|
|
this.vectors[i].translate(distanceFromOrigin);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* The normal gets assigned when the face calculates its normal
|
|
* @param position
|
|
* @param boneWeights GameLib.D3.BoneWeight[]
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.Vertex = function(
|
|
position,
|
|
boneWeights
|
|
) {
|
|
this.position = position;
|
|
this.boneWeights = boneWeights;
|
|
};
|
|
/**
|
|
* World SuperSet - contains the custom world instance
|
|
* @param id
|
|
* @param name
|
|
* @param engine
|
|
* @param gravity
|
|
* @param broadphase
|
|
* @param solver
|
|
* @param rigidBodies
|
|
* @constructor
|
|
*/
|
|
GameLib.D3.World = function(
|
|
id,
|
|
name,
|
|
engine,
|
|
gravity,
|
|
broadphase,
|
|
solver,
|
|
rigidBodies
|
|
) {
|
|
|
|
this.id = id;
|
|
|
|
this.name = name;
|
|
|
|
if (typeof gravity == 'undefined') {
|
|
gravity = new GameLib.D3.Vector3(0, -9.81, 0);
|
|
}
|
|
this.gravity = gravity;
|
|
|
|
if (typeof broadphase == 'undefined') {
|
|
broadphase = new GameLib.D3.Physics.Broadphase(
|
|
null,
|
|
'broadPhaseNaive',
|
|
GameLib.D3.Physics.BROADPHASE_TYPE_NAIVE
|
|
);
|
|
}
|
|
this.broadphase = broadphase;
|
|
|
|
if (typeof solver == 'undefined') {
|
|
solver = new GameLib.D3.Physics.Solver(
|
|
null,
|
|
'GSSolver',
|
|
GameLib.D3.Physics.GS_SOLVER
|
|
);
|
|
}
|
|
this.solver = solver;
|
|
|
|
if (typeof rigidBodies == 'undefined') {
|
|
rigidBodies = [];
|
|
}
|
|
this.rigidBodies = rigidBodies;
|
|
|
|
this.engine = null;
|
|
|
|
this.worldInstance = null;
|
|
|
|
/**
|
|
* We only set the physics property if we pass it in the constructor,
|
|
* because we don't always want the physics object (ex. when we store this world to the API - we also don't then
|
|
* want to store the custom worlds - we want to generate them after loading from API)
|
|
*/
|
|
if (engine) {
|
|
this.engine = engine;
|
|
this.worldInstance = this.createWorldInstance();
|
|
}
|
|
};
|
|
|
|
|
|
GameLib.D3.World.prototype.createWorldInstance = function() {
|
|
|
|
this.engine.isNotCannonThrow();
|
|
|
|
var customWorld = new this.engine.instance.World();
|
|
|
|
var cannonBroadphase = null;
|
|
|
|
|
|
customWorld.broadphase = cannonBroadphase;
|
|
|
|
var cannonSolver = null;
|
|
|
|
if (this.solver.solverType == GameLib.D3.Physics.SPLIT_SOLVER) {
|
|
cannonSolver = new this.engine.instance.SplitSolver();
|
|
} else if (this.solver.solverType == GameLib.D3.Physics.GS_SOLVER) {
|
|
cannonSolver = new this.engine.instance.GSSolver();
|
|
cannonSolver.iterations = this.solver.iterations;
|
|
}
|
|
|
|
customWorld.solver = cannonSolver;
|
|
|
|
customWorld.gravity.x = this.gravity.x;
|
|
customWorld.gravity.y = this.gravity.y;
|
|
customWorld.gravity.z = this.gravity.z;
|
|
|
|
for (var b = 0; b < this.rigidBodies.length; b++) {
|
|
|
|
var customBody = this.createCustomBody(this.rigidBodies[b]);
|
|
|
|
//customWorld.AddRigidBody();
|
|
}
|
|
|
|
customWorld.name = this.name;
|
|
|
|
return customWorld;
|
|
};
|
|
|
|
GameLib.D3.World.prototype.AddShape = function(
|
|
shape, // d3.physics.shape
|
|
rigidBody,
|
|
offset, // vec3
|
|
orientation //quaternion
|
|
) {
|
|
shape.shape = shape;
|
|
|
|
/**
|
|
* TODO:: fix this?
|
|
*/
|
|
if (this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
|
|
|
|
var _offset = null;
|
|
var _orientation = null;
|
|
|
|
if(offset != null && typeof offset !== 'undefined') {
|
|
_offset = new this.physics.CANNON.Vec3(offset.x, offset.y, offset.z);
|
|
}
|
|
|
|
if(orientation != null && typeof orientation !== 'undefined') {
|
|
_orientation = new this.physics.CANNON.Quaternion(orientation.x, orientation.y, orientation.z, orientation.w);
|
|
}
|
|
|
|
rigidBody.bodyObject.addShape(shape.shapeObject, _offset, _orientation);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.Wheel = function() {
|
|
|
|
};
|
|
|
|
GameLib.D3.World.prototype.CreateRigidVehicle = function(
|
|
chassisBody // Physics.RigidBody
|
|
) {
|
|
var rigidVehicle = new GameLib.D3.Physics.RigidVehicle();
|
|
|
|
if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
var vehicle = new this.physics.CANNON.RigidVehicle({
|
|
chassisBody: chassisBody.bodyObject
|
|
});
|
|
rigidVehicle.vehicleObject = vehicle;
|
|
return rigidVehicle;
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.CreateRaycastVehicle = function(
|
|
chassisBody // Physics.RigidBody
|
|
) {
|
|
var raycastVehicle = new GameLib.D3.Physics.RaycastVehicle();
|
|
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
var vehicle = new this.physics.CANNON.RaycastVehicle({
|
|
chassisBody: chassisBody.bodyObject
|
|
});
|
|
raycastVehicle.vehicleObject = vehicle;
|
|
return raycastVehicle;
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.AddWheelToRigidVehicle = function(
|
|
vehicle,
|
|
rigidBody,
|
|
position,
|
|
axis,
|
|
direction
|
|
) {
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
vehicle.vehicleObject.addWheel({
|
|
body: rigidBody.bodyObject,
|
|
position: new this.physics.CANNON.Vec3(position.x, position.y, position.z),
|
|
axis: new this.physics.CANNON.Vec3(axis.x, axis.y, axis.z),
|
|
direction: new this.physics.CANNON.Vec3(direction.x, direction.y, direction.z)
|
|
});
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.AddWheelToRaycastVehicle = function (
|
|
vehicle, // physics.raycastvehicle
|
|
options // cannon options
|
|
) {
|
|
if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
vehicle.vehicleObject.addWheel(options);
|
|
} else {
|
|
console.log("function for engine not implemented");
|
|
}
|
|
};
|
|
|
|
|
|
|
|
GameLib.D3.World.prototype.CreateTriMeshShape = function(
|
|
vertices, // flat list of floats
|
|
indices // flat list of floats
|
|
) {
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Trimesh(vertices, indices), GameLib.D3.Physics.SHAPE_TYPE_TRIMESH);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.CreateSphereShape = function (
|
|
radius
|
|
) {
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Sphere(radius), GameLib.D3.Physics.SHAPE_TYPE_SPHERE);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.CreateBoxShape = function(
|
|
halfExtensions // vec3
|
|
) {
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Box(new this.physics.CANNON.Vec3(halfExtensions.x, halfExtensions.y, halfExtensions.z)), GameLib.D3.Physics.SHAPE_TYPE_BOX);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.CreateCylinderShape = function(
|
|
radiusTop,
|
|
radiusBottom,
|
|
height,
|
|
numSegments
|
|
) {
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Cylinder(radiusTop, radiusBottom, height, numSegments), GameLib.D3.Physics.SHAPE_TYPE_CYLINDER);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.AddRigidBody = function(
|
|
rigidBody // Physics.RigidBody
|
|
) {
|
|
if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
|
|
this.worldObject.addBody(rigidBody.bodyObject);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.AddVehicle = function(
|
|
vehicle // note: physics.vehicle
|
|
) {
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
vehicle.vehicleObject.addToWorld(this.worldObject);
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.Step = function(
|
|
timeStep
|
|
) {
|
|
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
|
|
// todo: figure out, why this call to internal step is more stable for trimesh collisions.....
|
|
//this.worldObject.internalStep(timeStep);
|
|
//return;
|
|
|
|
var now = performance.now() / 1000;
|
|
|
|
if(!this.lastCallTime){
|
|
// last call time not saved, cant guess elapsed time. Take a simple step.
|
|
this.worldObject.step(timeStep);
|
|
this.lastCallTime = now;
|
|
return;
|
|
}
|
|
|
|
var timeSinceLastCall = now - this.lastCallTime;
|
|
|
|
this.worldObject.step(timeStep, timeSinceLastCall);
|
|
|
|
this.lastCallTime = now;
|
|
}
|
|
};
|
|
|
|
GameLib.D3.World.prototype.GetIndexedVertices = function(
|
|
triangleMeshShape
|
|
) {
|
|
|
|
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
|
|
return {
|
|
vertices : triangleMeshShape.vertices,
|
|
indices : triangleMeshShape.indices
|
|
};
|
|
|
|
} else {
|
|
// todo: implement this for other physics engines.
|
|
return null;
|
|
}
|
|
|
|
};
|
|
|
|
GameLib.D3.World.prototype.GenerateWireframeViewMesh = function(
|
|
triangleMeshShape,
|
|
normalLength,
|
|
scale,
|
|
opacity,
|
|
wireframeColor
|
|
) {
|
|
var geometryTHREE = new THREE.Geometry();
|
|
var wireframeTHREEMesh = new THREE.Mesh
|
|
(
|
|
geometryTHREE,
|
|
new THREE.MeshBasicMaterial({
|
|
color: wireframeColor ? wireframeColor : 0xfefefe,
|
|
wireframe: true,
|
|
opacity: opacity ? opacity : 0.5
|
|
})
|
|
);
|
|
|
|
var data = this.GetIndexedVertices(triangleMeshShape);
|
|
|
|
for(var i = 0, l = data.vertices.length / 3; i < l; i++) {
|
|
geometryTHREE.vertices.push(new THREE.Vector3(data.vertices[i * 3], data.vertices[i * 3 + 1], data.vertices[i * 3 + 2]));
|
|
}
|
|
|
|
for(var i = 0, l = data.indices.length / 3; i < l; i++) {
|
|
var i0 = data.indices[i * 3];
|
|
var i1 = data.indices[i * 3 + 1];
|
|
var i2 = data.indices[i * 3 + 2];
|
|
|
|
geometryTHREE.faces.push(new THREE.Face3(i0, i1, i2));
|
|
|
|
// Create debug view for normals
|
|
|
|
// Center point on the mesh itself
|
|
var centroid = new THREE.Vector3()
|
|
.add(geometryTHREE.vertices[i0])
|
|
.add(geometryTHREE.vertices[i1])
|
|
.add(geometryTHREE.vertices[i2])
|
|
.divideScalar(3);
|
|
|
|
var normal = null;
|
|
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
var normal = new this.physics.CANNON.Vec3();
|
|
triangleMeshShape.getNormal(i, normal);
|
|
} else {
|
|
// todo: calculate the normal for v0, v1 & v2 here.
|
|
}
|
|
|
|
var arrow = new THREE.ArrowHelper(new THREE.Vector3(normal.x, normal.y, normal.z), centroid, normalLength, new THREE.Color(normal.x, normal.y, normal.z));
|
|
wireframeTHREEMesh.add( arrow );
|
|
}
|
|
|
|
wireframeTHREEMesh.scale.x = scale.x;
|
|
wireframeTHREEMesh.scale.y = scale.y;
|
|
wireframeTHREEMesh.scale.z = scale.z;
|
|
|
|
return wireframeTHREEMesh;
|
|
};
|
|
|
|
GameLib.D3.World.prototype.GenerateTriangleCollisionMesh = function(
|
|
threeMesh,
|
|
mass, // default = 0
|
|
friction, // default = 10
|
|
createCollisionSubMeshes, // boolean. default = false
|
|
facesPerSubsection, // int. default = 0
|
|
subsectionsToMerge // int. default = 0
|
|
) {
|
|
var processedFaces = 0;
|
|
var facesPerSubSection = facesPerSubsection || 0;
|
|
var subMeshesToMerge = subsectionsToMerge || 0;
|
|
var totalAmtFaces = threeMesh.geometry.faces.length;
|
|
var facesToProcess = createCollisionSubMeshes ? (subMeshesToMerge * facesPerSubSection) : totalAmtFaces;
|
|
|
|
var pairs = []; // output
|
|
|
|
var vertices = [];
|
|
var indicies = [];
|
|
|
|
for(var i = 0; i <= totalAmtFaces; i++) {
|
|
if(processedFaces == facesToProcess || i == totalAmtFaces) {
|
|
|
|
var body = null;
|
|
|
|
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
|
|
|
|
var meshShape = new this.physics.CANNON.Trimesh(vertices, indicies);
|
|
meshShape.setScale(new this.physics.CANNON.Vec3(threeMesh.scale.x, threeMesh.scale.y, threeMesh.scale.z));
|
|
meshShape.updateAABB();
|
|
meshShape.updateNormals();
|
|
meshShape.updateEdges();
|
|
meshShape.updateBoundingSphereRadius();
|
|
meshShape.updateTree();
|
|
|
|
body = new this.physics.CANNON.Body({ mass: mass ? mass : 0, friction: friction ? friction : 10 });
|
|
body.addShape(meshShape);
|
|
|
|
} else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_AMMO) {
|
|
|
|
} else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_GOBLIN) {
|
|
|
|
}
|
|
|
|
pairs.push({
|
|
threeObject : createCollisionSubMeshes ? null : threeMesh,
|
|
physicsObject : body
|
|
});
|
|
|
|
vertices = [];
|
|
indicies = [];
|
|
processedFaces = 0;
|
|
|
|
if(i == totalAmtFaces) {
|
|
return pairs;
|
|
}
|
|
}
|
|
|
|
var face = threeMesh.geometry.faces[i];
|
|
indicies.push(indicies.length);
|
|
indicies.push(indicies.length);
|
|
indicies.push(indicies.length);
|
|
|
|
var v0 = threeMesh.geometry.vertices[face.a];
|
|
var v1 = threeMesh.geometry.vertices[face.b];
|
|
var v2 = threeMesh.geometry.vertices[face.c];
|
|
|
|
vertices.push(v0.x, v0.y, v0.z);
|
|
vertices.push(v1.x, v1.y, v1.z);
|
|
vertices.push(v2.x, v2.y, v2.z);
|
|
|
|
processedFaces++;
|
|
}
|
|
};
|
|
|
|
if (typeof module !== 'undefined') {
|
|
module.exports = GameLib;
|
|
} |