CSModuleWriter.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  3. // LICENSE: Atomic Game Engine Editor and Tools EULA
  4. // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
  5. // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
  6. //
  7. #include <Atomic/IO/File.h>
  8. #include <Atomic/IO/FileSystem.h>
  9. #include "../JSBind.h"
  10. #include "../JSBPackage.h"
  11. #include "../JSBModule.h"
  12. #include "../JSBEnum.h"
  13. #include "../JSBClass.h"
  14. #include "../JSBFunction.h"
  15. #include "CSTypeHelper.h"
  16. #include "CSClassWriter.h"
  17. #include "CSModuleWriter.h"
  18. namespace ToolCore
  19. {
  20. CSModuleWriter::CSModuleWriter(JSBModule *module) : JSBModuleWriter(module)
  21. {
  22. }
  23. void CSModuleWriter::WriteIncludes(String& source)
  24. {
  25. Vector<String>& includes = module_->includes_;
  26. for (unsigned i = 0; i < includes.Size(); i++)
  27. {
  28. if (includes[i].StartsWith("<"))
  29. source.AppendWithFormat("#include %s\n", includes[i].CString());
  30. else
  31. source.AppendWithFormat("#include \"%s\"\n", includes[i].CString());
  32. }
  33. Vector<JSBHeader*> allheaders;
  34. HashMap<StringHash, SharedPtr<JSBEnum> >::Iterator eitr = module_->enums_.Begin();
  35. while (eitr != module_->enums_.End())
  36. {
  37. allheaders.Push(eitr->second_->GetHeader());
  38. eitr++;
  39. }
  40. HashMap<StringHash, SharedPtr<JSBClass> >::Iterator citr = module_->classes_.Begin();
  41. while (citr != module_->classes_.End())
  42. {
  43. allheaders.Push(citr->second_->GetHeader());
  44. citr++;
  45. }
  46. Vector<JSBHeader*> included;
  47. for (unsigned i = 0; i < allheaders.Size(); i++)
  48. {
  49. JSBHeader* header = allheaders.At(i);
  50. if (included.Contains(header))
  51. continue;
  52. String headerPath = GetPath(header->GetFilePath());
  53. String headerfile = GetFileNameAndExtension(header->GetFilePath());
  54. JSBind* jsbind = header->GetSubsystem<JSBind>();
  55. headerPath.Replace(jsbind->GetSourceRootFolder() + "Source/", "");
  56. source.AppendWithFormat("#include <%s%s>\n", headerPath.CString(), headerfile.CString());
  57. included.Push(header);
  58. }
  59. source += ToString("\n#include \"CSPackage%s.h\"\n", module_->GetPackage()->GetName().CString());
  60. }
  61. void CSModuleWriter::GenerateNativeSource()
  62. {
  63. String source = "// This file was autogenerated by JSBind, changes will be lost\n";
  64. source += "#ifdef ATOMIC_PLATFORM_WINDOWS\n";
  65. source += "#pragma warning(disable: 4244) // possible loss of data\n";
  66. source += "#define ATOMIC_EXPORT_API __declspec(dllexport)\n";
  67. source += "#else\n";
  68. source += "#define ATOMIC_EXPORT_API\n";
  69. source += "#endif\n";
  70. if (module_->Requires("3D"))
  71. {
  72. source += "#ifdef ATOMIC_3D\n";
  73. }
  74. WriteIncludes(source);
  75. source += "\n#include <AtomicNET/NETCore/NETCore.h>\n";
  76. String ns = module_->GetPackage()->GetNamespace();
  77. source += "\n\nusing namespace " + ns + ";\n\n";
  78. source += "\n\nextern \"C\" \n{\n \n";
  79. source += "// Begin Class Declarations\n";
  80. source += "// End Class Declarations\n\n";
  81. source += "// Begin Classes\n";
  82. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  83. for (unsigned i = 0; i < classes.Size(); i++)
  84. {
  85. CSClassWriter clsWriter(classes[i]);
  86. clsWriter.GenerateNativeSource(source);
  87. }
  88. source += "// End Classes\n\n";
  89. // end Atomic namespace
  90. source += "\n}\n";
  91. if (module_->Requires("3D"))
  92. {
  93. source += "#endif //ATOMIC_3D\n";
  94. }
  95. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  96. String filepath = jsbind->GetDestNativeFolder() + "/CSModule" + module_->name_ + ".cpp";
  97. File file(module_->GetContext());
  98. file.Open(filepath, FILE_WRITE);
  99. file.Write(source.CString(), source.Length());
  100. file.Close();
  101. }
  102. String CSModuleWriter::GetManagedPrimitiveType(JSBPrimitiveType* ptype)
  103. {
  104. if (ptype->kind_ == JSBPrimitiveType::Bool)
  105. return "bool";
  106. if (ptype->kind_ == JSBPrimitiveType::Int && ptype->isUnsigned_)
  107. return "uint";
  108. else if (ptype->kind_ == JSBPrimitiveType::Int)
  109. return "int";
  110. if (ptype->kind_ == JSBPrimitiveType::Float)
  111. return "float";
  112. return "int";
  113. }
  114. void CSModuleWriter::GenerateManagedClasses(String& source)
  115. {
  116. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  117. for (unsigned i = 0; i < classes.Size(); i++)
  118. {
  119. JSBClass* klass = classes.At(i);
  120. if (klass->IsNumberArray())
  121. continue;
  122. CSClassWriter clsWriter(klass);
  123. clsWriter.GenerateManagedSource(source);
  124. }
  125. }
  126. void CSModuleWriter::GenerateManagedEnumsAndConstants(String& source)
  127. {
  128. Vector<SharedPtr<JSBEnum>> enums = module_->enums_.Values();
  129. Indent();
  130. for (unsigned i = 0; i < enums.Size(); i++)
  131. {
  132. JSBEnum* jenum = enums[i];
  133. source += "\n";
  134. String line = "public enum " + jenum->GetName() + "\n";
  135. source += IndentLine(line);
  136. source += IndentLine("{\n");
  137. HashMap<String, String>& values = jenum->GetValues();
  138. HashMap<String, String>::ConstIterator itr = values.Begin();
  139. Indent();
  140. while (itr != values.End())
  141. {
  142. String name = (*itr).first_;
  143. String value = (*itr).second_;
  144. if (value.Length())
  145. {
  146. line = name + " = " + value;
  147. }
  148. else
  149. {
  150. line = name;
  151. }
  152. itr++;
  153. if (itr != values.End())
  154. line += ",";
  155. line += "\n";
  156. source += IndentLine(line);
  157. }
  158. Dedent();
  159. source += IndentLine("}\n");
  160. }
  161. // constants
  162. HashMap<String, JSBModule::Constant>& constants = module_->GetConstants();
  163. if (constants.Size())
  164. {
  165. source += "\n";
  166. String line = "public static partial class Constants\n";
  167. source += IndentLine(line);
  168. source += IndentLine("{\n");
  169. const Vector<String>& constantsName = constants.Keys();
  170. Indent();
  171. for (unsigned i = 0; i < constantsName.Size(); i++)
  172. {
  173. const String& cname = constantsName.At(i);
  174. JSBModule::Constant& constant = constants[cname];
  175. String managedType = GetManagedPrimitiveType(constant.type);
  176. String value = constant.value;
  177. if (!value.Length())
  178. continue;
  179. //static const unsigned M_MIN_UNSIGNED = 0x00000000;
  180. // /static const unsigned M_MAX_UNSIGNED = 0xffffffff;
  181. if (cname == "M_MIN_INT")
  182. value = "int.MinValue";
  183. if (cname == "M_INFINITY")
  184. value = "float.MaxValue";
  185. if (value == "M_MAX_UNSIGNED")
  186. value = "0xffffffff";
  187. // Input stuff
  188. if (module_->GetName() == "Input")
  189. {
  190. if (cname.StartsWith("KEY_"))
  191. {
  192. if (value.Length() == 1 && (IsAlpha(value[0]) || IsDigit(value[0])))
  193. value = "'" + value + "'";
  194. }
  195. // https://raw.githubusercontent.com/flibitijibibo/SDL2-CS/master/src/SDL2.cs
  196. if (value.StartsWith("SDL_BUTTON_") || value.StartsWith("SDL_HAT_"))
  197. {
  198. value = "(int) SDL." + value;
  199. }
  200. else if (value.StartsWith("SDLK_"))
  201. {
  202. value = "(int) SDL.SDL_Keycode." + value;
  203. }
  204. else if (value.StartsWith("SDL_SCANCODE_"))
  205. {
  206. value = "(int) SDL.SDL_Scancode." + value;
  207. }
  208. else if (value.StartsWith("SDL_CONTROLLER_BUTTON_"))
  209. {
  210. value = "(int) SDL.SDL_GameControllerButton." + value;
  211. }
  212. else if (value.StartsWith("SDL_CONTROLLER_AXIS_"))
  213. {
  214. value = "(int) SDL.SDL_GameControllerAxis." + value;
  215. }
  216. }
  217. String line = "public const " + managedType + " " + cname + " = " + value;
  218. if (managedType == "float" && !line.EndsWith("f") && IsDigit(line[line.Length()-1]))
  219. line += "f";
  220. line += ";\n";
  221. source += IndentLine(line);
  222. }
  223. Dedent();
  224. source += "\n";
  225. line = "}\n";
  226. source += IndentLine(line);
  227. }
  228. source += "\n";
  229. Dedent();
  230. }
  231. void CSModuleWriter::GenerateManagedModuleClass(String& sourceOut)
  232. {
  233. Indent();
  234. String source;
  235. String line = ToString("public static partial class %sModule\n", module_->GetName().CString());
  236. source += IndentLine(line);
  237. source += IndentLine("{\n");
  238. Indent();
  239. source += IndentLine("public static void Initialize()\n");
  240. source += IndentLine("{\n");
  241. Indent();
  242. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  243. for (unsigned i = 0; i < classes.Size(); i++)
  244. {
  245. JSBClass* klass = classes.At(i);
  246. JSBPackage* package = module_->GetPackage();
  247. if (klass->IsNumberArray() || klass->IsAbstract())
  248. continue;
  249. line = ToString("NativeCore.RegisterNativeType(typeof(%s));\n", klass->GetName().CString());
  250. source += IndentLine(line);
  251. line = ToString("NativeCore.nativeClassIDToManagedConstructor [ %s.csb_%s_%s_GetClassIDStatic ()] = (IntPtr x) => {\n",
  252. klass->GetName().CString(), package->GetName().CString(), klass->GetName().CString());
  253. source += IndentLine(line);
  254. Indent();
  255. source += IndentLine(ToString("return new %s (x);\n", klass->GetName().CString()));
  256. Dedent();
  257. source += IndentLine("};\n");
  258. }
  259. Dedent();
  260. source += IndentLine("}\n");
  261. Dedent();
  262. source += IndentLine("}\n");
  263. sourceOut += source;
  264. Dedent();
  265. }
  266. void CSModuleWriter::GenerateManagedSource()
  267. {
  268. String source = "// Autogenerated";
  269. String moduleName = module_->GetPackage()->GetNamespace();
  270. source += "\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\n";
  271. if (moduleName == "Atomic")
  272. moduleName = "AtomicEngine";
  273. if (moduleName != "AtomicEngine")
  274. {
  275. source += "using AtomicEngine;\n";
  276. }
  277. source += "\n\n";
  278. source += "namespace " + moduleName + "\n";
  279. source += "{\n";
  280. GenerateManagedEnumsAndConstants(source);
  281. GenerateManagedModuleClass(source);
  282. GenerateManagedClasses(source);
  283. source += "}\n";
  284. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  285. String filepath = jsbind->GetDestScriptFolder() + "/CSModule" + module_->name_ + ".cs";
  286. File file(module_->GetContext());
  287. file.Open(filepath, FILE_WRITE);
  288. file.Write(source.CString(), source.Length());
  289. file.Close();
  290. }
  291. void CSModuleWriter::GenerateSource()
  292. {
  293. GenerateNativeSource();
  294. GenerateManagedSource();
  295. }
  296. }