diff --git a/Distro/CreatureAsset.cs b/Distro/CreatureAsset.cs index ebcace2..0df87be 100644 --- a/Distro/CreatureAsset.cs +++ b/Distro/CreatureAsset.cs @@ -46,82 +46,77 @@ [Serializable] public class CreatureAnimationAssetData { - [SerializeField] - public int start_frame; - [SerializeField] - public int end_frame; - - [SerializeField] - public bool make_point_cache; - - [SerializeField] - public int cache_approximation; - - public CreatureAnimationAssetData(int start_frame_in, int end_frame_in) { - start_frame = start_frame_in; - end_frame = end_frame_in; - make_point_cache = false; - cache_approximation = 1; - } + [SerializeField] + public int start_frame; + [SerializeField] + public int end_frame; + + [SerializeField] + public bool make_point_cache; + + [SerializeField] + public int cache_approximation; + + public CreatureAnimationAssetData(int start_frame_in, int end_frame_in) { + start_frame = start_frame_in; + end_frame = end_frame_in; + make_point_cache = false; + cache_approximation = 1; + } } [Serializable] -public class SerializableDictionary : Dictionary, ISerializationCallbackReceiver -{ - [SerializeField] - private List keys = new List(); - - [SerializeField] - private List values = new List(); - - // save the dictionary to lists - public void OnBeforeSerialize() - { - keys.Clear(); - values.Clear(); - foreach(KeyValuePair pair in this) - { - keys.Add(pair.Key); - values.Add(pair.Value); - } - } - - // load dictionary from lists - public void OnAfterDeserialize() - { - this.Clear(); - - if(keys.Count != values.Count) - throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable.")); - - for(int i = 0; i < keys.Count; i++) - this.Add(keys[i], values[i]); - } +public class SerializableDictionary : Dictionary, ISerializationCallbackReceiver { + [SerializeField] + private List keys = new List(); + + [SerializeField] + private List values = new List(); + + // save the dictionary to lists + public void OnBeforeSerialize() { + keys.Clear(); + values.Clear(); + foreach (KeyValuePair pair in this) { + keys.Add(pair.Key); + values.Add(pair.Value); + } + } + + // load dictionary from lists + public void OnAfterDeserialize() { + this.Clear(); + + if (keys.Count != values.Count) + throw new System.Exception(string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable.")); + + for (int i = 0; i < keys.Count; i++) + this.Add(keys[i], values[i]); + } } -[Serializable] public class DictionaryOfStringAndAnimation : SerializableDictionary {} +[Serializable] public class DictionaryOfStringAndAnimation : SerializableDictionary { } -public class CreatureAsset : MonoBehaviour -{ - public TextAsset creatureJSON, compressedCreatureJSON, flatCreatureData, creatureMetaJSON; - public CreatureManager creature_manager = null; - public CreatureMetaData creature_meta_data = null; - private bool is_dirty; +public class CreatureAsset : MonoBehaviour { + public TextAsset creatureJSON, compressedCreatureJSON, flatCreatureData, creatureMetaJSON; + public CreatureManager creature_manager = null; + public CreatureMetaData creature_meta_data = null; + private bool is_dirty; - [SerializeField] - public DictionaryOfStringAndAnimation animation_clip_overides = new DictionaryOfStringAndAnimation (); + [SerializeField] + public DictionaryOfStringAndAnimation animation_clip_overides = new DictionaryOfStringAndAnimation(); - [SerializeField] - public bool useCompressedAsset = false; + [SerializeField] + public bool useCompressedAsset = false; - [SerializeField] - public bool useFlatDataAsset = false; + [SerializeField] + public bool useFlatDataAsset = false; - [SerializeField] - public List physics_assets = new List(); + [SerializeField] + public List physics_assets = new List(); - [SerializeField] - public List skin_swap_names = new List(); + [SerializeField] + public List skin_swap_names = new List(); #if UNITY_EDITOR [MenuItem("GameObject/Creature/CreatureAsset")] @@ -131,160 +126,142 @@ static CreatureAsset CreateCreatureAsset() newObj.name = "New Creature Asset"; CreatureAsset new_asset; new_asset = newObj.AddComponent () as CreatureAsset; - - return new_asset; - } -#endif - - public CreatureAsset() - { + return new_asset; } +#endif - public void ResetState () { - creatureJSON = null; - compressedCreatureJSON = null; - creature_manager = null; - is_dirty = false; - } - - public bool GetIsDirty() - { - return is_dirty; - } - - public void SetIsDirty(bool flag_in) - { - is_dirty = flag_in; - } - - public void SaveCompressedText(string filename, string text_in) - { - /* - byte[] text1 = System.Text.Encoding.ASCII.GetBytes(text_in); - byte[] compressed = LZMAtools.CompressByteArrayToLZMAByteArray(text1); - File.WriteAllBytes (filename, compressed); - */ - Debug.LogWarning("This function is deprecated. Please use FlatBuffers Binary Format instead."); - } - - public string DecodeCompressedBytes(byte[] bytes) - { - /* - byte[] decompressed = LZMAtools.DecompressLZMAByteArrayToByteArray (bytes); - return System.Text.Encoding.Default.GetString(decompressed); - */ - - Debug.LogWarning("This function is deprecated. Please use FlatBuffers Binary Format instead."); - return null; - } - - public bool HasNoValidAsset() - { - bool regularCheck = !useCompressedAsset && !useFlatDataAsset && (creatureJSON == null); - bool compressedCheck = useCompressedAsset && (creatureJSON == null); - bool flatCheck = useFlatDataAsset && (flatCreatureData == null); - - return regularCheck || compressedCheck || flatCheck; - } - - public string GetAssetString() - { - if (HasNoValidAsset ()) { - return null; - } - - string readString = null; - if (useCompressedAsset) { - readString = DecodeCompressedBytes (compressedCreatureJSON.bytes); - } - else { - readString = creatureJSON.text; - } - - return readString; - } - - public Dictionary LoadCreatureJsonData() - { - Dictionary load_data = null; - - if(useFlatDataAsset) - { - byte[] readBytes = flatCreatureData.bytes; - load_data = CreatureModule.Utils.LoadCreatureFlatDataFromBytes(readBytes); - } - else { - string readString = GetAssetString (); - load_data = CreatureModule.Utils.LoadCreatureJSONDataFromString (readString); - } - - return load_data; - } - - public CreatureManager GetCreatureManager() - { - if (HasNoValidAsset()) - { - Debug.LogError("Input Creature JSON file not set for CreatureAsset: " + name, this); - ResetState (); - return null; - } - - if (creature_manager != null) - { - return creature_manager; - } - - Dictionary load_data = LoadCreatureJsonData (); - - CreatureModule.Creature new_creature = new CreatureModule.Creature(ref load_data); - creature_manager = new CreatureModule.CreatureManager (new_creature); - creature_manager.CreateAllAnimations (ref load_data); - - var all_animations = creature_manager.animations; - foreach (KeyValuePair entry in animation_clip_overides) - { - var cur_name = entry.Key; - var cur_animation_data = entry.Value; - - if(all_animations.ContainsKey(cur_name)) - { - // Set Animation Frame Ranges - all_animations[cur_name].start_time = cur_animation_data.start_frame; - all_animations[cur_name].end_time = cur_animation_data.end_frame; - - // Decide if we need to make point caches - if(cur_animation_data.make_point_cache) - { - var stopWatch = new System.Diagnostics.Stopwatch(); - stopWatch.Start(); - - creature_manager.MakePointCache(cur_name, cur_animation_data.cache_approximation); - - stopWatch.Stop (); - Debug.Log ("Creature Point Cache generation took: " + stopWatch.ElapsedMilliseconds); - } - } - } - - - - is_dirty = true; - - // Load meta data if available - creature_meta_data = null; - if(creatureMetaJSON != null) - { - creature_meta_data = new CreatureMetaData(); - CreatureModule.Utils.BuildCreatureMetaData( - creature_meta_data, - creatureMetaJSON.text, - physics_assets, - skin_swap_names); - } - - return creature_manager; - } + public CreatureAsset() { + + } + + public void ResetState() { + creatureJSON = null; + compressedCreatureJSON = null; + creature_manager = null; + is_dirty = false; + } + + public bool GetIsDirty() { + return is_dirty; + } + + public void SetIsDirty(bool flag_in) { + is_dirty = flag_in; + } + + public void SaveCompressedText(string filename, string text_in) { + /* + byte[] text1 = System.Text.Encoding.ASCII.GetBytes(text_in); + byte[] compressed = LZMAtools.CompressByteArrayToLZMAByteArray(text1); + File.WriteAllBytes (filename, compressed); + */ + Debug.LogWarning("This function is deprecated. Please use FlatBuffers Binary Format instead."); + } + + public string DecodeCompressedBytes(byte[] bytes) { + /* + byte[] decompressed = LZMAtools.DecompressLZMAByteArrayToByteArray (bytes); + return System.Text.Encoding.Default.GetString(decompressed); + */ + + Debug.LogWarning("This function is deprecated. Please use FlatBuffers Binary Format instead."); + return null; + } + + public bool HasNoValidAsset() { + bool regularCheck = !useCompressedAsset && !useFlatDataAsset && (creatureJSON == null); + bool compressedCheck = useCompressedAsset && (creatureJSON == null); + bool flatCheck = useFlatDataAsset && (flatCreatureData == null); + + return regularCheck || compressedCheck || flatCheck; + } + + public string GetAssetString() { + if (HasNoValidAsset()) { + return null; + } + + string readString = null; + if (useCompressedAsset) { + readString = DecodeCompressedBytes(compressedCreatureJSON.bytes); + } else { + readString = creatureJSON.text; + } + + return readString; + } + + public Dictionary LoadCreatureJsonData() { + Dictionary load_data = null; + + if (useFlatDataAsset) { + byte[] readBytes = flatCreatureData.bytes; + load_data = CreatureModule.Utils.LoadCreatureFlatDataFromBytes(readBytes); + } else { + string readString = GetAssetString(); + load_data = CreatureModule.Utils.LoadCreatureJSONDataFromString(readString); + } + + return load_data; + } + + public CreatureManager GetCreatureManager() { + if (HasNoValidAsset()) { + Debug.LogError("Input Creature JSON file not set for CreatureAsset: " + name, this); + ResetState(); + return null; + } + + if (creature_manager != null) { + return creature_manager; + } + + Dictionary load_data = LoadCreatureJsonData(); + + CreatureModule.Creature new_creature = new CreatureModule.Creature(ref load_data); + creature_manager = new CreatureModule.CreatureManager(new_creature); + creature_manager.CreateAllAnimations(ref load_data); + + var all_animations = creature_manager.animations; + foreach (KeyValuePair entry in animation_clip_overides) { + var cur_name = entry.Key; + var cur_animation_data = entry.Value; + + if (all_animations.ContainsKey(cur_name)) { + // Set Animation Frame Ranges + all_animations[cur_name].start_time = cur_animation_data.start_frame; + all_animations[cur_name].end_time = cur_animation_data.end_frame; + + // Decide if we need to make point caches + if (cur_animation_data.make_point_cache) { + var stopWatch = new System.Diagnostics.Stopwatch(); + stopWatch.Start(); + + creature_manager.MakePointCache(cur_name, cur_animation_data.cache_approximation); + + stopWatch.Stop(); + Debug.Log("Creature Point Cache generation took: " + stopWatch.ElapsedMilliseconds); + } + } + } + + + + is_dirty = true; + + // Load meta data if available + creature_meta_data = null; + if (creatureMetaJSON != null) { + creature_meta_data = new CreatureMetaData(); + CreatureModule.Utils.BuildCreatureMetaData( + creature_meta_data, + creatureMetaJSON.text, + physics_assets, + skin_swap_names); + } + + return creature_manager; + } } diff --git a/Distro/CreatureCanvasRenderer.cs b/Distro/CreatureCanvasRenderer.cs index aa1713d..00f1b26 100644 --- a/Distro/CreatureCanvasRenderer.cs +++ b/Distro/CreatureCanvasRenderer.cs @@ -10,328 +10,314 @@ #endif [RequireComponent(typeof(CanvasRenderer)), ExecuteInEditMode] -public class CreatureCanvasRenderer : MonoBehaviour -{ - private MeshFilter meshFilter; - private Mesh active_mesh, mesh1, mesh2; - private Vector3[] vertices; - private Vector3[] normals; - private Vector4[] tangents; - private Color32[] colors; - private Vector2[] uvs; - private int[] triangles, skin_swap_triangles; - private List final_indices, final_skin_swap_indices; - bool skin_swap_active = false; - String skin_swap_name = ""; - private bool swap_mesh; - private float local_time; - private bool use_custom_time_range; - private float custom_start_time, custom_end_time; - public float local_time_scale; - public CreatureAsset creature_asset = null; - public CreatureManager creature_manager; - private CreatureGameController game_controller = null; - public int animation_choice_index; - public string active_animation_name; - public float blend_rate = 0.1f; - public float region_offsets_z = 0.01f; - public bool should_loop = true; - public bool counter_clockwise = false; - public Material material; - public Dictionary feedback_bones; +public class CreatureCanvasRenderer : MonoBehaviour { + private MeshFilter meshFilter; + private Mesh active_mesh, mesh1, mesh2; + private Vector3[] vertices; + private Vector3[] normals; + private Vector4[] tangents; + private Color32[] colors; + private Vector2[] uvs; + private int[] triangles, skin_swap_triangles; + private List final_indices, final_skin_swap_indices; + bool skin_swap_active = false; + String skin_swap_name = ""; + private bool swap_mesh; + private float local_time; + private bool use_custom_time_range; + private float custom_start_time, custom_end_time; + public float local_time_scale; + public CreatureAsset creature_asset = null; + public CreatureManager creature_manager; + private CreatureGameController game_controller = null; + public int animation_choice_index; + public string active_animation_name; + public float blend_rate = 0.1f; + public float region_offsets_z = 0.01f; + public bool should_loop = true; + public bool counter_clockwise = false; + public Dictionary feedback_bones; + public CreatureMaterialPacker materialPacker = null; #if UNITY_EDITOR - [MenuItem("GameObject/Creature/CreatureCanvasRenderer")] - static CreatureCanvasRenderer CreateCanvasRenderer() - { - GameObject newObj = new GameObject(); - newObj.name = "New Creature Canvas Renderer"; - CreatureCanvasRenderer new_renderer; - new_renderer = newObj.AddComponent() as CreatureCanvasRenderer; - - return new_renderer; - } + [MenuItem("GameObject/Creature/CreatureCanvasRenderer")] + static CreatureCanvasRenderer CreateCanvasRenderer() { + GameObject newObj = new GameObject(); + newObj.name = "New Creature Canvas Renderer"; + CreatureCanvasRenderer new_renderer; + new_renderer = newObj.AddComponent() as CreatureCanvasRenderer; + + return new_renderer; + } #endif - public CreatureCanvasRenderer() - { - local_time_scale = 2.0f; - region_offsets_z = 0.01f; - feedback_bones = new Dictionary(); - } - - public virtual void Reset() - { - meshFilter = GetComponent(); - active_mesh = null; - mesh1 = CreatureRenderModule.createMesh(); - mesh2 = CreatureRenderModule.createMesh(); - vertices = null; - normals = null; - colors = null; - uvs = null; - swap_mesh = false; - local_time = 0; - } - - public void SetGameController(CreatureGameController controller_in) - { - game_controller = controller_in; - } - - public void InitData() - { - if (creature_asset) - { - CreatureManager ref_manager = creature_asset.GetCreatureManager(); - creature_manager = new CreatureManager(ref_manager.target_creature); - creature_manager.animations = ref_manager.animations; - creature_manager.active_blend_run_times = new Dictionary(ref_manager.active_blend_run_times); - creature_manager.active_blend_animation_names = new List(ref_manager.active_blend_animation_names); - creature_manager.auto_blend_names = new List(ref_manager.auto_blend_names); - creature_manager.feedback_bones_map = feedback_bones; - - SetActiveAnimation(active_animation_name); - creature_manager.SetIsPlaying(true); - } - - var renderer = GetComponent(); - renderer.materialCount = 1; - renderer.SetMaterial(material, 0); - } - - void Start() - { - Reset(); - InitData(); + CanvasRenderer _canvasRenderer = null; + public CanvasRenderer canvasRenderer { + get { + if (_canvasRenderer == null) { + _canvasRenderer = GetComponent(); + } + return _canvasRenderer; } - - private void doSwapMesh() - { - active_mesh = swap_mesh ? mesh1 : mesh2; - swap_mesh = !swap_mesh; + } + + public CreatureCanvasRenderer() { + local_time_scale = 2.0f; + region_offsets_z = 0.01f; + feedback_bones = new Dictionary(); + } + + public virtual void Reset() { + meshFilter = GetComponent(); + active_mesh = null; + mesh1 = CreatureRenderModule.createMesh(); + mesh2 = CreatureRenderModule.createMesh(); + vertices = null; + normals = null; + colors = null; + uvs = null; + swap_mesh = false; + local_time = 0; + } + + public void SetGameController(CreatureGameController controller_in) { + game_controller = controller_in; + } + + public void InitData() { + if (creature_asset) { + CreatureManager ref_manager = creature_asset.GetCreatureManager(); + creature_manager = new CreatureManager(ref_manager.target_creature); + creature_manager.animations = ref_manager.animations; + creature_manager.active_blend_run_times = new Dictionary(ref_manager.active_blend_run_times); + creature_manager.active_blend_animation_names = new List(ref_manager.active_blend_animation_names); + creature_manager.auto_blend_names = new List(ref_manager.auto_blend_names); + creature_manager.feedback_bones_map = feedback_bones; + + SetActiveAnimation(active_animation_name); + creature_manager.SetIsPlaying(true); } - public void Awake() - { - Reset(); - InitData(); + SetMaterials(); + } + + void Start() { + Reset(); + InitData(); + } + + private void doSwapMesh() { + active_mesh = swap_mesh ? mesh1 : mesh2; + swap_mesh = !swap_mesh; + } + + public void Awake() { + Reset(); + InitData(); + } + + // Sets the animation to the specified animation clip name + public void SetActiveAnimation(string animation_name, bool already_active_check = false) { + if (already_active_check) { + if (active_animation_name == animation_name) { + return; + } } - // Sets the animation to the specified animation clip name - public void SetActiveAnimation(string animation_name, bool already_active_check = false) - { - if (already_active_check) - { - if (active_animation_name == animation_name) - { - return; - } - } - - active_animation_name = animation_name; - creature_manager.SetAutoBlending(false); - - bool can_set = creature_manager.SetActiveAnimationName(active_animation_name); - if (!can_set) - { - creature_manager.SetActiveAnimationName(creature_manager.GetAnimationNames()[0]); - active_animation_name = creature_manager.GetActiveAnimationName(); - animation_choice_index = 0; - } - - - local_time = creature_manager.animations[creature_manager.GetActiveAnimationName()].start_time; - - if (game_controller) - { - game_controller.AnimClipChangeEvent(); - } - } + active_animation_name = animation_name; + creature_manager.SetAutoBlending(false); - public void BlendToAnimation(string animation_name) - { - if (active_animation_name == animation_name) - { - return; - } - - active_animation_name = animation_name; - creature_manager.SetAutoBlending(true); - creature_manager.AutoBlendTo(animation_name, blend_rate); - - if (game_controller) - { - game_controller.AnimClipChangeEvent(); - } + bool can_set = creature_manager.SetActiveAnimationName(active_animation_name); + if (!can_set) { + creature_manager.SetActiveAnimationName(creature_manager.GetAnimationNames()[0]); + active_animation_name = creature_manager.GetActiveAnimationName(); + animation_choice_index = 0; } - // Returns the local playback time - public float GetLocalTime() - { - return local_time; - } - // Set the local playback time - public void SetLocalTime(float t) - { - local_time = t; - } + local_time = creature_manager.animations[creature_manager.GetActiveAnimationName()].start_time; - // Returns the currently playing animation clip - public String GetActiveAnimation() - { - return active_animation_name; + if (game_controller) { + game_controller.AnimClipChangeEvent(); } + } - // If true, will use a user defined animation clip range - public void SetUseCustomTimeRange(bool flag_in) - { - use_custom_time_range = flag_in; + public void BlendToAnimation(string animation_name) { + if (active_animation_name == animation_name) { + return; } - // Sets the user specified animation clip range - public void SetCustomTimeRange(float start_time, float end_time) - { - custom_start_time = start_time; - custom_end_time = end_time; - } + active_animation_name = animation_name; + creature_manager.SetAutoBlending(true); + creature_manager.AutoBlendTo(animation_name, blend_rate); - public void EnableSkinSwap(String swap_name_in, bool active) - { - CreatureRenderModule.EnableSkinSwap( - swap_name_in, - active, - creature_manager, - creature_asset, - ref skin_swap_active, - ref skin_swap_name, - ref skin_swap_triangles, - ref final_skin_swap_indices); + if (game_controller) { + game_controller.AnimClipChangeEvent(); } - - public void DisableSkinSwap() - { - EnableSkinSwap("", false); + } + + // Returns the local playback time + public float GetLocalTime() { + return local_time; + } + + // Set the local playback time + public void SetLocalTime(float t) { + local_time = t; + } + + // Returns the currently playing animation clip + public String GetActiveAnimation() { + return active_animation_name; + } + + // If true, will use a user defined animation clip range + public void SetUseCustomTimeRange(bool flag_in) { + use_custom_time_range = flag_in; + } + + // Sets the user specified animation clip range + public void SetCustomTimeRange(float start_time, float end_time) { + custom_start_time = start_time; + custom_end_time = end_time; + } + + public void EnableSkinSwap + (String swap_name_in, bool active) { + CreatureRenderModule.EnableSkinSwap( + swap_name_in, + active, + creature_manager, + creature_asset, + ref skin_swap_active, + ref skin_swap_name, + ref skin_swap_triangles, + ref final_skin_swap_indices); + } + + public void DisableSkinSwap() { + EnableSkinSwap("", false); + } + + // Add your own custom Skin Swap into the object + public bool AddSkinSwap(String swap_name, HashSet swap_set) { + return CreatureRenderModule.AddSkinSwap(creature_asset, swap_name, swap_set); + } + + public void CreateRenderingData() { + CreatureRenderModule.CreateRenderingData( + creature_manager, + ref vertices, + ref normals, + ref tangents, + ref colors, + ref uvs, + ref triangles, + ref final_indices); + } + + public void UpdateRenderingData() { + CreatureRenderModule.UpdateRenderingData( + creature_manager, + counter_clockwise, + ref vertices, + ref normals, + ref tangents, + ref colors, + ref uvs, + creature_asset, + skin_swap_active, + active_animation_name, + ref final_indices, + ref final_skin_swap_indices, + ref triangles, + ref skin_swap_triangles); + + bool should_skin_swap = CreatureRenderModule.shouldSkinSwap(creature_asset, skin_swap_active, ref skin_swap_triangles); + + active_mesh.vertices = vertices; + active_mesh.colors32 = colors; + active_mesh.triangles = should_skin_swap ? skin_swap_triangles : triangles; + active_mesh.normals = normals; + active_mesh.tangents = tangents; + active_mesh.uv = uvs; + + //CreatureRenderModule.debugDrawBones(creature_manager.target_creature.render_composition.getRootBone ()); + } + + public void UpdateTime() { + CreatureRenderModule.UpdateTime( + creature_manager, + game_controller, + active_animation_name, + local_time_scale, + region_offsets_z, + should_loop, + ref local_time); + } + + /* + public List ConvertMesh() + { + Vector3[] vertices = active_mesh.vertices; + int[] triangles = active_mesh.triangles; + Vector3[] normals = active_mesh.normals; + Vector2[] uv = active_mesh.uv; + + List vertexList = new List(triangles.Length); + + UIVertex vertex; + for (int i = 0; i < triangles.Length; i++) + { + vertex = new UIVertex(); + int triangle = triangles[i]; + + vertex.position = (vertices[triangle] - active_mesh.bounds.center); + vertex.uv0 = uv[triangle]; + vertex.normal = normals[triangle]; + + vertexList.Add(vertex); + + if (i % 3 == 0) + vertexList.Add(vertex); + } + + return vertexList; + } + */ + + // Update is called once per frame + void LateUpdate() { + if (creature_manager != null) { + doSwapMesh(); + + if (creature_asset.GetIsDirty() || vertices == null) { + CreateRenderingData(); + creature_asset.SetIsDirty(false); + } + + UpdateTime(); + UpdateRenderingData(); } - // Add your own custom Skin Swap into the object - public bool AddSkinSwap(String swap_name, HashSet swap_set) - { - return CreatureRenderModule.AddSkinSwap(creature_asset, swap_name, swap_set); - } - - public void CreateRenderingData() - { - CreatureRenderModule.CreateRenderingData( - creature_manager, - ref vertices, - ref normals, - ref tangents, - ref colors, - ref uvs, - ref triangles, - ref final_indices); - } - - public void UpdateRenderingData() - { - CreatureRenderModule.UpdateRenderingData( - creature_manager, - counter_clockwise, - ref vertices, - ref normals, - ref tangents, - ref colors, - ref uvs, - creature_asset, - skin_swap_active, - active_animation_name, - ref final_indices, - ref final_skin_swap_indices, - ref triangles, - ref skin_swap_triangles); - - bool should_skin_swap = CreatureRenderModule.shouldSkinSwap(creature_asset, skin_swap_active, ref skin_swap_triangles); - - active_mesh.vertices = vertices; - active_mesh.colors32 = colors; - active_mesh.triangles = should_skin_swap ? skin_swap_triangles : triangles; - active_mesh.normals = normals; - active_mesh.tangents = tangents; - active_mesh.uv = uvs; - - //CreatureRenderModule.debugDrawBones(creature_manager.target_creature.render_composition.getRootBone ()); - } - - public void UpdateTime() - { - CreatureRenderModule.UpdateTime( - creature_manager, - game_controller, - active_animation_name, - local_time_scale, - region_offsets_z, - should_loop, - ref local_time); - } - - /* - public List ConvertMesh() - { - Vector3[] vertices = active_mesh.vertices; - int[] triangles = active_mesh.triangles; - Vector3[] normals = active_mesh.normals; - Vector2[] uv = active_mesh.uv; - - List vertexList = new List(triangles.Length); - - UIVertex vertex; - for (int i = 0; i < triangles.Length; i++) - { - vertex = new UIVertex(); - int triangle = triangles[i]; - - vertex.position = (vertices[triangle] - active_mesh.bounds.center); - vertex.uv0 = uv[triangle]; - vertex.normal = normals[triangle]; - - vertexList.Add(vertex); - - if (i % 3 == 0) - vertexList.Add(vertex); - } - - return vertexList; - } - */ - - // Update is called once per frame - void LateUpdate() - { - if (creature_manager != null) - { - doSwapMesh(); - - if (creature_asset.GetIsDirty() || vertices == null) - { - CreateRenderingData(); - creature_asset.SetIsDirty(false); - } - - UpdateTime(); - UpdateRenderingData(); - } - - var renderer = GetComponent(); - renderer.SetMesh(active_mesh); - renderer.materialCount = 1; - renderer.SetMaterial(material, 0); - } + canvasRenderer.SetMesh(active_mesh); + SetMaterials(); + } - void OnDisable() - { - var renderer = GetComponent(); - renderer.SetMesh(null); + protected void SetMaterials() { + if (canvasRenderer == null) { + canvasRenderer.materialCount = 0; + return; } + canvasRenderer.materialCount = 1; + bool alt = ((int)(Time.realtimeSinceStartup * 5.0f)) % 2 == 0; + canvasRenderer.SetMaterial(materialPacker.GetMaterial(new Dictionary() { + { "face", "Skin_Pale" }, + { "helmet", alt ? "Equip_Bronze" : "Equip_Silver"} + }), 0); + } + + void OnDisable() { + canvasRenderer.SetMesh(null); + } } diff --git a/Distro/CreatureMaterialPacker.cs b/Distro/CreatureMaterialPacker.cs new file mode 100644 index 0000000..6b3d255 --- /dev/null +++ b/Distro/CreatureMaterialPacker.cs @@ -0,0 +1,130 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System.Linq; +using System.IO; + +// A mapping from slot name => skin name +using CreatureMaterialAttachmentSet = System.Collections.Generic.Dictionary; + +public class CreatureMaterialPacker : MonoBehaviour { + public Material baseMaterial = null; + + /// + /// PNG image assets to extract skin regions from. + /// + public List attachmentSprites = null; + + /// + /// JSON definition of where different parts of the skin regions reside. + /// + public TextAsset attachmentRegionsJSON = null; + + // Cache of the last texture and its attachments for incremental rendering. + Texture2D _texture = null; + CreatureMaterialAttachmentSet _attachments = null; + + Dictionary _attachmentRegions; + + /// + /// The parsed skin regions, name => {x,y,width,height} + /// + /// The skin regions. + protected Dictionary attachmentRegions { + get { + if (_attachmentRegions == null && attachmentRegionsJSON != null) { + Dictionary dict = null; + _attachmentRegions = new Dictionary(); + dict = JsonFx.Json.JsonReader.Deserialize( + attachmentRegionsJSON.text, typeof(Dictionary) + ) as Dictionary; + foreach (string key in dict.Keys.ToList()) { + Dictionary packed = (Dictionary)dict[key]; + Rect r = new Rect(); + if (packed.ContainsKey("x")) r.x = float.Parse(packed["x"].ToString()); + if (packed.ContainsKey("y")) r.y = float.Parse(packed["y"].ToString()); + if (packed.ContainsKey("width")) r.width = float.Parse(packed["width"].ToString()); + if (packed.ContainsKey("height")) r.height = float.Parse(packed["height"].ToString()); + if (r.width < 1 || r.height < 1) { + Debug.LogError("The attachmentRegion " + key + " was less than 1x1 in size."); + } else { + _attachmentRegions[key] = r; + } + } + } + return _attachmentRegions; + } + } + + /// + /// Generates a material dynamically based upon the requested SkinSet. + /// + /// The material for use with a renderer + public Material GetMaterial(CreatureMaterialAttachmentSet equipmentSkinSet = null) { + Texture2D tex = BuildTexture(equipmentSkinSet); + if (tex == null) { + return baseMaterial; + } + Material mat = new Material(baseMaterial.shader); + mat.mainTexture = tex; + return mat; + } + + /// + /// Incrementally build the Texture2D based upon the requested attachments. + /// + /// The rendered texture for use in a Material. + /// The attached items. + protected Texture2D BuildTexture(CreatureMaterialAttachmentSet attachments) { + if (attachmentSprites == null || !attachmentSprites.Any() || attachments == null) { + return _texture; + } + if (baseMaterial == null || baseMaterial.name != attachmentSprites.First().name) { + Debug.LogError("The baseMaterial should match the first attachmentSprite."); + return _texture; + } + if (!Application.isPlaying) { + // In edit mode, always fully rebuild everything so its easy to work with asset changes. + _attachmentRegions = null; + _texture = null; + _attachments = null; + } + if (_texture == null) { + _texture = Instantiate(attachmentSprites.First().texture) as Texture2D; + } + if (_attachments == null) { + _attachments = new CreatureMaterialAttachmentSet() { }; + } + foreach (string slotName in attachmentRegions.Keys) { + Rect r = attachmentRegions[slotName]; + bool inNewSet = attachments.ContainsKey(slotName); + bool inOldSet = _attachments.ContainsKey(slotName); + bool changed = inNewSet != inOldSet || (inNewSet && inOldSet && attachments[slotName] != _attachments[slotName]); + if (!changed) { + continue; + } + if (inNewSet) { + // Copy from the sprite into the output texture. + Sprite sprite = FindSprite(attachments[slotName]); + if (sprite == null) { + Debug.LogError("No sprite found for " + attachments[slotName]); + continue; + } + Graphics.CopyTexture( + sprite.texture, 0, 0, (int)r.x, (int)r.y, (int)r.width, (int)r.height, + _texture, 0, 0, (int)r.x, (int)r.y + ); + } else { + // TODO: If it was in the old set but not in the new, do we need to delete it from the texture? + } + } + _texture.Apply(); + _attachments = attachments; + // File.WriteAllBytes("/Users/zaneclaes/Documents/test.png", _texture.EncodeToPNG()); + return _texture; + } + + protected Sprite FindSprite(string spriteName) { + return attachmentSprites.FirstOrDefault(s => s.name == spriteName); + } +}