Skip to content

Commit 4df5dac

Browse files
speed up model loading by caching finished canvases
1 parent 36c5c1f commit 4df5dac

1 file changed

Lines changed: 70 additions & 13 deletions

File tree

src/model/index.js

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const loadedTextureCache = {};
4343
const modelInstances = {};
4444

4545
const textureCache = {};
46+
const canvasCache = {};
4647
const materialCache = {};
4748
const geometryCache = {};
4849
const instanceCache = {};
@@ -449,10 +450,11 @@ let renderModel = function (modelRender, model, textures, textureNames, type, na
449450
false,
450451
false,
451452
false);
452-
cachedInstance = instanceCache[modelKey] = {
453+
cachedInstance = {
453454
instance: newInstance,
454455
index: 0
455456
};
457+
instanceCache[modelKey] = cachedInstance;
456458
let _v3o = new THREE.Vector3();
457459
let _v3s = new THREE.Vector3(1, 1, 1);
458460
let _q = new THREE.Quaternion();
@@ -474,6 +476,7 @@ let renderModel = function (modelRender, model, textures, textureNames, type, na
474476
};
475477

476478
if (instanceCache.hasOwnProperty(modelKey)) {
479+
console.debug("Using cached model instance (" + modelKey + ")");
477480
let cachedInstance = instanceCache[modelKey];
478481
applyModelTransforms(cachedInstance.instance, cachedInstance.index++);
479482
return;
@@ -513,9 +516,10 @@ let renderModel = function (modelRender, model, textures, textureNames, type, na
513516
};
514517

515518
promises.push(new Promise((resolve) => {
519+
let baseName =name.replaceAll(" ", "_").replaceAll("-", "_").toLowerCase() + "_" + (element.__comment ? element.__comment.replaceAll(" ", "_").replaceAll("-", "_").toLowerCase() + "_" : "");
516520
createCube(element.to[0] - element.from[0], element.to[1] - element.from[1], element.to[2] - element.from[2],
517-
name.replaceAll(" ", "_").replaceAll("-", "_").toLowerCase() + "_" + (element.__comment ? element.__comment.replaceAll(" ", "_").replaceAll("-", "_").toLowerCase() + "_" : "") + Date.now(),
518-
element.faces, fallbackFaces, textures, textureNames, modelRender.options.assetRoot)
521+
baseName + Date.now(),
522+
element.faces, fallbackFaces, textures, textureNames, modelRender.options.assetRoot, baseName)
519523
.then((cube) => {
520524
cube.applyMatrix(new THREE.Matrix4().makeTranslation((element.to[0] - element.from[0]) / 2, (element.to[1] - element.from[1]) / 2, (element.to[2] - element.from[2]) / 2));
521525
cube.applyMatrix(new THREE.Matrix4().makeTranslation(element.from[0], element.from[1], element.from[2]));
@@ -661,7 +665,7 @@ let createPlane = function (name, textures) {
661665

662666

663667
/// From https://github.com/InventivetalentDev/SkinRender/blob/master/js/render/skin.js#L353
664-
let createCube = function (width, height, depth, name, faces, fallbackFaces, textures, textureNames, assetRoot) {
668+
let createCube = function (width, height, depth, name, faces, fallbackFaces, textures, textureNames, assetRoot, baseName) {
665669
return new Promise((resolve) => {
666670
let geometryKey = width + "_" + height + "_" + depth;
667671
let geometry;
@@ -699,12 +703,9 @@ let createCube = function (width, height, depth, name, faces, fallbackFaces, tex
699703
return;
700704
}
701705

702-
let img = new Image();
703-
img.onerror = function(err){
704-
console.warn(err);
705-
resolve(null);
706-
};
707-
img.onload = function () {
706+
let canvasKey = textureRef + "_" + f + "_" + baseName;
707+
708+
let processImgToCanvasData = (img)=>{
708709
let uv = face.uv;
709710
if (!uv) {
710711
// console.warn("Missing UV mapping for face " + f + " in model " + name + ". Using defaults");
@@ -753,9 +754,29 @@ let createCube = function (width, height, depth, name, faces, fallbackFaces, tex
753754
}
754755
}
755756

757+
let dataUrl = canvas.toDataURL("image/png");
758+
let dataHash = md5(dataUrl);
759+
760+
let d = {
761+
data: canvasData,
762+
dataUrl: dataUrl,
763+
dataUrlHash: dataHash,
764+
hasTransparency: hasTransparency,
765+
width: canvas.width,
766+
height: canvas.height
767+
};
768+
console.debug("Caching new canvas ("+canvasKey+"/"+dataHash+")")
769+
canvasCache[canvasKey] = d;
770+
return d;
771+
};
772+
773+
let loadTextureFromCanvas = (canvas)=>{
774+
775+
756776
let loadTextureDefault = function (canvas) {
757-
let data = canvas.toDataURL("image/png");
758-
let hash = md5(data);
777+
let data = canvas.dataUrl;
778+
let hash =canvas.dataUrlHash;
779+
let hasTransparency = canvas.hasTransparency;
759780

760781
if (materialCache.hasOwnProperty(hash)) {// Use material from cache
761782
console.debug("Using cached Material (" + hash + ")");
@@ -812,6 +833,7 @@ let createCube = function (width, height, depth, name, faces, fallbackFaces, tex
812833
};
813834

814835
let loadTextureWithMeta = function (canvas, meta) {
836+
let hasTransparency = canvas.hasTransparency;
815837
let frametime = 1;
816838
if (meta.hasOwnProperty("animation")) {
817839
if (meta.animation.hasOwnProperty("frametime")) {
@@ -903,8 +925,42 @@ let createCube = function (width, height, depth, name, faces, fallbackFaces, tex
903925
loadTextureDefault(canvas);
904926
}
905927
};
906-
img.src = textures[textureRef];
907928

929+
930+
if (canvasCache.hasOwnProperty(canvasKey)) {
931+
let cachedCanvas = canvasCache[canvasKey];
932+
933+
if (cachedCanvas.hasOwnProperty("img")) {
934+
console.debug("Waiting for canvas image that's already loading ("+canvasKey+")")
935+
let img= cachedCanvas.img;
936+
img.waitingForCanvas.push(function (canvas) {
937+
loadTextureFromCanvas(canvas);
938+
});
939+
} else {
940+
console.debug("Using cached canvas (" + canvasKey + ")")
941+
loadTextureFromCanvas(canvasCache[canvasKey]);
942+
}
943+
} else {
944+
let img = new Image();
945+
img.onerror = function (err) {
946+
console.warn(err);
947+
resolve(null);
948+
};
949+
img.waitingForCanvas = [];
950+
img.onload = function () {
951+
let canvasData = processImgToCanvasData(img);
952+
loadTextureFromCanvas(canvasData);
953+
954+
for (let c = 0; c < img.waitingForCanvas.length; c++) {
955+
img.waitingForCanvas[c](canvasData);
956+
}
957+
};
958+
console.debug("Pre-caching canvas (" + canvasKey + ")");
959+
canvasCache[canvasKey] = {
960+
img: img
961+
};
962+
img.src = textures[textureRef];
963+
}
908964
}));
909965
}
910966
Promise.all(promises).then(materials => materialsLoaded(materials))
@@ -946,6 +1002,7 @@ ModelRender.cache = {
9461002
instanceCount: modelInstances,
9471003

9481004
texture: textureCache,
1005+
canvas: canvasCache,
9491006
material: materialCache,
9501007
geometry: geometryCache,
9511008
instances: instanceCache,

0 commit comments

Comments
 (0)