Home | History | Annotate | Download | only in particles
      1 package com.badlogic.gdx.graphics.g3d.particles;
      2 
      3 import com.badlogic.gdx.assets.AssetDescriptor;
      4 import com.badlogic.gdx.assets.AssetManager;
      5 import com.badlogic.gdx.utils.Array;
      6 import com.badlogic.gdx.utils.GdxRuntimeException;
      7 import com.badlogic.gdx.utils.IntArray;
      8 import com.badlogic.gdx.utils.Json;
      9 import com.badlogic.gdx.utils.JsonValue;
     10 import com.badlogic.gdx.utils.ObjectMap;
     11 import com.badlogic.gdx.utils.ObjectMap.Entry;
     12 import com.badlogic.gdx.utils.reflect.ClassReflection;
     13 import com.badlogic.gdx.utils.reflect.ReflectionException;
     14 
     15 /** This class handles the assets and configurations required by a given resource when de/serialized.
     16  * It's handy when a given object or one of its members requires some assets to be loaded to work properly after
     17  * being deserialized. To save the assets, the object should implement the {@link Configurable} interface and obtain
     18  * a {@link SaveData} object to store every required asset or information which will be used during the loading phase.
     19  * The passed in {@link AssetManager} is generally used to find the asset file name for a given resource of a given type.
     20  * The class can also store global configurations, this is useful when dealing with objects which should be allocated once
     21  * (i.e singleton).
     22  * The deserialization process must happen in the same order of serialization, because the per object {@link SaveData} blocks are stored
     23  * as an {@link Array} within the {@link ResourceData}, while the global {@link SaveData} instances can be accessed in any order because
     24  * require a unique {@link String} and are stored in an {@link ObjectMap}.
     25  * @author Inferno */
     26 public class ResourceData<T> implements Json.Serializable{
     27 
     28 	/** This interface must be implemented by any class requiring additional assets to be loaded/saved */
     29 	public static interface Configurable<T>{
     30 		public void save(AssetManager manager, ResourceData<T> resources);
     31 		public void load(AssetManager manager, ResourceData<T> resources);
     32 	}
     33 
     34 	/** Contains all the saved data.
     35 	 * {@link #data} is a map which link an asset name to its instance.
     36 	 * {@link #assets} is an array of indices addressing a given
     37 	 * {@link com.badlogic.gdx.graphics.g3d.particles.ResourceData.AssetData} in the {@link ResourceData} */
     38 	public static class SaveData implements Json.Serializable{
     39 		ObjectMap<String, Object> data;
     40 		IntArray assets;
     41 		private int loadIndex;
     42 		protected ResourceData resources;
     43 
     44 		public SaveData(){
     45 			data = new ObjectMap<String, Object>();
     46 			assets = new IntArray();
     47 			loadIndex = 0;
     48 		}
     49 
     50 		public SaveData(ResourceData resources){
     51 			data = new ObjectMap<String, Object>();
     52 			assets = new IntArray();
     53 			loadIndex = 0;
     54 			this.resources = resources;
     55 		}
     56 
     57 		public <K> void saveAsset(String filename, Class<K> type){
     58 			int i = resources.getAssetData(filename, type);
     59 			if(i == -1){
     60 				resources.sharedAssets.add(new AssetData(filename, type));
     61 				i = resources.sharedAssets.size -1;
     62 			}
     63 			assets.add(i);
     64 		}
     65 
     66 		public void save(String key, Object value){
     67 			data.put(key, value);
     68 		}
     69 
     70 		public AssetDescriptor loadAsset(){
     71 			if(loadIndex == assets.size) return null;
     72 			AssetData data = (AssetData)resources.sharedAssets.get(assets.get(loadIndex++));
     73 			return new AssetDescriptor(data.filename, data.type);
     74 		}
     75 
     76 		public <K> K load(String key){
     77 			return (K)data.get(key);
     78 		}
     79 
     80 		@Override
     81 		public void write (Json json) {
     82 			json.writeValue("data", data, ObjectMap.class);
     83 			json.writeValue("indices", assets.toArray(), int[].class);
     84 		}
     85 
     86 		@Override
     87 		public void read (Json json, JsonValue jsonData) {
     88 			data = json.readValue("data", ObjectMap.class, jsonData);
     89 			assets.addAll(json.readValue("indices", int[].class, jsonData));
     90 		}
     91 	}
     92 
     93 	/** This class contains all the information related to a given asset */
     94 	public static class AssetData<T> implements Json.Serializable{
     95 		public String filename;
     96 		public Class<T> type;
     97 		public AssetData(){}
     98 		public AssetData(String filename, Class<T> type){
     99 			this.filename = filename;
    100 			this.type = type;
    101 		}
    102 		@Override
    103 		public void write (Json json) {
    104 			json.writeValue("filename", filename);
    105 			json.writeValue("type", type.getName());
    106 		}
    107 		@Override
    108 		public void read (Json json, JsonValue jsonData) {
    109 			filename = json.readValue("filename", String.class, jsonData);
    110 			String className = json.readValue("type", String.class, jsonData);
    111 			try {
    112 				type = (Class<T>)ClassReflection.forName(className);
    113 			} catch (ReflectionException e) {
    114 				throw new GdxRuntimeException("Class not found: " + className, e);
    115 			}
    116 		}
    117 	}
    118 
    119 	/** Unique data, can be used to save/load generic data which is not always loaded back after saving.
    120 	 * Must be used to store data which is uniquely addressable by a given string (i.e a system configuration).*/
    121 	private ObjectMap<String, SaveData> uniqueData;
    122 
    123 	/** Objects save data, must be loaded in the same saving order*/
    124 	private Array<SaveData> data;
    125 
    126 	/** Shared assets among all the configurable objects*/
    127 	Array<AssetData> sharedAssets;
    128 	private int currentLoadIndex;
    129 	public T resource;
    130 
    131 	public ResourceData(){
    132 		uniqueData = new ObjectMap<String, SaveData>();
    133 		data = new Array<SaveData>(true, 3, SaveData.class);
    134 		sharedAssets = new Array<AssetData>();
    135 		currentLoadIndex = 0;
    136 	}
    137 
    138 	public ResourceData(T resource){
    139 		this();
    140 		this.resource = resource;
    141 	}
    142 
    143 	<K> int getAssetData(String filename, Class<K> type){
    144 		int i=0;
    145 		for(AssetData data : sharedAssets){
    146 			if(data.filename.equals(filename) && data.type.equals(type)){
    147 				return i;
    148 			}
    149 			++i;
    150 		}
    151 		return -1;
    152 	}
    153 
    154 	public Array<AssetDescriptor> getAssetDescriptors () {
    155 		Array<AssetDescriptor> descriptors = new Array<AssetDescriptor>();
    156 		for(AssetData data : sharedAssets){
    157 			descriptors.add(new AssetDescriptor<T>(data.filename, data.type));
    158 		}
    159 		return descriptors;
    160 	}
    161 
    162 	public Array<AssetData> getAssets(){
    163 		return sharedAssets;
    164 	}
    165 
    166 	/** Creates and adds a new SaveData object to the save data list*/
    167 	public SaveData createSaveData() {
    168 		SaveData saveData = new SaveData(this);
    169 		data.add(saveData);
    170 		return saveData;
    171 	}
    172 
    173 	/** Creates and adds a new and unique SaveData object to the save data map*/
    174 	public SaveData createSaveData(String key) {
    175 		SaveData saveData = new SaveData(this);
    176 		if(uniqueData.containsKey(key))
    177 			throw new RuntimeException("Key already used, data must be unique, use a different key");
    178 		uniqueData.put(key, saveData);
    179 		return saveData;
    180 	}
    181 
    182 	/** @return the next save data in the list */
    183 	public SaveData getSaveData() {
    184 		return data.get(currentLoadIndex++);
    185 	}
    186 
    187 	/** @return the unique save data in the map */
    188 	public SaveData getSaveData(String key) {
    189 		return uniqueData.get(key);
    190 	}
    191 
    192 	@Override
    193 	public void write (Json json) {
    194 		json.writeValue("unique", uniqueData, ObjectMap.class);
    195 		json.writeValue("data", data, Array.class, SaveData.class);
    196 		json.writeValue("assets", sharedAssets.toArray(AssetData.class), AssetData[].class);
    197 		json.writeValue("resource", resource, null);
    198 	}
    199 
    200 	@Override
    201 	public void read (Json json, JsonValue jsonData) {
    202 		uniqueData = json.readValue("unique", ObjectMap.class, jsonData);
    203 		for(Entry<String, SaveData> entry : uniqueData.entries()){
    204 			entry.value.resources = this;
    205 		}
    206 
    207 		data = json.readValue("data", Array.class, SaveData.class, jsonData);
    208 		for(SaveData saveData : data){
    209 			saveData.resources = this;
    210 		}
    211 
    212 		sharedAssets.addAll(json.readValue("assets", Array.class, AssetData.class, jsonData));
    213 		resource = json.readValue("resource", null, jsonData);
    214 	}
    215 
    216 
    217 }
    218