├── .gitignore ├── Assets └── Live2D │ └── Cubism │ └── Viewer │ ├── CubismViewer.cs │ ├── CubismViewerConfig.cs │ ├── CubismViewerIo.cs │ ├── CubismViewerKeyboardHotkey.cs │ ├── CubismViewerMouseButtonHotkey.cs │ ├── CubismViewerMouseScrollHotkey.cs │ ├── Gems │ ├── Animating │ │ └── SimpleAnimator.cs │ ├── CameraControls.cs │ └── Theming │ │ ├── TwoColorTheme.cs │ │ └── TwoColorThemer.cs │ ├── ICubismViewerHotkey.cs │ └── Plugins │ └── System.Windows.Forms.txt └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.* 2 | [Ll]ibrary 3 | [Tt]emp 4 | !Assets/Live2D/Cubism/Viewer/**/*.cs 5 | !Assets/Live2D/Cubism/Viewer/**/*.txt 6 | !.gitignore 7 | !Readme.md 8 | Assets/**/*.md 9 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/CubismViewer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using Live2D.Cubism.Core; 10 | using Live2D.Cubism.Framework.Json; 11 | using Live2D.Cubism.Rendering; 12 | using System.Windows.Forms; 13 | using UnityEngine; 14 | 15 | 16 | using EventSystem = UnityEngine.EventSystems.EventSystem; 17 | using Screen = UnityEngine.Screen; 18 | 19 | 20 | namespace Live2D.Cubism.Viewer 21 | { 22 | /// 23 | /// Unity-based viewer. 24 | /// 25 | public sealed class CubismViewer : MonoBehaviour 26 | { 27 | #region Events 28 | 29 | /// 30 | /// Handles model load events. 31 | /// 32 | /// Event source. 33 | /// New model. 34 | public delegate void NewModelHandler(CubismViewer sender, CubismModel model); 35 | 36 | /// 37 | /// Handles non-model JSON file drops. 38 | /// 39 | /// Events source. 40 | /// Absolute path to dropped file. 41 | public delegate void FileDropHandler(CubismViewer sender, string absolutePath); 42 | 43 | 44 | /// 45 | /// Called when new model loaded. 46 | /// 47 | public event NewModelHandler OnNewModel; 48 | 49 | /// 50 | /// Called on file drop. 51 | /// 52 | public event FileDropHandler OnFileDrop; 53 | 54 | #endregion 55 | 56 | /// 57 | /// backing field. 58 | /// 59 | [SerializeField] 60 | private Camera _camera; 61 | 62 | /// 63 | /// Viewer camera. 64 | /// 65 | public Camera Camera 66 | { 67 | get { return _camera; } 68 | } 69 | 70 | /// 71 | /// Model JSON of current model. 72 | /// 73 | public CubismModel3Json ModelJson { get; set; } 74 | 75 | /// 76 | /// Current model. 77 | /// 78 | public CubismModel Model { get; set; } 79 | 80 | /// 81 | /// File dialog. 82 | /// 83 | private OpenFileDialog FileDialog { get; set; } 84 | 85 | /// 86 | /// Config. 87 | /// 88 | private CubismViewerConfig Config { get; set; } 89 | 90 | 91 | /// 92 | /// Shows dialog for opening files. 93 | /// 94 | public void ShowFileDialog() 95 | { 96 | // HACK Deselect active UI element. 97 | EventSystem.current.SetSelectedGameObject(null); 98 | 99 | 100 | // Pre-filter for motions in case a model is loaded. 101 | if (Model != null) 102 | { 103 | FileDialog.FilterIndex = 2; 104 | } 105 | 106 | 107 | // Return unless a file was selected. 108 | if (FileDialog.ShowDialog() != DialogResult.OK) 109 | { 110 | return; 111 | } 112 | 113 | 114 | var absoluteFilePath = FileDialog.FileName; 115 | 116 | 117 | // Store path. 118 | Config.LastFileDialogPath = absoluteFilePath; 119 | 120 | 121 | // Handle model JSON files. 122 | if (absoluteFilePath.EndsWith(".model3.json")) 123 | { 124 | var lastModel = Model; 125 | 126 | 127 | // Load model. 128 | ModelJson = CubismModel3Json.LoadAtPath(absoluteFilePath, CubismViewerIo.LoadAsset); 129 | Model = ModelJson.ToModel(); 130 | 131 | 132 | // Trigger event. 133 | if (OnNewModel != null) 134 | { 135 | OnNewModel(this, Model); 136 | } 137 | 138 | 139 | // Remove previous model. 140 | if (lastModel != null) 141 | { 142 | Destroy(lastModel.gameObject); 143 | } 144 | 145 | 146 | // Guess best zoom and position. 147 | // TODO Improve if necessary. 148 | var modelBounds = Model 149 | .GetComponent() 150 | .Renderers 151 | .GetMeshRendererBounds(); 152 | 153 | 154 | Camera.transform.position = new Vector3(0f, 0f, -10f); 155 | Camera.orthographicSize = modelBounds.extents.y * 1.1f; 156 | 157 | 158 | return; 159 | } 160 | 161 | 162 | // Trigger event for other files. 163 | if (OnFileDrop != null) 164 | { 165 | OnFileDrop(this, absoluteFilePath); 166 | } 167 | } 168 | 169 | #region Unity Event Handling 170 | 171 | /// 172 | /// Called by Unity. Initializes viewer. 173 | /// 174 | private void Awake() 175 | { 176 | // Load config. 177 | Config = CubismViewerIo.LoadConfig(); 178 | 179 | 180 | // Initialize screen size. 181 | Screen.SetResolution(Config.ScreenWidth, Config.ScreenHeight, false); 182 | 183 | 184 | // Initialize file dialog. 185 | FileDialog = new OpenFileDialog(); 186 | 187 | if (!string.IsNullOrEmpty(Config.LastFileDialogPath)) 188 | { 189 | FileDialog.InitialDirectory = CubismViewerIo.GetDirectoryName(Config.LastFileDialogPath); 190 | } 191 | 192 | FileDialog.Filter = "Models (*.model3.json)|*.model3.json|Motions (*.motion3.json)|*.motion3.json|Others (*.*)|*.*"; 193 | FileDialog.FilterIndex = 1; 194 | FileDialog.RestoreDirectory = true; 195 | } 196 | 197 | 198 | /// 199 | /// Called by Unity. Stores config. 200 | /// 201 | private void OnDestroy() 202 | { 203 | Config.ScreenWidth = Screen.width; 204 | Config.ScreenHeight = Screen.height; 205 | 206 | 207 | CubismViewerIo.SaveConfig(Config); 208 | } 209 | 210 | #endregion 211 | } 212 | } -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/CubismViewerConfig.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using System; 10 | using UnityEngine; 11 | 12 | 13 | namespace Live2D.Cubism.Viewer 14 | { 15 | /// 16 | /// Viewer config file. 17 | /// 18 | [Serializable] 19 | public class CubismViewerConfig 20 | { 21 | /// 22 | /// Screen width. 23 | /// 24 | [SerializeField] 25 | public int ScreenWidth = 540; 26 | 27 | /// 28 | /// Screen height. 29 | /// 30 | [SerializeField] 31 | public int ScreenHeight = 720; 32 | 33 | /// 34 | /// Last path gotten via file dialog. 35 | /// 36 | [SerializeField] 37 | public string LastFileDialogPath; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/CubismViewerIo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using System; 10 | using System.IO; 11 | using UnityEngine; 12 | 13 | 14 | namespace Live2D.Cubism.Viewer 15 | { 16 | /// 17 | /// IO helpers. 18 | /// 19 | public static class CubismViewerIo 20 | { 21 | /// 22 | /// Gets file name. 23 | /// 24 | /// Path to query against. 25 | /// File name. 26 | public static string GetFileName(string path) 27 | { 28 | return Path.GetFileName(path); 29 | } 30 | 31 | /// 32 | /// Gets directory name. 33 | /// 34 | /// Path to query against. 35 | /// Directory name. 36 | public static string GetDirectoryName(string path) 37 | { 38 | return Path.GetDirectoryName(path); 39 | } 40 | 41 | 42 | /// 43 | /// Loads asset. 44 | /// 45 | /// Asset type. 46 | /// Path to asset. 47 | /// The asset on success; otherwise. 48 | public static T LoadAsset(string absolutePath) where T : class 49 | { 50 | return LoadAsset(typeof(T), absolutePath) as T; 51 | } 52 | 53 | /// 54 | /// Loads asset. 55 | /// 56 | /// Asset type. 57 | /// Path to asset. 58 | /// The asset on success; otherwise. 59 | public static object LoadAsset(Type assetType, string absolutePath) 60 | { 61 | if (assetType == typeof(byte[])) 62 | { 63 | return File.ReadAllBytes(absolutePath); 64 | } 65 | else if (assetType == typeof(string)) 66 | { 67 | return File.ReadAllText(absolutePath); 68 | } 69 | else if (assetType == typeof(Texture2D)) 70 | { 71 | var texture = new Texture2D(1, 1); 72 | 73 | 74 | texture.LoadImage(File.ReadAllBytes(absolutePath)); 75 | 76 | 77 | return texture; 78 | } 79 | 80 | 81 | // Fail hard. 82 | throw new NotSupportedException(); 83 | } 84 | 85 | 86 | /// 87 | /// Loads config for given type. 88 | /// 89 | /// Type to querey against 90 | /// Config. 91 | // HACK The whole thing is a hack for the lazy... 92 | public static T LoadConfig() where T : class, new() 93 | { 94 | // Always return new config in editor. 95 | if (Application.isEditor) 96 | { 97 | return new T(); 98 | } 99 | 100 | 101 | try 102 | { 103 | var serializedConfig = File.ReadAllText(Path.Combine(Application.persistentDataPath, typeof(T).Name + ".json")); 104 | 105 | 106 | return JsonUtility.FromJson(serializedConfig); 107 | } 108 | catch 109 | { 110 | return new T(); 111 | } 112 | } 113 | 114 | /// 115 | /// Saves config for given type. 116 | /// 117 | /// Type to querey against 118 | /// Config. 119 | // HACK The whole thing is a hack for the lazy... 120 | public static void SaveConfig(T config) where T : class 121 | { 122 | // Never save in editor. 123 | if (Application.isEditor) 124 | { 125 | return; 126 | } 127 | 128 | 129 | var serializedConfig = JsonUtility.ToJson(config); 130 | 131 | 132 | if (string.IsNullOrEmpty(serializedConfig)) 133 | { 134 | return; 135 | } 136 | 137 | 138 | File.WriteAllText(Path.Combine(Application.persistentDataPath, typeof(T).Name + ".json"), serializedConfig); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/CubismViewerKeyboardHotkey.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using System; 10 | using UnityEngine; 11 | 12 | 13 | namespace Live2D.Cubism.Viewer 14 | { 15 | /// 16 | /// Keyobard hotkey. 17 | /// 18 | [Serializable] 19 | public struct CubismViewerKeyboardHotkey: ICubismViewerHotkey 20 | { 21 | /// 22 | /// Auxuliary condition. 23 | /// 24 | [SerializeField] 25 | public KeyCode Modifier; 26 | 27 | /// 28 | /// Primary condition. 29 | /// 30 | [SerializeField] 31 | public KeyCode Key; 32 | 33 | 34 | /// 35 | /// Evaluates hotkey. 36 | /// 37 | /// if hotkey pressed; otherwise. 38 | public bool Evaluate() 39 | { 40 | if (Modifier != KeyCode.None && !Input.GetKey(Modifier)) 41 | { 42 | return false; 43 | } 44 | 45 | if (Key != KeyCode.None && !Input.GetKey(Key)) 46 | { 47 | return false; 48 | } 49 | 50 | 51 | return true; 52 | } 53 | 54 | /// 55 | /// Evaluates if hotkey just pressed. 56 | /// 57 | /// if hotkey pressed; otherwise. 58 | public bool EvaluateJust() 59 | { 60 | if (Modifier != KeyCode.None && !Input.GetKey(Modifier)) 61 | { 62 | return false; 63 | } 64 | 65 | if (!Input.GetKeyDown(Key)) 66 | { 67 | return false; 68 | } 69 | 70 | 71 | return true; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/CubismViewerMouseButtonHotkey.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using System; 10 | using UnityEngine; 11 | 12 | 13 | namespace Live2D.Cubism.Viewer 14 | { 15 | /// 16 | /// Keyobard hotkey. 17 | /// 18 | [Serializable] 19 | public struct CubismViewerMouseButtonHotkey : ICubismViewerHotkey 20 | { 21 | /// 22 | /// Key condition. 23 | /// 24 | [SerializeField] 25 | public KeyCode Modifier; 26 | 27 | /// 28 | /// Button condition. 29 | /// 30 | [SerializeField] 31 | public int Button; 32 | 33 | 34 | /// 35 | /// Evaluates hotkey. 36 | /// 37 | /// if hotkey pressed; otherwise. 38 | public bool Evaluate() 39 | { 40 | if (Modifier != KeyCode.None && !Input.GetKey(Modifier)) 41 | { 42 | return false; 43 | } 44 | 45 | 46 | return Input.GetMouseButton(Button); 47 | } 48 | 49 | /// 50 | /// Evaluates if hotkey just pressed. 51 | /// 52 | /// if hotkey pressed; otherwise. 53 | public bool EvaluateJust() 54 | { 55 | if (Modifier != KeyCode.None && !Input.GetKey(Modifier)) 56 | { 57 | return false; 58 | } 59 | 60 | 61 | return Input.GetMouseButtonDown(Button); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/CubismViewerMouseScrollHotkey.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using System; 10 | using UnityEngine; 11 | 12 | 13 | namespace Live2D.Cubism.Viewer 14 | { 15 | /// 16 | /// Keyobard hotkey. 17 | /// 18 | [Serializable] 19 | public struct CubismViewerMouseScrollHotkey : ICubismViewerHotkey 20 | { 21 | /// 22 | /// Key condition. 23 | /// 24 | [SerializeField] 25 | public KeyCode Modifier; 26 | 27 | 28 | /// 29 | /// Evaluates hotkey. 30 | /// 31 | /// if hotkey pressed; otherwise. 32 | public bool Evaluate() 33 | { 34 | if (Modifier != KeyCode.None && !Input.GetKey(Modifier)) 35 | { 36 | return false; 37 | } 38 | 39 | 40 | return Input.mouseScrollDelta != Vector2.zero; 41 | } 42 | 43 | /// 44 | /// Evaluates if hotkey just pressed. 45 | /// 46 | /// if hotkey pressed; otherwise. 47 | public bool EvaluateJust() 48 | { 49 | return Evaluate(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/Gems/Animating/SimpleAnimator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using Live2D.Cubism.Framework.Json; 10 | using UnityEngine; 11 | 12 | 13 | namespace Live2D.Cubism.Viewer.Gems.Animating 14 | { 15 | /// 16 | /// Loops the last animation dropped. 17 | /// 18 | // TODO Clean up clips as necessary 19 | public sealed class SimpleAnimator : MonoBehaviour 20 | { 21 | /// 22 | /// Called by Unity. Registers handler. 23 | /// 24 | private void Start() 25 | { 26 | var viewer = GetComponent(); 27 | 28 | 29 | // Fail silently in release. 30 | if (viewer == null) 31 | { 32 | Debug.LogWarning("Not attached to viewer!"); 33 | 34 | 35 | return; 36 | } 37 | 38 | 39 | // Register event handler. 40 | viewer.OnFileDrop += HandleFileDrop; 41 | } 42 | 43 | #region CubismViewer Event Handling 44 | 45 | /// 46 | /// Handles file drops. 47 | /// 48 | /// Event source. 49 | /// Absolute path of dropped file. 50 | private void HandleFileDrop(CubismViewer sender, string absolutePath) 51 | { 52 | // Skip non-motion files. 53 | if (!absolutePath.EndsWith("motion3.json")) 54 | { 55 | return; 56 | } 57 | 58 | 59 | var model = sender.Model; 60 | 61 | 62 | // Make sure animation component is attached to model. 63 | var animator = model.GetComponent(); 64 | 65 | 66 | if (animator == null) 67 | { 68 | animator = model.gameObject.AddComponent(); 69 | } 70 | 71 | 72 | // Deserialize animation. 73 | var model3Json = CubismMotion3Json.LoadFrom(CubismViewerIo.LoadAsset(absolutePath)); 74 | var clipName = CubismViewerIo.GetFileName(absolutePath); 75 | var clip = model3Json.ToAnimationClip(); 76 | clip.wrapMode = WrapMode.Loop; 77 | clip.legacy = true; 78 | 79 | 80 | // Play animation. 81 | animator.AddClip(clip, clipName); 82 | animator.Play(clipName); 83 | } 84 | 85 | #endregion 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/Gems/CameraControls.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using UnityEngine; 10 | 11 | 12 | namespace Live2D.Cubism.Viewer.Gems 13 | { 14 | /// 15 | /// Controls . 16 | /// 17 | public sealed class CameraControls : MonoBehaviour 18 | { 19 | /// 20 | /// Hotkey for moving camera. 21 | /// 22 | [SerializeField] 23 | CubismViewerMouseButtonHotkey MoveHotkey = new CubismViewerMouseButtonHotkey 24 | { 25 | Modifier = KeyCode.LeftControl, 26 | Button = 0 27 | }; 28 | 29 | /// 30 | /// Scale to apply to mouse movement on move. 31 | /// 32 | [SerializeField, Range(-1f, 1f)] 33 | float MoveScale = 1.0f; 34 | 35 | /// 36 | /// Hotkey for zooming in. 37 | /// 38 | [SerializeField] 39 | CubismViewerMouseScrollHotkey ZoomHotkey = new CubismViewerMouseScrollHotkey 40 | { 41 | Modifier = KeyCode.LeftAlt 42 | }; 43 | 44 | /// 45 | /// Scale to apply to mouse movement on zoom. 46 | /// 47 | [SerializeField, Range(-10f, 10f)] 48 | float ZoomScale = -5f; 49 | 50 | /// 51 | /// Maximum zoom in value. 52 | /// 53 | [SerializeField, Range(0.1f, 10f)] 54 | float ZoomInLimit = 0.1f; 55 | 56 | 57 | /// 58 | /// Target camera. 59 | /// 60 | private Camera Camera { get; set; } 61 | 62 | /// 63 | /// Last mouse position to compute mouse delta. 64 | /// 65 | private Vector3 LastMousePosition { get; set; } 66 | 67 | #region Unity Event Handling 68 | 69 | /// 70 | /// Called by Unity. Initializes instance. 71 | /// 72 | private void Start() 73 | { 74 | var viewer = GetComponent(); 75 | 76 | 77 | // Fail silently in release. 78 | if (viewer == null) 79 | { 80 | Debug.LogWarning("Not attached to viewer!"); 81 | 82 | 83 | return; 84 | } 85 | 86 | 87 | Camera = viewer.Camera; 88 | } 89 | 90 | /// 91 | /// Called by Unity. Updates controls. 92 | /// 93 | private void Update() 94 | { 95 | // Return if nothing to control. 96 | if (Camera == null) 97 | { 98 | return; 99 | } 100 | 101 | 102 | // Handle move. 103 | if (MoveHotkey.Evaluate()) 104 | { 105 | var position = Camera.transform.position; 106 | 107 | 108 | position += ((LastMousePosition - Input.mousePosition) * Time.deltaTime * MoveScale); 109 | 110 | 111 | Camera.transform.position = position; 112 | } 113 | 114 | 115 | // Handle zoom. 116 | else if (ZoomHotkey.Evaluate()) 117 | { 118 | var size = Camera.orthographicSize; 119 | 120 | 121 | size += (Input.mouseScrollDelta.y * Time.deltaTime * ZoomScale); 122 | 123 | 124 | // Apply limit. 125 | if (size < ZoomInLimit) 126 | { 127 | size = ZoomInLimit; 128 | } 129 | 130 | 131 | Camera.orthographicSize = size; 132 | } 133 | 134 | 135 | // Keep track of mouse position. 136 | LastMousePosition = Input.mousePosition; 137 | } 138 | 139 | #endregion 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/Gems/Theming/TwoColorTheme.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using System; 10 | using UnityEngine; 11 | 12 | 13 | namespace Live2D.Cubism.Viewer.Gems.Theming 14 | { 15 | /// 16 | /// 2-color theme 17 | /// 18 | [Serializable] 19 | public struct TwoColorTheme 20 | { 21 | /// 22 | /// Primary color. 23 | /// 24 | /// 25 | /// This color will be used for the background, too. 26 | /// 27 | public Color Primary; 28 | 29 | /// 30 | /// Secondary color. 31 | /// 32 | public Color Secondary; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/Gems/Theming/TwoColorThemer.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | using UnityEngine; 10 | 11 | 12 | namespace Live2D.Cubism.Viewer.Gems.Theming 13 | { 14 | /// 15 | /// 2-color themer. 16 | /// 17 | public sealed class TwoColorThemer : MonoBehaviour 18 | { 19 | /// 20 | /// Hotkey for triggering theme switches. 21 | /// 22 | [SerializeField] 23 | CubismViewerKeyboardHotkey NextThemeHotkey = new CubismViewerKeyboardHotkey 24 | { 25 | Modifier = KeyCode.LeftControl, 26 | Key = KeyCode.T 27 | }; 28 | 29 | /// 30 | /// Themes. 31 | /// 32 | [SerializeField] 33 | public TwoColorTheme[] Themes = 34 | { 35 | new TwoColorTheme 36 | { 37 | Primary = Color.white, 38 | Secondary = Color.black 39 | } 40 | }; 41 | 42 | /// 43 | /// Primary color UI elements. 44 | /// 45 | [SerializeField] 46 | public UnityEngine.UI.Graphic[] PrimaryColorElements; 47 | 48 | /// 49 | /// Secondary color UI elements. 50 | /// 51 | [SerializeField] 52 | public UnityEngine.UI.Graphic[] SecondaryColorElements; 53 | 54 | 55 | /// 56 | /// Currently active theme. 57 | /// 58 | private int ActiveTheme { get; set; } 59 | 60 | 61 | /// 62 | /// Switches to next scene. 63 | /// 64 | private void NextTheme() 65 | { 66 | ++ActiveTheme; 67 | 68 | 69 | if (ActiveTheme >= Themes.Length) 70 | { 71 | ActiveTheme = 0; 72 | } 73 | 74 | 75 | // Try update camera. 76 | var viewer = GetComponent(); 77 | 78 | 79 | if (viewer != null) 80 | { 81 | viewer.Camera.backgroundColor = Themes[ActiveTheme].Primary; 82 | } 83 | 84 | 85 | // Update primary color elements. 86 | if (PrimaryColorElements != null) 87 | { 88 | for (var e = 0; e < PrimaryColorElements.Length; ++e) 89 | { 90 | PrimaryColorElements[e].color = Themes[ActiveTheme].Primary; 91 | } 92 | } 93 | 94 | 95 | // Update secondary color elements. 96 | if (SecondaryColorElements != null) 97 | { 98 | for (var e = 0; e < SecondaryColorElements.Length; ++e) 99 | { 100 | SecondaryColorElements[e].color = Themes[ActiveTheme].Secondary; 101 | } 102 | } 103 | } 104 | 105 | #region Unity Event Handling 106 | 107 | /// 108 | /// Called by Unity. Initializes themer. 109 | /// 110 | private void Start() 111 | { 112 | ActiveTheme = -1; 113 | 114 | 115 | NextTheme(); 116 | } 117 | 118 | /// 119 | /// Called by Unity. Handles hotkeys. 120 | /// 121 | private void Update() 122 | { 123 | if (NextThemeHotkey.EvaluateJust()) 124 | { 125 | NextTheme(); 126 | } 127 | } 128 | 129 | #endregion 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/ICubismViewerHotkey.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright(c) Live2D Inc. All rights reserved. 3 | * 4 | * Use of this source code is governed by the Live2D Open Software license 5 | * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html. 6 | */ 7 | 8 | 9 | namespace Live2D.Cubism.Viewer 10 | { 11 | /// 12 | /// Common hotkey interface. 13 | /// 14 | public interface ICubismViewerHotkey 15 | { 16 | /// 17 | /// Evaluates hotkey. 18 | /// 19 | /// if hotkey pressed; otherwise. 20 | bool Evaluate(); 21 | 22 | /// 23 | /// Evaluates if hotkey just pressed. 24 | /// 25 | /// if hotkey pressed; otherwise. 26 | bool EvaluateJust(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Assets/Live2D/Cubism/Viewer/Plugins/System.Windows.Forms.txt: -------------------------------------------------------------------------------- 1 | Make sure to copy the Mono 'System.Windows.Forms.dll' into this directory. 2 | A good place to start your search might be '/Editor/Data/Mono/lib/mono/2.0/'. 3 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Cubism DIY Viewer 2 | 3 | Welcome to the *Unity*-based Cubism 3 do-it-yourself viewer. Came here looking for the official Live2D homepage? 4 | Go [here](http://www.live2d.com/products/cubism3). 5 | 6 | 7 | ## Do-it-yourself!? 8 | 9 | Instead of providing a complete solution like the 2.x viewers did, 10 | this project aims to serve as a starting point and to provide common functionality 11 | for making it easy to create a viewer tailored to your needs. 12 | 13 | Want to preview models easily without access to *Unity*? Create a viewer with built-in functionality. 14 | 15 | Need model related data in your app that you can't create in Cubism itself? 16 | Customize the viewer to create just the data you need. 17 | 18 | 19 | ## Design 20 | 21 | The viewer itself basically is a single `MonoBehaviour`. 22 | You customize the viewer by attaching other `MonoBehaviour`s to it. 23 | As *Plugin* is a somewhat reserved term in *Unity* (and because I like *Ruby*), 24 | let's call such custom behaviours *gem*s. 25 | 26 | 27 | ## Built-in *Gem*s 28 | 29 | This project contains a few *gem*s to get you started. 30 | 31 | 32 | ### `CameraControls` 33 | 34 | This *gem* allows you to move the canvas and zoom-in. 35 | Hotkeys default to `Spacebar + Left Mouse Button + Drag` for navigating the canvas, and 36 | `Mouse Wheel Scroll Up/Down` for zooming. 37 | 38 | 39 | ### `SimpleAnimator` 40 | 41 | This *gem* allows you to play back a single animation at a time. 42 | 43 | 44 | ### `TwoColorThemer` 45 | 46 | This *gem* allows you to quickly theme the viewer using a 2 color theme. 47 | The background color will be set to the primary color of the theme. 48 | You can register any number of UI elements you want themed, too, through the *Inspector*. 49 | Hotkey defaults to `Left Control + T` for switching between themes. 50 | 51 | 52 | ## User *Gem*s 53 | 54 | - [DenchiSoft/CubismViewerGems](https://github.com/DenchiSoft/CubismViewerGems) 55 | 56 | 57 | ## Getting Started 58 | 59 | First, you have to download a few files and get them into a *Unity* project: 60 | 61 | 1. Download the latest [SDK](https://live2d.github.io/#unity) and import it into your project. 62 | 1. Make sure to restart *Unity*. 63 | 1. Download the latest [Components for Unity](https://github.com/Live2D/CubismUnityComponents/tree/develop) into your project. Overwrite any previous SDK files with the new ones. 64 | 1. Download/Clone this repository into your project. 65 | 1. Copy the *Mono* `System.Windows.Forms.dll` into your project. (Check out `./Assets/Live2D/Cubism/Viewer/Plugins/System.Windows.Forms.txt` for instructions). 66 | 1. Set `API Compability Level` to *.NET 2.0* (default is *.NET 2.0 Subset*) in the *Player Settings*. 67 | 68 | From here things are easy because you do the rest completely inside the *Unity Editor*: 69 | 70 | 6. Create an empty *GameObject* and add the `CubismViewer` component to it. 71 | 1. Assign the `Main Camera` in your scene to the `CubismViewer` through the *Inspector*. 72 | 1. Create an UI button and add the `CubismViewer.ShowFileDialog` method of the `CubismViewer` object to `On Click ()`. 73 | 1. Hit play, click the UI button. A file dialog should open. 74 | 1. Select a `model3.json` file via the file dialog. The model should be displayed. 75 | 1. Add *gem*s to the `CubismViewer` object for additional functionality. 76 | 77 | 78 | ## Contributing 79 | 80 | Wrote a cool *gem*? We're looking forward to it. 81 | You can either submit its source code or a link (as Live2D Community or as pull requests). 82 | 83 | Besides that, there are many other ways to contribute to the project, too: 84 | logging bugs, submitting pull requests on this GitHub, and reporting issues and making suggestions at Live2D Community. 85 | 86 | 87 | ### Forking And Pull Requests 88 | 89 | We very appreciate your pull requests whether they bring fixes, improvements, or even new features. 90 | Note, however, that the wrapper is designed to be as lightweight and shallow as possible and 91 | should therefore only be subject to bug fixes and memory/performance improvements. 92 | To keep the main repository as clean as possible, create a personal fork and feature branches there as needed. 93 | 94 | 95 | ### Bugs 96 | 97 | We are regularly checking issue-reports and feature requests at Live2D Community. 98 | Before filing a bug report, please do a search in Live2D Community to see if the issue-report or feature request has already been posted. 99 | If you find your issue already exists, make relevant comments and add your reaction. 100 | 101 | 102 | ### Discussion Etiquette 103 | 104 | Please limit the discussion to English and keep it professional and things on topic. 105 | 106 | 107 | ## License 108 | 109 | If you plan on using this project or parts of it for non-personal or non-in-house use, 110 | make sure to read the [license](http://live2d.com/eula/live2d-open-software-license-agreement_en.html) carefully. 111 | Otherwise, you shouldn't have to worry to much as the license that applies to the source code in this project 112 | allows you to modify all sources without the need to submit any changes you made. 113 | --------------------------------------------------------------------------------