Created
December 19, 2016 15:37
-
-
Save spacejack/8a0907911556a6d71ebb1609b3dc63cd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Loader that provides a dictionary of named assets | |
import xhr from './xhr' | |
export interface Assets { | |
images: {[id: string]: HTMLImageElement} | |
geometries: {[id: string]: THREE.Geometry} | |
text: {[id: string]: string} | |
textures: {[id: string]: THREE.Texture} | |
sounds: {[id: string]: Howler.Howl} | |
} | |
export interface AssetDescription { | |
name: string | |
url: string | |
} | |
export interface AssetList { | |
geometries?: AssetDescription[] | |
images?: AssetDescription[] | |
text?: AssetDescription[] | |
textures?: AssetDescription[] | |
sounds?: AssetDescription[] | |
} | |
interface LoaderOptions { | |
success?: (a: Assets) => any, | |
progress?: (p: number) => any, | |
error?: (e: string) => any, | |
done?: (ok: boolean) => any | |
} | |
/** | |
* Create a Loader instance | |
*/ | |
export default function Loader() { | |
let isLoading = false | |
let totalToLoad = 0 | |
let numLoaded = 0 | |
let numFailed = 0 | |
let success_cb: ((a: Assets) => any) | undefined | |
let progress_cb: ((p: number) => any) | undefined | |
let error_cb: ((e: string) => any) | undefined | |
let done_cb: ((ok: boolean) => any) | undefined | |
let assets: Assets = { | |
images: {}, geometries: {}, text: {}, textures: {}, sounds: {} | |
} | |
/** | |
* Start loading a list of assets | |
*/ | |
function load(assetList: AssetList, opts: LoaderOptions = {}) { | |
success_cb = opts.success | |
progress_cb = opts.progress | |
error_cb = opts.error | |
done_cb = opts.done | |
totalToLoad = 0 | |
numLoaded = 0 | |
numFailed = 0 | |
isLoading = true | |
if (assetList.text) { | |
totalToLoad += assetList.text.length | |
for (let i = 0; i < assetList.text.length; ++i) | |
loadText(assetList.text[i]) | |
} | |
if (assetList.geometries) { | |
totalToLoad += assetList.geometries.length | |
for (let i = 0; i < assetList.geometries.length; ++i) | |
loadGeometry(assetList.geometries[i]) | |
} | |
if (assetList.images) { | |
totalToLoad += assetList.images.length | |
for (let i = 0; i < assetList.images.length; ++i) | |
loadImage(assetList.images[i]) | |
} | |
if (assetList.textures) { | |
totalToLoad += assetList.textures.length | |
for (let i = 0; i < assetList.textures.length; ++i) | |
loadTexture(assetList.textures[i]) | |
} | |
if (assetList.sounds) { | |
totalToLoad += assetList.sounds.length | |
for (let i = 0; i < assetList.sounds.length; ++i) | |
loadSound(assetList.sounds[i]) | |
} | |
} | |
function loadText (ad: AssetDescription) { | |
const req = new XMLHttpRequest() | |
req.overrideMimeType('*/*') | |
req.onreadystatechange = function() { | |
if (req.readyState === 4) { | |
if (req.status === 200) { | |
assets.text[ad.name] = req.responseText | |
doProgress() | |
} else { | |
doError("Error " + req.status + " loading " + ad.url) | |
} | |
} | |
} | |
req.open('GET', ad.url) | |
req.send() | |
} | |
function loadImage (ad: AssetDescription) { | |
const img = new Image() | |
assets.images[ad.name] = img | |
img.onload = doProgress | |
img.onerror = doError | |
img.src = ad.url | |
} | |
function loadTexture (ad: AssetDescription) { | |
assets.textures[ad.name] = new THREE.TextureLoader().load(ad.url, doProgress) | |
} | |
function loadGeometry (ad: AssetDescription) { | |
xhr(ad.url, { | |
success: jsrc => { | |
const data = JSON.parse(jsrc) | |
const jloader = new THREE.JSONLoader() | |
const result = jloader.parse(data) | |
assets.geometries[ad.name] = result.geometry | |
doProgress() | |
}, | |
error: e => { | |
doError("Failed to load model: '" + ad.url + "'") | |
} | |
}) | |
} | |
function loadSound (ad: AssetDescription) { | |
assets.sounds[ad.name] = new Howl({ | |
src: [ad.url + '.ogg', ad.url + '.mp3'], | |
onload: () => { | |
doProgress() | |
}, | |
onloaderror: () => { | |
doError("Failed to load sound: '" + ad.url + "'") | |
} | |
}) | |
} | |
function doProgress() { | |
numLoaded += 1 | |
progress_cb && progress_cb(numLoaded / totalToLoad) | |
tryDone() | |
} | |
function doError (e: any) { | |
error_cb && error_cb(e) | |
numFailed += 1 | |
tryDone() | |
} | |
function tryDone() { | |
if (!isLoading) | |
return true | |
if (numLoaded + numFailed >= totalToLoad) { | |
const ok = !numFailed | |
ok && success_cb && success_cb(assets) | |
done_cb && done_cb(ok) | |
isLoading = false | |
} | |
return !isLoading | |
} | |
/** | |
* Public interface | |
*/ | |
return { | |
load: load, | |
getAssets: () => assets | |
} | |
} // end Loader |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment