/*
* Copyright 2012 Benjamin Glatzel <benjamin.glatzel@me.com>
*
* 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 org.terasology.asset.loaders;
import com.google.common.collect.Maps;
import com.google.gson.*;
import org.terasology.asset.AssetLoader;
import org.terasology.asset.AssetType;
import org.terasology.asset.AssetUri;
import org.terasology.logic.manager.AssetManager;
import org.terasology.rendering.assets.Material;
import org.terasology.rendering.assets.Shader;
import org.terasology.rendering.assets.Texture;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.net.URL;
import java.util.List;
import java.util.Map;
/**
* @author Immortius
*/
public class MaterialLoader implements AssetLoader<Material> {
Gson gson;
public MaterialLoader() {
gson = new GsonBuilder().registerTypeAdapter(MaterialMetadata.class, new MaterialMetadataHandler()).create();
}
@Override
public Material load(InputStream stream, AssetUri uri, List<URL> urls) throws IOException {
MaterialMetadata metadata = gson.fromJson(new InputStreamReader(stream), MaterialMetadata.class);
Shader shader = AssetManager.load(new AssetUri(AssetType.SHADER, metadata.shader), Shader.class);
if (shader == null) return null;
Material result = new Material(uri, shader);
for (Map.Entry<String, Texture> entry : metadata.textures.entrySet()) {
result.setTexture(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Float> entry : metadata.floatParams.entrySet()) {
result.setFloat(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Integer> entry : metadata.intParams.entrySet()) {
result.setInt(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, float[]> entry : metadata.floatArrayParams.entrySet()) {
switch (entry.getValue().length) {
case 1:
result.setFloat(entry.getKey(), entry.getValue()[0]);
break;
case 2:
result.setFloat2(entry.getKey(), entry.getValue()[0], entry.getValue()[1]);
break;
case 3:
result.setFloat3(entry.getKey(), entry.getValue()[0], entry.getValue()[1], entry.getValue()[2]);
break;
case 4:
result.setFloat4(entry.getKey(), entry.getValue()[0], entry.getValue()[1], entry.getValue()[2], entry.getValue()[3]);
break;
}
}
return result;
}
private static class MaterialMetadata {
String shader;
Map<String, Texture> textures = Maps.newHashMap();
Map<String, Float> floatParams = Maps.newHashMap();
Map<String, float[]> floatArrayParams = Maps.newHashMap();
Map<String, Integer> intParams = Maps.newHashMap();
}
private static class MaterialMetadataHandler implements JsonDeserializer<MaterialMetadata> {
@Override
public MaterialMetadata deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
MaterialMetadata metadata = new MaterialMetadata();
JsonObject obj = json.getAsJsonObject();
if (obj.has("shader")) {
metadata.shader = obj.getAsJsonPrimitive("shader").getAsString();
}
if (obj.has("params") && obj.get("params").isJsonObject()) {
JsonObject params = obj.get("params").getAsJsonObject();
for (Map.Entry<String, JsonElement> prop : params.entrySet()) {
if (prop.getValue().isJsonPrimitive()) {
if (prop.getValue().getAsJsonPrimitive().isString()) {
Texture texture = AssetManager.loadTexture(prop.getValue().getAsString());
if (texture != null) {
metadata.textures.put(prop.getKey(), texture);
}
} else if (prop.getValue().getAsJsonPrimitive().isNumber()) {
metadata.floatParams.put(prop.getKey(), prop.getValue().getAsFloat());
} else if (prop.getValue().getAsJsonPrimitive().isBoolean()) {
metadata.intParams.put(prop.getKey(), (prop.getValue().getAsBoolean()) ? 1 : 0);
}
} else if (prop.getValue().isJsonArray()) {
JsonArray array = prop.getValue().getAsJsonArray();
float[] result = new float[array.size()];
boolean valid = true;
for (int i = 0; i < array.size(); ++i) {
if (!array.get(i).isJsonPrimitive() || !array.get(i).getAsJsonPrimitive().isNumber()) {
valid = false;
break;
}
result[i] = array.get(i).getAsFloat();
}
if (valid) {
metadata.floatArrayParams.put(prop.getKey(), result);
}
}
}
}
return metadata;
}
}
}