getting therer -- deep linking objects
parent
59650c739e
commit
dd148226c9
|
@ -23,7 +23,7 @@ GameLib.API.Component = function(
|
|||
loaded = false;
|
||||
}
|
||||
this.loaded = loaded;
|
||||
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(parentEntity)) {
|
||||
parentEntity = null;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,10 @@ GameLib.Component = function(
|
|||
|
||||
this.idToObject = {};
|
||||
|
||||
this.parentObjects = [];
|
||||
|
||||
this.build = true;
|
||||
|
||||
this.linkedObjects.parentEntity = GameLib.Entity;
|
||||
};
|
||||
|
||||
|
@ -55,6 +59,7 @@ GameLib.Component.COMPONENT_SKELETON = 0x19;
|
|||
GameLib.Component.COMPONENT_TEXTURE = 0x1a;
|
||||
GameLib.Component.COMPONENT_ENTITY_MANAGER = 0x1b;
|
||||
GameLib.Component.COMPONENT_DOM_ELEMENT = 0x1c;
|
||||
GameLib.Component.COMPONENT_IMAGE_FACTORY = 0x1d;
|
||||
|
||||
/**
|
||||
* Components are linked at runtime - for storing, we just store the ID
|
||||
|
@ -66,12 +71,19 @@ GameLib.Component.prototype.toApiComponent = function() {
|
|||
|
||||
GameLib.Component.prototype.buildIdToObject = function() {
|
||||
|
||||
if (!this.build) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.build = false;
|
||||
|
||||
this.idToObject = {};
|
||||
|
||||
for (var property in this.linkedObjects) {
|
||||
if (
|
||||
this.linkedObjects.hasOwnProperty(property) &&
|
||||
this.hasOwnProperty(property)
|
||||
this.hasOwnProperty(property) &&
|
||||
this[property]
|
||||
) {
|
||||
if (this.linkedObjects[property] instanceof Array) {
|
||||
this.idToObject = GameLib.Utils.LoadIdsFromArrayToIdObject(this[property], this.idToObject);
|
||||
|
@ -82,4 +94,115 @@ GameLib.Component.prototype.buildIdToObject = function() {
|
|||
}
|
||||
|
||||
this.idToObject[this.id] = this;
|
||||
|
||||
this.build = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Some components need to be loaded first, and are referenced by ID string from other objects.
|
||||
* These components should implement this 'linkObjects' function - this will be implementation specific.
|
||||
* Example: Scene has meshes which have materials which have textures.
|
||||
* However, we don't store the texture inside the material inside the mesh, since they are re-usable among meshes.
|
||||
* Instead, we store them on the scene object, reference them by string id from the mesh, and after scene has loaded,
|
||||
* we link the objects
|
||||
*/
|
||||
GameLib.Component.prototype.linkObjects = function(idToObject) {
|
||||
|
||||
if (this.loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
|
||||
for (var property in this.linkedObjects) {
|
||||
if (
|
||||
this.linkedObjects.hasOwnProperty(property) &&
|
||||
this.hasOwnProperty(property) &&
|
||||
this[property]
|
||||
) {
|
||||
|
||||
if (this.linkedObjects[property] instanceof Array) {
|
||||
if (this[property] instanceof Array) {
|
||||
|
||||
this[property] = this[property].map(
|
||||
function(p) {
|
||||
if (p instanceof Object) {
|
||||
|
||||
p.parentObjects.push(this);
|
||||
|
||||
/**
|
||||
* This object is already an object, does not need to be linked
|
||||
*/
|
||||
if (p.linkObjects) {
|
||||
p.linkObjects(idToObject);
|
||||
}
|
||||
|
||||
return p;
|
||||
} else if (typeof p == 'string') {
|
||||
|
||||
if (!idToObject[p]) {
|
||||
console.warn('Could not locate the object to be linked in array - fix this');
|
||||
throw new Error('Could not locate the object to be linked in array - fix this');
|
||||
}
|
||||
|
||||
idToObject[p].parentObjects.push(this);
|
||||
|
||||
/**
|
||||
* Perform deep-linking
|
||||
*/
|
||||
if (idToObject[p].linkObjects) {
|
||||
idToObject[p].linkObjects(idToObject);
|
||||
}
|
||||
|
||||
return idToObject[p];
|
||||
} else {
|
||||
console.warn('Unhandled type : ', p);
|
||||
throw new Error('Unhandled type : ', p);
|
||||
}
|
||||
|
||||
}.bind(this)
|
||||
)
|
||||
} else {
|
||||
console.warn('Incompatible Link Type - should be instance of array');
|
||||
throw new Error('Incompatible Link Type - should be instance of array');
|
||||
}
|
||||
} else {
|
||||
|
||||
if (this[property] instanceof Object) {
|
||||
|
||||
this[property].parentObjects.push(this);
|
||||
|
||||
/**
|
||||
* This object is already an object
|
||||
*/
|
||||
if (this[property].linkObjects) {
|
||||
this[property].linkObjects(idToObject);
|
||||
}
|
||||
|
||||
return this[property];
|
||||
|
||||
} else if (typeof this[property] == 'string') {
|
||||
|
||||
if (!idToObject[this[property]]) {
|
||||
console.warn('Could not locate the object to be linked - fix this');
|
||||
throw new Error('Could not locate the object to be linked - fix this');
|
||||
}
|
||||
|
||||
this[property] = idToObject[this[property]];
|
||||
|
||||
this[property].parentObjects.push(this);
|
||||
|
||||
/**
|
||||
* Perform deep-linking
|
||||
*/
|
||||
if (this[property].linkObjects) {
|
||||
this[property].linkObjects(idToObject);
|
||||
}
|
||||
} else {
|
||||
console.warn('Unhandled property type - fix this : ' + typeof this[property]);
|
||||
throw new Error('Unhandled property type - fix this : ' + typeof this[property]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* Raw ImageFactory API object - should always correspond with the ImageFactory Schema
|
||||
* @param id
|
||||
* @param name
|
||||
* @param baseUrl String
|
||||
* @param parentEntity
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.API.ImageFactory = function(
|
||||
id,
|
||||
name,
|
||||
baseUrl,
|
||||
parentEntity
|
||||
) {
|
||||
GameLib.Component.call(
|
||||
this,
|
||||
GameLib.Component.COMPONENT_IMAGE_FACTORY,
|
||||
null,
|
||||
null,
|
||||
parentEntity
|
||||
);
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(id)) {
|
||||
id = GameLib.Utils.RandomId();
|
||||
}
|
||||
this.id = id;
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(name)) {
|
||||
name = 'ImageFactory (' + this.id + ')';
|
||||
}
|
||||
this.name = name;
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(baseUrl)) {
|
||||
baseUrl = '';
|
||||
console.warn('No baseURL defined for image factory');
|
||||
}
|
||||
this.baseUrl = baseUrl;
|
||||
};
|
||||
|
||||
GameLib.D3.API.ImageFactory.prototype = Object.create(GameLib.Component.prototype);
|
||||
GameLib.D3.API.ImageFactory.prototype.constructor = GameLib.D3.API.ImageFactory;
|
||||
|
||||
/**
|
||||
* Returns an API ImageFactory from an Object ImageFactory
|
||||
* @param objectImageFactory
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.API.ImageFactory.FromObjectImageFactory = function(objectImageFactory) {
|
||||
return new GameLib.D3.API.ImageFactory(
|
||||
objectImageFactory.id,
|
||||
objectImageFactory.name,
|
||||
objectImageFactory.baseUrl,
|
||||
objectImageFactory.parentEntity
|
||||
);
|
||||
};
|
|
@ -33,8 +33,7 @@ GameLib.D3.API.Scene = function(
|
|||
'meshes' : [GameLib.D3.Mesh],
|
||||
'lights' : [GameLib.D3.Light],
|
||||
'textures' : [GameLib.D3.Texture],
|
||||
'materials' : [GameLib.D3.Material],
|
||||
'imageFactory' : GameLib.D3.ImageFactory
|
||||
'materials' : [GameLib.D3.Material]
|
||||
},
|
||||
false,
|
||||
parentEntity
|
||||
|
|
|
@ -41,7 +41,7 @@ GameLib.D3.Helper = function Helper(
|
|||
object instanceof GameLib.D3.Mesh &&
|
||||
object.meshType != GameLib.D3.Mesh.TYPE_CURVE
|
||||
) {
|
||||
helperType = GameLib.D3.Helper.HELPER_TYPE_WIREFRAME;
|
||||
helperType = GameLib.D3.Helper.HELPER_TYPE_EDGES;
|
||||
}
|
||||
|
||||
if (object instanceof GameLib.D3.Light) {
|
||||
|
@ -92,7 +92,7 @@ GameLib.D3.Helper.prototype.createInstance = function(update) {
|
|||
}
|
||||
|
||||
if (this.helperType == GameLib.D3.Helper.HELPER_TYPE_EDGES) {
|
||||
instance = new THREE.WireframeHelper(this.object.instance, 0x007700);
|
||||
instance = new THREE.EdgesHelper(this.object.instance, 0x007700);
|
||||
}
|
||||
|
||||
if (this.helperType == GameLib.D3.Helper.HELPER_TYPE_DIRECTIONAL_LIGHT) {
|
||||
|
|
|
@ -1,71 +1,136 @@
|
|||
/**
|
||||
* The image factory takes care that we only make requests for Image URLs which we have not already started downloading
|
||||
* @param graphics GameLib.D3.Graphics
|
||||
* @param baseUrl
|
||||
* @param apiImageFactory GameLib.D3.API.ImageFactory
|
||||
* @param progressCallback
|
||||
* @returns {Function}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.ImageFactory = function (
|
||||
graphics,
|
||||
baseUrl
|
||||
apiImageFactory,
|
||||
progressCallback
|
||||
) {
|
||||
|
||||
graphics.isNotThreeThrow();
|
||||
this.graphics = graphics;
|
||||
|
||||
var promiseList = {};
|
||||
|
||||
return function(imagePath, progressCallback) {
|
||||
|
||||
if (!imagePath) {
|
||||
console.log('Attempted to download bad URL : ' + imagePath);
|
||||
throw new Error('Bad URL : ' + imagePath);
|
||||
}
|
||||
|
||||
if (promiseList[imagePath]) {
|
||||
return promiseList[imagePath];
|
||||
}
|
||||
|
||||
var defer = Q.defer();
|
||||
|
||||
promiseList[imagePath] = defer.promise;
|
||||
|
||||
GameLib.D3.ImageFactory.LoadImage(graphics, baseUrl + imagePath, defer, progressCallback);
|
||||
|
||||
return promiseList[imagePath];
|
||||
if (GameLib.Utils.UndefinedOrNull(apiImageFactory)) {
|
||||
apiImageFactory = {};
|
||||
}
|
||||
|
||||
if (GameLib.Utils.UndefinedOrNull(progressCallback)) {
|
||||
progressCallback = null;
|
||||
}
|
||||
this.progressCallback = progressCallback;
|
||||
|
||||
GameLib.D3.API.ImageFactory.call(
|
||||
this,
|
||||
apiImageFactory.id,
|
||||
apiImageFactory.name,
|
||||
apiImageFactory.baseUrl,
|
||||
apiImageFactory.parentEntity
|
||||
);
|
||||
|
||||
this.buildIdToObject();
|
||||
|
||||
this.promiseList = {};
|
||||
|
||||
this.instance = this.createInstance();
|
||||
};
|
||||
|
||||
GameLib.D3.ImageFactory.prototype = Object.create(GameLib.D3.API.ImageFactory.prototype);
|
||||
GameLib.D3.ImageFactory.prototype.constructor = GameLib.D3.ImageFactory;
|
||||
|
||||
GameLib.D3.ImageFactory.prototype.createInstance = function(update) {
|
||||
|
||||
var instance = null;
|
||||
|
||||
if (update) {
|
||||
instance = this.instance;
|
||||
} else {
|
||||
instance = new THREE.ImageLoader();
|
||||
}
|
||||
|
||||
instance.crossOrigin = '';
|
||||
|
||||
return instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads an image and resolves the defered promise once it succeeded (or failed)
|
||||
* @param graphics
|
||||
* @param url
|
||||
* @param defer
|
||||
* @param progressCallback
|
||||
* Update instance
|
||||
*/
|
||||
GameLib.D3.ImageFactory.prototype.updateInstance = function() {
|
||||
this.instance = this.createInstance(true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Loads an image, either returns the image immediately if already loaded, or a promise to load the image
|
||||
* @param imagePath
|
||||
* @returns {*}
|
||||
* @constructor
|
||||
*/
|
||||
GameLib.D3.ImageFactory.LoadImage = function (
|
||||
graphics,
|
||||
url,
|
||||
defer,
|
||||
progressCallback
|
||||
GameLib.D3.ImageFactory.prototype.loadImage = function(
|
||||
imagePath
|
||||
) {
|
||||
|
||||
var loader = new graphics.instance.ImageLoader();
|
||||
imagePath = imagePath.replace(new RegExp('\/*'), '/');
|
||||
|
||||
loader.crossOrigin = '';
|
||||
if (!imagePath) {
|
||||
console.log('Attempted to download bad URL : ' + imagePath);
|
||||
throw new Error('Bad URL : ' + imagePath);
|
||||
}
|
||||
|
||||
loader.load(
|
||||
url + '?ts=' + Date.now(),
|
||||
if (this.promiseList[imagePath]) {
|
||||
return this.promiseList[imagePath];
|
||||
}
|
||||
|
||||
var defer = Q.defer();
|
||||
|
||||
this.promiseList[imagePath] = defer.promise;
|
||||
|
||||
this.instance.load(
|
||||
this.baseUrl + imagePath + '?ts=' + Date.now(),
|
||||
function (image) {
|
||||
defer.resolve(image);
|
||||
},
|
||||
}.bind(this),
|
||||
function onProgress(xhr) {
|
||||
if (progressCallback) {
|
||||
progressCallback((xhr.loaded / xhr.total * 100));
|
||||
if (this.progressCallback) {
|
||||
this.progressCallback((xhr.loaded / xhr.total * 100));
|
||||
}
|
||||
},
|
||||
}.bind(this),
|
||||
function onError() {
|
||||
defer.reject('Failed to download image : ' + url);
|
||||
}
|
||||
defer.reject('Failed to download image : ' + this.baseUrl + imagePath);
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
return this.promiseList[imagePath];
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a GameLib.D3.ImageFactory to a GameLib.D3.API.ImageFactory
|
||||
* @returns {GameLib.D3.API.ImageFactory}
|
||||
*/
|
||||
GameLib.D3.ImageFactory.prototype.toApiImageFactory = function() {
|
||||
return new GameLib.D3.API.ImageFactory(
|
||||
this.id,
|
||||
this.name,
|
||||
this.baseUrl,
|
||||
GameLib.Utils.IdOrNull(this.parentEntity)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a new GameLib.D3.ImageFactory from a GameLib.D3.API.ImageFactory
|
||||
* @param graphics GameLib.D3.Graphics
|
||||
* @param objectImageFactory GameLib.D3.API.ImageFactory
|
||||
* @returns {GameLib.D3.ImageFactory}
|
||||
*/
|
||||
GameLib.D3.ImageFactory.FromObjectImageFactory = function(graphics, objectImageFactory) {
|
||||
|
||||
return new GameLib.D3.ImageFactory(
|
||||
graphics,
|
||||
GameLib.D3.API.ImageFactory.FromObjectImageFactory(objectImageFactory)
|
||||
);
|
||||
|
||||
};
|
|
@ -101,20 +101,20 @@ GameLib.D3.Material = function Material(
|
|||
|
||||
this.specular = new GameLib.Color(
|
||||
graphics,
|
||||
this,
|
||||
this.specular
|
||||
this.specular,
|
||||
this
|
||||
);
|
||||
|
||||
this.color = new GameLib.Color(
|
||||
graphics,
|
||||
this,
|
||||
this.color
|
||||
this.color,
|
||||
this
|
||||
);
|
||||
|
||||
this.emissive = new GameLib.Color(
|
||||
graphics,
|
||||
this,
|
||||
this.emissive
|
||||
this.emissive,
|
||||
this
|
||||
);
|
||||
|
||||
if (this.alphaMap) {
|
||||
|
@ -273,6 +273,8 @@ GameLib.D3.Material = function Material(
|
|||
}
|
||||
}
|
||||
|
||||
this.needsUpdate = false;
|
||||
|
||||
this.buildIdToObject();
|
||||
|
||||
this.instance = this.createInstance();
|
||||
|
|
|
@ -296,11 +296,11 @@ GameLib.D3.Mesh.prototype.createInstance = function(update) {
|
|||
}
|
||||
|
||||
if (this.meshType == GameLib.D3.Mesh.TYPE_NORMAL) {
|
||||
instance = new THREE.Mesh(instanceGeometry, this.materials[0].instance);
|
||||
instance = new THREE.Mesh(instanceGeometry);
|
||||
}
|
||||
|
||||
if (this.meshType == GameLib.D3.Mesh.TYPE_CURVE) {
|
||||
instance = new THREE.Points(instanceGeometry, this.materials[0].instance);
|
||||
instance = new THREE.Points(instanceGeometry);
|
||||
}
|
||||
|
||||
if (this.meshType == GameLib.D3.Mesh.TYPE_SKINNED) {
|
||||
|
@ -333,7 +333,7 @@ GameLib.D3.Mesh.prototype.createInstance = function(update) {
|
|||
);
|
||||
}
|
||||
|
||||
instance = new THREE.SkinnedMesh(instanceGeometry, this.materials[0].instance);
|
||||
instance = new THREE.SkinnedMesh(instanceGeometry);
|
||||
|
||||
instance.add(this.skeleton.rootBoneInstance);
|
||||
|
||||
|
@ -402,6 +402,10 @@ GameLib.D3.Mesh.prototype.createInstance = function(update) {
|
|||
instance.rotateZ(this.localRotation.z);
|
||||
}
|
||||
|
||||
if (this.materials.length == 1 && this.materials[0].instance) {
|
||||
instance.material = this.materials[0].instance;
|
||||
}
|
||||
|
||||
instance.renderOrder = this.renderOrder;
|
||||
|
||||
return instance;
|
||||
|
|
|
@ -54,8 +54,8 @@ GameLib.D3.Scene = function (
|
|||
return new GameLib.D3.Mesh(
|
||||
this.graphics,
|
||||
apiMesh,
|
||||
this.computeNormals,
|
||||
this.imageFactory
|
||||
this.imageFactory,
|
||||
this.computeNormals
|
||||
);
|
||||
|
||||
} else {
|
||||
|
@ -106,11 +106,15 @@ GameLib.D3.Scene = function (
|
|||
function(apiTexture) {
|
||||
|
||||
if (apiTexture instanceof GameLib.D3.API.Texture) {
|
||||
return new GameLib.D3.Texture(
|
||||
var texture = new GameLib.D3.Texture(
|
||||
this.graphics,
|
||||
apiTexture,
|
||||
this.imageFactory
|
||||
);
|
||||
|
||||
this.idToObject[texture.id] = texture;
|
||||
|
||||
return texture;
|
||||
} else {
|
||||
console.warn('apiTexture not an instance of API.Texture');
|
||||
throw new Error('apiTexture not an instance of API.Texture');
|
||||
|
@ -123,20 +127,39 @@ GameLib.D3.Scene = function (
|
|||
function(apiMaterial) {
|
||||
|
||||
if (apiMaterial instanceof GameLib.D3.API.Material) {
|
||||
return new GameLib.D3.Material(
|
||||
|
||||
var material = new GameLib.D3.Material(
|
||||
this.graphics,
|
||||
apiMaterial,
|
||||
this.imageFactory
|
||||
);
|
||||
|
||||
this.idToObject[material.id] = material;
|
||||
|
||||
return material;
|
||||
|
||||
} else {
|
||||
console.warn('apiMaterial not an instance of API.Material');
|
||||
throw new Error('apiMaterial not an instance of API.Material');
|
||||
}
|
||||
|
||||
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
this.linkObjects();
|
||||
this.idToObject[this.id] = this;
|
||||
|
||||
this.linkObjects(this.idToObject);
|
||||
|
||||
this.meshes.map(
|
||||
function(mesh) {
|
||||
mesh.updateInstance();
|
||||
mesh.materials.map(
|
||||
function(material) {
|
||||
material.updateInstance();
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
this.buildIdToObject();
|
||||
|
||||
|
@ -146,24 +169,6 @@ GameLib.D3.Scene = function (
|
|||
GameLib.D3.Scene.prototype = Object.create(GameLib.D3.API.Scene.prototype);
|
||||
GameLib.D3.Scene.prototype.constructor = GameLib.D3.Scene;
|
||||
|
||||
GameLib.D3.Scene.prototype.linkObjects = function() {
|
||||
this.meshes.map(
|
||||
function(mesh) {
|
||||
this.materials = mesh.materials.map(
|
||||
function(material) {
|
||||
return this.idToObject[material];
|
||||
}
|
||||
);
|
||||
|
||||
mesh.materials.map(
|
||||
function(material) {
|
||||
material.diffuseMap = this.idToObject[material.diffuseMap];
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an instance scene
|
||||
* @returns {THREE.Scene}
|
||||
|
|
|
@ -77,14 +77,22 @@ GameLib.D3.Texture.prototype.constructor = GameLib.D3.Texture;
|
|||
*/
|
||||
GameLib.D3.Texture.prototype.loadTexture = function() {
|
||||
|
||||
this.imageData = this.imageFactory(this.imagePath);
|
||||
this.imageData = this.imageFactory.loadImage(this.imagePath);
|
||||
|
||||
this.imageData.then(
|
||||
function (imageInstance){
|
||||
this.imageInstance = imageInstance;
|
||||
this.instance = this.createInstance();
|
||||
this.parentObjects.map(
|
||||
function(parentObject){
|
||||
if (parentObject instanceof GameLib.D3.Material && parentObject.updateInstance) {
|
||||
parentObject.updateInstance();
|
||||
}
|
||||
}
|
||||
)
|
||||
}.bind(this),
|
||||
function onRejected() {
|
||||
function onRejected(message) {
|
||||
console.warn(message);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -173,7 +181,8 @@ GameLib.D3.Texture.TEXTURE_TYPE_SPECULAR = 'specular';
|
|||
|
||||
/**
|
||||
* Creates an instance of our texture object
|
||||
* @returns {GameLib.D3.Texture|THREE.SoftwareRenderer.Texture|THREE.Texture|*|Texture}
|
||||
* @param update
|
||||
* @returns {*}
|
||||
*/
|
||||
GameLib.D3.Texture.prototype.createInstance = function(update) {
|
||||
|
||||
|
@ -213,8 +222,6 @@ GameLib.D3.Texture.prototype.createInstance = function(update) {
|
|||
instance.premultiplyAlpha = this.premultiplyAlpha;
|
||||
instance.textureType = this.textureType;
|
||||
|
||||
instance.needsUpdate = true;
|
||||
|
||||
return instance;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue