// // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved // LICENSE: Atomic Game Engine Editor and Tools EULA // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for // license information: https://github.com/AtomicGameEngine/AtomicGameEngine // #include #include #include "../JSBind.h" #include "../JSBPackage.h" #include "../JSBModule.h" #include "../JSBEnum.h" #include "../JSBClass.h" #include "../JSBFunction.h" #include "CSTypeHelper.h" #include "CSClassWriter.h" #include "CSModuleWriter.h" namespace ToolCore { CSModuleWriter::CSModuleWriter(JSBModule *module) : JSBModuleWriter(module) { } void CSModuleWriter::WriteIncludes(String& source) { Vector& includes = module_->includes_; for (unsigned i = 0; i < includes.Size(); i++) { if (includes[i].StartsWith("<")) source.AppendWithFormat("#include %s\n", includes[i].CString()); else source.AppendWithFormat("#include \"%s\"\n", includes[i].CString()); } Vector allheaders; HashMap >::Iterator eitr = module_->enums_.Begin(); while (eitr != module_->enums_.End()) { allheaders.Push(eitr->second_->GetHeader()); eitr++; } HashMap >::Iterator citr = module_->classes_.Begin(); while (citr != module_->classes_.End()) { allheaders.Push(citr->second_->GetHeader()); citr++; } Vector included; for (unsigned i = 0; i < allheaders.Size(); i++) { JSBHeader* header = allheaders.At(i); if (included.Contains(header)) continue; String headerPath = GetPath(header->GetFilePath()); String headerfile = GetFileNameAndExtension(header->GetFilePath()); JSBind* jsbind = header->GetSubsystem(); headerPath.Replace(jsbind->GetSourceRootFolder() + "Source/", ""); source.AppendWithFormat("#include <%s%s>\n", headerPath.CString(), headerfile.CString()); included.Push(header); } source += ToString("\n#include \"CSPackage%s.h\"\n", module_->GetPackage()->GetName().CString()); } void CSModuleWriter::GenerateNativeSource() { String source = "// This file was autogenerated by JSBind, changes will be lost\n"; source += "#ifdef ATOMIC_PLATFORM_WINDOWS\n"; source += "#pragma warning(disable: 4244) // possible loss of data\n"; source += "#define ATOMIC_EXPORT_API __declspec(dllexport)\n"; source += "#else\n"; source += "#define ATOMIC_EXPORT_API\n"; source += "#endif\n"; if (module_->Requires("3D")) { source += "#ifdef ATOMIC_3D\n"; } WriteIncludes(source); source += "\n#include \n"; String ns = module_->GetPackage()->GetNamespace(); source += "\n\nusing namespace " + ns + ";\n\n"; source += "\n\nextern \"C\" \n{\n \n"; source += "// Begin Class Declarations\n"; source += "// End Class Declarations\n\n"; source += "// Begin Classes\n"; Vector> classes = module_->classes_.Values(); for (unsigned i = 0; i < classes.Size(); i++) { CSClassWriter clsWriter(classes[i]); clsWriter.GenerateNativeSource(source); } source += "// End Classes\n\n"; // end Atomic namespace source += "\n}\n"; if (module_->Requires("3D")) { source += "#endif //ATOMIC_3D\n"; } JSBind* jsbind = module_->GetSubsystem(); String filepath = jsbind->GetDestNativeFolder() + "/CSModule" + module_->name_ + ".cpp"; File file(module_->GetContext()); file.Open(filepath, FILE_WRITE); file.Write(source.CString(), source.Length()); file.Close(); } String CSModuleWriter::GetManagedPrimitiveType(JSBPrimitiveType* ptype) { if (ptype->kind_ == JSBPrimitiveType::Bool) return "bool"; if (ptype->kind_ == JSBPrimitiveType::Int && ptype->isUnsigned_) return "uint"; else if (ptype->kind_ == JSBPrimitiveType::Int) return "int"; if (ptype->kind_ == JSBPrimitiveType::Float) return "float"; return "int"; } void CSModuleWriter::GenerateManagedClasses(String& source) { Vector> classes = module_->classes_.Values(); for (unsigned i = 0; i < classes.Size(); i++) { JSBClass* klass = classes.At(i); if (klass->IsNumberArray()) continue; CSClassWriter clsWriter(klass); clsWriter.GenerateManagedSource(source); } } void CSModuleWriter::GenerateManagedEnumsAndConstants(String& source) { Vector> enums = module_->enums_.Values(); Indent(); for (unsigned i = 0; i < enums.Size(); i++) { JSBEnum* jenum = enums[i]; source += "\n"; String line = "public enum " + jenum->GetName() + "\n"; source += IndentLine(line); source += IndentLine("{\n"); HashMap& values = jenum->GetValues(); HashMap::ConstIterator itr = values.Begin(); Indent(); while (itr != values.End()) { String name = (*itr).first_; String value = (*itr).second_; if (value.Length()) { line = name + " = " + value; } else { line = name; } itr++; if (itr != values.End()) line += ","; line += "\n"; source += IndentLine(line); } Dedent(); source += IndentLine("}\n"); } // constants HashMap& constants = module_->GetConstants(); if (constants.Size()) { source += "\n"; String line = "public static partial class Constants\n"; source += IndentLine(line); source += IndentLine("{\n"); const Vector& constantsName = constants.Keys(); Indent(); for (unsigned i = 0; i < constantsName.Size(); i++) { const String& cname = constantsName.At(i); JSBModule::Constant& constant = constants[cname]; String managedType = GetManagedPrimitiveType(constant.type); String value = constant.value; if (!value.Length()) continue; //static const unsigned M_MIN_UNSIGNED = 0x00000000; // /static const unsigned M_MAX_UNSIGNED = 0xffffffff; if (value == "M_MAX_UNSIGNED") value = "0xffffffff"; // Input stuff if (module_->GetName() == "Input") { if (cname.StartsWith("KEY_")) { if (value.Length() == 1 && (IsAlpha(value[0]) || IsDigit(value[0]))) value = "'" + value + "'"; } // https://raw.githubusercontent.com/flibitijibibo/SDL2-CS/master/src/SDL2.cs if (value.StartsWith("SDL_BUTTON_") || value.StartsWith("SDL_HAT_")) { value = "(int) SDL." + value; } else if (value.StartsWith("SDLK_")) { value = "(int) SDL.SDL_Keycode." + value; } else if (value.StartsWith("SDL_SCANCODE_")) { value = "(int) SDL.SDL_Scancode." + value; } else if (value.StartsWith("SDL_CONTROLLER_BUTTON_")) { value = "(int) SDL.SDL_GameControllerButton." + value; } else if (value.StartsWith("SDL_CONTROLLER_AXIS_")) { value = "(int) SDL.SDL_GameControllerAxis." + value; } } String line = "public const " + managedType + " " + cname + " = " + value; if (managedType == "float" && !line.EndsWith("f")) line += "f"; line += ";\n"; source += IndentLine(line); } Dedent(); source += "\n"; line = "}\n"; source += IndentLine(line); } source += "\n"; Dedent(); } void CSModuleWriter::GenerateManagedModuleClass(String& sourceOut) { Indent(); String source; String line = ToString("public static partial class %sModule\n", module_->GetName().CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); source += IndentLine("public static void Initialize()\n"); source += IndentLine("{\n"); Indent(); Vector> classes = module_->classes_.Values(); for (unsigned i = 0; i < classes.Size(); i++) { JSBClass* klass = classes.At(i); JSBPackage* package = module_->GetPackage(); if (klass->IsNumberArray() || klass->IsAbstract()) continue; line = ToString("NativeCore.RegisterNativeType(typeof(%s));\n", klass->GetName().CString()); source += IndentLine(line); line = ToString("NativeCore.nativeClassIDToManagedConstructor [ %s.csb_%s_%s_GetClassIDStatic ()] = (IntPtr x) => {\n", klass->GetName().CString(), package->GetName().CString(), klass->GetName().CString()); source += IndentLine(line); Indent(); source += IndentLine(ToString("return new %s (x);\n", klass->GetName().CString())); Dedent(); source += IndentLine("};\n"); } Dedent(); source += IndentLine("}\n"); Dedent(); source += IndentLine("}\n"); sourceOut += source; Dedent(); } void CSModuleWriter::GenerateManagedSource() { String source = "// Autogenerated"; String moduleName = module_->GetPackage()->GetNamespace(); source += "\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\n"; if (moduleName == "Atomic") moduleName = "AtomicEngine"; if (moduleName != "AtomicEngine") { source += "using AtomicEngine;\n"; } source += "\n\n"; source += "namespace " + moduleName + "\n"; source += "{\n"; GenerateManagedEnumsAndConstants(source); GenerateManagedModuleClass(source); GenerateManagedClasses(source); source += "}\n"; JSBind* jsbind = module_->GetSubsystem(); String filepath = jsbind->GetDestScriptFolder() + "/CSModule" + module_->name_ + ".cs"; File file(module_->GetContext()); file.Open(filepath, FILE_WRITE); file.Write(source.CString(), source.Length()); file.Close(); } void CSModuleWriter::GenerateSource() { GenerateNativeSource(); GenerateManagedSource(); } }