Initial commit: Wycz WoW Portfolio
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
window.model3d = (function () {
|
||||
const CONTENT_PATH = '/mv/';
|
||||
let libsLoaded = false;
|
||||
|
||||
function loadScript(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const s = document.createElement('script');
|
||||
s.src = src;
|
||||
s.onload = resolve;
|
||||
s.onerror = () => reject(new Error('Impossible de charger ' + src));
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
}
|
||||
|
||||
async function ensureLibs() {
|
||||
if (libsLoaded && window.jQuery && window.ZamModelViewer) return;
|
||||
if (!window.jQuery) await loadScript('https://code.jquery.com/jquery-3.7.1.min.js');
|
||||
if (!window.ZamModelViewer) await loadScript(CONTENT_PATH + 'viewer/viewer.min.js');
|
||||
if (!window.jQuery) throw new Error('jQuery indisponible');
|
||||
if (!window.ZamModelViewer) throw new Error('Moteur 3D indisponible');
|
||||
if (!window.WH) window.WH = {};
|
||||
window.WH.defaultAnimation = 'Stand';
|
||||
if (!window.WH.debug) window.WH.debug = function () {};
|
||||
if (!window.WH.WebP) {
|
||||
window.WH.WebP = {
|
||||
getImageExtension: function () { return '.webp'; }
|
||||
};
|
||||
}
|
||||
libsLoaded = true;
|
||||
}
|
||||
|
||||
async function loadCharacterOptions(race, gender) {
|
||||
const id = race * 2 - 1 + gender;
|
||||
const res = await fetch(`${CONTENT_PATH}meta/charactercustomization/${id}.json`);
|
||||
if (!res.ok) return { Options: [] };
|
||||
return res.json();
|
||||
}
|
||||
|
||||
function buildOptions(model, fullOptions) {
|
||||
const map = {
|
||||
'Face': model.appearance && model.appearance.face,
|
||||
'Skin Color': model.appearance && model.appearance.skin_color,
|
||||
'Hair Style': model.appearance && model.appearance.hair_variation,
|
||||
'Hair Color': model.appearance && model.appearance.hair_color,
|
||||
'Facial Hair': model.appearance && model.appearance.facial_hair
|
||||
};
|
||||
const hasAppearance = Object.values(map).some((v) => v !== null && v !== undefined && v !== false);
|
||||
const options = [];
|
||||
if (!hasAppearance) return options;
|
||||
for (const part of fullOptions.Options || []) {
|
||||
const val = map[part.Name];
|
||||
if (val === null || val === undefined || val === false) continue;
|
||||
const choice = part.Choices && (part.Choices[val] || part.Choices.find((c) => String(c.Id) === String(val)));
|
||||
if (choice) options.push({ optionId: part.Id, choiceId: choice.Id });
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
async function render(container, model) {
|
||||
await ensureLibs();
|
||||
const $c = jQuery(container);
|
||||
$c.empty();
|
||||
const viewerOptions = {
|
||||
type: 2,
|
||||
contentPath: CONTENT_PATH,
|
||||
container: $c,
|
||||
aspect: 1,
|
||||
models: { id: model.race * 2 - 1 + model.gender, type: 16 },
|
||||
items: model.items || [],
|
||||
hd: true
|
||||
};
|
||||
|
||||
let viewer = null;
|
||||
try {
|
||||
const options = buildOptions(model, await loadCharacterOptions(model.race, model.gender));
|
||||
if (options.length) viewerOptions.charCustomization = { options };
|
||||
viewer = await new window.ZamModelViewer(viewerOptions);
|
||||
} catch (e) {
|
||||
viewer = null;
|
||||
}
|
||||
|
||||
if (!viewer) {
|
||||
const options = buildOptions(model, { Options: [] });
|
||||
viewer = await new window.ZamModelViewer(Object.assign({}, viewerOptions, { charCustomization: { options } }));
|
||||
}
|
||||
|
||||
try { viewer.renderer.distance = 2.1; } catch (e) {}
|
||||
try {
|
||||
const actor = viewer.renderer.actors && viewer.renderer.actors[0];
|
||||
if (actor && actor.setAnimation) actor.setAnimation('Stand');
|
||||
} catch (e) {}
|
||||
return viewer;
|
||||
}
|
||||
|
||||
function dispose(viewer) {
|
||||
try { viewer && viewer.dispose && viewer.dispose(); } catch (e) {}
|
||||
}
|
||||
|
||||
return { render, dispose, ensureLibs };
|
||||
})();
|
||||
Reference in New Issue
Block a user