AtomicNET.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Collections.Generic;
  4. namespace AtomicEngine
  5. {
  6. public class AtomicNETRuntime
  7. {
  8. [DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  9. public static extern int csb_Atomic_Test (int id);
  10. public static void Startup()
  11. {
  12. //Console.WriteLine("AtomicNETRuntime Startup:" + csb_Atomic_Test(42));
  13. Atomic.Initialize();
  14. }
  15. }
  16. public static class Atomic
  17. {
  18. static public void Initialize()
  19. {
  20. ContainerModule.Initialize ();
  21. CoreModule.Initialize ();
  22. MathModule.Initialize ();
  23. EngineModule.Initialize ();
  24. InputModule.Initialize ();
  25. IOModule.Initialize ();
  26. ResourceModule.Initialize ();
  27. AudioModule.Initialize ();
  28. GraphicsModule.Initialize ();
  29. SceneModule.Initialize ();
  30. Atomic2DModule.Initialize ();
  31. Atomic3DModule.Initialize ();
  32. NavigationModule.Initialize ();
  33. NetworkModule.Initialize ();
  34. PhysicsModule.Initialize ();
  35. EnvironmentModule.Initialize ();
  36. UIModule.Initialize ();
  37. AtomicPlayer.PlayerModule.Initialize ();
  38. initSubsystems();
  39. }
  40. static Dictionary<Type, RefCounted> subSystems = new Dictionary<Type, RefCounted>();
  41. static private void registerSubsystem (RefCounted subsystem)
  42. {
  43. subSystems[subsystem.GetType()] = subsystem;
  44. }
  45. static public T GetSubsystem<T>() where T : RefCounted
  46. {
  47. return (T) subSystems [typeof(T)];
  48. }
  49. static private void initSubsystems()
  50. {
  51. registerSubsystem (NativeCore.WrapNative<Graphics> (csb_AtomicEngine_GetSubsystem("Graphics")));
  52. registerSubsystem (NativeCore.WrapNative<Renderer> (csb_AtomicEngine_GetSubsystem("Renderer")));
  53. registerSubsystem (NativeCore.WrapNative<ResourceCache> (csb_AtomicEngine_GetSubsystem("ResourceCache")));
  54. }
  55. [DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  56. private static extern IntPtr csb_AtomicEngine_GetSubsystem(string name);
  57. }
  58. public static partial class Constants
  59. {
  60. public const string LIBNAME = "__Internal";
  61. }
  62. public partial class RefCounted
  63. {
  64. public RefCounted()
  65. {
  66. }
  67. protected RefCounted (IntPtr native)
  68. {
  69. nativeInstance = native;
  70. }
  71. public IntPtr nativeInstance;
  72. [DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  73. public static extern IntPtr csb_Atomic_RefCounted_GetClassID (IntPtr self);
  74. }
  75. static class NativeCore
  76. {
  77. [DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
  78. private static extern void csb_AtomicEngine_ReleaseRef (IntPtr refCounted);
  79. // given an existing instance classID, construct the managed instance, with downcast support (ask for Component, get StaticModel for example)
  80. public static Dictionary<IntPtr, Func<IntPtr, RefCounted>> nativeClassIDToManagedConstructor = new Dictionary<IntPtr, Func<IntPtr, RefCounted>>();
  81. // weak references here, hold a ref native side
  82. public static Dictionary<IntPtr, WeakReference> nativeLookup = new Dictionary<IntPtr, WeakReference> ();
  83. // native engine types, instances of these types can be trivially recreated managed side
  84. private static Dictionary<Type, Type> nativeTypes = new Dictionary<Type, Type> ();
  85. public static bool GetNativeType (Type type)
  86. {
  87. return nativeTypes.ContainsKey (type);
  88. }
  89. public static void RegisterNativeType (Type type)
  90. {
  91. nativeTypes.Add (type, type);
  92. }
  93. public static void ReleaseExpiredNativeReferences()
  94. {
  95. List<IntPtr> released = null;
  96. foreach(KeyValuePair<IntPtr, WeakReference> entry in nativeLookup)
  97. {
  98. if (entry.Value.Target == null || !entry.Value.IsAlive)
  99. {
  100. if (released == null)
  101. released = new List<IntPtr> ();
  102. released.Add (entry.Key);
  103. }
  104. }
  105. if (released == null)
  106. return;
  107. foreach (IntPtr native in released) {
  108. nativeLookup.Remove (native);
  109. csb_AtomicEngine_ReleaseRef(native);
  110. //Console.WriteLine("Released: " + test);
  111. }
  112. }
  113. static IntPtr test = IntPtr.Zero;
  114. // called by native code
  115. public static void NETUpdate (float timeStep)
  116. {
  117. GC.Collect();
  118. GC.WaitForPendingFinalizers();
  119. GC.Collect();
  120. ReleaseExpiredNativeReferences();
  121. if (test == IntPtr.Zero || !nativeLookup.ContainsKey(test))
  122. {
  123. test = Atomic.GetSubsystem<Renderer>().GetDefaultZone().nativeInstance;
  124. //Console.WriteLine("Allocated: " + test);
  125. }
  126. }
  127. // called by native code for every refcounted deleted
  128. public static void RefCountedDeleted (IntPtr native)
  129. {
  130. // native side deleted, immediate remove, if we have a script reference still this is an error
  131. WeakReference w;
  132. if (nativeLookup.TryGetValue (native, out w)) {
  133. if ( w != null && w.IsAlive) {
  134. throw new System.InvalidOperationException("Native Refcounted was deleted with live managed instance");
  135. }
  136. }
  137. nativeLookup.Remove(native);
  138. }
  139. // register a newly created native
  140. public static IntPtr RegisterNative (IntPtr native, RefCounted r)
  141. {
  142. r.nativeInstance = native;
  143. var w = new WeakReference (r);
  144. NativeCore.nativeLookup [native] = w;
  145. // keep native side alive
  146. r.AddRef();
  147. return native;
  148. }
  149. // wraps an existing native instance, with downcast support
  150. public static T WrapNative<T> (IntPtr native) where T:RefCounted
  151. {
  152. if (native == IntPtr.Zero)
  153. return null;
  154. WeakReference w;
  155. // first see if we're already available
  156. if (nativeLookup.TryGetValue (native, out w)) {
  157. if (w.IsAlive) {
  158. // we're alive!
  159. return (T)w.Target;
  160. } else {
  161. // we were seen before, but have since been GC'd, remove!
  162. nativeLookup.Remove (native);
  163. csb_AtomicEngine_ReleaseRef(native);
  164. }
  165. }
  166. IntPtr classID = RefCounted.csb_Atomic_RefCounted_GetClassID (native);
  167. // and store, with downcast support for instance Component -> StaticModel
  168. // we never want to hit this path for script inherited natives
  169. RefCounted r = nativeClassIDToManagedConstructor[classID](native);
  170. w = new WeakReference (r);
  171. NativeCore.nativeLookup [native] = w;
  172. // store a ref, so native side will not be released while we still have a reference in managed code
  173. r.AddRef();
  174. return (T) r;
  175. }
  176. }
  177. public class InspectorAttribute : Attribute
  178. {
  179. public InspectorAttribute(string DefaultValue = "", string Value1 = "", string Value2 = "")
  180. {
  181. }
  182. public string DefaultValue;
  183. public string Value1;
  184. public string Value2;
  185. }
  186. }