├── .gitignore ├── .vs └── LOOM-Multi-Threading-Framework │ └── v14 │ └── .suo ├── Assembly-CSharp.csproj ├── Assets ├── LOOM Framework.meta └── LOOM Framework │ ├── Examples.meta │ ├── Examples │ ├── Prefabs.meta │ ├── Prefabs │ │ ├── CannonBall.prefab │ │ ├── CannonBall.prefab.meta │ │ ├── FlockingManager.prefab │ │ └── FlockingManager.prefab.meta │ ├── Scenes.meta │ ├── Scenes │ │ ├── FlockingMassive.unity │ │ ├── FlockingMassive.unity.meta │ │ ├── SimpleExampleImplementation.unity │ │ ├── SimpleExampleImplementation.unity.meta │ │ ├── TextureBlur.unity │ │ └── TextureBlur.unity.meta │ ├── Scripts.meta │ ├── Scripts │ │ ├── FlockingMassive.meta │ │ ├── FlockingMassive │ │ │ ├── Cannon.cs │ │ │ ├── Cannon.cs.meta │ │ │ ├── FlockHelper.cs │ │ │ ├── FlockHelper.cs.meta │ │ │ ├── HUDmanager.cs │ │ │ ├── HUDmanager.cs.meta │ │ │ ├── MassiveFlockingExample.cs │ │ │ ├── MassiveFlockingExample.cs.meta │ │ │ ├── MovingBodies.cs │ │ │ ├── MovingBodies.cs.meta │ │ │ ├── ThreadedFlocking.cs │ │ │ └── ThreadedFlocking.cs.meta │ │ ├── Simple Implementations.meta │ │ ├── Simple Implementations │ │ │ ├── SimpleThreadingExample.cs │ │ │ └── SimpleThreadingExample.cs.meta │ │ ├── TextureBlur.meta │ │ └── TextureBlur │ │ │ ├── TextureBlurCodeExplained.jpg │ │ │ ├── TextureBlurCodeExplained.jpg.meta │ │ │ ├── TextureBlurThreaded.cs │ │ │ └── TextureBlurThreaded.cs.meta │ ├── Visuals.meta │ └── Visuals │ │ ├── Cubemap.jpg │ │ ├── Cubemap.jpg.meta │ │ ├── FlockingDemoLogo.jpg │ │ ├── FlockingDemoLogo.jpg.meta │ │ ├── Floor.jpg │ │ ├── Floor.jpg.meta │ │ ├── FrameClean.fbx │ │ ├── FrameClean.fbx.meta │ │ ├── FrameHighPoly.fbx │ │ ├── FrameHighPoly.fbx.meta │ │ ├── Materials.meta │ │ ├── Materials │ │ ├── CannonBall.mat │ │ ├── CannonBall.mat.meta │ │ ├── Export_Logo_Clean_mi_car_paint_phen_x_passes1.mat │ │ ├── Export_Logo_Clean_mi_car_paint_phen_x_passes1.mat.meta │ │ ├── Floor.mat │ │ ├── Floor.mat.meta │ │ ├── Frame.mat │ │ ├── Frame.mat.meta │ │ ├── Particle.mat │ │ ├── Particle.mat.meta │ │ ├── Spheres.mat │ │ ├── Spheres.mat.meta │ │ ├── lambert1.mat │ │ ├── lambert1.mat.meta │ │ ├── mi_car_paint_phen_x_passes1.mat │ │ └── mi_car_paint_phen_x_passes1.mat.meta │ │ ├── Particle.png │ │ ├── Particle.png.meta │ │ ├── Plane1x1.fbx │ │ ├── Plane1x1.fbx.meta │ │ ├── Rock_n_Snow.JPG │ │ └── Rock_n_Snow.JPG.meta │ ├── LOOM.meta │ └── LOOM │ ├── IThreadWorkerObject.cs │ ├── IThreadWorkerObject.cs.meta │ ├── Internal.meta │ ├── Internal │ ├── MainThreadDispatcher.cs │ ├── MainThreadDispatcher.cs.meta │ ├── MainThreadWatchdog.cs │ ├── MainThreadWatchdog.cs.meta │ ├── MultithreadedWorkloadHelper.cs │ ├── MultithreadedWorkloadHelper.cs.meta │ ├── SingleThreadStarter.cs │ ├── SingleThreadStarter.cs.meta │ ├── ThreadDispatchAction.cs │ ├── ThreadDispatchAction.cs.meta │ ├── ThreadPoolSchedulerWorkerObjects.cs │ ├── ThreadPoolSchedulerWorkerObjects.cs.meta │ ├── ThreadWaitCommands.cs │ ├── ThreadWaitCommands.cs.meta │ ├── UnityActivityWatchdog.cs │ └── UnityActivityWatchdog.cs.meta │ ├── Loom.cs │ ├── Loom.cs.meta │ ├── ThreadPoolScheduler.cs │ └── ThreadPoolScheduler.cs.meta ├── LOOM - Multi Threading Framework16.unitypackage ├── LOOM-Multi-Threading-Framework.csproj ├── LOOM-Multi-Threading-Framework.sln └── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityAdsSettings.asset └── UnityConnectSettings.asset /.gitignore: -------------------------------------------------------------------------------- 1 | Library/ 2 | Temp/ 3 | -------------------------------------------------------------------------------- /.vs/LOOM-Multi-Threading-Framework/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/.vs/LOOM-Multi-Threading-Framework/v14/.suo -------------------------------------------------------------------------------- /Assembly-CSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 10.0.20506 7 | 2.0 8 | 9 | {1531EB7A-9E70-6350-9B3A-FB55757FB8FD} 10 | Library 11 | Properties 12 | Assembly-CSharp 13 | v3.5 14 | 512 15 | Assets 16 | 17 | 18 | true 19 | full 20 | false 21 | Temp\bin\Debug\ 22 | DEBUG;TRACE;UNITY_5_3_OR_NEWER;UNITY_5_3_4;UNITY_5_3;UNITY_5;ENABLE_NEW_BUGREPORTER;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_FRAME_DEBUGGER;ENABLE_GENERICS;ENABLE_HOME_SCREEN;ENABLE_IMAGEEFFECTS;ENABLE_LIGHT_PROBES_LEGACY;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_PLUGIN_INSPECTOR;ENABLE_SHADOWS;ENABLE_SINGLE_INSTANCE_BUILD_SETTING;ENABLE_SPRITERENDERER_FLIPPING;ENABLE_SPRITES;ENABLE_SPRITE_POLYGON;ENABLE_TERRAIN;ENABLE_RAKNET;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_HUB;ENABLE_CLOUD_PROJECT_ID;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_METRICS;ENABLE_EDITOR_METRICS_CACHING;INCLUDE_DYNAMIC_GI;INCLUDE_GI;INCLUDE_IL2CPP;INCLUDE_DIRECTX12;PLATFORM_SUPPORTS_MONO;ENABLE_LOCALIZATION;ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION;ENABLE_EDITOR_TESTS_RUNNER;UNITY_ANDROID;UNITY_ANDROID_API;ENABLE_SUBSTANCE;ENABLE_TEXTUREID_MAP;ENABLE_EGL;ENABLE_NETWORK;ENABLE_RUNTIME_GI;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_LOG_MIXED_STACKTRACE;ENABLE_UNITYWEBREQUEST;PLATFORM_SUPPORTS_ADS_ID;ENABLE_UNITYADS_RUNTIME;UNITY_UNITYADS_API;ENABLE_MONO;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;UNITY_TEAM_LICENSE;UNITY_PRO_LICENSE 23 | prompt 24 | 4 25 | 0169 26 | 27 | 28 | pdbonly 29 | true 30 | Temp\bin\Release\ 31 | prompt 32 | 4 33 | 0169 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | C:/Program Files/Unity/Editor/Data/Managed/UnityEngine.dll 42 | 43 | 44 | C:/Program Files/Unity/Editor/Data/Managed/UnityEditor.dll 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | C:/Program Files/Unity/Editor/Data/UnityExtensions/Unity/GUISystem/UnityEngine.UI.dll 69 | 70 | 71 | C:/Program Files/Unity/Editor/Data/UnityExtensions/Unity/Networking/UnityEngine.Networking.dll 72 | 73 | 74 | 75 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Assets/LOOM Framework.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19266bd63c5fd4d1aabe5a5fb93a10ae 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c9fcae2849e7cf4699c28a9bbe2d9f2 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ea9b0669b96b46046b14fac37577b925 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Prefabs/CannonBall.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Prefabs/CannonBall.prefab -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Prefabs/CannonBall.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eaf411afab22f0d46a05bc6761c04263 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Prefabs/FlockingManager.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Prefabs/FlockingManager.prefab -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Prefabs/FlockingManager.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bafca668293ac4840a771ba443f76963 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82d3af87267129e43b539639ca30cc0c 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scenes/FlockingMassive.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Scenes/FlockingMassive.unity -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scenes/FlockingMassive.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 15f6e8237305ce343922a426c214c637 3 | DefaultImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scenes/SimpleExampleImplementation.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Scenes/SimpleExampleImplementation.unity -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scenes/SimpleExampleImplementation.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2aba94d896fd9114691ae36beac41c5d 3 | DefaultImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scenes/TextureBlur.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Scenes/TextureBlur.unity -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scenes/TextureBlur.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a9f9b379d1b8be64883c6181f8d6e4ec 3 | DefaultImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c2e17f82cc9859b4c81cc6a5976f3356 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba2e25d3c1a5e734d8cc03470d26e754 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/Cannon.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class Cannon : MonoBehaviour 6 | { 7 | public Transform CannonballToInstantiate; 8 | 9 | public float LeftBorder; 10 | public float BottomBorder; 11 | public float TopBorder; 12 | public float RightBorder = 350; 13 | 14 | public float CannonballSpeed = 80; 15 | 16 | private List cannonBalls = new List(); 17 | private Camera cam; 18 | private float lastShot = 0f; 19 | private HUDmanager hud; 20 | 21 | private void Start() 22 | { 23 | cam = this.gameObject.GetComponentInChildren(); 24 | hud = (HUDmanager)GameObject.FindObjectOfType(typeof(HUDmanager)); 25 | } 26 | 27 | 28 | // Update is called once per frame 29 | void Update () 30 | { 31 | if (hud.panelIdx == 0 && Input.GetMouseButton(0)) 32 | { 33 | if (Time.realtimeSinceStartup - lastShot > 0.35f) 34 | { 35 | Vector2 invMousePos = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y); 36 | if (invMousePos.y > 50) 37 | { 38 | 39 | //New Cananball 40 | Transform cannonball = (Transform)Instantiate(CannonballToInstantiate); 41 | Vector3 newForward = cam.ScreenPointToRay(Input.mousePosition).direction; 42 | cannonball.position = cam.transform.position + (newForward * 15f); 43 | cannonball.forward = newForward; 44 | cannonBalls.Add(cannonball); 45 | 46 | lastShot = Time.realtimeSinceStartup; 47 | } 48 | } 49 | } 50 | 51 | 52 | List destroyAndRemove = new List(); 53 | foreach (Transform cannonball in cannonBalls) 54 | { 55 | cannonball.position += cannonball.forward * (Time.deltaTime * CannonballSpeed); 56 | 57 | if (cannonball.position.y < -20f) 58 | destroyAndRemove.Add(cannonball); 59 | } 60 | 61 | if (destroyAndRemove.Count > 0) 62 | { 63 | foreach (Transform cannonball in destroyAndRemove) 64 | { 65 | Destroy(cannonball.gameObject); 66 | cannonBalls.Remove(cannonball); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/Cannon.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d636995327d02ed45bd342e438441c2a 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/FlockHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public static class FlockHelper 6 | { 7 | public static void Shuffle(this IList list) 8 | { 9 | System.Random rng = new System.Random(); 10 | int n = list.Count; 11 | while (n > 1) 12 | { 13 | n--; 14 | int k = rng.Next(n + 1); 15 | T value = list[k]; 16 | list[k] = list[n]; 17 | list[n] = value; 18 | } 19 | } 20 | 21 | public static Vector3 ReflectVector(Vector3 surfaceUpNormalized, Vector3 incommingDirection) 22 | { 23 | return 2f * -Vector3.Dot(incommingDirection, surfaceUpNormalized) * surfaceUpNormalized + incommingDirection; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/FlockHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e225f75706cc01f4ba1268dfd766cbc4 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/HUDmanager.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | public class HUDmanager : MonoBehaviour 6 | { 7 | private Vector2 guiScale = new Vector2(1f, 1f); 8 | public float IntroDuration = 3f; 9 | public Texture2D IntroScreen; 10 | private float fadeAlpha = 1f; 11 | 12 | 13 | 14 | public int panelIdx = 0; 15 | private float particleDestinationLerp = 0f; 16 | 17 | 18 | private MassiveFlockingExample flockingManager; 19 | private Transform[] Cubes; 20 | 21 | // Use this for initialization 22 | void Start () 23 | { 24 | flockingManager = (MassiveFlockingExample)GameObject.FindObjectOfType(typeof(MassiveFlockingExample)); 25 | 26 | List cubeList = new List(); 27 | GameObject[] colliders = GameObject.FindGameObjectsWithTag("EnvironmentCollider"); 28 | foreach (GameObject coll in colliders) 29 | { 30 | if (coll.name == "Cube") 31 | { 32 | cubeList.Add(coll.transform); 33 | } 34 | } 35 | 36 | if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) 37 | guiScale = new Vector2(1.5f, 1.5f); 38 | 39 | Cubes = cubeList.ToArray(); 40 | UpdateStickToFrame(); 41 | } 42 | 43 | 44 | 45 | private void UpdateStickToFrame() 46 | { 47 | flockingManager.FlockingDestinationAttractRadius = Mathf.Lerp(0, flockingManager.FlockingBoundsRadius, particleDestinationLerp); 48 | flockingManager.FlockingDestinationReachedRadius = Mathf.Lerp(0, 20, particleDestinationLerp); 49 | flockingManager.ParticleSize = Mathf.Lerp(1.5f, 2.5f, particleDestinationLerp); 50 | 51 | float cubeScale = Mathf.Lerp(7, 1, particleDestinationLerp); 52 | foreach (Transform cube in Cubes) 53 | cube.localScale = new Vector3(cubeScale, cubeScale, cubeScale); 54 | } 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | void OnGUI() 71 | { 72 | 73 | GUI.color = panelIdx == 0 ? Color.grey : panelIdx == 1 ? Color.cyan : Color.yellow ; 74 | if (GUI.Button(new Rect(0, 0, Screen.width, 40), panelIdx == 0 ? "Tap here to toggle modes" : panelIdx == 1 ? "Flocking settings" : "Threading settings")) 75 | { 76 | panelIdx ++; 77 | if (panelIdx >= 3) 78 | panelIdx = 0; 79 | } 80 | 81 | GUI.color = Color.white; 82 | Matrix4x4 mBackup = GUI.matrix; 83 | 84 | 85 | //Flocking settings 86 | if (panelIdx == 1) 87 | { 88 | Rect PanelRect = new Rect(0, 50, Screen.width / guiScale.x, 200); 89 | GUIUtility.ScaleAroundPivot(guiScale, Vector2.zero); 90 | GUI.Box(PanelRect, string.Empty); 91 | GUILayout.BeginArea(PanelRect); 92 | 93 | 94 | 95 | //--------------- Stick-to-Frame Slider -------------------- 96 | GUILayout.BeginHorizontal(); 97 | 98 | if (GUILayout.Button("Randomize", GUILayout.Width(85), GUILayout.Height(85))) 99 | { 100 | //flockingManager.FlockingSteeringSpeed = Random.Range(0f, 4f); 101 | //flockingManager.FlockingBoundsRadius = Random.Range(25f, 150f); 102 | 103 | flockingManager.FlockingSeperationWeight = Random.Range(0, 10f); 104 | flockingManager.FlockingSeperationRadius = Random.Range(0f, flockingManager.FlockingBoundsRadius); 105 | 106 | flockingManager.FlockingCohesionWeight = Random.Range(0, 10f); 107 | flockingManager.FlockingCohesionRadius = Random.Range(0f, flockingManager.FlockingBoundsRadius); 108 | 109 | flockingManager.FlockingAlignmentWeight = Random.Range(0, 10f); 110 | flockingManager.FlockingAlignmentRadius = Random.Range(0f, flockingManager.FlockingBoundsRadius); 111 | } 112 | 113 | GUILayout.BeginVertical(); 114 | DrawSlider("Stick to Frame", ref particleDestinationLerp, 0f, 1f); 115 | DrawSlider("BoundsRadius", ref flockingManager.FlockingBoundsRadius, 25f, 150f); 116 | DrawSlider("Steer Speed", ref flockingManager.FlockingSteeringSpeed, 0f, 4f); 117 | GUILayout.EndVertical(); 118 | 119 | UpdateStickToFrame(); 120 | GUILayout.EndHorizontal(); 121 | //--------------- Stick-to-Frame Slider -------------------- 122 | 123 | 124 | GUILayout.BeginVertical(); 125 | GUILayout.Space(15); 126 | 127 | GUILayout.BeginHorizontal(); 128 | GUILayout.BeginVertical(); 129 | DrawSlider("Seperation W", ref flockingManager.FlockingSeperationWeight, 0f, 10); 130 | DrawSlider("Alignment W", ref flockingManager.FlockingAlignmentWeight, 0f, 10); 131 | DrawSlider("Cohesion W", ref flockingManager.FlockingCohesionWeight, 0f, 10); 132 | GUILayout.EndVertical(); 133 | 134 | 135 | GUILayout.BeginVertical(); 136 | DrawSlider("Seperation R", ref flockingManager.FlockingSeperationRadius, 0f, flockingManager.FlockingBoundsRadius); 137 | DrawSlider("Alignment R", ref flockingManager.FlockingAlignmentRadius, 0f, flockingManager.FlockingBoundsRadius); 138 | DrawSlider("Cohesion R", ref flockingManager.FlockingCohesionRadius, 0f, flockingManager.FlockingBoundsRadius); 139 | GUILayout.EndVertical(); 140 | 141 | GUILayout.EndHorizontal(); 142 | GUILayout.EndVertical(); 143 | GUILayout.EndArea(); 144 | 145 | GUI.matrix = mBackup; 146 | } 147 | 148 | //Threading Settings 149 | else if (panelIdx == 2) 150 | { 151 | Rect PanelRect = new Rect(0, 50, Screen.width / guiScale.x, 100); 152 | GUIUtility.ScaleAroundPivot(guiScale, Vector2.zero); 153 | GUI.Box(PanelRect, string.Empty); 154 | GUILayout.BeginArea(PanelRect); 155 | 156 | GUILayout.BeginVertical(); 157 | GUILayout.BeginHorizontal(); 158 | 159 | GUI.color = flockingManager.MultithreadingEnabled ? Color.green : Color.red; 160 | if (GUILayout.Button(flockingManager.MultithreadingEnabled ? "Multi Threading Enabled" : " Multi Threading Disabled", GUILayout.Height(50))) 161 | flockingManager.MultithreadingEnabled = !flockingManager.MultithreadingEnabled; 162 | 163 | GUI.color = Color.white; 164 | if (GUILayout.Button("Add 500 boids", GUILayout.Height(50))) 165 | flockingManager.FlockingSpawnCount += 500; 166 | 167 | if (GUILayout.Button("Remove 500 boids", GUILayout.Height(50))) 168 | flockingManager.FlockingSpawnCount = Mathf.Max(0, flockingManager.FlockingSpawnCount - 500); 169 | 170 | GUILayout.EndHorizontal(); 171 | GUILayout.BeginHorizontal(); 172 | 173 | GUI.color = Color.white; 174 | GUILayout.Space(20); 175 | GUI.enabled = flockingManager.MultithreadingEnabled; 176 | 177 | GUILayout.BeginVertical(); 178 | DrawTextField("Number of Threads", ref flockingManager.ThreadingMaxThreads); 179 | GUILayout.EndVertical(); 180 | 181 | GUI.enabled = true; 182 | 183 | GUILayout.EndHorizontal(); 184 | GUILayout.EndVertical(); 185 | GUILayout.EndArea(); 186 | GUI.matrix = mBackup; 187 | } 188 | 189 | 190 | //--------------- FPS Feedback -------------------- 191 | if (flockingManager.myThreadScheduler != null) 192 | { 193 | Rect totalBar = new Rect(20, Screen.height - 125, 350, 25); 194 | DrawProgressBar(totalBar, "FLocking Behaviour Progress: ", flockingManager.myThreadScheduler.Progress); 195 | } 196 | 197 | Rect particleCountRect = new Rect(20, Screen.height - 100, 350, 25); 198 | GUI.Label(particleCountRect, "Number of Boids: " + flockingManager.FlockingSpawnCount); 199 | 200 | Rect flockingFpsRect = new Rect(20, Screen.height - 75, 350, 20); 201 | GUI.Label(flockingFpsRect, "FLocking Behaviour FPS: " + (1f / flockingManager.flockingUpdateTime)); 202 | 203 | Rect gameFpsRect = new Rect(20, Screen.height - 50, 350, 20); 204 | float gameFPS = (1f / Time.deltaTime); 205 | 206 | GUI.color = gameFPS < 20f ? Color.red : Color.white; 207 | GUI.Label(gameFpsRect, "Game FPS: " + gameFPS); 208 | 209 | GUI.color = Color.white; 210 | //--------------- FPS Feedback -------------------- 211 | 212 | 213 | //--------------- Intro Screen -------------------- 214 | if (Time.realtimeSinceStartup < IntroDuration) 215 | { 216 | GUI.DrawTexture(new Rect(0f, 0f, Screen.width, Screen.height), IntroScreen, ScaleMode.ScaleAndCrop); 217 | } 218 | else 219 | { 220 | fadeAlpha -= Time.deltaTime; 221 | if (fadeAlpha > 0f) 222 | { 223 | GUI.color = new Color(1f, 1f, 1f, fadeAlpha); 224 | GUI.DrawTexture(new Rect(0f, 0f, Screen.width, Screen.height), IntroScreen, ScaleMode.ScaleAndCrop); 225 | } 226 | else 227 | { 228 | GUI.enabled = true; 229 | } 230 | } 231 | //--------------- Intro Screen -------------------- 232 | 233 | } 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | //--------------- GUI Calls -------------------- 242 | private void DrawTextField(string prefix, ref int value) 243 | { 244 | GUILayout.BeginHorizontal(); 245 | GUILayout.Label(prefix + ": ", GUILayout.Width(150)); 246 | 247 | string strValue = value.ToString(); 248 | strValue = GUILayout.TextField(strValue); 249 | int.TryParse(strValue, out value); 250 | 251 | GUILayout.EndHorizontal(); 252 | } 253 | 254 | private void DrawSlider(string prefix, ref float value, float minValue, float maxValue) 255 | { 256 | GUILayout.BeginHorizontal(); 257 | GUILayout.Label(prefix + ": " + RoundWithPrecision(value, 1).ToString(), GUILayout.Width(125)); 258 | 259 | if (GUILayout.Button("-", GUILayout.Width(30), GUILayout.Height(25))) 260 | value = Mathf.Clamp(value - ((maxValue - minValue) / 5f), minValue, maxValue); 261 | 262 | value = GUILayout.HorizontalSlider(value, minValue, maxValue); 263 | 264 | if (GUILayout.Button("+", GUILayout.Width(30), GUILayout.Height(25))) 265 | value = Mathf.Clamp(value + ((maxValue - minValue) / 5f), minValue, maxValue); 266 | 267 | GUILayout.EndHorizontal(); 268 | } 269 | 270 | public static float RoundWithPrecision(float value, int precision) 271 | { 272 | float multiplier = Mathf.Pow(10, (float)precision); 273 | value *= multiplier; 274 | value = Mathf.Round(value); 275 | 276 | return value / multiplier; 277 | } 278 | 279 | 280 | private void DrawProgressBar(Rect rect, string prefix, float progress) 281 | { 282 | GUI.Box(rect, prefix + Mathf.Round(progress * 100f).ToString()); 283 | rect.width *= progress; 284 | 285 | GUI.color = Color.green; 286 | GUI.Box(rect, string.Empty); 287 | GUI.color = Color.white; 288 | } 289 | 290 | //--------------- GUI Calls -------------------- 291 | 292 | } 293 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/HUDmanager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1d891166f7cfb714ea54e74712261412 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/MassiveFlockingExample.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Frankfort.Threading; 5 | 6 | 7 | public class MassiveFlockingExample : MonoBehaviour 8 | { 9 | public bool FlockingDebugMode = false; 10 | public int TargetFrameRate = 30; 11 | public float ParticleSize = 3f; 12 | public float ParticleColorLerpSpeed = 3f; 13 | public int FlockingSpawnCount = 10000; 14 | public int FlockingMaxRandomSiblingsTested = 500; 15 | 16 | public float FlockingMaxSpawnRadius = 50f; 17 | public float FlockingStartVelocityMin = 15f; 18 | public float FlockingStartVelocityMax = 20f; 19 | public float FlockingSteeringSpeed = 0.5f; 20 | 21 | public float FlockingSeperationWeight = 1f; 22 | public float FlockingAlignmentWeight = 1f; 23 | public float FlockingCohesionWeight = 1f; 24 | 25 | public float FlockingSeperationRadius = 10; 26 | public float FlockingAlignmentRadius = 30; 27 | public float FlockingCohesionRadius = 75f; 28 | 29 | public float FlockingDestinationAttractRadius = 0f; 30 | public float FlockingDestinationReachedRadius = 0f; 31 | public float FlockingBoundsRadius = 100f; 32 | 33 | 34 | public bool MultithreadingEnabled = false; 35 | public int ThreadingMaxThreads = -1; 36 | public int ThreadingPackagesPerThread = 4; 37 | 38 | private FlockData[] flockers; 39 | private EnvironmentCollider[] colliders; 40 | private Vector3[] destinationPoints; 41 | 42 | private ParticleSystem flockParticleEmitter; 43 | private FlockingDataWorker[] workerObjects; 44 | 45 | public ThreadPoolScheduler myThreadScheduler; 46 | 47 | private float flockingStartTime = 0; 48 | public float flockingUpdateTime = 0; 49 | 50 | 51 | void awake() 52 | { 53 | Application.targetFrameRate = TargetFrameRate; 54 | } 55 | 56 | 57 | // Use this for initialization 58 | void Start () 59 | { 60 | flockParticleEmitter = this.gameObject.GetComponentInChildren(); 61 | 62 | 63 | //--------------- Gather all colliders -------------------- 64 | colliders = GetColliders(); 65 | //--------------- Gather all colliders -------------------- 66 | 67 | 68 | //--------------- Gather all Destination points -------------------- 69 | destinationPoints = GetDestinationPoints(); 70 | destinationPoints.Shuffle(); 71 | //--------------- Gather all Destination points -------------------- 72 | 73 | 74 | //--------------- Spawn Flocks -------------------- 75 | flockers = new FlockData[FlockingSpawnCount]; 76 | int i = FlockingSpawnCount; 77 | 78 | Vector3 center = this.transform.position; 79 | while (--i > -1) 80 | SpawnRandomFlockSpherical(center, flockers, i); 81 | //--------------- Spawn Flocks -------------------- 82 | 83 | 84 | 85 | //--------------- For each Flock, spawn a Particle-------------------- 86 | if (flockParticleEmitter != null) 87 | { 88 | ParticleSystem.Particle[] particles = new ParticleSystem.Particle[FlockingSpawnCount]; 89 | i = FlockingSpawnCount; 90 | while (--i > -1) 91 | SpawnNewParticle(particles, i); 92 | 93 | flockParticleEmitter.SetParticles(particles, particles.Length); 94 | flockParticleEmitter.Play(); 95 | } 96 | //--------------- For each Flock, spawn a Particle -------------------- 97 | 98 | InitThreadPool(); 99 | } 100 | 101 | 102 | private void InitThreadPool() 103 | { 104 | //--------------- Cap the number of threads -------------------- 105 | int maxThreads = ThreadingMaxThreads; 106 | if (maxThreads <= 0) 107 | maxThreads = Mathf.Max(SystemInfo.processorCount - 1, 1); 108 | //--------------- Cap the number of threads -------------------- 109 | 110 | //--------------- Spread the Flocks over multiple worker-packages -------------------- 111 | int ThreadingPoolPackages = ThreadingPackagesPerThread * maxThreads; 112 | 113 | int flocksPerBlock = Mathf.CeilToInt((float)FlockingSpawnCount / (float)ThreadingPoolPackages); 114 | workerObjects = new FlockingDataWorker[ThreadingPoolPackages]; 115 | 116 | int i = ThreadingPoolPackages; 117 | int startIdx = 0; 118 | while (--i > -1) 119 | { 120 | FlockingDataWorker workerBlock = new FlockingDataWorker(); 121 | UpdateWorkerObjectStats(workerBlock); 122 | 123 | workerBlock.startWorkIndex = startIdx; 124 | workerBlock.endWorkIndex = Mathf.Min(flockers.Length, startIdx + flocksPerBlock); 125 | workerObjects[i] = workerBlock; 126 | startIdx += flocksPerBlock; 127 | } 128 | //--------------- Spread the Flocks over multiple worker-packages -------------------- 129 | 130 | 131 | myThreadScheduler = Loom.CreateThreadPoolScheduler(); 132 | myThreadScheduler.ForceToMainThread = !MultithreadingEnabled; 133 | myThreadScheduler.StartASyncThreads(workerObjects, onThreadWorkComplete, null, maxThreads); 134 | } 135 | 136 | private void RestartThreadPoolWork() 137 | { 138 | //if (tickTock && !myThreadScheduler.isBusy && workerObjects != null) 139 | if (workerObjects != null) 140 | { 141 | //--------------- Update WorkerObjects first-------------------- 142 | colliders = GetColliders(); 143 | 144 | int i = workerObjects.Length; 145 | while (--i > -1) 146 | UpdateWorkerObjectStats(workerObjects[i]); 147 | //--------------- Update WorkerObjects first -------------------- 148 | 149 | //--------------- Then restart the calculations -------------------- 150 | myThreadScheduler.ForceToMainThread = !MultithreadingEnabled; 151 | myThreadScheduler.StartASyncThreads(workerObjects, onThreadWorkComplete, null, ThreadingMaxThreads); 152 | //--------------- Then restart the calculations -------------------- 153 | } 154 | } 155 | 156 | 157 | 158 | 159 | private EnvironmentCollider[] GetColliders() 160 | { 161 | GameObject[] collGOs = GameObject.FindGameObjectsWithTag("EnvironmentCollider"); 162 | 163 | EnvironmentCollider[] result = new EnvironmentCollider[collGOs.Length]; 164 | int i = collGOs.Length; 165 | while(--i > -1) 166 | { 167 | MeshFilter filter = collGOs[i].gameObject.GetComponentInChildren(); 168 | if(filter != null) 169 | { 170 | Vector3 sizeRadius = Vector3.Scale( filter.mesh.bounds.extents, collGOs[i].transform.localScale); 171 | result[i] = new EnvironmentCollider(collGOs[i].transform.position, Mathf.Max(sizeRadius.x, sizeRadius.y, sizeRadius.z) * 1.2f); 172 | } 173 | } 174 | return result; 175 | } 176 | 177 | 178 | 179 | private Vector3[] GetDestinationPoints() 180 | { 181 | List result = new List(); 182 | 183 | GameObject[] destGOs = GameObject.FindGameObjectsWithTag("ParticleDestination"); 184 | int i = destGOs.Length; 185 | while (--i > -1) 186 | { 187 | Transform goTransform = destGOs[i].transform; 188 | MeshFilter filter = destGOs[i].gameObject.GetComponentInChildren(); 189 | if (filter != null) 190 | { 191 | Vector3[] verts = filter.mesh.vertices; 192 | int j = verts.Length; 193 | while (--j > -1) 194 | verts[j] = goTransform.TransformPoint(verts[j]); 195 | 196 | result.AddRange(verts); 197 | } 198 | } 199 | 200 | return result.ToArray(); 201 | } 202 | 203 | 204 | 205 | private void SpawnRandomFlockSpherical(Vector3 center, FlockData[] storeTo, int index) 206 | { 207 | Vector3 randomDirection = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)).normalized; 208 | Vector3 randomOrientation = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)).normalized; 209 | Vector3 pos = center + (randomDirection * Random.Range(0f, FlockingMaxSpawnRadius)); 210 | 211 | FlockData flock = new FlockData(); 212 | flock.position = pos; 213 | flock.currentDirection = randomOrientation; 214 | flock.targetDirection = randomOrientation; 215 | flock.targetVelocity = Random.Range(FlockingStartVelocityMin, FlockingStartVelocityMax); 216 | 217 | if (index < destinationPoints.Length) 218 | flock.destinationPoint = destinationPoints[index]; 219 | 220 | storeTo[index] = flock; 221 | } 222 | 223 | private void SpawnNewParticle(ParticleSystem.Particle[] storeTo, int index) 224 | { 225 | ParticleSystem.Particle particle = new ParticleSystem.Particle(); 226 | particle.position = flockers[index].position; 227 | particle.startLifetime = float.MaxValue; 228 | particle.lifetime = float.MaxValue; 229 | particle.size = ParticleSize; 230 | particle.color = Color.white; 231 | storeTo[index] = particle; 232 | } 233 | 234 | 235 | private void UpdateWorkerObjectStats(FlockingDataWorker flockingDataWorker) 236 | { 237 | flockingDataWorker.universeCenter = this.transform.position; 238 | flockingDataWorker.AllFlocks = flockers; 239 | flockingDataWorker.AllColliders = colliders; 240 | flockingDataWorker.maxRandomSiblingsTested = FlockingMaxRandomSiblingsTested; 241 | flockingDataWorker.maxBoundsRadius = FlockingBoundsRadius; 242 | flockingDataWorker.seperationWeight = FlockingSeperationWeight; 243 | flockingDataWorker.seperationRadius = FlockingSeperationRadius; 244 | flockingDataWorker.alignmentWeight = FlockingAlignmentWeight; 245 | flockingDataWorker.alignmentRadius = FlockingAlignmentRadius; 246 | flockingDataWorker.cohesionWeight = FlockingCohesionWeight; 247 | flockingDataWorker.cohesionRadius = FlockingCohesionRadius; 248 | flockingDataWorker.destinationAttractRadius = FlockingDestinationAttractRadius; 249 | flockingDataWorker.destinationReachedRadius = FlockingDestinationReachedRadius; 250 | } 251 | 252 | 253 | private void onThreadWorkComplete(IThreadWorkerObject[] finishedObjects) 254 | { 255 | flockingUpdateTime = Time.realtimeSinceStartup - flockingStartTime; 256 | flockingStartTime = Time.realtimeSinceStartup; 257 | 258 | //--------------- Resize arrays if needed -------------------- 259 | if (flockers.Length != FlockingSpawnCount) 260 | { 261 | int startCount = flockers.Length; 262 | System.Array.Resize(ref flockers, FlockingSpawnCount); 263 | 264 | ParticleSystem.Particle[] particles = new ParticleSystem.Particle[flockParticleEmitter.particleCount]; 265 | flockParticleEmitter.GetParticles(particles); 266 | System.Array.Resize(ref particles, FlockingSpawnCount); 267 | 268 | if (startCount < FlockingSpawnCount) 269 | { 270 | Vector3 center = this.transform.position; 271 | for (int i = startCount; i < FlockingSpawnCount; i++) 272 | { 273 | SpawnRandomFlockSpherical(center, flockers, i); 274 | SpawnNewParticle(particles, i); 275 | } 276 | } 277 | flockParticleEmitter.SetParticles(particles, particles.Length); 278 | 279 | if (myThreadScheduler != null) 280 | Destroy(myThreadScheduler.gameObject); 281 | 282 | //Reinit the threadpool 283 | InitThreadPool(); 284 | } 285 | else 286 | { 287 | //Restart the threadpool 288 | RestartThreadPoolWork(); 289 | } 290 | //--------------- Resize arrays if needed -------------------- 291 | 292 | } 293 | 294 | 295 | 296 | 297 | 298 | 299 | // Update is called once per frame 300 | void Update () 301 | { 302 | //--------------- Get particles to alter -------------------- 303 | ParticleSystem.Particle[] particles = new ParticleSystem.Particle[flockParticleEmitter.particleCount]; 304 | flockParticleEmitter.GetParticles(particles); 305 | //--------------- Get particles to alter -------------------- 306 | 307 | 308 | 309 | int i = Mathf.Min(flockers.Length, particles.Length); //Should be the same, but hey... 310 | while (--i > -1) 311 | { 312 | //--------------- Update Flocking positions based on Velocity and targetDirection -------------------- 313 | FlockData flock = flockers[i]; 314 | flock.currentDirection = Vector3.Slerp(flock.currentDirection, flock.targetDirection, Time.deltaTime * FlockingSteeringSpeed); 315 | flock.position += flock.currentDirection * (Time.deltaTime * flock.currentVelocity); 316 | flock.currentColor = Color.Lerp(flock.currentColor, flock.targetColor, Time.deltaTime * ParticleColorLerpSpeed); 317 | //--------------- Update Flocking positions based on Velocity and targetDirection -------------------- 318 | 319 | //--------------- Update assosiated particle -------------------- 320 | particles[i].position = flock.position; 321 | particles[i].lifetime = float.MaxValue; 322 | particles[i].color = flock.currentColor; 323 | particles[i].size = ParticleSize; 324 | //--------------- Update assosiated particle -------------------- 325 | 326 | if (FlockingDebugMode) 327 | { 328 | Debug.DrawRay(flock.position, flock.targetDirection * 2f, Color.white); 329 | Debug.DrawRay(flock.position, flock.currentDirection * 2f, Color.red); 330 | } 331 | } 332 | 333 | flockParticleEmitter.SetParticles(particles, particles.Length); 334 | } 335 | } 336 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/MassiveFlockingExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 06775bb744db53240a14a12dd4579847 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/MovingBodies.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | public class MovingBodies : MonoBehaviour 5 | { 6 | public Transform rotateAroundTarget; 7 | public Vector3 rotateAroundAxis = Vector3.up; 8 | public float rotateAroundSpeed; 9 | 10 | private float angle; 11 | 12 | 13 | // Update is called once per frame 14 | void Update () 15 | { 16 | this.transform.RotateAround(rotateAroundTarget.position, rotateAroundAxis, Time.deltaTime * rotateAroundSpeed); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/MovingBodies.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 95ae2982143650543879a70c590d86d7 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/ThreadedFlocking.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Frankfort.Threading; 5 | 6 | 7 | 8 | public class FlockData 9 | { 10 | public Vector3 position; 11 | public Vector3 currentDirection; 12 | public Vector3 targetDirection; 13 | public Color targetColor; 14 | public Color currentColor; 15 | public Vector3 destinationPoint; 16 | public float targetVelocity; 17 | public float currentVelocity; 18 | } 19 | 20 | 21 | public struct EnvironmentCollider 22 | { 23 | public Vector3 position; 24 | public float radius; 25 | public float radiusSqr; 26 | 27 | public EnvironmentCollider(Vector3 position, float radius) 28 | { 29 | this.position = position; 30 | this.radius = radius; 31 | this.radiusSqr = radius * radius; 32 | } 33 | } 34 | 35 | 36 | public class FlockingDataWorker : IThreadWorkerObject 37 | { 38 | 39 | //--------------- Flock Frame/Cycledata -------------------- 40 | public FlockData[] AllFlocks; 41 | public EnvironmentCollider[] AllColliders; 42 | public int startWorkIndex; 43 | public int endWorkIndex; 44 | public int maxRandomSiblingsTested; 45 | 46 | public Vector3 universeCenter; 47 | public float maxBoundsRadius; 48 | 49 | public float seperationWeight; 50 | public float alignmentWeight; 51 | public float cohesionWeight; 52 | 53 | private float _seperationRadius; 54 | private float _seperationRadiusSqr; 55 | private float _alignmentRadius; 56 | private float _alignmentRadiusSqr; 57 | private float _cohesionRadius; 58 | private float _cohesionRadiusSqr; 59 | private float _destinationAttractRadius; 60 | private float _destinationAttractRadiusSqr; 61 | public float destinationReachedRadius; 62 | 63 | 64 | public float seperationRadius 65 | { 66 | get { return _seperationRadius; } 67 | set { _seperationRadius = value; _seperationRadiusSqr = value * value; } 68 | } 69 | public float alignmentRadius 70 | { 71 | get { return _alignmentRadius; } 72 | set { _alignmentRadius = value; _alignmentRadiusSqr = value * value; } 73 | } 74 | 75 | public float cohesionRadius 76 | { 77 | get { return _cohesionRadius; } 78 | set { _cohesionRadius = value; _cohesionRadiusSqr = value * value; } 79 | } 80 | public float destinationAttractRadius 81 | { 82 | get { return _destinationAttractRadius; } 83 | set { _destinationAttractRadius = value; _destinationAttractRadiusSqr = value * value; } 84 | } 85 | 86 | 87 | public float seperationRadiusSqr 88 | { 89 | get { return _seperationRadiusSqr; } 90 | } 91 | public float alignmentRadiusSqr 92 | { 93 | get { return _alignmentRadiusSqr; } 94 | } 95 | public float cohesionRadiusSqr 96 | { 97 | get { return _cohesionRadiusSqr; } 98 | } 99 | public float destinationAttractRadiusSqr 100 | { 101 | get { return _destinationAttractRadiusSqr; } 102 | } 103 | //--------------- Flock Frame/Cycledata -------------------- 104 | 105 | 106 | 107 | 108 | //--------------- IThreadWorker Implementation -------------------- 109 | private bool isAborted = false; 110 | 111 | public void AbortThreadedWork() 112 | { 113 | isAborted = true; 114 | } 115 | //--------------- IThreadWorker Implementation -------------------- 116 | 117 | 118 | 119 | 120 | public void ExecuteThreadedWork() 121 | { 122 | startWorkIndex = Mathf.Clamp(startWorkIndex, 0, AllFlocks.Length); 123 | endWorkIndex = Mathf.Clamp(endWorkIndex, 0, AllFlocks.Length); 124 | 125 | //--------------- Creat list with indexes -------------------- 126 | int[] randomIndexes = new int[AllFlocks.Length]; 127 | int i = AllFlocks.Length; 128 | while (--i > -1) 129 | randomIndexes[i] = i; 130 | 131 | //--------------- Creat list with indexes -------------------- 132 | 133 | 134 | for (i = startWorkIndex; i < endWorkIndex && !isAborted; i++) 135 | { 136 | //--------------- Shuffle indexes every-something-flocks -------------------- 137 | if ((float)i % (float)maxRandomSiblingsTested == 0f) 138 | randomIndexes.Shuffle(); 139 | //--------------- Shuffle indexes every-something-flocks -------------------- 140 | 141 | FlockData flock = AllFlocks[i]; 142 | 143 | if (flock.position.y < 0f) //Through the ground.... 144 | { 145 | flock.position.y = -flock.position.y; 146 | flock.targetDirection.y = Mathf.Abs(flock.targetDirection.y); 147 | flock.currentDirection = flock.targetDirection; 148 | flock.currentColor = flock.targetColor = new Color(1f, 1f, 0f, 0.65f); 149 | flock.currentVelocity = flock.targetVelocity; 150 | } 151 | else 152 | { 153 | Vector3 toCenterVec = universeCenter - flock.position; 154 | if (toCenterVec.sqrMagnitude > maxBoundsRadius * maxBoundsRadius) //If outside of univere limits 155 | { 156 | flock.targetDirection = toCenterVec.normalized; 157 | flock.targetColor = new Color(1f, 0f, 1f, 0.25f); 158 | flock.currentVelocity = flock.targetVelocity; 159 | } 160 | else 161 | { 162 | //--------------- Check for Collisions -------------------- 163 | bool isColliding = false; 164 | int j = AllColliders.Length; 165 | 166 | Vector3 collisionAvoidenceDir = Vector3.zero; 167 | while (--j > -1 && !isAborted) 168 | { 169 | EnvironmentCollider coll = AllColliders[j]; 170 | Vector3 diffVec = coll.position - flock.position; 171 | 172 | if (diffVec.sqrMagnitude < coll.radiusSqr) 173 | { 174 | isColliding = true; 175 | Vector3 invDiff = -diffVec.normalized; 176 | Vector3 reflectionDir = FlockHelper.ReflectVector(invDiff, flock.currentDirection); 177 | collisionAvoidenceDir += reflectionDir; 178 | flock.position = coll.position + (invDiff * coll.radius); 179 | } 180 | } 181 | //--------------- Check for Collisions -------------------- 182 | 183 | if (isColliding) //If Colliding 184 | { 185 | flock.targetDirection = flock.currentDirection = collisionAvoidenceDir.normalized; 186 | flock.currentColor = flock.targetColor = new Color(1f, 0.1f, 0f, 0.85f); 187 | flock.currentVelocity = flock.targetVelocity * 2f; 188 | } 189 | else 190 | { 191 | Vector3 diffDestionation = flock.destinationPoint - flock.position; 192 | if (diffDestionation.sqrMagnitude < destinationAttractRadiusSqr) //If close to unique target point... 193 | { 194 | flock.targetDirection = diffDestionation.normalized; 195 | float lerpT = Mathf.Clamp01(diffDestionation.magnitude / destinationReachedRadius); 196 | flock.currentVelocity = flock.targetVelocity * lerpT; 197 | flock.targetColor = Color.Lerp(new Color(0f, 1f, 0f, 1f), new Color(1f, 1f, 1f, 0.15f), lerpT); 198 | } 199 | else 200 | { 201 | Vector3 combinedDirection = flock.targetDirection; 202 | Vector3 combinedColor = Vector3.zero; 203 | 204 | j = Mathf.Min(AllFlocks.Length, maxRandomSiblingsTested); 205 | while (--j > -1 && !isAborted) 206 | { 207 | 208 | //--------------- Get a random sibling -------------------- 209 | int randomIndex = randomIndexes[j]; 210 | if (i == randomIndex) 211 | continue; 212 | FlockData sibling = AllFlocks[randomIndex]; 213 | //--------------- Get a random sibling -------------------- 214 | 215 | 216 | Vector3 diffVec = sibling.position - flock.position; 217 | float distSqr = diffVec.sqrMagnitude; 218 | 219 | if (distSqr < seperationRadiusSqr) 220 | { 221 | combinedDirection += Vector3.Cross(flock.currentDirection, diffVec.normalized) * seperationWeight; 222 | combinedColor.y += seperationWeight; //y == green; 223 | } 224 | //else if (distSqr < alignmentRadiusSqr) 225 | if (distSqr < alignmentRadiusSqr) 226 | { 227 | combinedDirection += sibling.currentDirection * alignmentWeight; 228 | combinedColor.z += alignmentWeight; //z == blue; 229 | } 230 | //else if (distSqr < cohesionRadiusSqr) 231 | if (distSqr < cohesionRadiusSqr) 232 | { 233 | combinedDirection += diffVec.normalized * cohesionWeight; 234 | combinedColor += new Vector3(cohesionWeight, cohesionWeight, cohesionWeight); //Add white 235 | } 236 | } 237 | 238 | flock.targetDirection = combinedDirection.normalized; 239 | flock.currentVelocity = flock.targetVelocity; 240 | combinedColor.Normalize(); 241 | flock.targetColor = new Color(combinedColor.x, combinedColor.y, combinedColor.z, 0.15f); 242 | } 243 | } 244 | } 245 | } 246 | } 247 | } 248 | 249 | } -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/FlockingMassive/ThreadedFlocking.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 271342b3c6fbfa741b8a107ce3997267 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/Simple Implementations.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 84c06b5da589be54397746f0ce5dae32 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/Simple Implementations/SimpleThreadingExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Frankfort.Threading; 4 | using System.Threading; 5 | using System.Collections; 6 | 7 | 8 | public class SimpleThreadingExample : MonoBehaviour 9 | { 10 | // TEST>>>>>>>>>>>>>>>>>>>>>>>>>> 11 | 12 | public int maxThreads = 2; 13 | public int TestWorkerObjects = 40; 14 | public int minCalculations = 10000000; 15 | public int maxCalculations = 50000000; 16 | public float abortAfterSeconds = 3f; 17 | 18 | public Thread threadA; 19 | public Thread threadB; 20 | 21 | private ThreadPoolScheduler myThreadScheduler; 22 | 23 | void Awake() 24 | { 25 | Application.targetFrameRate = 25; 26 | myThreadScheduler = Loom.CreateThreadPoolScheduler(); 27 | 28 | //--------------- Ending Single threaded routine -------------------- 29 | threadA = Loom.StartSingleThread(EndingSingleThreadCoroutine, System.Threading.ThreadPriority.Normal, true); 30 | //--------------- Ending Single threaded routine -------------------- 31 | 32 | //--------------- Continues Single threaded routine -------------------- 33 | threadB = Loom.StartSingleThread(ContinuesSingleThreadCoroutine, System.Threading.ThreadPriority.Normal, true); 34 | //--------------- Continues Single threaded routine -------------------- 35 | 36 | //--------------- Start Multithreaded packages -------------------- 37 | int i = TestWorkerObjects; 38 | IThreadWorkerObject[] workerObjects = new IThreadWorkerObject[TestWorkerObjects]; 39 | 40 | while (--i > -1) 41 | workerObjects[i] = new LotsOfNumbers(UnityEngine.Random.Range(minCalculations, maxCalculations)); 42 | 43 | myThreadScheduler.StartASyncThreads(workerObjects, OnThreadWorkComplete, OnWorkerObjectDone, maxThreads); 44 | StartCoroutine(AbortAllThreadsAfterDelay()); 45 | //--------------- Start Multithreaded packages -------------------- 46 | } 47 | 48 | 49 | 50 | 51 | 52 | //--------------- Managing a simple single Thread -------------------- 53 | private void EndingSingleThreadCoroutine() 54 | { 55 | Debug.Log("Starting an Coroutine on a seperate Thread!"); 56 | 57 | Loom.WaitForNextFrame(30); 58 | Loom.DispatchToMainThread(() => Debug.Log("I waited atleast 30 frames. Whats the current frameCount? : " + Time.frameCount), true); 59 | 60 | Loom.WaitForSeconds(10); 61 | Loom.DispatchToMainThread(() => Debug.Log("I waited atleast 10 seconds. Whats the current frameCount? : " + Time.frameCount), true); 62 | 63 | //Throw error to show safemode nicely throws errors in the MainThread. 64 | 65 | Debug.LogWarning("About the throw an error..."); 66 | throw new Exception("This is an safe Error and should showup in the Console"); 67 | 68 | Debug.Log("It won't get here, but the Thread will die anyways."); 69 | } 70 | 71 | 72 | 73 | private void ContinuesSingleThreadCoroutine() 74 | { 75 | Debug.Log("Starting an never ending Coroutine on a seperate Thread!"); 76 | while (true) 77 | { 78 | Loom.WaitForNextFrame(10); 79 | Loom.DispatchToMainThread(() => Debug.Log("I waited atleast 10 frames. Whats the current frameCount? : " + Time.frameCount), true); 80 | 81 | Loom.WaitForSeconds(1); 82 | Loom.DispatchToMainThread(() => Debug.Log("I waited atleast 1 second. Whats the current frameCount? : " + Time.frameCount), true); 83 | } 84 | Debug.Log("It will never get here, but thats oke..."); 85 | } 86 | //--------------- Managing a simple single Thread -------------------- 87 | 88 | 89 | 90 | 91 | 92 | 93 | //--------------- Managing a simple multithreaded ThreadPoolScheduler implementation -------------------- 94 | public void OnWorkerObjectDone(IThreadWorkerObject finishedObj) 95 | { 96 | LotsOfNumbers fCast = (LotsOfNumbers)finishedObj; 97 | Debug.LogWarning("Object done! result: " + fCast.result + ", maxIterations: " + fCast.maxIterations + ", ID: " + Thread.CurrentThread.ManagedThreadId + ", progress: " + (myThreadScheduler.Progress * 100f)); 98 | } 99 | 100 | public void OnThreadWorkComplete(IThreadWorkerObject[] finishedObjects) 101 | { 102 | Debug.LogWarning("All work done! Managed Thread ID:" + Thread.CurrentThread.ManagedThreadId); 103 | } 104 | private IEnumerator AbortAllThreadsAfterDelay() 105 | { 106 | yield return new WaitForSeconds(abortAfterSeconds); 107 | 108 | if (myThreadScheduler.isBusy) //Threaded work didn't finish in the meantime: time to abort. 109 | { 110 | Debug.Log("Terminate all worker Threads."); 111 | myThreadScheduler.AbortASyncThreads(); 112 | 113 | Debug.Log("Terminate thread A & B."); 114 | if (threadA != null && threadA.IsAlive) 115 | threadA.Abort(); 116 | 117 | if (threadB != null && threadB.IsAlive) 118 | threadB.Abort(); 119 | } 120 | } 121 | //--------------- Managing a simple multithreaded ThreadPoolScheduler implementation -------------------- 122 | 123 | } 124 | 125 | 126 | 127 | 128 | public class LotsOfNumbers : IThreadWorkerObject 129 | { 130 | private bool isAborted; 131 | public long maxIterations = 0; 132 | public long result = 0; 133 | 134 | 135 | public LotsOfNumbers(long maxIterations) 136 | { 137 | this.maxIterations = maxIterations; 138 | } 139 | 140 | public void ExecuteThreadedWork() 141 | { 142 | long i = maxIterations; 143 | while (--i > -1 && !isAborted) 144 | { 145 | //This lightweight method checks if Unity is still active. 146 | //If your app lozes focus or gets pauzed, it will sleep the thread. 147 | //If the application quits, it will abort the thread. 148 | Loom.SleepOrAbortIfUnityInactive(); 149 | 150 | if (i == (maxIterations / 2)) 151 | { 152 | Loom.DispatchToMainThread(() => 153 | Debug.Log("Dispatch: is this the MainThread? " + Loom.CheckIfMainThread()), true); 154 | 155 | Debug.Log("From WorkerThread: is this the MainThread? " + Loom.CheckIfMainThread()); 156 | 157 | GameObject cube = (GameObject)Loom.DispatchToMainThreadReturn(TestThreadSafeDispatch, true); 158 | Loom.DispatchToMainThread(() => cube.name += "_RenamedFrom: " + Thread.CurrentThread.Name); 159 | } 160 | result++; 161 | } 162 | } 163 | 164 | public void AbortThreadedWork() 165 | { 166 | isAborted = true; 167 | } 168 | 169 | 170 | private object TestThreadSafeDispatch() 171 | { 172 | GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); 173 | cube.transform.position = new Vector3(UnityEngine.Random.Range(-20, 20), UnityEngine.Random.Range(-20, 20), UnityEngine.Random.Range(-20, 20)); 174 | cube.name = "MainThreadCube"; 175 | return cube; 176 | } 177 | 178 | private object ThreadSafeGetFrameCount() 179 | { 180 | return Time.frameCount; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/Simple Implementations/SimpleThreadingExample.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f665c9e031556854d9cc008d9e560d4a 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/TextureBlur.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1b8c710e9fc383543a7299502a484ad7 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/TextureBlur/TextureBlurCodeExplained.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Scripts/TextureBlur/TextureBlurCodeExplained.jpg -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/TextureBlur/TextureBlurCodeExplained.jpg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35945138b9ab61c4db6dfe344c68de59 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | serializedVersion: 2 6 | mipmaps: 7 | mipMapMode: 0 8 | enableMipMap: 1 9 | linearTexture: 0 10 | correctGamma: 0 11 | fadeOut: 0 12 | borderMipMap: 0 13 | mipMapFadeDistanceStart: 1 14 | mipMapFadeDistanceEnd: 3 15 | bumpmap: 16 | convertToNormalMap: 0 17 | externalNormalMap: 0 18 | heightScale: .25 19 | normalMapFilter: 0 20 | isReadable: 0 21 | grayScaleToAlpha: 0 22 | generateCubemap: 0 23 | cubemapConvolution: 0 24 | cubemapConvolutionSteps: 8 25 | cubemapConvolutionExponent: 1.5 26 | seamlessCubemap: 0 27 | textureFormat: -1 28 | maxTextureSize: 1024 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | rGBM: 0 37 | compressionQuality: 50 38 | allowsAlphaSplitting: 0 39 | spriteMode: 0 40 | spriteExtrude: 1 41 | spriteMeshType: 1 42 | alignment: 0 43 | spritePivot: {x: .5, y: .5} 44 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 45 | spritePixelsToUnits: 100 46 | alphaIsTransparency: 0 47 | textureType: -1 48 | buildTargetSettings: [] 49 | spriteSheet: 50 | sprites: [] 51 | spritePackingTag: 52 | userData: 53 | assetBundleName: 54 | assetBundleVariant: 55 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/TextureBlur/TextureBlurThreaded.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Scripts/TextureBlur/TextureBlurThreaded.cs -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Scripts/TextureBlur/TextureBlurThreaded.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: df25dc8cc1736674281c69b30da3fe61 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0cd7ef8f6350bea4da72277f5f3ac154 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Cubemap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Cubemap.jpg -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Cubemap.jpg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: afcb080795d535a4099391b07e41fe9e 3 | TextureImporter: 4 | fileIDToRecycleName: 5 | 8900000: generatedCubemap 6 | serializedVersion: 2 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | linearTexture: 0 11 | correctGamma: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapFadeDistanceStart: 1 15 | mipMapFadeDistanceEnd: 3 16 | bumpmap: 17 | convertToNormalMap: 0 18 | externalNormalMap: 0 19 | heightScale: .25 20 | normalMapFilter: 0 21 | isReadable: 0 22 | grayScaleToAlpha: 0 23 | generateCubemap: 1 24 | cubemapConvolution: 0 25 | cubemapConvolutionSteps: 8 26 | cubemapConvolutionExponent: 1.5 27 | seamlessCubemap: 0 28 | textureFormat: -1 29 | maxTextureSize: 1024 30 | textureSettings: 31 | filterMode: -1 32 | aniso: -1 33 | mipBias: -1 34 | wrapMode: 1 35 | nPOTScale: 1 36 | lightmap: 0 37 | rGBM: 0 38 | compressionQuality: 50 39 | allowsAlphaSplitting: 0 40 | spriteMode: 0 41 | spriteExtrude: 1 42 | spriteMeshType: 1 43 | alignment: 0 44 | spritePivot: {x: .5, y: .5} 45 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 46 | spritePixelsToUnits: 100 47 | alphaIsTransparency: 0 48 | textureType: 3 49 | buildTargetSettings: [] 50 | spriteSheet: 51 | sprites: [] 52 | spritePackingTag: 53 | userData: 54 | assetBundleName: 55 | assetBundleVariant: 56 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/FlockingDemoLogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/FlockingDemoLogo.jpg -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/FlockingDemoLogo.jpg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d477911e69fc6e428e856c20744b4c7 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | serializedVersion: 2 6 | mipmaps: 7 | mipMapMode: 0 8 | enableMipMap: 0 9 | linearTexture: 0 10 | correctGamma: 0 11 | fadeOut: 0 12 | borderMipMap: 0 13 | mipMapFadeDistanceStart: 1 14 | mipMapFadeDistanceEnd: 3 15 | bumpmap: 16 | convertToNormalMap: 0 17 | externalNormalMap: 0 18 | heightScale: .25 19 | normalMapFilter: 0 20 | isReadable: 0 21 | grayScaleToAlpha: 0 22 | generateCubemap: 0 23 | cubemapConvolution: 0 24 | cubemapConvolutionSteps: 8 25 | cubemapConvolutionExponent: 1.5 26 | seamlessCubemap: 0 27 | textureFormat: 32 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | rGBM: 0 37 | compressionQuality: 50 38 | allowsAlphaSplitting: 0 39 | spriteMode: 0 40 | spriteExtrude: 1 41 | spriteMeshType: 1 42 | alignment: 0 43 | spritePivot: {x: .5, y: .5} 44 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 45 | spritePixelsToUnits: 100 46 | alphaIsTransparency: 0 47 | textureType: 5 48 | buildTargetSettings: 49 | - buildTarget: Android 50 | maxTextureSize: 2048 51 | textureFormat: 34 52 | compressionQuality: 100 53 | allowsAlphaSplitting: 0 54 | spriteSheet: 55 | sprites: [] 56 | spritePackingTag: 57 | userData: 58 | assetBundleName: 59 | assetBundleVariant: 60 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Floor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Floor.jpg -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Floor.jpg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b89995f6caf9814892cda064ad152a8 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | serializedVersion: 2 6 | mipmaps: 7 | mipMapMode: 0 8 | enableMipMap: 1 9 | linearTexture: 0 10 | correctGamma: 0 11 | fadeOut: 0 12 | borderMipMap: 0 13 | mipMapFadeDistanceStart: 1 14 | mipMapFadeDistanceEnd: 3 15 | bumpmap: 16 | convertToNormalMap: 0 17 | externalNormalMap: 0 18 | heightScale: .25 19 | normalMapFilter: 0 20 | isReadable: 0 21 | grayScaleToAlpha: 0 22 | generateCubemap: 0 23 | cubemapConvolution: 0 24 | cubemapConvolutionSteps: 8 25 | cubemapConvolutionExponent: 1.5 26 | seamlessCubemap: 0 27 | textureFormat: -1 28 | maxTextureSize: 1024 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | rGBM: 0 37 | compressionQuality: 50 38 | allowsAlphaSplitting: 0 39 | spriteMode: 0 40 | spriteExtrude: 1 41 | spriteMeshType: 1 42 | alignment: 0 43 | spritePivot: {x: .5, y: .5} 44 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 45 | spritePixelsToUnits: 100 46 | alphaIsTransparency: 0 47 | textureType: -1 48 | buildTargetSettings: [] 49 | spriteSheet: 50 | sprites: [] 51 | spritePackingTag: 52 | userData: 53 | assetBundleName: 54 | assetBundleVariant: 55 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/FrameClean.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/FrameClean.fbx -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/FrameClean.fbx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4cf1f862042268f42be35324a029e68b 3 | ModelImporter: 4 | serializedVersion: 18 5 | fileIDToRecycleName: 6 | 4300000: FrameClean 7 | materials: 8 | importMaterials: 1 9 | materialName: 0 10 | materialSearch: 1 11 | animations: 12 | legacyGenerateAnimations: 4 13 | bakeSimulation: 0 14 | optimizeGameObjects: 0 15 | motionNodeName: 16 | animationImportErrors: 17 | animationImportWarnings: 18 | animationRetargetingWarnings: 19 | animationDoRetargetingWarnings: 0 20 | animationCompression: 1 21 | animationRotationError: .5 22 | animationPositionError: .5 23 | animationScaleError: .5 24 | animationWrapMode: 0 25 | extraExposedTransformPaths: [] 26 | clipAnimations: [] 27 | isReadable: 1 28 | meshes: 29 | lODScreenPercentages: [] 30 | globalScale: 1 31 | meshCompression: 0 32 | addColliders: 0 33 | importBlendShapes: 1 34 | swapUVChannels: 0 35 | generateSecondaryUV: 0 36 | useFileUnits: 1 37 | optimizeMeshForGPU: 1 38 | keepQuads: 0 39 | weldVertices: 1 40 | secondaryUVAngleDistortion: 8 41 | secondaryUVAreaDistortion: 15.000001 42 | secondaryUVHardAngle: 88 43 | secondaryUVPackMargin: 4 44 | useFileScale: 0 45 | tangentSpace: 46 | normalSmoothAngle: 60 47 | splitTangentsAcrossUV: 1 48 | normalImportMode: 0 49 | tangentImportMode: 1 50 | importAnimation: 1 51 | copyAvatar: 0 52 | humanDescription: 53 | human: [] 54 | skeleton: [] 55 | armTwist: .5 56 | foreArmTwist: .5 57 | upperLegTwist: .5 58 | legTwist: .5 59 | armStretch: .0500000007 60 | legStretch: .0500000007 61 | feetSpacing: 0 62 | rootMotionBoneName: 63 | hasTranslationDoF: 0 64 | lastHumanDescriptionAvatarSource: {instanceID: 0} 65 | animationType: 1 66 | humanoidOversampling: 1 67 | additionalBone: 0 68 | userData: 69 | assetBundleName: 70 | assetBundleVariant: 71 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/FrameHighPoly.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/FrameHighPoly.fbx -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/FrameHighPoly.fbx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 00938428866bd134fac665e08a6602c4 3 | ModelImporter: 4 | serializedVersion: 18 5 | fileIDToRecycleName: 6 | 4300000: FrameHighPoly 7 | 4300002: FrameHighPoly_MeshPart0 8 | 4300004: FrameHighPoly_MeshPart1 9 | materials: 10 | importMaterials: 1 11 | materialName: 0 12 | materialSearch: 1 13 | animations: 14 | legacyGenerateAnimations: 4 15 | bakeSimulation: 0 16 | optimizeGameObjects: 0 17 | motionNodeName: 18 | animationImportErrors: 19 | animationImportWarnings: 20 | animationRetargetingWarnings: 21 | animationDoRetargetingWarnings: 0 22 | animationCompression: 1 23 | animationRotationError: .5 24 | animationPositionError: .5 25 | animationScaleError: .5 26 | animationWrapMode: 0 27 | extraExposedTransformPaths: [] 28 | clipAnimations: [] 29 | isReadable: 1 30 | meshes: 31 | lODScreenPercentages: [] 32 | globalScale: 1 33 | meshCompression: 0 34 | addColliders: 0 35 | importBlendShapes: 1 36 | swapUVChannels: 0 37 | generateSecondaryUV: 0 38 | useFileUnits: 1 39 | optimizeMeshForGPU: 1 40 | keepQuads: 0 41 | weldVertices: 1 42 | secondaryUVAngleDistortion: 8 43 | secondaryUVAreaDistortion: 15.000001 44 | secondaryUVHardAngle: 88 45 | secondaryUVPackMargin: 4 46 | useFileScale: 0 47 | tangentSpace: 48 | normalSmoothAngle: 60 49 | splitTangentsAcrossUV: 1 50 | normalImportMode: 0 51 | tangentImportMode: 1 52 | importAnimation: 1 53 | copyAvatar: 0 54 | humanDescription: 55 | human: [] 56 | skeleton: [] 57 | armTwist: .5 58 | foreArmTwist: .5 59 | upperLegTwist: .5 60 | legTwist: .5 61 | armStretch: .0500000007 62 | legStretch: .0500000007 63 | feetSpacing: 0 64 | rootMotionBoneName: 65 | hasTranslationDoF: 0 66 | lastHumanDescriptionAvatarSource: {instanceID: 0} 67 | animationType: 1 68 | humanoidOversampling: 1 69 | additionalBone: 0 70 | userData: 71 | assetBundleName: 72 | assetBundleVariant: 73 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d73b0eb5902dec41898f64eab8fb411 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/CannonBall.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/CannonBall.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/CannonBall.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9973d51ae6bcbd048a5aacddf0256477 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Export_Logo_Clean_mi_car_paint_phen_x_passes1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/Export_Logo_Clean_mi_car_paint_phen_x_passes1.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Export_Logo_Clean_mi_car_paint_phen_x_passes1.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f1b46cbf81d77be4f88ea176051b01a4 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Floor.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/Floor.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Floor.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b1b8b6e6bf5e4f1449abc772e4464f3d 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Frame.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/Frame.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Frame.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 836d2a376d9bc5f4dbdb04a462eb1dec 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Particle.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/Particle.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Particle.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a61d61f5dab29b249929635ed32edab7 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Spheres.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/Spheres.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/Spheres.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cd662e242d655b64bb9bee15b56bae85 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/lambert1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/lambert1.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/lambert1.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d18537a22534fde4b8a52630439a08af 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/mi_car_paint_phen_x_passes1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Materials/mi_car_paint_phen_x_passes1.mat -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Materials/mi_car_paint_phen_x_passes1.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 25bb2686a20873645b48d26335869eec 3 | NativeFormatImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Particle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Particle.png -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Particle.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3ea02907605adc145b9db0787c419ade 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | serializedVersion: 2 6 | mipmaps: 7 | mipMapMode: 0 8 | enableMipMap: 0 9 | linearTexture: 0 10 | correctGamma: 0 11 | fadeOut: 0 12 | borderMipMap: 0 13 | mipMapFadeDistanceStart: 1 14 | mipMapFadeDistanceEnd: 3 15 | bumpmap: 16 | convertToNormalMap: 0 17 | externalNormalMap: 0 18 | heightScale: .25 19 | normalMapFilter: 0 20 | isReadable: 0 21 | grayScaleToAlpha: 0 22 | generateCubemap: 0 23 | cubemapConvolution: 0 24 | cubemapConvolutionSteps: 8 25 | cubemapConvolutionExponent: 1.5 26 | seamlessCubemap: 0 27 | textureFormat: -3 28 | maxTextureSize: 1024 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | rGBM: 0 37 | compressionQuality: 50 38 | allowsAlphaSplitting: 0 39 | spriteMode: 0 40 | spriteExtrude: 1 41 | spriteMeshType: 1 42 | alignment: 0 43 | spritePivot: {x: .5, y: .5} 44 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 45 | spritePixelsToUnits: 100 46 | alphaIsTransparency: 0 47 | textureType: 5 48 | buildTargetSettings: [] 49 | spriteSheet: 50 | sprites: [] 51 | spritePackingTag: 52 | userData: 53 | assetBundleName: 54 | assetBundleVariant: 55 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Plane1x1.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Plane1x1.fbx -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Plane1x1.fbx.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3745e45a63361c04b8df832bc4b69bd9 3 | ModelImporter: 4 | serializedVersion: 18 5 | fileIDToRecycleName: 6 | 4300000: pPlane1 7 | materials: 8 | importMaterials: 1 9 | materialName: 0 10 | materialSearch: 1 11 | animations: 12 | legacyGenerateAnimations: 4 13 | bakeSimulation: 0 14 | optimizeGameObjects: 0 15 | motionNodeName: 16 | animationImportErrors: 17 | animationImportWarnings: 18 | animationRetargetingWarnings: 19 | animationDoRetargetingWarnings: 0 20 | animationCompression: 1 21 | animationRotationError: .5 22 | animationPositionError: .5 23 | animationScaleError: .5 24 | animationWrapMode: 0 25 | extraExposedTransformPaths: [] 26 | clipAnimations: [] 27 | isReadable: 1 28 | meshes: 29 | lODScreenPercentages: [] 30 | globalScale: 1 31 | meshCompression: 0 32 | addColliders: 0 33 | importBlendShapes: 1 34 | swapUVChannels: 0 35 | generateSecondaryUV: 0 36 | useFileUnits: 1 37 | optimizeMeshForGPU: 1 38 | keepQuads: 0 39 | weldVertices: 1 40 | secondaryUVAngleDistortion: 8 41 | secondaryUVAreaDistortion: 15.000001 42 | secondaryUVHardAngle: 88 43 | secondaryUVPackMargin: 4 44 | useFileScale: 0 45 | tangentSpace: 46 | normalSmoothAngle: 60 47 | splitTangentsAcrossUV: 1 48 | normalImportMode: 0 49 | tangentImportMode: 1 50 | importAnimation: 1 51 | copyAvatar: 0 52 | humanDescription: 53 | human: [] 54 | skeleton: [] 55 | armTwist: .5 56 | foreArmTwist: .5 57 | upperLegTwist: .5 58 | legTwist: .5 59 | armStretch: .0500000007 60 | legStretch: .0500000007 61 | feetSpacing: 0 62 | rootMotionBoneName: 63 | hasTranslationDoF: 0 64 | lastHumanDescriptionAvatarSource: {instanceID: 0} 65 | animationType: 1 66 | humanoidOversampling: 1 67 | additionalBone: 0 68 | userData: 69 | assetBundleName: 70 | assetBundleVariant: 71 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Rock_n_Snow.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/Assets/LOOM Framework/Examples/Visuals/Rock_n_Snow.JPG -------------------------------------------------------------------------------- /Assets/LOOM Framework/Examples/Visuals/Rock_n_Snow.JPG.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 284d8e2e94c7b6141b82e70f60f6fecd 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | serializedVersion: 2 6 | mipmaps: 7 | mipMapMode: 0 8 | enableMipMap: 0 9 | linearTexture: 0 10 | correctGamma: 0 11 | fadeOut: 0 12 | borderMipMap: 0 13 | mipMapFadeDistanceStart: 1 14 | mipMapFadeDistanceEnd: 3 15 | bumpmap: 16 | convertToNormalMap: 0 17 | externalNormalMap: 0 18 | heightScale: .25 19 | normalMapFilter: 0 20 | isReadable: 1 21 | grayScaleToAlpha: 0 22 | generateCubemap: 0 23 | cubemapConvolution: 0 24 | cubemapConvolutionSteps: 8 25 | cubemapConvolutionExponent: 1.5 26 | seamlessCubemap: 0 27 | textureFormat: 32 28 | maxTextureSize: 512 29 | textureSettings: 30 | filterMode: -1 31 | aniso: -1 32 | mipBias: -1 33 | wrapMode: -1 34 | nPOTScale: 1 35 | lightmap: 0 36 | rGBM: 0 37 | compressionQuality: 50 38 | allowsAlphaSplitting: 0 39 | spriteMode: 0 40 | spriteExtrude: 1 41 | spriteMeshType: 1 42 | alignment: 0 43 | spritePivot: {x: .5, y: .5} 44 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 45 | spritePixelsToUnits: 100 46 | alphaIsTransparency: 0 47 | textureType: 5 48 | buildTargetSettings: 49 | - buildTarget: Android 50 | maxTextureSize: 512 51 | textureFormat: 34 52 | compressionQuality: 100 53 | allowsAlphaSplitting: 0 54 | spriteSheet: 55 | sprites: [] 56 | spritePackingTag: 57 | userData: 58 | assetBundleName: 59 | assetBundleVariant: 60 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5b4e7e6d2eee0324db98fbfe6de8a534 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/IThreadWorkerObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | 4 | namespace Frankfort.Threading 5 | { 6 | 7 | 8 | 9 | public interface IThreadWorkerObject 10 | { 11 | /// 12 | /// This method is called by the Scheduler as the main entryPoint to start working. 13 | /// - Note: Make sure it doesn't throw any errors, because errors outside of the Mainthread are "eaten" by Unity. 14 | /// - You can enable "savemode" if required, which executes all the work within a Try-catch statement to keep it going... 15 | /// Example: 16 | /// 17 | /// private bool isAborted; 18 | /// public void ExecuteThreadedWork() 19 | /// { 20 | /// long i = 10000000; 21 | /// while (--i > -1 && !isAborted) 22 | /// result++; 23 | /// } 24 | /// 25 | /// public void AbortThreadedWork() 26 | /// { 27 | /// isAborted = true; 28 | /// } 29 | /// 30 | void ExecuteThreadedWork(); 31 | 32 | 33 | /// 34 | /// When called by the Scheduler, do whatever you need to do to directly interupt/stop the work in progress. 35 | /// Why no aborting the thread? Its not possible to interupt an loop without calling Thread.Abort() or Thread.Join(). 36 | /// This freamwork does NOT use Thread.Abort & Thread.Join because of webplayer-sandbox restrictions etc. 37 | /// Therefore its up to you to implement a way to always directly abort the process as shown in the example bellow. 38 | /// - Note: Make sure it doesn't throw any errors, because errors outside of the Mainthread are "eaten" by Unity. 39 | /// - You can enable "savemode" if required, which executes all the work within a Try-catch statement to keep it going... 40 | /// 41 | /// Example: 42 | /// 43 | /// private bool isAborted; 44 | /// public void ExecuteThreadedWork() 45 | /// { 46 | /// long i = 10000000; 47 | /// while (--i > -1 && !isAborted) 48 | /// result++; 49 | /// } 50 | /// 51 | /// public void AbortThreadedWork() 52 | /// { 53 | /// isAborted = true; 54 | /// } 55 | /// 56 | void AbortThreadedWork(); 57 | } 58 | } -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/IThreadWorkerObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 279175d999cc838408e393434804488e 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 903616312b54f644d84a2043649ba33c 3 | folderAsset: yes 4 | timeCreated: 1496323769 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/MainThreadDispatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using System.Threading; 4 | using System.Collections.Generic; 5 | 6 | 7 | 8 | namespace Frankfort.Threading 9 | { 10 | /// 11 | /// Fire and forget: The MainThread will execute this method witout any arguments to pass, nothing will be returned. 12 | /// 13 | public delegate void ThreadDispatchDelegate(); 14 | 15 | /// 16 | /// Alows you to pass a argument to the delegate. 17 | /// 18 | /// Once the MainThread executes this action, the argument will be passed to the delegate 19 | public delegate void ThreadDispatchDelegateArg(object arg); 20 | 21 | /// 22 | /// Alows you to pass a argument to the delegate. 23 | /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread. 24 | /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly 25 | /// 26 | /// Once the MainThread executes this action, the argument will be passed to the delegate 27 | /// 28 | public delegate object ThreadDispatchDelegateArgReturn(object arg); 29 | 30 | 31 | /// 32 | /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread. 33 | /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly 34 | /// 35 | /// Once the MainThread executes this action, the argument will be passed to the delegate 36 | public delegate object ThreadDispatchDelegateReturn(); 37 | } 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | namespace Frankfort.Threading.Internal 47 | { 48 | /// 49 | /// This static class helps you use Unity-engine related objects like GameObjects or Components, without violating threadsafty of Unity. 50 | /// 51 | public static class MainThreadDispatcher 52 | { 53 | 54 | private static List dispatchActions = new List(); 55 | private static bool helperCreated; 56 | public static int currentFrame = 0; 57 | 58 | 59 | 60 | 61 | //--------------------------------------- INIT -------------------------------------- 62 | //--------------------------------------- INIT -------------------------------------- 63 | #region INIT 64 | 65 | //Sins this class is static, it needs to be called from the MainThread, by some monobehaviour-awake (ThreadPoolScheduler that is...) 66 | public static void Init() 67 | { 68 | if (!helperCreated) 69 | CreateHelperGameObject(); 70 | } 71 | 72 | private static void CreateHelperGameObject() 73 | { 74 | GameObject helperGO = new GameObject("MainThreadDispatchHelper"); 75 | MainThreadDispatchHelper helper = helperGO.AddComponent(); 76 | helper.hideFlags = helperGO.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; 77 | GameObject.DontDestroyOnLoad(helperGO); 78 | helperCreated = true; 79 | } 80 | 81 | #endregion 82 | //--------------------------------------- INIT -------------------------------------- 83 | //--------------------------------------- INIT -------------------------------------- 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | //--------------------------------------- UPDATE CALLED BY HELPER -------------------------------------- 94 | //--------------------------------------- UPDATE CALLED BY HELPER -------------------------------------- 95 | 96 | #region UPDATE CALLED BY HELPER 97 | public static void Update() 98 | { 99 | DispatchActionsIfPresent(); 100 | } 101 | 102 | 103 | private static void DispatchActionsIfPresent() 104 | { 105 | if (dispatchActions != null && dispatchActions.Count > 0) 106 | { 107 | lock (dispatchActions) 108 | { 109 | foreach (ThreadDispatchAction action in dispatchActions) 110 | { 111 | if (!action.executed) //Might be executed internally. This happens when de event was dispatched from the MainThread in the firstplace.... 112 | action.ExecuteDispatch(); 113 | } 114 | dispatchActions.Clear(); 115 | Monitor.PulseAll(dispatchActions); 116 | } 117 | } 118 | } 119 | 120 | #endregion 121 | 122 | //--------------------------------------- UPDATE CALLED BY HELPER -------------------------------------- 123 | //--------------------------------------- UPDATE CALLED BY HELPER -------------------------------------- 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | //--------------------------------------- 4 DISPATCH OVERLOADS -------------------------------------- 136 | //--------------------------------------- 4 DISPATCH OVERLOADS -------------------------------------- 137 | #region 4 DISPATCH OVERLOADS 138 | 139 | 140 | /// 141 | /// Fire and forget: The MainThread will execute this method witout any arguments to pass, nothing will be returned. 142 | /// 143 | /// Example: "() => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name)" 144 | /// Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall". 145 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 146 | public static void DispatchToMainThread(ThreadDispatchDelegate dispatchCall, bool waitForExecution = false, bool safeMode = true) 147 | { 148 | if (MainThreadWatchdog.CheckIfMainThread()) 149 | { 150 | if (dispatchCall != null) 151 | dispatchCall(); 152 | } 153 | else 154 | { 155 | ThreadDispatchAction action = new ThreadDispatchAction(); 156 | lock (dispatchActions) { dispatchActions.Add(action); } 157 | action.Init(dispatchCall, waitForExecution, safeMode); 158 | } 159 | } 160 | 161 | 162 | 163 | /// 164 | /// When executed by the MainThread, this argument will be passed to the "dispatchCall"; 165 | /// 166 | /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())" 167 | /// Once the MainThread executes this action, the argument will be passed to the delegate 168 | /// Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall". 169 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 170 | public static void DispatchToMainThread(ThreadDispatchDelegateArg dispatchCall, object dispatchArgument, bool waitForExecution = false, bool safeMode = true) 171 | { 172 | if (MainThreadWatchdog.CheckIfMainThread()) 173 | { 174 | if (dispatchCall != null) 175 | dispatchCall(dispatchArgument); 176 | } 177 | else 178 | { 179 | ThreadDispatchAction action = new ThreadDispatchAction(); 180 | lock (dispatchActions) { dispatchActions.Add(action); } 181 | action.Init(dispatchCall, dispatchArgument, waitForExecution, safeMode); 182 | } 183 | } 184 | 185 | 186 | 187 | 188 | /// 189 | /// When executed by the MainThread, this argument will be passed to the "dispatchCall"; 190 | /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread. 191 | /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly 192 | /// 193 | /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())" 194 | /// Once the MainThread executes this action, the argument will be passed to the delegate 195 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 196 | /// After the MainThread has executed the "dispatchCall" (and the worker-thread has been waiting), it will return whatever the dispatchCall returns to the worker-thread 197 | public static object DispatchToMainThreadReturn(ThreadDispatchDelegateArgReturn dispatchCall, object dispatchArgument, bool safeMode = true) 198 | { 199 | if (MainThreadWatchdog.CheckIfMainThread()) 200 | { 201 | if (dispatchCall != null) 202 | return dispatchCall(dispatchArgument); 203 | } 204 | else 205 | { 206 | ThreadDispatchAction action = new ThreadDispatchAction(); 207 | lock (dispatchActions) { dispatchActions.Add(action); } 208 | action.Init(dispatchCall, dispatchArgument, safeMode); //Puts the Thread to sleep while waiting for the action to be invoked. 209 | return action.dispatchExecutionResult; 210 | } 211 | return null; 212 | } 213 | 214 | 215 | 216 | 217 | 218 | /// 219 | /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread. 220 | /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly 221 | /// 222 | /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())" 223 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 224 | /// After the MainThread has executed the "dispatchCall" (and the worker-thread has been waiting), it will return whatever the dispatchCall returns to the worker-thread 225 | public static object DispatchToMainThreadReturn(ThreadDispatchDelegateReturn dispatchCall, bool safeMode = true) 226 | { 227 | if (MainThreadWatchdog.CheckIfMainThread()) 228 | { 229 | if (dispatchCall != null) 230 | return dispatchCall(); 231 | } 232 | else 233 | { 234 | ThreadDispatchAction action = new ThreadDispatchAction(); 235 | lock (dispatchActions) { dispatchActions.Add(action); } 236 | action.Init(dispatchCall, safeMode); //Puts the Thread to sleep while waiting for the action to be invoked. 237 | return action.dispatchExecutionResult; 238 | } 239 | return null; 240 | } 241 | 242 | #endregion 243 | //--------------------------------------- 4 DISPATCH OVERLOADS -------------------------------------- 244 | //--------------------------------------- 4 DISPATCH OVERLOADS -------------------------------------- 245 | 246 | } 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | //--------------------------------------- HELPER GAME OBJECT WITH COMPONENT -------------------------------------- 257 | //--------------------------------------- HELPER GAME OBJECT WITH COMPONENT -------------------------------------- 258 | #region HELPER GAME OBJECT WITH COMPONENT 259 | 260 | 261 | public class MainThreadDispatchHelper : MonoBehaviour 262 | { 263 | private float WaitForSecondsTime = 0.005f; 264 | 265 | private void Awake() 266 | { 267 | MainThreadWatchdog.Init(); 268 | UnityActivityWatchdog.Init(); 269 | InvokeRepeating("UpdateMainThreadDispatcher", WaitForSecondsTime, WaitForSecondsTime); 270 | } 271 | 272 | 273 | private void Update() 274 | { 275 | MainThreadDispatcher.currentFrame = Time.frameCount; 276 | } 277 | private void UpdateMainThreadDispatcher() 278 | { 279 | MainThreadDispatcher.Update(); 280 | } 281 | } 282 | #endregion 283 | //--------------------------------------- HELPER GAME OBJECT WITH COMPONENT -------------------------------------- 284 | //--------------------------------------- HELPER GAME OBJECT WITH COMPONENT -------------------------------------- 285 | 286 | } -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/MainThreadDispatcher.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9f6b754fff034db41bfd722da8b9daf1 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/MainThreadWatchdog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using UnityEngine; 4 | 5 | namespace Frankfort.Threading.Internal 6 | { 7 | /// 8 | /// Keeps track of the MainThread. This is needed to handle the MainThread-edispatcher, WaitForNextFrame & WaitForSeconds safely. 9 | /// 10 | public class MainThreadWatchdog 11 | { 12 | 13 | //--------------------------------------- MANAGE MAIN THREAD VALIDATION -------------------------------------- 14 | //--------------------------------------- MANAGE MAIN THREAD VALIDATION -------------------------------------- 15 | #region MANAGE MAIN THREAD VALIDATION 16 | private static Thread mainThread = null; 17 | 18 | /// 19 | /// Set the CurrentThread to be the MainThread, if the CurrentThread happens NOT to be MultiThreadedApartment, NOT a ThreadPoolThread, and with an ID of <= 1; 20 | /// 21 | public static void Init() 22 | { 23 | if (mainThread == null) 24 | { 25 | Thread currentThread = Thread.CurrentThread; 26 | if(currentThread.GetApartmentState() == ApartmentState.MTA || currentThread.ManagedThreadId > 1 || currentThread.IsThreadPoolThread) 27 | { 28 | Debug.Log("Trying to Init a WorkerThread as the MainThread! "); 29 | } 30 | else 31 | { 32 | mainThread = currentThread; 33 | } 34 | } 35 | } 36 | 37 | 38 | 39 | /// 40 | /// If you need your current code to be running on the MainThread, you can always call this method to check if its the MainThread or not... 41 | /// 42 | /// Returns TRUE if its the MainThread 43 | public static bool CheckIfMainThread() 44 | { 45 | Init(); //Just to be sure.... 46 | return Thread.CurrentThread == mainThread; 47 | } 48 | #endregion 49 | 50 | //--------------------------------------- MANAGE MAIN THREAD VALIDATION -------------------------------------- 51 | //--------------------------------------- MANAGE MAIN THREAD VALIDATION -------------------------------------- 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/MainThreadWatchdog.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68cbbba4b882bd94985461106f12aee3 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/MultithreadedWorkloadHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Frankfort.Threading; 3 | using UnityEngine; 4 | 5 | namespace Frankfort.Threading 6 | { 7 | public delegate void MultithreadedWorkloadComplete(T[] workLoad); 8 | public delegate void MultithreadedWorkloadPackageComplete(T[] workLoad, int firstIndex, int lastIndex); 9 | } 10 | 11 | 12 | 13 | 14 | namespace Frankfort.Threading.Internal 15 | { 16 | public delegate void ThreadWorkloadExecutor(T workload); 17 | public delegate void ThreadWorkloadExecutorIndexed(T workload, int workloadIndex); 18 | public delegate void ThreadWorkloadExecutorArg(T workload, object extraArgument); 19 | public delegate void ThreadWorkloadExecutorArgIndexed(T workload, int workloadIndex, object extraArgument); 20 | 21 | 22 | 23 | /// 24 | /// Helps making use of the IThreadWorkerObject-interface and helps you distribute the workload evenly to multiple-cores the easy way. 25 | /// This class divides your workload into smaller pieces, feeds them to the ThreadPool. 26 | /// 27 | public static class MultithreadedWorkloadHelper 28 | { 29 | 30 | 31 | /// 32 | /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way. 33 | /// 34 | /// Generic-Type of the delegate that will be executed and compute the workload 35 | /// Generic-Type of the object you want to be computed by the executor 36 | /// A (static) method that computes one workLoad-object at a time 37 | /// An array with objects you want to get computed by the executor 38 | /// Fired when all re-packaged workLoad-objects are finished computing 39 | /// Fires foreach finished re-packaged set of workLoad-object 40 | /// Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler) 41 | /// If Null, a new ThreadPoolScheduler will be instantiated. 42 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 43 | /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects = 44 | public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(D executor, T[] workLoad, object extraArgument, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true) 45 | { 46 | if (scheduler == null) 47 | { 48 | scheduler = Loom.CreateThreadPoolScheduler(); 49 | } 50 | else if (scheduler.isBusy) 51 | { 52 | Debug.LogError("Provided Scheduler stil busy!!!"); 53 | } 54 | 55 | if (maxThreads <= 0) 56 | maxThreads = Mathf.Max(SystemInfo.processorCount - 1, 1); 57 | 58 | int packagesPerThread = 1; 59 | if (maxThreads > 1) //If we are running in just one thread at a time, just use one, if more, for sake of better cpu-saturation, subdive into smaller packages per core. 60 | packagesPerThread = 2; 61 | 62 | int packages = Mathf.Min(maxThreads * packagesPerThread, workLoad.Length); 63 | int objectsPerPackage = (int)Mathf.Ceil((float)workLoad.Length / (float)packages); 64 | 65 | ThreadWorkDistribution[] workerPackages = new ThreadWorkDistribution[packages]; 66 | Type delegateType = typeof(D); 67 | //Debug.Log(delegateType.FullName); 68 | 69 | int count = 0; 70 | for (int i = 0; i < packages; i++) 71 | { 72 | int packagedSize = Mathf.Min(workLoad.Length - count, objectsPerPackage); 73 | if (delegateType == typeof(ThreadWorkloadExecutor)) 74 | { 75 | workerPackages[i] = new ThreadWorkDistribution((executor as ThreadWorkloadExecutor), workLoad, count, count + packagedSize); 76 | } 77 | else if (delegateType == typeof(ThreadWorkloadExecutorIndexed)) 78 | { 79 | workerPackages[i] = new ThreadWorkDistribution((executor as ThreadWorkloadExecutorIndexed), workLoad, count, count + packagedSize); 80 | } 81 | else if (delegateType == typeof(ThreadWorkloadExecutorArg)) 82 | { 83 | workerPackages[i] = new ThreadWorkDistribution((executor as ThreadWorkloadExecutorArg), workLoad, extraArgument, count, count + packagedSize); 84 | } 85 | else if (delegateType == typeof(ThreadWorkloadExecutorArgIndexed)) 86 | { 87 | workerPackages[i] = new ThreadWorkDistribution((executor as ThreadWorkloadExecutorArgIndexed), workLoad, extraArgument, count, count + packagedSize); 88 | } 89 | 90 | workerPackages[i].ID = i; 91 | count += objectsPerPackage; 92 | } 93 | 94 | 95 | 96 | //--------------- Store session data -------------------- 97 | ThreadWorkDistributionSession sessionData = new ThreadWorkDistributionSession(); 98 | sessionData.workLoad = workLoad; 99 | sessionData.onComplete = onComplete; 100 | sessionData.onPackageComplete = onPackageComplete; 101 | sessionData.packages = workerPackages; 102 | //--------------- Store session data -------------------- 103 | 104 | 105 | scheduler.StartASyncThreads(workerPackages, sessionData.onCompleteBubble, sessionData.onPackageCompleteBubble, maxThreads, safeMode); 106 | return scheduler; 107 | } 108 | 109 | } 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | /// 124 | /// Generic class to store temporary divideed Threadwork data for internal usage 125 | /// 126 | /// The generic Type of the object being processed by the Executor 127 | public class ThreadWorkDistributionSession 128 | { 129 | public MultithreadedWorkloadComplete onComplete; 130 | public MultithreadedWorkloadPackageComplete onPackageComplete; 131 | public T[] workLoad; 132 | public ThreadWorkDistribution[] packages; 133 | 134 | 135 | public void onCompleteBubble(IThreadWorkerObject[] finishedObjects) 136 | { 137 | if (onComplete != null) 138 | onComplete(workLoad); 139 | } 140 | public void onPackageCompleteBubble(IThreadWorkerObject finishedObject) 141 | { 142 | if (onPackageComplete != null) 143 | { 144 | ThreadWorkDistribution fCast = (ThreadWorkDistribution)finishedObject; 145 | 146 | if (fCast != null) 147 | onPackageComplete(fCast.workLoad, fCast.startIndex, fCast.endIndex - 1); 148 | } 149 | } 150 | } 151 | 152 | 153 | 154 | /// 155 | /// Simple IThreadWorkerObject implementation that spreads the workload-objects for you. This saves you the efford to subdive your workload into multiple packages yourself. 156 | /// 157 | /// Generic-Type of the object you want to be computed by the executor 158 | public class ThreadWorkDistribution : IThreadWorkerObject 159 | { 160 | public int ID; 161 | public ThreadWorkloadExecutor workloadExecutor; 162 | public ThreadWorkloadExecutorIndexed workloadExecutorIndexed; 163 | public ThreadWorkloadExecutorArg workloadExecutorArg; 164 | public ThreadWorkloadExecutorArgIndexed workloadExecutorArgIndexed; 165 | 166 | public int startIndex; 167 | public int endIndex; 168 | public T[] workLoad; 169 | public object extraArgument; 170 | private bool _isAborted = false; 171 | 172 | 173 | /// 174 | /// ThreadWorkDistribion is a workload-packages containing a subdived segment of work based on the workload divided by the amount of packages 175 | /// 176 | /// A (static) method that computes one workLoad-object at a time 177 | /// An array with objects you want to get computed by the executor 178 | public ThreadWorkDistribution(ThreadWorkloadExecutor workloadExecutor, T[] workLoad, int startIndex, int endIndex) 179 | { 180 | this.workloadExecutor = workloadExecutor; 181 | this.workLoad = workLoad; 182 | this.startIndex = startIndex; 183 | this.endIndex = endIndex; 184 | } 185 | 186 | /// 187 | /// ThreadWorkDistribion is a workload-packages containing a subdived segment of work based on the workload divided by the amount of packages 188 | /// 189 | /// A (static) method that computes one workLoad-object at a time and provides the index of the array it origionally came from 190 | /// An array with objects you want to get computed by the executor 191 | public ThreadWorkDistribution(ThreadWorkloadExecutorIndexed workloadExecutorIndexed, T[] workLoad, int startIndex, int endIndex) 192 | { 193 | this.workloadExecutorIndexed = workloadExecutorIndexed; 194 | this.workLoad = workLoad; 195 | this.startIndex = startIndex; 196 | this.endIndex = endIndex; 197 | } 198 | 199 | 200 | /// 201 | /// ThreadWorkDistribion is a workload-packages containing a subdived segment of work based on the workload divided by the amount of packages 202 | /// 203 | /// A (static) method that computes one workLoad-object at a time and provides the index of the array it origionally came from 204 | /// An array with objects you want to get computed by the executor 205 | /// An extra Argument will be passed to the Executor if present 206 | public ThreadWorkDistribution(ThreadWorkloadExecutorArg workloadExecutorArg, T[] workLoad, object extraArgument, int startIndex, int endIndex) 207 | { 208 | this.workloadExecutorArg = workloadExecutorArg; 209 | this.workLoad = workLoad; 210 | this.startIndex = startIndex; 211 | this.endIndex = endIndex; 212 | this.extraArgument = extraArgument; 213 | } 214 | 215 | /// 216 | /// ThreadWorkDistribion is a workload-packages containing a subdived segment of work based on the workload divided by the amount of packages 217 | /// 218 | /// A (static) method that computes one workLoad-object at a time and provides the index of the array it origionally came from 219 | /// An array with objects you want to get computed by the executor 220 | /// An extra Argument will be passed to the Executor if present 221 | public ThreadWorkDistribution(ThreadWorkloadExecutorArgIndexed workloadExecutorArgIndexed, T[] workLoad, object extraArgument, int startIndex, int endIndex) 222 | { 223 | this.workloadExecutorArgIndexed = workloadExecutorArgIndexed; 224 | this.workLoad = workLoad; 225 | this.startIndex = startIndex; 226 | this.endIndex = endIndex; 227 | this.extraArgument = extraArgument; 228 | } 229 | 230 | 231 | 232 | 233 | 234 | /// 235 | /// IThreadWorkerObject implementation: This method computes all the work. 236 | /// 237 | public void ExecuteThreadedWork() 238 | { 239 | if (workLoad == null || workLoad.Length == 0) 240 | return; 241 | 242 | //Debug.Log("Execute ID: " + ID + ", startIndex: " + startIndex + ", endIndex: " + endIndex); 243 | if (workloadExecutor != null) 244 | { 245 | for (int i = startIndex; i < endIndex && !_isAborted; i++) 246 | { 247 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 248 | workloadExecutor(workLoad[i]); 249 | } 250 | } 251 | else if (workloadExecutorIndexed != null) 252 | { 253 | for (int i = startIndex; i < endIndex && !_isAborted; i++) 254 | { 255 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 256 | workloadExecutorIndexed(workLoad[i], i); 257 | } 258 | } 259 | else if (workloadExecutorArg != null) 260 | { 261 | for (int i = startIndex; i < endIndex && !_isAborted; i++) 262 | { 263 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 264 | workloadExecutorArg(workLoad[i], extraArgument); 265 | } 266 | } 267 | else if (workloadExecutorArgIndexed != null) 268 | { 269 | for (int i = startIndex; i < endIndex && !_isAborted; i++) 270 | { 271 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 272 | workloadExecutorArgIndexed(workLoad[i], i, extraArgument); 273 | } 274 | } 275 | } 276 | 277 | public void AbortThreadedWork() 278 | { 279 | _isAborted = true; 280 | } 281 | } 282 | 283 | } 284 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/MultithreadedWorkloadHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b29333d89ca53dd49837fcd9418f3cf3 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/SingleThreadStarter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using Frankfort.Threading; 5 | using UnityEngine; 6 | 7 | 8 | namespace Frankfort.Threading.Internal 9 | { 10 | 11 | /// 12 | /// The SingleThreadStarter is a safe/managed wrapper around the normal new Thread() & Thread.Start(); 13 | /// It also initiates all the helpers such as the MainThreadDispatcher, WaitForSeconds & WaitForSeconds commands. 14 | /// 15 | public static class SingleThreadStarter 16 | { 17 | 18 | //--------------------------------------- SAFEMODE WRAPPERS -------------------------------------- 19 | //--------------------------------------- SAFEMODE WRAPPERS -------------------------------------- 20 | #region SAFEMODE WRAPPERS 21 | 22 | /// 23 | /// Internal temporary session data needed to fire a Singele-thread safely. 24 | /// 25 | private class SafeSingleThreadSession 26 | { 27 | private ThreadStart targetMethod; 28 | private ParameterizedThreadStart paramTargetMethod; 29 | 30 | public SafeSingleThreadSession(ThreadStart targetMethod) 31 | { 32 | this.targetMethod = targetMethod; 33 | } 34 | public SafeSingleThreadSession(ParameterizedThreadStart targetMethod) 35 | { 36 | this.paramTargetMethod = targetMethod; 37 | } 38 | 39 | 40 | 41 | public void SafeExecte_ThreadStart() 42 | { 43 | try 44 | { 45 | targetMethod(); 46 | } 47 | catch (Exception e) 48 | { 49 | Loom.DispatchToMainThread(() => Debug.LogError(e.Message + e.StackTrace + "\n\n"), true); 50 | } 51 | } 52 | 53 | public void SafeExecte_ParamThreadStart(object argument) 54 | { 55 | try 56 | { 57 | paramTargetMethod(argument); 58 | } 59 | catch (Exception e) 60 | { 61 | Loom.DispatchToMainThread(() => Debug.LogError(e.Message + e.StackTrace + "\n\n"), true); 62 | } 63 | } 64 | } 65 | 66 | #endregion 67 | //--------------------------------------- SAFEMODE WRAPPERS -------------------------------------- 68 | //--------------------------------------- SAFEMODE WRAPPERS -------------------------------------- 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 84 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 85 | #region 2 START SINGLE THREAD OVERLOADS 86 | 87 | 88 | private static bool helperCreated; 89 | private static List startedThreads = new List(); 90 | 91 | 92 | 93 | /// 94 | /// Starts an method running on a new thread. The Thread dies when the method has stopped running. 95 | /// You can now make use of the DispatchToMainThread-actions & WaitForNextFrame 96 | /// 97 | /// The method that will be executed by the thread 98 | /// Thread priority 99 | /// Newly instantiated Thread 100 | public static Thread StartSingleThread(ThreadStart targetMethod, System.Threading.ThreadPriority priority = System.Threading.ThreadPriority.Normal, bool safeMode = true) 101 | { 102 | Init(); 103 | MainThreadWatchdog.Init(); 104 | MainThreadDispatcher.Init(); 105 | UnityActivityWatchdog.Init(); 106 | 107 | Thread result = null; 108 | if(safeMode) 109 | { 110 | SafeSingleThreadSession sessionData = new SafeSingleThreadSession(targetMethod); 111 | result = new Thread(sessionData.SafeExecte_ThreadStart); 112 | } 113 | else 114 | { 115 | result = new Thread(targetMethod); 116 | } 117 | 118 | result.Priority = priority; 119 | startedThreads.Add(result); 120 | result.Start(); 121 | return result; 122 | } 123 | 124 | 125 | 126 | /// 127 | /// Starts an method running on a new thread. The Thread dies when the method has stopped running. 128 | /// You can now make use of the DispatchToMainThread-actions & WaitForNextFrame 129 | /// 130 | /// The method that will be executed by the thread 131 | /// Object to pass to the targetMethod as soon as the Thread is started 132 | /// Thread priority 133 | /// Newly instantiated Thread 134 | public static Thread StartSingleThread(ParameterizedThreadStart targetMethod, object argument, System.Threading.ThreadPriority priority = System.Threading.ThreadPriority.Normal, bool safeMode = true) 135 | { 136 | Init(); 137 | MainThreadWatchdog.Init(); 138 | MainThreadDispatcher.Init(); 139 | UnityActivityWatchdog.Init(); 140 | 141 | Thread result = null; 142 | if (safeMode) 143 | { 144 | SafeSingleThreadSession sessionData = new SafeSingleThreadSession(targetMethod); 145 | result = new Thread(sessionData.SafeExecte_ParamThreadStart); 146 | } 147 | else 148 | { 149 | result = new Thread(targetMethod); 150 | } 151 | 152 | result.Priority = priority; 153 | startedThreads.Add(result); 154 | 155 | result.Start(argument); 156 | return result; 157 | } 158 | 159 | #endregion 160 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 161 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | //--------------------------------------- INIT -------------------------------------- 177 | //--------------------------------------- INIT -------------------------------------- 178 | #region INIT 179 | 180 | /// 181 | /// Starts the Helper & validates the running Threads. 182 | /// 183 | private static void Init() 184 | { 185 | ValidateThreadStates(); 186 | if (!helperCreated) 187 | CreateHelperGameObject(); 188 | } 189 | 190 | 191 | private static void CreateHelperGameObject() 192 | { 193 | GameObject helperGO = new GameObject("SingleThreadHelper"); 194 | SingleThreadHelper helper = helperGO.AddComponent(); 195 | helperGO.hideFlags = helper.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; 196 | GameObject.DontDestroyOnLoad(helperGO); 197 | helperCreated = true; 198 | } 199 | #endregion 200 | //--------------------------------------- INIT -------------------------------------- 201 | //--------------------------------------- INIT -------------------------------------- 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | //--------------------------------------- MANAGE THREADS -------------------------------------- 215 | //--------------------------------------- MANAGE THREADS -------------------------------------- 216 | #region MANAGE THREADS 217 | 218 | /// 219 | /// Aborts all running threads. 220 | /// 221 | public static void AbortRunningThreads() 222 | { 223 | ValidateThreadStates(); 224 | Debug.Log("Abort running Threads: " + startedThreads.Count); 225 | foreach (Thread thread in startedThreads) 226 | thread.Abort(); 227 | } 228 | 229 | /// 230 | /// Thread-state validation. 231 | /// 232 | private static void ValidateThreadStates() 233 | { 234 | int i = startedThreads.Count; 235 | while (--i > -1) 236 | { 237 | Thread thread = startedThreads[i]; 238 | if( thread.ThreadState == ThreadState.Aborted || 239 | thread.ThreadState == ThreadState.AbortRequested || 240 | thread.ThreadState == ThreadState.Stopped || 241 | thread.ThreadState == ThreadState.StopRequested || 242 | thread.ThreadState == ThreadState.Unstarted ) 243 | { 244 | startedThreads.RemoveAt(i); 245 | } 246 | } 247 | } 248 | 249 | #endregion 250 | //--------------------------------------- MANAGE THREADS -------------------------------------- 251 | //--------------------------------------- MANAGE THREADS -------------------------------------- 252 | } 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | //--------------------------------------- SINGLE THREAD HELPER COMPONENT -------------------------------------- 265 | //--------------------------------------- SINGLE THREAD HELPER COMPONENT -------------------------------------- 266 | #region SINGLE THREAD HELPER COMPONENT 267 | 268 | public class SingleThreadHelper : MonoBehaviour 269 | { 270 | private void OnApplicationQuit() 271 | { 272 | SingleThreadStarter.AbortRunningThreads(); 273 | } 274 | } 275 | 276 | #endregion 277 | //--------------------------------------- SINGLE THREAD HELPER COMPONENT -------------------------------------- 278 | //--------------------------------------- SINGLE THREAD HELPER COMPONENT -------------------------------------- 279 | 280 | } 281 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/SingleThreadStarter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ecb136529f44b7d4992d3dbf506fd649 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/ThreadDispatchAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Frankfort.Threading.Internal 5 | { 6 | public class ThreadDispatchAction 7 | { 8 | public bool executed = false; 9 | public object dispatchExecutionResult = null; 10 | 11 | private ThreadDispatchDelegate dispatchCallClean; 12 | private ThreadDispatchDelegateArg dispatchCallArg; 13 | private ThreadDispatchDelegateArgReturn dispatchCallArgReturn; 14 | private ThreadDispatchDelegateReturn dispatchCallReturn; 15 | 16 | private object dispatchArgParam; 17 | private bool safeMode; 18 | 19 | 20 | public ThreadDispatchAction() 21 | { 22 | //Do nothing... 23 | } 24 | 25 | 26 | 27 | //--------------------------------------- 4 DIFFERENT OVERLOADS -------------------------------------- 28 | //--------------------------------------- 4 DIFFERENT OVERLOADS -------------------------------------- 29 | #region 4 DIFFERENT OVERLOADS 30 | 31 | public void Init(ThreadDispatchDelegate dispatchCall, bool waitForExecution, bool safeMode) 32 | { 33 | this.safeMode = safeMode; 34 | this.dispatchCallClean = dispatchCall; 35 | ValidateExecutionOnInit(waitForExecution); 36 | } 37 | 38 | public void Init(ThreadDispatchDelegateArg dispatchCall, object dispatchArgumentParameter, bool waitForExecution, bool safeMode) 39 | { 40 | this.safeMode = safeMode; 41 | this.dispatchCallArg = dispatchCall; 42 | this.dispatchArgParam = dispatchArgumentParameter; 43 | ValidateExecutionOnInit(waitForExecution); 44 | } 45 | 46 | public void Init(ThreadDispatchDelegateArgReturn dispatchCall, object dispatchArgumentParameter, bool safeMode) 47 | { 48 | this.safeMode = safeMode; 49 | this.dispatchCallArgReturn = dispatchCall; 50 | this.dispatchArgParam = dispatchArgumentParameter; 51 | ValidateExecutionOnInit(true); //Forced to wait, the return-result should always be available after execution 52 | } 53 | 54 | public void Init(ThreadDispatchDelegateReturn dispatchCall, bool safeMode) 55 | { 56 | this.safeMode = safeMode; 57 | this.dispatchCallReturn = dispatchCall; 58 | ValidateExecutionOnInit(true); //Forced to wait, the return-result should always be available after execution 59 | } 60 | #endregion 61 | //--------------------------------------- 4 DIFFERENT OVERLOADS -------------------------------------- 62 | //--------------------------------------- 4 DIFFERENT OVERLOADS -------------------------------------- 63 | 64 | 65 | 66 | 67 | 68 | 69 | private void ValidateExecutionOnInit(bool waitForExecution) 70 | { 71 | if (waitForExecution) 72 | { 73 | if (!MainThreadWatchdog.CheckIfMainThread()) 74 | { 75 | while (!executed) 76 | Thread.Sleep(1); 77 | } 78 | else 79 | { 80 | ExecuteDispatch(); 81 | } 82 | } 83 | } 84 | 85 | public void ExecuteDispatch() 86 | { 87 | if (safeMode) 88 | { 89 | try 90 | { 91 | if (dispatchCallClean != null) 92 | { 93 | dispatchCallClean(); 94 | } 95 | else if (dispatchCallArg != null) 96 | { 97 | dispatchCallArg(dispatchArgParam); 98 | } 99 | else if (dispatchCallArgReturn != null) 100 | { 101 | dispatchExecutionResult = dispatchCallArgReturn(dispatchArgParam); 102 | } 103 | else if (dispatchCallReturn != null) 104 | { 105 | dispatchExecutionResult = dispatchCallReturn(); 106 | } 107 | } 108 | catch (Exception e) 109 | { 110 | //At this point, we should always be in the MainThread anyways... 111 | UnityEngine.Debug.Log(e.Message + e.StackTrace); 112 | } 113 | } 114 | else 115 | { 116 | if (dispatchCallClean != null) 117 | { 118 | dispatchCallClean(); 119 | } 120 | else if (dispatchCallArg != null) 121 | { 122 | dispatchCallArg(dispatchArgParam); 123 | } 124 | else if (dispatchCallArgReturn != null) 125 | { 126 | dispatchExecutionResult = dispatchCallArgReturn(dispatchArgParam); 127 | } 128 | else if (dispatchCallReturn != null) 129 | { 130 | dispatchExecutionResult = dispatchCallReturn(); 131 | } 132 | } 133 | 134 | executed = true; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/ThreadDispatchAction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79a2844752fc02e4f9b1fe3a3e63a0f2 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/ThreadPoolSchedulerWorkerObjects.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using UnityEngine; 5 | 6 | 7 | 8 | namespace Frankfort.Threading.Internal 9 | { 10 | public class ThreadWorkStatePackage 11 | { 12 | public bool safeMode = true; 13 | //public bool safeModeErrorFound; 14 | //public List safeModeErrorLog = new List(); 15 | 16 | public bool started; 17 | public bool running; 18 | public bool finishedWorking; 19 | public bool eventFired; 20 | 21 | public IThreadWorkerObject workerObject; 22 | public AutoResetEvent waitHandle; 23 | 24 | 25 | public void ExecuteThreadWork(object obj) 26 | { 27 | running = true; 28 | 29 | if (workerObject == null || waitHandle == null) 30 | return; 31 | 32 | //Thread.CurrentThread.Priority = System.Threading.ThreadPriority.AboveNormal; 33 | 34 | if (safeMode) 35 | { 36 | try 37 | { 38 | workerObject.ExecuteThreadedWork(); 39 | } 40 | catch (Exception e) 41 | { 42 | //safeModeErrorFound = true; 43 | //safeModeErrorLog.Add(e.Message + e.StackTrace); 44 | Loom.DispatchToMainThread(() => Debug.LogError(e.Message + e.StackTrace + "\n\n"), true); 45 | } 46 | } 47 | else 48 | { 49 | workerObject.ExecuteThreadedWork(); 50 | } 51 | 52 | running = false; 53 | finishedWorking = true; 54 | waitHandle.Set(); //Fire back to the MainThread! 55 | } 56 | } 57 | 58 | 59 | 60 | 61 | /// 62 | /// Used as packaged set of variables to be fed to the WorkProvider-Thread. 63 | /// 64 | public class ASyncThreadWorkData 65 | { 66 | public ThreadWorkStatePackage[] workerPackages; 67 | public int maxWorkingThreads; 68 | 69 | public ASyncThreadWorkData(IThreadWorkerObject[] workerObjects, bool safeMode, int maxWorkingThreads = -1) 70 | { 71 | if (workerObjects == null) 72 | return; 73 | 74 | workerPackages = new ThreadWorkStatePackage[workerObjects.Length]; 75 | 76 | int i = workerObjects.Length; 77 | while (--i > -1) 78 | { 79 | ThreadWorkStatePackage package = new ThreadWorkStatePackage(); 80 | package.waitHandle = new AutoResetEvent(false); 81 | package.workerObject = workerObjects[i]; 82 | package.safeMode = safeMode; 83 | workerPackages[i] = package; 84 | } 85 | 86 | if (maxWorkingThreads <= 0) 87 | { 88 | maxWorkingThreads = Mathf.Max(SystemInfo.processorCount - 1, 1); 89 | } 90 | else 91 | { 92 | this.maxWorkingThreads = maxWorkingThreads; 93 | } 94 | } 95 | 96 | 97 | public void Dispose() 98 | { 99 | if (workerPackages != null) 100 | { 101 | foreach (ThreadWorkStatePackage package in workerPackages) 102 | { 103 | if (package.waitHandle != null) 104 | package.waitHandle.Close(); 105 | 106 | package.waitHandle = null; 107 | package.workerObject = null; 108 | } 109 | } 110 | workerPackages = null; 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/ThreadPoolSchedulerWorkerObjects.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4d6f36171468b624bac7bf4b80fc3744 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/ThreadWaitCommands.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using UnityEngine; 4 | 5 | namespace Frankfort.Threading.Internal 6 | { 7 | public class ThreadWaitForSeconds 8 | { 9 | public ThreadWaitForSeconds(float seconds) 10 | { 11 | if (MainThreadWatchdog.CheckIfMainThread()) 12 | { 13 | Debug.Log("Its not allowed to put the MainThread to sleep!"); 14 | return; 15 | } 16 | 17 | Thread.Sleep((int)Mathf.Max( 1, Mathf.Round(seconds * 1000f))); 18 | 19 | while (!UnityActivityWatchdog.CheckUnityActive()) 20 | Thread.Sleep(5); 21 | } 22 | } 23 | 24 | 25 | public class ThreadWaitForNextFrame 26 | { 27 | public ThreadWaitForNextFrame(int waitFrames = 1, int sleepTime = 5) 28 | { 29 | if (waitFrames > 0) 30 | { 31 | if (MainThreadWatchdog.CheckIfMainThread()) 32 | { 33 | Debug.Log("Its not allowed to put the MainThread to sleep!"); 34 | return; 35 | } 36 | 37 | int startFrame = MainThreadDispatcher.currentFrame; 38 | Thread.Sleep(sleepTime); 39 | 40 | while (!UnityActivityWatchdog.CheckUnityActive() || startFrame + waitFrames >= MainThreadDispatcher.currentFrame) 41 | Thread.Sleep(sleepTime); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/ThreadWaitCommands.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 675d17e578edce543b1e6db0561c5e87 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/UnityActivityWatchdog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using System.Threading; 4 | 5 | 6 | namespace Frankfort.Threading.Internal 7 | { 8 | public class UnityActivityWatchdog : MonoBehaviour 9 | { 10 | private static bool helperCreated = false; 11 | private static bool unityRunning = true; 12 | private static bool unityPaused = false; 13 | private static bool unityFocused = true; 14 | private static bool combinedActive = true; 15 | 16 | 17 | 18 | 19 | //--------------------------------------- CHECK UNTIY ACTIVE -------------------------------------- 20 | //--------------------------------------- CHECK UNTIY ACTIVE -------------------------------------- 21 | #region CHECK UNTIY ACTIVE 22 | 23 | /// 24 | /// A easy way to check if Unity is still running, focused and not pauzed. 25 | /// This comes in handy if threads keep running heavy workloads on seperate threads while IOS for example tries to puch the Application to the background. 26 | /// If you are executing a giant routine on a seperate thread that takes several seconds per cycle, you might want to check regularly if unity is still active by using this check. 27 | /// 28 | /// Returns TRUE if Unity is still running, not pauzed and has focus. 29 | public static bool CheckUnityActive() 30 | { 31 | Init(); 32 | return combinedActive; 33 | } 34 | 35 | 36 | 37 | /// 38 | /// !IMPORTANT! This method should be called regularly within routines that take more then half a second to complete, to make sure IOS for example is able to force an application to sleep when it looses focus or gets puched to the background. 39 | /// This is a very light-weight check, internally it only needs to check two static booleans once everything is Initialized and running. 40 | /// You can use this without causing any serious overhead. 41 | /// Motivation: Sins Threads cannot be put asleep from the outside, it needs the be managed from within the thread itself, thats why this method was build. 42 | /// 43 | /// Example: 44 | /// for(int i = 0; i < 999999999; i++) 45 | /// { 46 | /// Loom.SleepOrAbortIfUnityInactive(); //Prevents IOS for example of killing this app because the threads won't sleep once your unity-app is puched to the background. 47 | /// //Do something heavy that will cause this routine to run more then 0.5 seconds. 48 | /// } 49 | /// 50 | public static void SleepOrAbortIfUnityInactive() 51 | { 52 | Init(); 53 | while (!combinedActive && !MainThreadWatchdog.CheckIfMainThread()) 54 | { 55 | if (unityRunning) 56 | { 57 | //Debug.Log("UNITY INACTIVE: About to sleep for 100 ms: " + Thread.CurrentThread.ManagedThreadId); 58 | Thread.Sleep(100); 59 | } 60 | else 61 | { 62 | //Debug.Log("UNITY NOT RUNNING: About to abort: " + Thread.CurrentThread.ManagedThreadId); 63 | Thread.CurrentThread.Abort(); 64 | } 65 | } 66 | } 67 | 68 | #endregion 69 | //--------------------------------------- CHECK UNTIY ACTIVE -------------------------------------- 70 | //--------------------------------------- CHECK UNTIY ACTIVE -------------------------------------- 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | //--------------------------------------- INIT -------------------------------------- 83 | //--------------------------------------- INIT -------------------------------------- 84 | #region INIT 85 | 86 | /// 87 | /// Starts the Helper & validates the running Threads. 88 | /// 89 | public static void Init() 90 | { 91 | if (!helperCreated) 92 | CreateHelperGameObject(); 93 | } 94 | 95 | 96 | private static void CreateHelperGameObject() 97 | { 98 | GameObject helperGO = new GameObject("UnityActivityHelper"); 99 | UnityActivityWatchdog helper = helperGO.AddComponent(); 100 | helperGO.hideFlags = helper.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; 101 | GameObject.DontDestroyOnLoad(helperGO); 102 | helperCreated = true; 103 | } 104 | 105 | #endregion 106 | //--------------------------------------- INIT -------------------------------------- 107 | //--------------------------------------- INIT -------------------------------------- 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | //--------------------------------------- LISTEN TO UNITY CALLS -------------------------------------- 119 | //--------------------------------------- LISTEN TO UNITY CALLS -------------------------------------- 120 | #region LISTEN TO UNITY CALLS 121 | 122 | private void OnApplicationQuit() 123 | { 124 | unityRunning = false; 125 | UpdateStatus(); 126 | Debug.Log("UnityActivityWatchdog: OnApplicationQuit"); 127 | } 128 | private void OnApplicationPause(bool pause) 129 | { 130 | unityPaused = pause; 131 | UpdateStatus(); 132 | Debug.Log("UnityActivityWatchdog: OnApplicationPauze [" + pause + "]"); 133 | } 134 | private void OnApplicationFocus(bool focus) 135 | { 136 | unityFocused = focus; 137 | UpdateStatus(); 138 | Debug.Log("UnityActivityWatchdog: OnApplicationFocus [" + focus + "]"); 139 | } 140 | 141 | private static void UpdateStatus() 142 | { 143 | #if UNITY_IPHONE 144 | combinedActive = unityRunning && unityFocused && !unityPaused; 145 | #elif UNITY_ANDROID 146 | combinedActive = unityRunning && unityFocused && !unityPaused; 147 | #else 148 | combinedActive = unityRunning && !unityPaused; 149 | #endif 150 | } 151 | #endregion 152 | //--------------------------------------- LISTEN TO UNITY CALLS -------------------------------------- 153 | //--------------------------------------- LISTEN TO UNITY CALLS -------------------------------------- 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | } 162 | } -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Internal/UnityActivityWatchdog.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4f34b4872834024097444da6c8b8ae0 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Loom.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Thank you for using "Loom for Unity". This code was written by Michiel Frankfort - Q1 2013. 3 | 4 | Features: 5 | - Turn your app into a true Multi-Threaded application overnight! Starting a simple worker/background thread is not a challenge... Utilizing all the available cores for one (or more) heavy-duty tasks is a true challenge! This framework helps you spread the workload to all cores and manage them the easy way. 6 | - Powerfull “DispatchToMainThread” tools, which let you instantiate and directly use Unity-objects from the external threads! 7 | - Three Demo's included: 8 | Flocking Massive: A Multi-threaded flocking demo, prept to run on a Samsung Galaxy S3 with 7000 boids!!! 9 | 10 | Texture blur: Shows how easy it is to use this framework for repetitive tasks, using the “StartMultithreadedWorkloadExecution” tool, which subdivides work into smaller packages and feeds them to multiple cores/threads. 11 | 12 | SimpleExampleImplementation: Showing how to use the “Abort”, “DispatchToMainThread-tools” and “WaitForNextFrame” actions. 13 | 14 | - No Threading experience required: you'll learn fast enough from the provided examples! 15 | - Pick your max Cores/Threads to do the work for you. 16 | - All ThreadPoolScheduler events (onComplete, onWorkerObjectDone) are fired in the MainThread / GameThread. 17 | 18 | 19 | Why did I build this? 20 | This framework was initially created as the cornerstone of the Realtime-Raytracing-engine that I'm currently working on (yes, when its done, I'll put it in the store as well) 21 | In order to obtain Realtime-Raytracing, I needed more horsepower and utilize multiple cores while keeping the MainThread alive, smooth & unblocked. 22 | So I ended up building a ThreadScheduler which fires all events in the MainThread, but does not block it. 23 | 24 | Any Field-experience so far? 25 | Products always get better when you use them yourself and where born out of need instead of theoretical appliances. 26 | This framework is up and running within my own Raytracer and has proves perfect workload delegation between cores, with low overhead. 27 | For as long as my Raytracer is under development, I'll keep iterating on this tool, and if people actually buy this tool, I'll keep providing Updates :-) 28 | 29 | API Documentation: http://www.frankfortsoftware.com/LOOM/Documentation/ 30 | Support: LoomThreadingFramework@gmail.com 31 | */ 32 | 33 | 34 | 35 | //111 36 | 37 | 38 | 39 | using System; 40 | using System.Threading; 41 | using System.Collections.Generic; 42 | using Frankfort.Threading; 43 | using Frankfort.Threading.Internal; 44 | using UnityEngine; 45 | 46 | 47 | 48 | 49 | 50 | /// 51 | /// Primairy accespoint/interface to all framework methods & helpers. This is just a static wrapper-class for sake of ease... 52 | /// 53 | public static class Loom 54 | { 55 | 56 | 57 | // -----test win 10.。。。。。。。 速度 58 | 59 | 60 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 61 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 62 | #region 2 START SINGLE THREAD OVERLOADS 63 | 64 | 65 | 66 | /// 67 | /// Starts an method running on a new thread. The Thread dies when the method has stopped running. 68 | /// You can now make use of the DispatchToMainThread-actions & WaitForNextFrame 69 | /// 70 | /// The method that will be executed by the new thread 71 | /// Thread Priority 72 | /// Default TRUE: Executes the targetMethod within a Try-Catch statement and will log any errors back to the MainThread 73 | /// Newly instantiated Thread 74 | public static Thread StartSingleThread(ThreadStart targetMethod, System.Threading.ThreadPriority priority = System.Threading.ThreadPriority.Normal, bool safeMode = true) 75 | { 76 | return SingleThreadStarter.StartSingleThread(targetMethod, priority, safeMode); 77 | } 78 | 79 | 80 | 81 | 82 | /// 83 | /// Starts an method running on a new thread. The Thread dies when the method has stopped running. 84 | /// You can now make use of the DispatchToMainThread-actions & WaitForNextFrame 85 | /// 86 | /// The method that will be executed by the new thread 87 | /// Object to pass to the targetMethod as soon as the Thread is started 88 | /// Thread Priority 89 | /// Default TRUE: Executes the targetMethod within a Try-Catch statement and will log any errors back to the MainThread 90 | /// Newly instantiated Thread 91 | public static Thread StartSingleThread(ParameterizedThreadStart targetMethod, object argument, System.Threading.ThreadPriority priority = System.Threading.ThreadPriority.Normal, bool safeMode = true) 92 | { 93 | return SingleThreadStarter.StartSingleThread(targetMethod, argument, priority, safeMode); 94 | } 95 | 96 | 97 | #endregion 98 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 99 | //--------------------------------------- 2 START SINGLE THREAD OVERLOADS -------------------------------------- 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS -------------------------------------- 114 | //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS -------------------------------------- 115 | 116 | #region 4 MULTI THREADED WORK EXECUTION OVERLOADS 117 | /// 118 | /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way. 119 | /// 120 | /// T: Generic-Type of the object you want to be computed by the executor 121 | /// A (static) method that computes one workLoad-object at a time 122 | /// An array with objects you want to get computed by the executor 123 | /// Fired when all re-packaged workLoad-objects are finished computing 124 | /// Fires foreach finished re-packaged set of workLoad-object 125 | /// Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler) 126 | /// If Null, a new ThreadPoolScheduler will be instantiated. 127 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 128 | /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects 129 | public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutor workloadExecutor, T[] workLoad, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true) 130 | { 131 | return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, null, onComplete, onPackageComplete, maxThreads, scheduler, safeMode); 132 | } 133 | 134 | 135 | 136 | /// 137 | /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way. 138 | /// Besides the workLoad-object, the current index of the workLoad-array is passed to the Executor-delegate. 139 | /// 140 | /// T: Generic-Type of the object you want to be computed by the executor 141 | /// A (static) method that computes one workLoad-object at a time 142 | /// An array with objects you want to get computed by the executor 143 | /// Fired when all re-packaged workLoad-objects are finished computing 144 | /// Fires foreach finished re-packaged set of workLoad-object 145 | /// Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler) 146 | /// If Null, a new ThreadPoolScheduler will be instantiated. 147 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 148 | /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects 149 | public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutorIndexed workloadExecutor, T[] workLoad, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true) 150 | { 151 | return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, null, onComplete, onPackageComplete, maxThreads, scheduler, safeMode); 152 | } 153 | 154 | 155 | /// 156 | /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way. 157 | /// Besides the workLoad-object, an extra Argument will be passed to the Executor-delegate 158 | /// 159 | /// T: Generic-Type of the object you want to be computed by the executor 160 | /// A (static) method that computes one workLoad-object at a time 161 | /// An array with objects you want to get computed by the executor 162 | /// Fired when all re-packaged workLoad-objects are finished computing 163 | /// Fires foreach finished re-packaged set of workLoad-object 164 | /// Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler) 165 | /// If Null, a new ThreadPoolScheduler will be instantiated. 166 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 167 | /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects 168 | public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutorArg workloadExecutor, T[] workLoad, object extraArgument, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true) 169 | { 170 | return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, extraArgument, onComplete, onPackageComplete, maxThreads, scheduler, safeMode); 171 | } 172 | 173 | 174 | /// 175 | /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way. 176 | /// Besides the workLoad-object, an extra Argument & the current index of the workLoad-array is passed to the Executor-delegate. 177 | /// 178 | /// T: Generic-Type of the object you want to be computed by the executor 179 | /// A (static) method that computes one workLoad-object at a time 180 | /// An array with objects you want to get computed by the executor 181 | /// Fired when all re-packaged workLoad-objects are finished computing 182 | /// Fires foreach finished re-packaged set of workLoad-object 183 | /// Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler) 184 | /// If Null, a new ThreadPoolScheduler will be instantiated. 185 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 186 | /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects 187 | public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutorArgIndexed workloadExecutor, T[] workLoad, object extraArgument, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true) 188 | { 189 | return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, extraArgument, onComplete, onPackageComplete, maxThreads, scheduler, safeMode); 190 | } 191 | 192 | #endregion 193 | 194 | //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS -------------------------------------- 195 | //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS -------------------------------------- 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | //--------------------------------------- THREAD POOL SCHEDULER -------------------------------------- 212 | //--------------------------------------- THREAD POOL SCHEDULER -------------------------------------- 213 | 214 | #region THREAD POOL SCHEDULER 215 | 216 | 217 | /// 218 | /// Unlike "StartMultithreadedWorkloadExecution", you will have to build your own IThreadWorkerObject. 219 | /// Downside: It requires some extra work. Upside: you got more controll over what goes in and comes out 220 | /// Infact: You can create you own polymorphed IThreadWorkerObject-array, each ellement being a completely different type. For example: the statemachines of enemies are IThreadWorkerObject's and the array contains completely different classes with enemies/AI-behaviours. 221 | /// 222 | /// An array of IThreadWorkerObject objects to be handled by the threads. If you want multiple cores/threads to be active, make sure that the number of IThreadWorkerObject's proves matches/exeeds your preferred number maxWorkingThreads. 223 | /// Fired when all re-packaged workLoad-objects are finished computing 224 | /// Fires foreach finished re-packaged set of workLoad-object 225 | /// Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler) 226 | /// If Null, a new ThreadPoolScheduler will be instantiated. 227 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 228 | /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects 229 | public static ThreadPoolScheduler StartMultithreadedWorkerObjects(IThreadWorkerObject[] workerObjects, ThreadPoolSchedulerEvent onCompleteCallBack, ThreadedWorkCompleteEvent onPackageExecuted = null, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true) 230 | { 231 | if (scheduler == null) 232 | scheduler = CreateThreadPoolScheduler(); 233 | 234 | scheduler.StartASyncThreads(workerObjects, onCompleteCallBack, onPackageExecuted, maxThreads, safeMode); 235 | return scheduler; 236 | } 237 | 238 | 239 | 240 | /// 241 | /// Creates an ThreadPoolScheduler instance, which happens to be a Monobehaviour and therefore will showup as gameobject "ThreadPoolScheduler"; 242 | /// 243 | /// 244 | public static ThreadPoolScheduler CreateThreadPoolScheduler() 245 | { 246 | GameObject go = new GameObject("ThreadPoolScheduler"); 247 | return go.AddComponent(); 248 | } 249 | 250 | 251 | /// 252 | /// Creates an ThreadPoolScheduler instance, which happens to be a Monobehaviour and therefore will showup by the name you provide (default: "ThreadPoolScheduler"); 253 | /// 254 | /// 255 | public static ThreadPoolScheduler CreateThreadPoolScheduler(string name) 256 | { 257 | GameObject go = new GameObject(name == null || name == string.Empty ? "ThreadPoolScheduler" : name); 258 | return go.AddComponent(); 259 | } 260 | 261 | 262 | #endregion 263 | 264 | //--------------------------------------- THREAD POOL SCHEDULER -------------------------------------- 265 | //--------------------------------------- THREAD POOL SCHEDULER -------------------------------------- 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | //--------------------------------------- THREAD WAIT COMMANDS -------------------------------------- 282 | //--------------------------------------- THREAD WAIT COMMANDS -------------------------------------- 283 | 284 | #region THREAD WAIT COMMANDS 285 | 286 | /// 287 | /// Halts/Sleeps the current thread until Unity has rendered a frame. This can be used Coroutine-wise and is safe to be placed within an endless while-loop. Not recommended though... 288 | /// If fired from the MainThread, an error-log will be thrown because its not allowed to freeze the MainThread. 289 | /// 290 | /// By default set to 1. You can let the Thread wait several frames if needed 291 | public static void WaitForNextFrame(int waitFrames = 1) 292 | { 293 | new ThreadWaitForNextFrame(waitFrames); 294 | } 295 | 296 | 297 | /// 298 | /// Halts/Sleeps the current thread until "seconds" has expired. This can be used Coroutine-wise and is safe to be placed within an endless while-loop. Not recommended though... 299 | /// If fired from the MainThread, an error-log will be thrown because its not allowed to freeze the MainThread. 300 | /// 301 | /// Amount of time you want the Thread to sleep. 302 | public static void WaitForSeconds(float seconds) 303 | { 304 | new ThreadWaitForSeconds(seconds); 305 | } 306 | 307 | #endregion 308 | 309 | //--------------------------------------- THREAD WAIT COMMANDS -------------------------------------- 310 | //--------------------------------------- THREAD WAIT COMMANDS -------------------------------------- 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | //--------------------------------------- 4 DISPATCHER OVERLOADS -------------------------------------- 326 | //--------------------------------------- 4 DISPATCHER OVERLOADS -------------------------------------- 327 | 328 | #region 4 DISPATCHER OVERLOADS 329 | 330 | 331 | 332 | /// 333 | /// Fire and forget: The MainThread will execute this method witout any arguments to pass, nothing will be returned. 334 | /// 335 | /// Example: "() => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name)" 336 | /// Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall". 337 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 338 | public static void DispatchToMainThread(ThreadDispatchDelegate dispatchCall, bool waitForExecution = false, bool safeMode = true) 339 | { 340 | MainThreadDispatcher.DispatchToMainThread(dispatchCall, waitForExecution, safeMode); 341 | } 342 | 343 | 344 | 345 | 346 | /// 347 | /// When executed by the MainThread, this argument will be passed to the "dispatchCall"; 348 | /// 349 | /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())" 350 | /// Once the MainThread executes this action, the argument will be passed to the delegate 351 | /// Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall". 352 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 353 | public static void DispatchToMainThread(ThreadDispatchDelegateArg dispatchCall, object dispatchArgument, bool waitForExecution = false, bool safeMode = true) 354 | { 355 | MainThreadDispatcher.DispatchToMainThread(dispatchCall, dispatchArgument, waitForExecution, safeMode); 356 | } 357 | 358 | 359 | 360 | 361 | /// 362 | /// When executed by the MainThread, this argument will be passed to the "dispatchCall"; 363 | /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread. 364 | /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly 365 | /// 366 | /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())" 367 | /// Once the MainThread executes this action, the argument will be passed to the delegate 368 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 369 | /// After the MainThread has executed the "dispatchCall" (and the worker-thread has been waiting), it will return whatever the dispatchCall returns to the worker-thread 370 | public static object DispatchToMainThreadReturn(ThreadDispatchDelegateArgReturn dispatchCall, object dispatchArgument, bool safeMode = true) 371 | { 372 | return MainThreadDispatcher.DispatchToMainThreadReturn(dispatchCall, dispatchArgument, safeMode); 373 | } 374 | 375 | 376 | /// 377 | /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread. 378 | /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly 379 | /// 380 | /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())" 381 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 382 | /// After the MainThread has executed the "dispatchCall" (and the worker-thread has been waiting), it will return whatever the dispatchCall returns to the worker-thread 383 | public static object DispatchToMainThreadReturn(ThreadDispatchDelegateReturn dispatchCall, bool safeMode = true) 384 | { 385 | return MainThreadDispatcher.DispatchToMainThreadReturn(dispatchCall, safeMode); 386 | } 387 | 388 | 389 | #endregion 390 | 391 | //--------------------------------------- 4 DISPATCHER OVERLOADS -------------------------------------- 392 | //--------------------------------------- 4 DISPATCHER OVERLOADS -------------------------------------- 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | //--------------------------------------- CHECK UNITY ACTIVITY -------------------------------------- 402 | //--------------------------------------- CHECK UNITY ACTIVITY -------------------------------------- 403 | #region CHECK UNITY ACTIVITY 404 | 405 | /// 406 | /// A easy way to check if Unity is still running, focused and not pauzed. 407 | /// This comes in handy if threads keep running heavy workloads on seperate threads while IOS for example tries to puch the Application to the background. 408 | /// If you are executing a giant routine on a seperate thread that takes several seconds per cycle, you might want to check regularly if unity is still active by using this check. 409 | /// 410 | /// Returns TRUE if Unity is still running, not pauzed and has focus. 411 | public static bool CheckUnityActive() 412 | { 413 | return UnityActivityWatchdog.CheckUnityActive(); 414 | } 415 | 416 | 417 | 418 | 419 | /// 420 | /// !IMPORTANT! This method should be called regularly within routines that take more then half a second to complete, to make sure IOS for example is able to force an application to sleep when it looses focus or gets puched to the background. 421 | /// This is a very light-weight check, internally it only needs to check two static booleans once everything is Initialized and running. 422 | /// You can use this without causing any serious overhead. 423 | /// Motivation: Sins Threads cannot be put asleep from the outside, it needs the be managed from within the thread itself, thats why this method was build. 424 | /// 425 | /// Example: 426 | /// for(int i = 0; i < 999999999; i++) 427 | /// { 428 | /// Loom.SleepOrAbortIfUnityInactive(); //Prevents IOS for example of killing this app because the threads won't sleep once your unity-app is puched to the background. 429 | /// //Do something heavy that will cause this routine to run more then 0.5 seconds. 430 | /// } 431 | /// 432 | public static void SleepOrAbortIfUnityInactive() 433 | { 434 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 435 | } 436 | #endregion 437 | //--------------------------------------- CHECK UNITY ACTIVITY -------------------------------------- 438 | //--------------------------------------- CHECK UNITY ACTIVITY -------------------------------------- 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | //--------------------------------------- MAIN THREAD WATCHDOG -------------------------------------- 450 | //--------------------------------------- MAIN THREAD WATCHDOG -------------------------------------- 451 | #region MAIN THREAD WATCHDOG 452 | 453 | /// 454 | /// If you need your current code to be running on the MainThread, you can always call this method to check if its the MainThread or not... 455 | /// 456 | /// Returns TRUE if its the MainThread 457 | public static bool CheckIfMainThread() 458 | { 459 | return MainThreadWatchdog.CheckIfMainThread(); 460 | } 461 | 462 | 463 | #endregion 464 | //--------------------------------------- MAIN THREAD WATCHDOG -------------------------------------- 465 | //--------------------------------------- MAIN THREAD WATCHDOG -------------------------------------- 466 | 467 | } -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/Loom.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 09415fb5e1c39ea4fa09211559d64bd7 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/ThreadPoolScheduler.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | using System; 4 | using System.Collections; 5 | using System.Threading; 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | using Frankfort.Threading.Internal; 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | namespace Frankfort.Threading 19 | { 20 | public delegate void ThreadPoolSchedulerEvent(IThreadWorkerObject[] finishedObjects); 21 | public delegate void ThreadedWorkCompleteEvent(IThreadWorkerObject finishedObject); 22 | 23 | 24 | /// 25 | /// This is the most important class of the framework. It starts & stops threads, caps the amount of threads running at the same time, handles Mainthread completion-delegates, etc. 26 | /// 27 | public class ThreadPoolScheduler : MonoBehaviour 28 | { 29 | 30 | //--------------- public Session Variables -------------------- 31 | public bool DebugMode = false; 32 | public bool ForceToMainThread = false; 33 | public float WaitForSecondsTime = 0.001f; //Wait 1 ms per tick! 34 | 35 | public bool isBusy 36 | { 37 | get 38 | { 39 | return _shedularBusy; 40 | } 41 | } 42 | 43 | public float Progress 44 | { 45 | get 46 | { 47 | if (workData == null || workData.workerPackages == null || workData.workerPackages.Length == 0) 48 | return 1f; 49 | 50 | //return (float)GetHandledFinishedPackages().Length / (float)workData.workerPackages.Length; 51 | int finishedPackages = 0; 52 | int i = workData.workerPackages.Length; 53 | while(--i > -1) 54 | { 55 | if (workData.workerPackages[i].finishedWorking) 56 | finishedPackages++; 57 | } 58 | 59 | return (float)finishedPackages / (float)workData.workerPackages.Length; 60 | } 61 | } 62 | //--------------- public Session Variables -------------------- 63 | 64 | 65 | 66 | 67 | //--------------- PrivateSession Variables -------------------- 68 | private bool _providerThreadBusy; 69 | private bool _shedularBusy; 70 | private bool _isAborted; 71 | private ASyncThreadWorkData workData; 72 | private Thread providerThread; 73 | private int workObjectIndex; 74 | private ThreadPoolSchedulerEvent onCompleteCallBack; 75 | private ThreadedWorkCompleteEvent onWorkerObjectDoneCallBack; 76 | private bool safeMode; 77 | //--------------- Private Session Variables -------------------- 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | //--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS -------------------------------------- 87 | //--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS -------------------------------------- 88 | #region UNITY MONOBEHAVIOUR COMMANDS 89 | 90 | protected virtual void Awake() 91 | { 92 | MainThreadWatchdog.Init(); 93 | MainThreadDispatcher.Init(); 94 | UnityActivityWatchdog.Init(); 95 | } 96 | 97 | protected virtual void OnApplicationQuit() 98 | { 99 | Debug.Log("ThreadPoolScheduler.OnApplicationQuit!"); 100 | AbortASyncThreads(false); 101 | } 102 | 103 | protected virtual void OnDestroy() 104 | { 105 | Debug.Log("ThreadPoolScheduler.OnDestroy!"); 106 | AbortASyncThreads(false); 107 | 108 | if (providerThread != null && providerThread.IsAlive) 109 | providerThread.Abort(); 110 | } 111 | #endregion 112 | //--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS -------------------------------------- 113 | //--------------------------------------- UNITY MONOBEHAVIOUR COMMANDS -------------------------------------- 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | //--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION -------------------------------------- 128 | //--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION -------------------------------------- 129 | #region UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION 130 | 131 | /// 132 | /// Unlike "StartMultithreadedWorkloadExecution", you will have to build your own IThreadWorkerObject. 133 | /// Downside: It requires some extra work. Upside: you got more controll over what goes in and comes out 134 | /// Infact: You can create you own polymorphed IThreadWorkerObject-array, each ellement being a completely different type. For example: the statemachines of enemies are IThreadWorkerObject's and the array contains completely different classes with enemies/AI-behaviours. 135 | /// 136 | /// An array of IThreadWorkerObject objects to be handled by the threads. If you want multiple cores/threads to be active, make sure that the number of IThreadWorkerObject's proves matches/exeeds your preferred number maxWorkingThreads. 137 | /// Fired when all re-packaged workLoad-objects are finished computing 138 | /// Fires foreach finished re-packaged set of workLoad-object 139 | /// Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler) 140 | /// If Null, a new ThreadPoolScheduler will be instantiated. 141 | /// Executes all the computations within try-catch events, logging it the message + stacktrace 142 | public void StartASyncThreads(IThreadWorkerObject[] workerObjects, ThreadPoolSchedulerEvent onCompleteCallBack, ThreadedWorkCompleteEvent onPackageExecuted = null, int maxThreads = -1, bool safeMode = true) 143 | { 144 | if (_shedularBusy) 145 | { 146 | Debug.LogError("You are trying the start a new ASync threading-process, but is still Busy!"); 147 | return; 148 | } 149 | 150 | if (workerObjects == null || workerObjects.Length == 0) 151 | { 152 | Debug.LogError("Please provide an Array with atleast \"IThreadWorkerObject\"-object!"); 153 | return; 154 | } 155 | 156 | _isAborted = false; 157 | _shedularBusy = true; 158 | _providerThreadBusy = true; 159 | this.onCompleteCallBack = onCompleteCallBack; 160 | this.onWorkerObjectDoneCallBack = onPackageExecuted; 161 | 162 | if (!ForceToMainThread) 163 | { 164 | //--------------- Start Waiting for the Provider-thread to complete -------------------- 165 | StartCoroutine("WaitForCompletion"); 166 | workData = new ASyncThreadWorkData(workerObjects, safeMode, maxThreads); 167 | providerThread = new Thread(new ThreadStart(InvokeASyncThreadPoolWork)); 168 | providerThread.Start(); 169 | //--------------- Start Waiting for the Provider-thread to complete -------------------- 170 | } 171 | else 172 | { 173 | //--------------- Execute all work in one bunch! -------------------- 174 | StartCoroutine(WaitAndExecuteWorkerObjects(workerObjects)); 175 | //--------------- Execute all work in one bunch! -------------------- 176 | } 177 | } 178 | 179 | 180 | 181 | 182 | private IEnumerator WaitAndExecuteWorkerObjects(IThreadWorkerObject[] workerObjects) 183 | { 184 | yield return new WaitForEndOfFrame(); 185 | for (int i = 0; i < workerObjects.Length; i++) 186 | { 187 | workerObjects[i].ExecuteThreadedWork(); 188 | 189 | if (onWorkerObjectDoneCallBack != null) 190 | onWorkerObjectDoneCallBack(workerObjects[i]); 191 | } 192 | 193 | _shedularBusy = false; 194 | _providerThreadBusy = false; 195 | 196 | if (onCompleteCallBack != null) 197 | onCompleteCallBack(workerObjects); 198 | } 199 | 200 | 201 | 202 | 203 | private IEnumerator WaitForCompletion() 204 | { 205 | if (DebugMode) 206 | Debug.Log(" ----- WaitForCompletion: " + Thread.CurrentThread.ManagedThreadId); 207 | 208 | while (true) 209 | { 210 | //After waiting a while, in the meantime it might have finished itself, or got aborted! 211 | yield return new WaitForSeconds(WaitForSecondsTime); 212 | if (_isAborted) 213 | break; 214 | 215 | //--------------- fire events while still working -------------------- 216 | int finishedObjectsCount = GetFinishedPackagesCount(); 217 | if (finishedObjectsCount == workData.workerPackages.Length) 218 | break; 219 | 220 | int unhandledPackagesCount = GetUnhandledFinishedPackagesCount(); 221 | if (DebugMode) 222 | Debug.Log(" ----- unhandledPackages: " + unhandledPackagesCount + " ( out of: " + finishedObjectsCount + " completed so far...)"); 223 | 224 | if (unhandledPackagesCount > 0) 225 | { 226 | foreach (ThreadWorkStatePackage package in workData.workerPackages) 227 | { 228 | if (package.finishedWorking && !package.eventFired) 229 | { 230 | if (onWorkerObjectDoneCallBack != null) 231 | onWorkerObjectDoneCallBack(package.workerObject); 232 | 233 | package.eventFired = true; 234 | } 235 | } 236 | } 237 | //--------------- fire events while still working -------------------- 238 | } 239 | 240 | if (DebugMode) 241 | Debug.Log(" ----- Coroutine knows its done!"); 242 | 243 | IThreadWorkerObject[] workedObjects = GetWorkerObjectsFromPackages(); 244 | 245 | workData.Dispose(); 246 | workData = null; 247 | _shedularBusy = false; 248 | 249 | if (onCompleteCallBack != null) 250 | onCompleteCallBack(workedObjects); 251 | } 252 | 253 | #endregion 254 | //--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION -------------------------------------- 255 | //--------------------------------------- UNITY COROUTINE & PROVIDER-THREAD IMPLEMENTATION -------------------------------------- 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | //--------------------------------------- EXTRA COMMANDS & ACTIONS -------------------------------------- 268 | //--------------------------------------- EXTRA COMMANDS & ACTIONS -------------------------------------- 269 | #region EXTRA COMMANDS & ACTIONS 270 | 271 | /// 272 | /// Aborts all worker processes currently queued. 273 | /// 274 | /// if true: Makes sure that after invoking "AbortASyncThreads" the ThreadPoolSheduler is available again, but halts the MainThread while waiting for the other threads to finish 275 | public void AbortASyncThreads(bool sleepTillAborted = false) 276 | { 277 | if (!_providerThreadBusy) 278 | return; 279 | 280 | _isAborted = true; 281 | StopCoroutine("WaitForCompletion"); 282 | 283 | if(workData != null && workData.workerPackages != null) 284 | { 285 | lock (workData.workerPackages) 286 | { 287 | foreach (ThreadWorkStatePackage package in workData.workerPackages) 288 | { 289 | if (package.running && !package.finishedWorking) 290 | package.workerObject.AbortThreadedWork(); 291 | } 292 | } 293 | 294 | //At this point in code, _isBusy should be set to FALSE, by the providerThread; 295 | if (sleepTillAborted && isBusy) 296 | { 297 | while (_providerThreadBusy) 298 | Thread.Sleep(1); 299 | } 300 | } 301 | 302 | workData = null; 303 | } 304 | 305 | #endregion 306 | //--------------------------------------- EXTRA COMMANDS & ACTIONS -------------------------------------- 307 | //--------------------------------------- EXTRA COMMANDS & ACTIONS -------------------------------------- 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | //--------------------------------------- .NET THREADPOOL IMPLEMENTATION -------------------------------------- 320 | //--------------------------------------- .NET THREADPOOL IMPLEMENTATION -------------------------------------- 321 | #region .NET THREADPOOL IMPLEMENTATION 322 | 323 | /// 324 | /// This method is the work-provider-method. It makes sure the .NET threadpool has things to do... 325 | /// This method is NOT invoked by the mainThread, therefor is safe to use WaitHandle.WaitAll / WaitAny without halting Unity's gameThread! 326 | /// 327 | public void InvokeASyncThreadPoolWork() 328 | { 329 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 330 | 331 | int totalWork = workData.workerPackages.Length; 332 | int startBurst = Mathf.Clamp(workData.maxWorkingThreads, 1, totalWork); 333 | 334 | if (DebugMode) 335 | Debug.Log(" ----- InvokeASyncThreadPoolWork. startBurst: " + startBurst + ", totalWork: " + totalWork); 336 | 337 | //--------------- Initial Startup burst -------------------- 338 | for (int i = 0; i < startBurst && !_isAborted; i++) 339 | { 340 | //Add to .NET ThreadPool 341 | if (workData.workerPackages[i] != null) 342 | { 343 | workData.workerPackages[i].started = true; 344 | ThreadPool.QueueUserWorkItem(workData.workerPackages[i].ExecuteThreadWork, i); 345 | } 346 | } 347 | //--------------- Initial Startup burst ---------------s----- 348 | 349 | 350 | if (DebugMode) 351 | Debug.Log(" ----- Burst with WorkerObjects being processed!"); 352 | 353 | //--------------- Create a new Thread to keep the Threadpool running & cores saturated! -------------------- 354 | workObjectIndex = startBurst; //at this point the amount of running WorkObjects/Threads is equal to the startBurst; 355 | while (workObjectIndex < totalWork && !_isAborted) 356 | { 357 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 358 | 359 | AutoResetEvent[] startedEvents = GetStartedPackageEvents(); 360 | if (startedEvents.Length > 0) 361 | WaitHandle.WaitAny(startedEvents); 362 | 363 | workData.workerPackages[workObjectIndex].started = true; 364 | ThreadPool.QueueUserWorkItem(workData.workerPackages[workObjectIndex].ExecuteThreadWork, workObjectIndex); 365 | workObjectIndex++; 366 | } 367 | //--------------- Create a new Thread to keep the Threadpool running & cores saturated! -------------------- 368 | 369 | 370 | if (DebugMode) 371 | Debug.Log(" ----- all packages fed to the pool!"); 372 | 373 | //--------------- Wait till all are finished! -------------------- 374 | //All WorkObjects have been set to work, but the last few Threads might still be pending! 375 | AutoResetEvent[] pendingEvents = GetStartedPackageEvents(); 376 | if (pendingEvents.Length > 0) 377 | { 378 | UnityActivityWatchdog.SleepOrAbortIfUnityInactive(); 379 | WaitHandle.WaitAll(pendingEvents); 380 | } 381 | //--------------- Wait till all are finished! -------------------- 382 | 383 | 384 | if (DebugMode) 385 | Debug.Log(" ----- PROVIDER THREAD DONE"); 386 | 387 | //DONE! 388 | _providerThreadBusy = false; 389 | } 390 | 391 | #endregion 392 | //--------------------------------------- .NET THREADPOOL IMPLEMENTATION -------------------------------------- 393 | //--------------------------------------- .NET THREADPOOL IMPLEMENTATION -------------------------------------- 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | //--------------------------------------- MISC -------------------------------------- 408 | //--------------------------------------- MISC -------------------------------------- 409 | #region MISC 410 | 411 | private AutoResetEvent[] GetStartedPackageEvents() 412 | { 413 | List result = new List(); 414 | for (int i = 0; i < workData.workerPackages.Length; i++) 415 | { 416 | ThreadWorkStatePackage package = workData.workerPackages[i]; 417 | if(package.started && !package.finishedWorking) 418 | result.Add(package.waitHandle); 419 | } 420 | return result.ToArray(); 421 | } 422 | 423 | 424 | private IThreadWorkerObject[] GetWorkerObjectsFromPackages() 425 | { 426 | if (workData == null || workData.workerPackages == null) 427 | return new IThreadWorkerObject[0]; 428 | 429 | IThreadWorkerObject[] result = new IThreadWorkerObject[workData.workerPackages.Length]; 430 | int i = workData.workerPackages.Length; 431 | while (--i > -1) 432 | result[i] = workData.workerPackages[i].workerObject; 433 | 434 | return result; 435 | } 436 | 437 | public int GetFinishedPackagesCount() 438 | { 439 | if (workData == null || workData.workerPackages == null) 440 | return 0; 441 | 442 | int count = 0; 443 | int i = workData.workerPackages.Length; 444 | while (--i > -1) 445 | { 446 | if (workData.workerPackages[i].finishedWorking) 447 | count++; 448 | } 449 | return count; 450 | } 451 | 452 | public int GetUnhandledFinishedPackagesCount() 453 | { 454 | if (workData == null || workData.workerPackages == null) 455 | return 0; 456 | 457 | int count = 0; 458 | int i = workData.workerPackages.Length; 459 | while (--i > -1) 460 | { 461 | if (workData.workerPackages[i].finishedWorking && !workData.workerPackages[i].eventFired) 462 | count++; 463 | } 464 | return count; 465 | } 466 | 467 | #endregion 468 | //--------------------------------------- MISC -------------------------------------- 469 | //--------------------------------------- MISC -------------------------------------- 470 | 471 | 472 | } 473 | } -------------------------------------------------------------------------------- /Assets/LOOM Framework/LOOM/ThreadPoolScheduler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e1034b8fef65f454f91a663a126ba33a 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /LOOM - Multi Threading Framework16.unitypackage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/LOOM - Multi Threading Framework16.unitypackage -------------------------------------------------------------------------------- /LOOM-Multi-Threading-Framework.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 10.0.20506 7 | 2.0 8 | {68004739-CEDE-0F70-A436-F1A2003B06A1} 9 | Library 10 | Assembly-CSharp 11 | 512 12 | {E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 13 | .NETFramework 14 | v4.5.2 15 | 16 | 17 | 18 | 19 | Game:1 20 | Android:13 21 | 5.3.4f1 22 | 23 | 24 | 4 25 | 26 | 27 | pdbonly 28 | false 29 | Temp\UnityVS_bin\Debug\ 30 | Temp\UnityVS_obj\Debug\ 31 | prompt 32 | 4 33 | DEBUG;TRACE;UNITY_5_3_OR_NEWER;UNITY_5_3_4;UNITY_5_3;UNITY_5;ENABLE_NEW_BUGREPORTER;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_FRAME_DEBUGGER;ENABLE_GENERICS;ENABLE_HOME_SCREEN;ENABLE_IMAGEEFFECTS;ENABLE_LIGHT_PROBES_LEGACY;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_PLUGIN_INSPECTOR;ENABLE_SHADOWS;ENABLE_SINGLE_INSTANCE_BUILD_SETTING;ENABLE_SPRITERENDERER_FLIPPING;ENABLE_SPRITES;ENABLE_SPRITE_POLYGON;ENABLE_TERRAIN;ENABLE_RAKNET;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_HUB;ENABLE_CLOUD_PROJECT_ID;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_METRICS;ENABLE_EDITOR_METRICS_CACHING;INCLUDE_DYNAMIC_GI;INCLUDE_GI;INCLUDE_IL2CPP;INCLUDE_DIRECTX12;PLATFORM_SUPPORTS_MONO;ENABLE_LOCALIZATION;ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION;ENABLE_EDITOR_TESTS_RUNNER;UNITY_ANDROID;UNITY_ANDROID_API;ENABLE_SUBSTANCE;UNITY_ANDROID_API;ENABLE_TEXTUREID_MAP;ENABLE_EGL;ENABLE_NETWORK;ENABLE_RUNTIME_GI;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_LOG_MIXED_STACKTRACE;ENABLE_UNITYWEBREQUEST;PLATFORM_SUPPORTS_ADS_ID;ENABLE_UNITYADS_RUNTIME;UNITY_UNITYADS_API;ENABLE_MONO;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;UNITY_TEAM_LICENSE;UNITY_PRO_LICENSE 34 | false 35 | false 36 | 37 | 38 | pdbonly 39 | false 40 | Temp\UnityVS_bin\Release\ 41 | Temp\UnityVS_obj\Release\ 42 | prompt 43 | 4 44 | TRACE;UNITY_5_3_OR_NEWER;UNITY_5_3_4;UNITY_5_3;UNITY_5;ENABLE_NEW_BUGREPORTER;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_FRAME_DEBUGGER;ENABLE_GENERICS;ENABLE_HOME_SCREEN;ENABLE_IMAGEEFFECTS;ENABLE_LIGHT_PROBES_LEGACY;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_PLUGIN_INSPECTOR;ENABLE_SHADOWS;ENABLE_SINGLE_INSTANCE_BUILD_SETTING;ENABLE_SPRITERENDERER_FLIPPING;ENABLE_SPRITES;ENABLE_SPRITE_POLYGON;ENABLE_TERRAIN;ENABLE_RAKNET;ENABLE_UNET;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_HUB;ENABLE_CLOUD_PROJECT_ID;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_METRICS;ENABLE_EDITOR_METRICS_CACHING;INCLUDE_DYNAMIC_GI;INCLUDE_GI;INCLUDE_IL2CPP;INCLUDE_DIRECTX12;PLATFORM_SUPPORTS_MONO;ENABLE_LOCALIZATION;ENABLE_ANDROID_ATLAS_ETC1_COMPRESSION;ENABLE_EDITOR_TESTS_RUNNER;UNITY_ANDROID;UNITY_ANDROID_API;ENABLE_SUBSTANCE;UNITY_ANDROID_API;ENABLE_TEXTUREID_MAP;ENABLE_EGL;ENABLE_NETWORK;ENABLE_RUNTIME_GI;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_LOG_MIXED_STACKTRACE;ENABLE_UNITYWEBREQUEST;PLATFORM_SUPPORTS_ADS_ID;ENABLE_UNITYADS_RUNTIME;UNITY_UNITYADS_API;ENABLE_MONO;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;UNITY_TEAM_LICENSE;UNITY_PRO_LICENSE 45 | false 46 | false 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Library\UnityAssemblies\UnityEngine.dll 59 | 60 | 61 | Library\UnityAssemblies\UnityEngine.UI.dll 62 | 63 | 64 | Library\UnityAssemblies\UnityEngine.Networking.dll 65 | 66 | 67 | Library\UnityAssemblies\UnityEditor.dll 68 | 69 | 70 | Library\UnityAssemblies\UnityEditor.iOS.Extensions.Xcode.dll 71 | 72 | 73 | Library\UnityAssemblies\UnityEditor.iOS.Extensions.Common.dll 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /LOOM-Multi-Threading-Framework.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2015 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LOOM-Multi-Threading-Framework", "LOOM-Multi-Threading-Framework.csproj", "{68004739-CEDE-0F70-A436-F1A2003B06A1}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {68004739-CEDE-0F70-A436-F1A2003B06A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {68004739-CEDE-0F70-A436-F1A2003B06A1}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {68004739-CEDE-0F70-A436-F1A2003B06A1}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {68004739-CEDE-0F70-A436-F1A2003B06A1}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 5.3.4f1 2 | m_StandardAssetsVersion: 0 3 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityAdsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/UnityAdsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superowner/LOOM-Multi-Threading-Framework/56a811efcc3e135782559424e51392c69de8fb2f/ProjectSettings/UnityConnectSettings.asset --------------------------------------------------------------------------------