/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.backends.gwt.preloader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import com.badlogic.gdx.Files.FileType;
import com.badlogic.gdx.backends.gwt.GwtFileHandle;
import com.badlogic.gdx.backends.gwt.preloader.AssetDownloader.AssetLoaderListener;
import com.badlogic.gdx.backends.gwt.preloader.AssetFilter.AssetType;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.ObjectMap;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.ImageElement;
public class Preloader {
public interface PreloaderCallback {
public void update(PreloaderState state);
public void error (String file);
}
public ObjectMap<String, Void> directories = new ObjectMap<String, Void>();
public ObjectMap<String, ImageElement> images = new ObjectMap<String, ImageElement>();
public ObjectMap<String, Void> audio = new ObjectMap<String, Void>();
public ObjectMap<String, String> texts = new ObjectMap<String, String>();
public ObjectMap<String, Blob> binaries = new ObjectMap<String, Blob>();
public static class Asset {
public Asset (String url, AssetType type, long size, String mimeType) {
this.url = url;
this.type = type;
this.size = size;
this.mimeType = mimeType;
}
public boolean succeed;
public boolean failed;
public long loaded;
public final String url;
public final AssetType type;
public final long size;
public final String mimeType;
}
public static class PreloaderState {
public PreloaderState(Array<Asset> assets) {
this.assets = assets;
}
public long getDownloadedSize() {
long size = 0;
for (int i = 0; i < assets.size; i++) {
Asset asset = assets.get(i);
size += (asset.succeed || asset.failed) ? asset.size : Math.min(asset.size, asset.loaded);
}
return size;
}
public long getTotalSize() {
long size = 0;
for (int i = 0; i < assets.size; i++) {
Asset asset = assets.get(i);
size += asset.size;
}
return size;
}
public float getProgress() {
long total = getTotalSize();
return total == 0 ? 1 : (getDownloadedSize() / (float) total);
}
public boolean hasEnded() {
return getDownloadedSize() == getTotalSize();
}
public final Array<Asset> assets;
}
public final String baseUrl;
public Preloader (String newBaseURL) {
baseUrl = newBaseURL;
// trigger copying of assets and creation of assets.txt
GWT.create(PreloaderBundle.class);
}
public void preload (final String assetFileUrl, final PreloaderCallback callback) {
final AssetDownloader loader = new AssetDownloader();
loader.loadText(baseUrl + assetFileUrl, new AssetLoaderListener<String>() {
@Override
public void onProgress (double amount) {
}
@Override
public void onFailure () {
callback.error(assetFileUrl);
}
@Override
public void onSuccess (String result) {
String[] lines = result.split("\n");
Array<Asset> assets = new Array<Asset>(lines.length);
for (String line : lines) {
String[] tokens = line.split(":");
if (tokens.length != 4) {
throw new GdxRuntimeException("Invalid assets description file.");
}
AssetType type = AssetType.Text;
if (tokens[0].equals("i")) type = AssetType.Image;
if (tokens[0].equals("b")) type = AssetType.Binary;
if (tokens[0].equals("a")) type = AssetType.Audio;
if (tokens[0].equals("d")) type = AssetType.Directory;
long size = Long.parseLong(tokens[2]);
if (type == AssetType.Audio && !loader.isUseBrowserCache()) {
size = 0;
}
assets.add(new Asset(tokens[1].trim(), type, size, tokens[3]));
}
final PreloaderState state = new PreloaderState(assets);
for (int i = 0; i < assets.size; i++) {
final Asset asset = assets.get(i);
if (contains(asset.url)) {
asset.loaded = asset.size;
asset.succeed = true;
continue;
}
loader.load(baseUrl + asset.url, asset.type, asset.mimeType, new AssetLoaderListener<Object>() {
@Override
public void onProgress (double amount) {
asset.loaded = (long) amount;
callback.update(state);
}
@Override
public void onFailure () {
asset.failed = true;
callback.error(asset.url);
callback.update(state);
}
@Override
public void onSuccess (Object result) {
switch (asset.type) {
case Text:
texts.put(asset.url, (String) result);
break;
case Image:
images.put(asset.url, (ImageElement) result);
break;
case Binary:
binaries.put(asset.url, (Blob) result);
break;
case Audio:
audio.put(asset.url, null);
break;
case Directory:
directories.put(asset.url, null);
break;
}
asset.succeed = true;
callback.update(state);
}
});
}
callback.update(state);
}
});
}
public InputStream read (String url) {
if (texts.containsKey(url)) {
try {
return new ByteArrayInputStream(texts.get(url).getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
return null;
}
}
if (images.containsKey(url)) {
return new ByteArrayInputStream(new byte[1]); // FIXME, sensible?
}
if (binaries.containsKey(url)) {
return binaries.get(url).read();
}
if (audio.containsKey(url)) {
return new ByteArrayInputStream(new byte[1]); // FIXME, sensible?
}
return null;
}
public boolean contains (String url) {
return texts.containsKey(url) || images.containsKey(url) || binaries.containsKey(url) || audio.containsKey(url) || directories.containsKey(url);
}
public boolean isText (String url) {
return texts.containsKey(url);
}
public boolean isImage (String url) {
return images.containsKey(url);
}
public boolean isBinary (String url) {
return binaries.containsKey(url);
}
public boolean isAudio (String url) {
return audio.containsKey(url);
}
public boolean isDirectory (String url) {
return directories.containsKey(url);
}
private boolean isChild(String path, String url) {
return path.startsWith(url) && (path.indexOf('/', url.length() + 1) < 0);
}
public FileHandle[] list (String url) {
Array<FileHandle> files = new Array<FileHandle>();
for (String path : texts.keys()) {
if (isChild(path, url)) {
files.add(new GwtFileHandle(this, path, FileType.Internal));
}
}
FileHandle[] list = new FileHandle[files.size];
System.arraycopy(files.items, 0, list, 0, list.length);
return list;
}
public FileHandle[] list (String url, FileFilter filter) {
Array<FileHandle> files = new Array<FileHandle>();
for (String path : texts.keys()) {
if (isChild(path, url) && filter.accept(new File(path))) {
files.add(new GwtFileHandle(this, path, FileType.Internal));
}
}
FileHandle[] list = new FileHandle[files.size];
System.arraycopy(files.items, 0, list, 0, list.length);
return list;
}
public FileHandle[] list (String url, FilenameFilter filter) {
Array<FileHandle> files = new Array<FileHandle>();
for (String path : texts.keys()) {
if (isChild(path, url) && filter.accept(new File(url), path.substring(url.length() + 1))) {
files.add(new GwtFileHandle(this, path, FileType.Internal));
}
}
FileHandle[] list = new FileHandle[files.size];
System.arraycopy(files.items, 0, list, 0, list.length);
return list;
}
public FileHandle[] list (String url, String suffix) {
Array<FileHandle> files = new Array<FileHandle>();
for (String path : texts.keys()) {
if (isChild(path, url) && path.endsWith(suffix)) {
files.add(new GwtFileHandle(this, path, FileType.Internal));
}
}
FileHandle[] list = new FileHandle[files.size];
System.arraycopy(files.items, 0, list, 0, list.length);
return list;
}
public long length (String url) {
if (texts.containsKey(url)) {
try {
return texts.get(url).getBytes("UTF-8").length;
} catch (UnsupportedEncodingException e) {
return texts.get(url).getBytes().length;
}
}
if (images.containsKey(url)) {
return 1; // FIXME, sensible?
}
if (binaries.containsKey(url)) {
return binaries.get(url).length();
}
if (audio.containsKey(url)) {
return 1; // FIXME sensible?
}
return 0;
}
}