From 1ec8f1037e86b1f48303fb5f3c5c0d18f1b181ab Mon Sep 17 00:00:00 2001 From: Josh Engebretson Date: Sat, 10 Sep 2016 18:51:06 -0700 Subject: [PATCH] Atomic C# iOS Squashed commits: [82410ba] Updating Linux Build [38113c5] Build updates for Windows [9024b32] Handle iOS AtomicNET reference on binary editor [6a2b2d6] Map to AnyCPU for iPhone libraries, which aren't executables [1f9bc0f] ./Build_AtomicEditor.sh --with-ios --with-android working on Mac [1807791] Running on iOS [10a6d4f] WIP Atomic C# iOS support --- Build/CMake/IOS/AtomicNET.framework.plist | 58 +++++ Build/Scripts/Bootstrap.js | 60 +++++ Build/Scripts/BuildAndroid.js | 21 +- Build/Scripts/BuildAtomicNET.js | 44 ++++ Build/Scripts/BuildIOS.js | 48 ++++ Build/Scripts/BuildLinux.js | 189 +++++++++----- Build/Scripts/BuildMac.js | 173 ++++++++----- Build/Scripts/BuildWindows.js | 165 +++++++----- Build/Scripts/Host.js | 2 + Build/Scripts/HostCommon.js | 24 ++ Build/Scripts/Minimist.js | 235 ++++++++++++++++++ Build/Scripts/Windows/CompileAndroid.bat | 2 +- .../Windows/CompileAtomicEditorPhase1.bat | 3 + .../Windows/CompileAtomicEditorPhase2.bat | 2 + Build_AtomicEditor.bat | 37 +-- Build_AtomicEditor.sh | 20 +- .../AtomicNET/Application/Application.cs | 9 +- Script/AtomicNET/AtomicNET/Core/AtomicNET.cs | 9 +- Script/AtomicNET/AtomicNET/Core/Constants.cs | 4 +- Script/AtomicNET/AtomicNET/Core/NativeCore.cs | 43 +++- .../AtomicNET/AtomicNET/Core/NativeEvents.cs | 18 -- Script/AtomicNET/AtomicNET/Core/SDLEvents.cs | 144 +++++++++++ .../AtomicNET/AtomicNET/Graphics/Graphics.cs | 8 + Script/AtomicNET/AtomicNETProject.json | 26 ++ Script/AtomicNET/AtomicNETService/Program.cs | 7 - Script/AtomicNET/AtomicProject.json | 31 +++ .../iOS/ApiDefinition/ApiDefinition.cs | 10 + .../AtomicNETNative.framework.linkwith.cs | 3 + Source/AtomicNET/NETNative/CMakeLists.txt | 29 +++ .../AtomicNET/NETNative/NETAtomicPlayer.cpp | 14 +- Source/AtomicNET/NETNative/NETCInterop.cpp | 55 +++- .../AtomicPlayer/Application/CMakeLists.txt | 2 +- Source/CMakeLists.txt | 2 +- Source/ToolCore/Command/NETCmd.cpp | 52 +++- Source/ToolCore/Command/NETCmd.h | 4 +- Source/ToolCore/NETTools/NETBuildSystem.cpp | 108 +++++--- Source/ToolCore/NETTools/NETBuildSystem.h | 11 +- Source/ToolCore/NETTools/NETProjectGen.cpp | 180 ++++++++++++-- Source/ToolCore/NETTools/NETProjectGen.h | 15 +- Source/ToolCore/Project/ProjectSettings.cpp | 3 +- 40 files changed, 1497 insertions(+), 373 deletions(-) create mode 100644 Build/CMake/IOS/AtomicNET.framework.plist create mode 100644 Build/Scripts/BuildAtomicNET.js create mode 100644 Build/Scripts/BuildIOS.js create mode 100644 Build/Scripts/Minimist.js create mode 100644 Build/Scripts/Windows/CompileAtomicEditorPhase1.bat create mode 100644 Build/Scripts/Windows/CompileAtomicEditorPhase2.bat create mode 100644 Script/AtomicNET/AtomicNET/Core/SDLEvents.cs create mode 100644 Script/AtomicNET/Platform/iOS/ApiDefinition/ApiDefinition.cs create mode 100644 Script/AtomicNET/Platform/iOS/AtomicNET/AtomicNETNative.framework.linkwith.cs diff --git a/Build/CMake/IOS/AtomicNET.framework.plist b/Build/CMake/IOS/AtomicNET.framework.plist new file mode 100644 index 0000000000..edcdb35478 --- /dev/null +++ b/Build/CMake/IOS/AtomicNET.framework.plist @@ -0,0 +1,58 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleIdentifier + com.atomicgameengine.atomicnetframework + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Mono + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 3.12 + NSPrincipalClass + + CFBundleExecutable + AtomicNETNative + + BuildMachineOSBuild + 13F34 + CFBundleDevelopmentRegion + en + CFBundleSupportedPlatforms + + iPhoneOS + + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 12D508 + DTPlatformName + iphoneos + DTPlatformVersion + 8.2 + DTSDKBuild + 12D508 + DTSDKName + iphoneos8.2 + DTXcode + 0620 + DTXcodeBuild + 6C131e + MinimumOSVersion + 8.0 + UIDeviceFamily + + 1 + 2 + + + diff --git a/Build/Scripts/Bootstrap.js b/Build/Scripts/Bootstrap.js index 21831f55fd..eb469e643b 100644 --- a/Build/Scripts/Bootstrap.js +++ b/Build/Scripts/Bootstrap.js @@ -1 +1,61 @@ + +var os = require('os'); + +// Parse args +var options = require('./Minimist')(process.argv.slice(2)); +var cmd = options._[0]; + +// Load `jake` global +require('../node_modules/jake/lib/jake'); + +// Load jake tasks, etc var host = require('./Host'); + +// Make options availabe to host +host.options = options; + +function printHelp() { + + console.log("\nAtomic Editor Build Script") + console.log("--------------------------") + console.log("--help : This help text") + console.log("--with-android : Build with Android platform support"); + console.log("--with-ios : Build with iOS platform support"); + console.log("--debug : Build debug version of the editor and associated platform runtimes") + console.log("--noclean : Do not clean before building, useful during development") + console.log("--nonet : Build without AtomicNET C# scripting support") + console.log("--------------------------") + + process.exit(0); +} + +if (options["help"]) { + printHelp(); +} + +// Atomic Editor Build +if (cmd == "buildeditor") { + + console.log("\n\nBuilding Atomic Editor, this process will take a few minutes\n"); + + var buildTask = jake.Task['build:atomiceditor']; + + if (options["with-android"]) { + + if (!process.env.ANDROID_NDK) { + console.log("\nANDROID_NDK environment variable not set, exiting\n"); + process.exit(1); + } + } + + if (options["with-ios"]) { + + if (os.platform() != "darwin") { + console.log("\niOS platform requires macOS, exiting\n"); + process.exit(1); + } + } + + buildTask.invoke(); + +} diff --git a/Build/Scripts/BuildAndroid.js b/Build/Scripts/BuildAndroid.js index 3390b17b15..89d61f4c1a 100644 --- a/Build/Scripts/BuildAndroid.js +++ b/Build/Scripts/BuildAndroid.js @@ -2,8 +2,8 @@ var fs = require('fs-extra'); var path = require("path"); var host = require("./Host"); var os = require('os'); -var atomicRoot = host.atomicRoot; +var atomicRoot = host.atomicRoot; var buildDir = host.artifactsRoot + "Build/Android/"; namespace('build', function() { @@ -12,34 +12,39 @@ namespace('build', function() { async: true }, function() { - // Clean build - common.cleanCreateDir(buildDir); + var options = host.options; + var cleanBuild = options["noclean"] ? false : true; + var debug = options["debug"] ? true : false; + var config = debug ? "Debug" : "Release"; + + + host.setupDirs(cleanBuild, [buildDir]); process.chdir(buildDir); var cmds = []; if (os.platform() == "win32") { - cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAndroid.bat"); + cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAndroid.bat " + config); } else { - cmds.push("cmake -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=../../../Build/CMake/Toolchains/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release ../../../"); + cmds.push("cmake -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=../../../Build/CMake/Toolchains/android.toolchain.cmake -DCMAKE_BUILD_TYPE=" + config + " ../../../"); cmds.push("make -j4"); } jake.exec(cmds, function() { - var editorAppFolder = host.artifactsRoot + (os.platform() == "win32" ? "AtomicEditor/" : "AtomicEditor/AtomicEditor.app/"); + var editorResourceFolder = host.artifactsRoot + (os.platform() == "win32" ? "AtomicEditor/Resources/" : "AtomicEditor/AtomicEditor.app/Contents/Resources/"); // Install Deployment fs.copySync(buildDir + "Source/AtomicPlayer/Application/libAtomicPlayer.so", - editorAppFolder + "Contents/Resources/ToolData/Deployment/Android/libs/armeabi-v7a/libAtomicPlayer.so"); + editorResourceFolder + "ToolData/Deployment/Android/libs/armeabi-v7a/libAtomicPlayer.so"); complete(); }, { printStdout: true, - breakOnError : false + printStderr: true }); }); diff --git a/Build/Scripts/BuildAtomicNET.js b/Build/Scripts/BuildAtomicNET.js new file mode 100644 index 0000000000..f0c12b0d38 --- /dev/null +++ b/Build/Scripts/BuildAtomicNET.js @@ -0,0 +1,44 @@ +var fs = require('fs-extra'); +var path = require("path"); +var host = require("./Host"); +var os = require('os'); +var atomicRoot = host.atomicRoot; + +namespace('build', function() { + + task('atomicnet', { + async: true + }, function() { + + var options = host.options; + + var android = options["with-android"] ? true : false; + var ios = options["with-ios"] ? true : false; + var debug = options["debug"] ? true : false; + + var cmds = []; + + platforms = "-platform desktop"; + if (android) + platforms += " -platform android"; + if (ios) + platforms += " -platform ios"; + + var netCmd = host.atomicTool + " net compile " + atomicRoot + "Script/AtomicNET/AtomicNETProject.json " + platforms + " -config " + (debug ? "Debug" : "Release"); + + console.log(netCmd); + + cmds.push(netCmd); + + jake.exec(cmds, function() { + + complete(); + + }, { + printStdout: true, + printStderr: true + }); + + }); + +}); // end of build namespace diff --git a/Build/Scripts/BuildIOS.js b/Build/Scripts/BuildIOS.js new file mode 100644 index 0000000000..81e7a07d59 --- /dev/null +++ b/Build/Scripts/BuildIOS.js @@ -0,0 +1,48 @@ +var fs = require('fs-extra'); +var path = require("path"); +var host = require("./Host"); +var os = require('os'); + +var atomicRoot = host.atomicRoot; +var buildDir = host.artifactsRoot + "Build/IOS/"; + +namespace('build', function() { + + task('ios_native', { + async: true + }, function() { + + var options = host.options; + var cleanBuild = options["noclean"] ? false : true; + var debug = options["debug"] ? true : false; + + var NETNativeSrcDir = buildDir + "Source/AtomicNET/NETNative/" + (debug ? "Debug" : "Release") + "-iphoneos/"; + var NETNativeDestDir = host.artifactsRoot + "AtomicNET/" + (debug ? "Debug" : "Release") + "/Native/iOS/"; + + host.setupDirs(cleanBuild, [buildDir, NETNativeDestDir]); + + process.chdir(buildDir); + + var cmds = []; + + cmds.push("cmake -DIOS=1 -DATOMIC_DEV_BUILD=0 -G Xcode ../../../"); + cmds.push("xcodebuild -configuration " + (debug ? "Debug" : "Release") + " -parallelizeTargets -jobs 4"); + //cmds.push("cd \"" + NETNativeSrcDir + "\" && install_name_tool -id @rpath/AtomicNETNative.framework/AtomicNETNative AtomicNETNative.framework/AtomicNETNative"); + //cmds.push("cd \"" + NETNativeSrcDir + "\" && codesign --deep --force --verify --sign \"iPhone Developer\" ./AtomicNETNative.framework/"); + cmds.push("cd \"" + NETNativeSrcDir + "\" && zip -r AtomicNETNative.framework.zip AtomicNETNative.framework"); + + jake.exec(cmds, function() { + + fs.copySync(NETNativeSrcDir + "AtomicNETNative.framework", NETNativeDestDir + "AtomicNETNative.framework"); + fs.copySync(NETNativeSrcDir + "AtomicNETNative.framework.zip", NETNativeDestDir + "AtomicNETNative.framework.zip"); + + complete(); + + }, { + printStdout: true, + printStderr: true + }); + + }); + +}); // end of build namespace diff --git a/Build/Scripts/BuildLinux.js b/Build/Scripts/BuildLinux.js index 39bc470c0b..16f378589c 100755 --- a/Build/Scripts/BuildLinux.js +++ b/Build/Scripts/BuildLinux.js @@ -1,106 +1,169 @@ var fs = require('fs-extra'); var path = require("path"); -var spawnSync = require('child_process').spawnSync var host = require("./Host"); -var atomicRoot = host.atomicRoot; +var spawnSync = require('child_process').spawnSync +var atomicRoot = host.atomicRoot; var buildDir = host.artifactsRoot + "Build/Linux/"; var editorAppFolder = host.artifactsRoot + "AtomicEditor/"; -namespace('build', function() { +var buildAtomicNET = false; +var debug = false; +var config = "Release"; - // Builds a standalone Atomic Editor, which can be distributed out of build tree - task('atomiceditor', { - async: true - }, function() { +function copyAtomicNET() { - // Clean build - var cleanBuild = true; - if (cleanBuild) { - common.cleanCreateDir(buildDir); - common.cleanCreateDir(editorAppFolder); - common.cleanCreateDir(host.getGenScriptRootDir("LINUX")); - } + if (!buildAtomicNET) + return; - var buildAtomicNET = false; + fs.copySync(atomicRoot + "Artifacts/AtomicNET/" + config, + editorAppFolder + "Resources/ToolData/AtomicNET/" + config); - // TODO: build box has old node - if (spawnSync) - buildAtomicNET = spawnSync("which", ["xbuild"]).status == 1 ? false : true; + fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json", + editorAppFolder + "Resources/ToolData/AtomicNET/Build/Projects/AtomicProject.json"); + +} + +function copyAtomicEditor() { + + // Copy the Editor binaries + fs.copySync(buildDir + "Source/AtomicEditor/AtomicEditor", + host.artifactsRoot + "AtomicEditor/AtomicEditor"); + + // We need some resources to run + fs.copySync(atomicRoot + "Resources/CoreData", + editorAppFolder + "Resources/CoreData"); + + fs.copySync(atomicRoot + "Resources/PlayerData", + editorAppFolder + "Resources/PlayerData"); + + fs.copySync(atomicRoot + "Data/AtomicEditor", + editorAppFolder + "Resources/ToolData"); + + fs.copySync(atomicRoot + "Resources/EditorData", + editorAppFolder + "Resources/EditorData"); + + fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts", + editorAppFolder + "Resources/EditorData/AtomicEditor/EditorScripts"); + + fs.copySync(buildDir + "Source/AtomicPlayer/Application/AtomicPlayer", + editorAppFolder + "Resources/ToolData/Deployment/Linux/AtomicPlayer"); + + var binaryFiles = ["chrome-sandbox", "libcef.so", "natives_blob.bin", "snapshot_blob.bin"]; + + var resourceFiles = ["cef.pak", + "cef_100_percent.pak", + "cef_200_percent.pak", + "cef_extensions.pak", + "devtools_resources.pak", + "icudtl.dat", + "locales"]; + + for (var i = 0; i < binaryFiles.length; i++) { + fs.copySync(atomicRoot + "Submodules/CEF/Linux/Release/" + binaryFiles[i], editorAppFolder+"/" + binaryFiles[i]); + } + + for (var i = 0; i < resourceFiles.length; i++) { + fs.copySync(atomicRoot + "Submodules/CEF/Linux/Resources/" + resourceFiles[i], editorAppFolder+"/" + resourceFiles[i]); + } + + + if (buildAtomicNET) { + copyAtomicNET(); + } + +} + +namespace('build', function() { + + task('atomiceditor_phase2', { + async: true + }, function() { process.chdir(buildDir); var cmds = []; + cmds.push("make AtomicEditor AtomicPlayer -j2") - cmds.push("cmake ../../../ -DATOMIC_DEV_BUILD=0 -DCMAKE_BUILD_TYPE=Release"); - cmds.push("make -j2") + jake.exec(cmds, function() { - if (buildAtomicNET) - cmds.push(host.atomicTool + " net compile " + atomicRoot + "Script/AtomicNET/AtomicNETProject.json LINUX Release"); + copyAtomicEditor(); - jake.exec(cmds, function() { + complete(); - // Copy the Editor binaries - fs.copySync(buildDir + "Source/AtomicEditor/AtomicEditor", - host.artifactsRoot + "AtomicEditor/AtomicEditor"); + }, { + printStdout: true + }); - // We need some resources to run - fs.copySync(atomicRoot + "Resources/CoreData", - editorAppFolder + "Resources/CoreData"); + }); + // Builds a standalone Atomic Editor, which can be distributed out of build tree + task('atomiceditor', { + async: true + }, function() { - fs.copySync(atomicRoot + "Resources/PlayerData", - editorAppFolder + "Resources/PlayerData"); + var options = host.options; - fs.copySync(atomicRoot + "Data/AtomicEditor", - editorAppFolder + "Resources/ToolData"); + var android = options["with-android"] ? true : false; + var cleanBuild = options["noclean"] ? false : true; + debug = options["debug"] ? true : false; + config = debug ? "Debug" : "Release"; - fs.copySync(atomicRoot + "Resources/EditorData", - editorAppFolder + "Resources/EditorData"); + var createDirs = []; + var removeDirs = []; - fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts", - editorAppFolder + "Resources/EditorData/AtomicEditor/EditorScripts"); + // We clean atomicNET here as otherwise platform binaries would be deleted + createDirs.push(host.artifactsRoot + "AtomicNET/"); + createDirs.push(buildDir); + createDirs.push(editorAppFolder); + createDirs.push(host.getGenScriptRootDir()); - fs.copySync(buildDir + "Source/AtomicPlayer/Application/AtomicPlayer", - editorAppFolder + "Resources/ToolData/Deployment/Linux/AtomicPlayer"); + removeDirs.push(host.artifactsRoot + "Build/Android/"); - // AtomicNET + host.setupDirs(cleanBuild, createDirs, removeDirs); - if (buildAtomicNET) { + // TODO: build box has old node + if (spawnSync) + buildAtomicNET = spawnSync("which", ["xbuild"]).status == 1 ? false : true; - fs.copySync(atomicRoot + "Artifacts/AtomicNET/Release", - editorAppFolder + "Resources/ToolData/AtomicNET/Release"); + process.chdir(buildDir); - fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json", - editorAppFolder + "Resources/ToolData/AtomicNET/Build/Projects/AtomicProject.json"); - } + var cmds = []; - var binaryFiles = ["chrome-sandbox", "libcef.so", "natives_blob.bin", "snapshot_blob.bin"]; + // Generate Atomic solution, AtomicTool binary, and script bindings + cmds.push("cmake ../../../ -DATOMIC_DEV_BUILD=0 -DCMAKE_BUILD_TYPE=" + config); + cmds.push("make AtomicNETNative -j2") - var resourceFiles = ["cef.pak", - "cef_100_percent.pak", - "cef_200_percent.pak", - "cef_extensions.pak", - "devtools_resources.pak", - "icudtl.dat", - "locales"]; + jake.exec(cmds, function() { + + var rootTask = jake.Task['build:atomiceditor_phase2']; + var task = rootTask; - for (var i = 0; i < binaryFiles.length; i++) { - fs.copySync(atomicRoot + "Submodules/CEF/Linux/Release/" + binaryFiles[i], editorAppFolder+"/" + binaryFiles[i]); + // add optional build components in reverse order + if (buildAtomicNET) { + var netTask = jake.Task['build:atomicnet']; + task.prereqs.push("build:atomicnet") + task = netTask; } - for (var i = 0; i < resourceFiles.length; i++) { - fs.copySync(atomicRoot + "Submodules/CEF/Linux/Resources/" + resourceFiles[i], editorAppFolder+"/" + resourceFiles[i]); + if (android) { + var androidTask = jake.Task['build:android_native']; + task.prereqs.push("build:android_native") + task = androidTask; } + rootTask.addListener('complete', function () { + console.log("\n\nAtomic Editor built to " + editorAppFolder + "\n\n"); + complete(); + }); - console.log("\n\nAtomic Editor build to " + editorAppFolder + "\n\n"); - - complete(); + rootTask.invoke(); }, { - printStdout: true + printStdout: true, + printStderr: true }); }); -}); + +});// end of build namespace diff --git a/Build/Scripts/BuildMac.js b/Build/Scripts/BuildMac.js index 0ccfd88518..f8009f477b 100644 --- a/Build/Scripts/BuildMac.js +++ b/Build/Scripts/BuildMac.js @@ -2,102 +2,156 @@ var fs = require('fs-extra'); var path = require("path"); var spawnSync = require('child_process').spawnSync var host = require("./Host"); -var atomicRoot = host.atomicRoot; +var atomicRoot = host.atomicRoot; var buildDir = host.artifactsRoot + "Build/Mac/"; var editorAppFolder = host.artifactsRoot + "/AtomicEditor/AtomicEditor.app/"; var resourceDest = editorAppFolder + "/Contents/Resources/" -namespace('build', function() { +var buildAtomicNET = false; +var debug = false; +var config = "Release"; - // Builds a standalone Atomic Editor, which can be distributed out of build tree - task('atomiceditor', { - async: true - }, function(android) { +function copyAtomicNET() { - android = android == "android" ? true : false; + if (!buildAtomicNET) + return; - // Clean build - var cleanBuild = true; - if (cleanBuild) { - common.cleanCreateDir(host.artifactsRoot + "AtomicNET/"); - common.cleanCreateDir(buildDir); - common.cleanCreateDir(editorAppFolder); - common.cleanCreateDir(host.getGenScriptRootDir()); - } + fs.copySync(atomicRoot + "Artifacts/AtomicNET/" + config, + resourceDest + "ToolData/AtomicNET/" + config); - var buildAtomicNET = spawnSync("which", ["xbuild"]).status == 1 ? false : true; + fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json", + resourceDest + "ToolData/AtomicNET/Build/Projects/AtomicProject.json"); - process.chdir(buildDir); +} - var cmds = []; +function copyAtomicEditor() { - cmds.push("cmake ../../../ -DATOMIC_DEV_BUILD=0 -G Xcode"); - cmds.push("xcodebuild -target AtomicEditor -target AtomicPlayer -target AtomicNETNative -configuration Release -parallelizeTargets -jobs 4") + fs.copySync(buildDir + "Source/AtomicEditor/" + config + "/AtomicEditor.app", editorAppFolder); - if (buildAtomicNET) - cmds.push(host.atomicTool + " net compile " + atomicRoot + "Script/AtomicNET/AtomicNETProject.json " + (android ? "ANDROID" : "WINDOWS") + " Release"); + // We need some resources to run + fs.copySync(atomicRoot + "Resources/CoreData", + resourceDest + "CoreData"); - function copyAtomicNET() { + fs.copySync(atomicRoot + "Resources/PlayerData", + resourceDest + "PlayerData"); - if (!buildAtomicNET) - return; + fs.copySync(atomicRoot + "Data/AtomicEditor", + resourceDest + "ToolData"); - fs.copySync(atomicRoot + "Artifacts/AtomicNET/Release", - resourceDest + "ToolData/AtomicNET/Release"); + fs.copySync(atomicRoot + "Resources/EditorData", + resourceDest + "EditorData"); - fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json", - resourceDest + "ToolData/AtomicNET/Build/Projects/AtomicProject.json"); + fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts", + resourceDest + "EditorData/AtomicEditor/EditorScripts"); - } + // copy the mac player binary to deployment + var playerBinary = buildDir + "Source/AtomicPlayer/Application/" + config + "/AtomicPlayer.app/Contents/MacOS/AtomicPlayer"; + + fs.copySync(playerBinary, resourceDest + "ToolData/Deployment/MacOS/AtomicPlayer.app/Contents/MacOS/AtomicPlayer"); + + if (buildAtomicNET) { + copyAtomicNET(); + } +} + +namespace('build', function() { + + task('atomiceditor_phase2', { + async: true + }, function() { + + process.chdir(buildDir); + + var cmds = []; + cmds.push("xcodebuild -target AtomicEditor -target AtomicPlayer -configuration " + config + " -parallelizeTargets -jobs 4") jake.exec(cmds, function() { - fs.copySync(buildDir + "Source/AtomicEditor/Release/AtomicEditor.app", editorAppFolder); + copyAtomicEditor(); + + complete(); + + }, { + printStdout: true + }); + + }); - // We need some resources to run - fs.copySync(atomicRoot + "Resources/CoreData", - resourceDest + "CoreData"); + // Builds a standalone Atomic Editor, which can be distributed out of build tree + task('atomiceditor', { + async: true + }, function() { - fs.copySync(atomicRoot + "Resources/PlayerData", - resourceDest + "PlayerData"); + var options = host.options; - fs.copySync(atomicRoot + "Data/AtomicEditor", - resourceDest + "ToolData"); + var android = options["with-android"] ? true : false; + var ios = options["with-ios"] ? true : false; + var cleanBuild = options["noclean"] ? false : true; + debug = options["debug"] ? true : false; + config = debug ? "Debug" : "Release"; - fs.copySync(atomicRoot + "Resources/EditorData", - resourceDest + "EditorData"); + var createDirs = []; + var removeDirs = []; - fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts", - resourceDest + "EditorData/AtomicEditor/EditorScripts"); + // We clean atomicNET here as otherwise platform binaries would be deleted + createDirs.push(host.artifactsRoot + "AtomicNET/"); + createDirs.push(buildDir); + createDirs.push(editorAppFolder); + createDirs.push(host.getGenScriptRootDir()); - // copy the mac player binary to deployment - var playerBinary = buildDir + "Source/AtomicPlayer/Application/Release/AtomicPlayer.app/Contents/MacOS/AtomicPlayer"; + removeDirs.push(host.artifactsRoot + "Build/Android/"); + removeDirs.push(host.artifactsRoot + "Build/IOS/"); - fs.copySync(playerBinary, resourceDest + "ToolData/Deployment/MacOS/AtomicPlayer.app/Contents/MacOS/AtomicPlayer"); + host.setupDirs(cleanBuild, createDirs, removeDirs); - if (android) { + if (!options["nonet"]) { + buildAtomicNET = spawnSync("which", ["xbuild"]).status == 1 ? false : true; + } + + process.chdir(buildDir); + + var cmds = []; - var androidNativeTask = jake.Task['build:android_native']; + // Generate XCode project, AtomicTool binary, and script bindings + cmds.push("cmake ../../../ -DATOMIC_DEV_BUILD=0 -G Xcode"); + cmds.push("xcodebuild -target GenerateScriptBindings -target AtomicNETNative -configuration " + config + " -parallelizeTargets -jobs 4") - androidNativeTask.addListener('complete', function () { - copyAtomicNET(); - console.log("\n\nAtomic Editor build to " + editorAppFolder + "\n\n"); - complete(); - }); + jake.exec(cmds, function() { - androidNativeTask.invoke(); + var rootTask = jake.Task['build:atomiceditor_phase2']; + var task = rootTask; + // add optional build components in reverse order + if (buildAtomicNET) { + var netTask = jake.Task['build:atomicnet']; + task.prereqs.push("build:atomicnet") + task = netTask; } - else { - copyAtomicNET(); - console.log("\n\nAtomic Editor build to " + editorAppFolder + "\n\n"); - complete(); + + if (ios) { + var iosTask = jake.Task['build:ios_native']; + task.prereqs.push("build:ios_native") + task = iosTask; } + if (android) { + var androidTask = jake.Task['build:android_native']; + task.prereqs.push("build:android_native") + task = androidTask; + } + + rootTask.addListener('complete', function () { + console.log("\n\nAtomic Editor built to " + editorAppFolder + "\n\n"); + complete(); + }); + + rootTask.invoke(); + }, { - printStdout: true + printStdout: true, + printStderr: true }); }); @@ -124,7 +178,8 @@ namespace('build', function() { complete(); }, { - printStdout: true + printStdout: true, + printStderr: true }); }); diff --git a/Build/Scripts/BuildWindows.js b/Build/Scripts/BuildWindows.js index 07daec2f27..724eaa2166 100644 --- a/Build/Scripts/BuildWindows.js +++ b/Build/Scripts/BuildWindows.js @@ -1,96 +1,144 @@ var fs = require('fs-extra'); var path = require("path"); var host = require("./Host"); -var atomicRoot = host.atomicRoot; +var atomicRoot = host.atomicRoot; var buildDir = host.artifactsRoot + "Build/Windows/"; var editorAppFolder = host.artifactsRoot + "AtomicEditor/"; -namespace('build', function() { +var buildAtomicNET = true; +var debug = false; +var config = "Release"; - // Builds a standalone Atomic Editor, which can be distributed out of build tree - task('atomiceditor', { - async: true - }, function(android) { +function copyAtomicNET() { - android = android == "android" ? true : false; + if (!buildAtomicNET) + return; - // Clean build - var cleanBuild = true; - if (cleanBuild) { - common.cleanCreateDir(host.artifactsRoot + "AtomicNET/"); - common.cleanCreateDir(buildDir); - common.cleanCreateDir(editorAppFolder); - common.cleanCreateDir(host.getGenScriptRootDir()); - } + fs.copySync(atomicRoot + "Artifacts/AtomicNET/" + config, + editorAppFolder + "Resources/ToolData/AtomicNET/" + config); - process.chdir(buildDir); + fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json", + editorAppFolder + "Resources/ToolData/AtomicNET/Build/Projects/AtomicProject.json"); - var cmds = []; +} - // Build the AtomicEditor - cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAtomicEditor.bat"); - cmds.push(host.atomicTool + " net compile " + atomicRoot + "Script/AtomicNET/AtomicNETProject.json " + (android ? "ANDROID" : "WINDOWS") + " Release"); +function copyAtomicEditor() { - function copyAtomicNET() { + // Copy the Editor binaries + fs.copySync(buildDir + "Source/AtomicEditor/" + config, + host.artifactsRoot + "AtomicEditor"); - fs.copySync(atomicRoot + "Artifacts/AtomicNET/Release", - editorAppFolder + "Resources/ToolData/AtomicNET/Release"); + // We need some resources to run + fs.copySync(atomicRoot + "Resources/CoreData", + editorAppFolder + "Resources/CoreData"); - fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json", - editorAppFolder + "Resources/ToolData/AtomicNET/Build/Projects/AtomicProject.json"); + fs.copySync(atomicRoot + "Resources/PlayerData", + editorAppFolder + "Resources/PlayerData"); - } + fs.copySync(atomicRoot + "Data/AtomicEditor", + editorAppFolder + "Resources/ToolData"); + + fs.copySync(atomicRoot + "Resources/EditorData", + editorAppFolder + "Resources/EditorData"); + + fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts", + editorAppFolder + "Resources/EditorData/AtomicEditor/EditorScripts"); + + fs.copySync(buildDir + "Source/AtomicPlayer/Application/" + config +"/AtomicPlayer.exe", + editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/AtomicPlayer.exe"); + + fs.copySync(buildDir + "Source/AtomicPlayer/Application/" + config + "/D3DCompiler_47.dll", + editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/D3DCompiler_47.dll"); + + if (buildAtomicNET) { + copyAtomicNET(); + } + +} + +namespace('build', function() { + + task('atomiceditor_phase2', { + async: true + }, function() { + + process.chdir(buildDir); + + var cmds = []; + cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAtomicEditorPhase2.bat " + config); jake.exec(cmds, function() { - // Copy the Editor binaries - fs.copySync(buildDir + "Source/AtomicEditor/Release", - host.artifactsRoot + "AtomicEditor"); + copyAtomicEditor(); - // We need some resources to run - fs.copySync(atomicRoot + "Resources/CoreData", - editorAppFolder + "Resources/CoreData"); + complete(); + + }, { + printStdout: true + }); - fs.copySync(atomicRoot + "Resources/PlayerData", - editorAppFolder + "Resources/PlayerData"); + }); + // Builds a standalone Atomic Editor, which can be distributed out of build tree + task('atomiceditor', { + async: true + }, function() { - fs.copySync(atomicRoot + "Data/AtomicEditor", - editorAppFolder + "Resources/ToolData"); + var options = host.options; - fs.copySync(atomicRoot + "Resources/EditorData", - editorAppFolder + "Resources/EditorData"); + var android = options["with-android"] ? true : false; + var cleanBuild = options["noclean"] ? false : true; + debug = options["debug"] ? true : false; + config = debug ? "Debug" : "Release"; - fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts", - editorAppFolder + "Resources/EditorData/AtomicEditor/EditorScripts"); + var createDirs = []; + var removeDirs = []; - fs.copySync(buildDir + "Source/AtomicPlayer/Application/Release/AtomicPlayer.exe", - editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/AtomicPlayer.exe"); + // We clean atomicNET here as otherwise platform binaries would be deleted + createDirs.push(host.artifactsRoot + "AtomicNET/"); + createDirs.push(buildDir); + createDirs.push(editorAppFolder); + createDirs.push(host.getGenScriptRootDir()); - fs.copySync(buildDir + "Source/AtomicPlayer/Application/Release/D3DCompiler_47.dll", - editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/D3DCompiler_47.dll"); + removeDirs.push(host.artifactsRoot + "Build/Android/"); - if (android) { + host.setupDirs(cleanBuild, createDirs, removeDirs); - var androidNativeTask = jake.Task['build:android_native']; + process.chdir(buildDir); - androidNativeTask.addListener('complete', function () { - copyAtomicNET(); - console.log("\nAtomic Editor build to ", editorAppFolder); - complete(); - }); + var cmds = []; - androidNativeTask.invoke(); + // Generate Atomic solution, AtomicTool binary, and script bindings + cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAtomicEditorPhase1.bat " + config); + jake.exec(cmds, function() { + + var rootTask = jake.Task['build:atomiceditor_phase2']; + var task = rootTask; + + // add optional build components in reverse order + if (buildAtomicNET) { + var netTask = jake.Task['build:atomicnet']; + task.prereqs.push("build:atomicnet") + task = netTask; } - else { - copyAtomicNET(); - console.log("\nAtomic Editor build to ", editorAppFolder); - complete(); + + if (android) { + var androidTask = jake.Task['build:android_native']; + task.prereqs.push("build:android_native") + task = androidTask; } + rootTask.addListener('complete', function () { + console.log("\n\nAtomic Editor built to " + editorAppFolder + "\n\n"); + complete(); + }); + + rootTask.invoke(); + }, { - printStdout: true + printStdout: true, + printStderr: true }); }); @@ -124,4 +172,5 @@ namespace('build', function() { }); -}); // end of build namespace + +});// end of build namespace diff --git a/Build/Scripts/Host.js b/Build/Scripts/Host.js index 6c2a0e521d..7d23ae00ec 100644 --- a/Build/Scripts/Host.js +++ b/Build/Scripts/Host.js @@ -13,4 +13,6 @@ if (os.platform() == "win32") { require("./BuildCommon"); require("./BuildAndroid"); +require("./BuildIOS"); require("./BuildWeb"); +require("./BuildAtomicNET"); diff --git a/Build/Scripts/HostCommon.js b/Build/Scripts/HostCommon.js index ed18543694..313ba5e4bf 100644 --- a/Build/Scripts/HostCommon.js +++ b/Build/Scripts/HostCommon.js @@ -138,6 +138,29 @@ function testCreateDir(directory) { } } +function setupDirs(clean, createDirs, removeDirs) { + + if (createDirs) { + for (var i = 0; i < createDirs.length; i++) { + + var path = createDirs[i]; + if (!fs.existsSync(path) || clean) { + cleanCreateDir(path); + } + } + } + + if (removeDirs) { + for (var i = 0; i < removeDirs.length; i++) { + + var path = removeDirs[i]; + if (fs.existsSync(path) && clean) { + testRemoveDir(path); + } + } + } + +} function testRemoveDir(path) { @@ -160,3 +183,4 @@ exports.getScriptModules = getScriptModules; exports.getGenScriptFilenames = getGenScriptFilenames; exports.createGenScriptFiles = createGenScriptFiles; exports.getGenScriptRootDir = getGenScriptRootDir; +exports.setupDirs = setupDirs; diff --git a/Build/Scripts/Minimist.js b/Build/Scripts/Minimist.js new file mode 100644 index 0000000000..e06783fb1c --- /dev/null +++ b/Build/Scripts/Minimist.js @@ -0,0 +1,235 @@ +module.exports = function (args, opts) { + if (!opts) opts = {}; + + var flags = { bools : {}, strings : {}, unknownFn: null }; + + if (typeof opts['unknown'] === 'function') { + flags.unknownFn = opts['unknown']; + } + + if (typeof opts['boolean'] === 'boolean' && opts['boolean']) { + flags.allBools = true; + } else { + [].concat(opts['boolean']).filter(Boolean).forEach(function (key) { + flags.bools[key] = true; + }); + } + + var aliases = {}; + Object.keys(opts.alias || {}).forEach(function (key) { + aliases[key] = [].concat(opts.alias[key]); + aliases[key].forEach(function (x) { + aliases[x] = [key].concat(aliases[key].filter(function (y) { + return x !== y; + })); + }); + }); + + [].concat(opts.string).filter(Boolean).forEach(function (key) { + flags.strings[key] = true; + if (aliases[key]) { + flags.strings[aliases[key]] = true; + } + }); + + var defaults = opts['default'] || {}; + + var argv = { _ : [] }; + Object.keys(flags.bools).forEach(function (key) { + setArg(key, defaults[key] === undefined ? false : defaults[key]); + }); + + var notFlags = []; + + if (args.indexOf('--') !== -1) { + notFlags = args.slice(args.indexOf('--')+1); + args = args.slice(0, args.indexOf('--')); + } + + function argDefined(key, arg) { + return (flags.allBools && /^--[^=]+$/.test(arg)) || + flags.strings[key] || flags.bools[key] || aliases[key]; + } + + function setArg (key, val, arg) { + if (arg && flags.unknownFn && !argDefined(key, arg)) { + if (flags.unknownFn(arg) === false) return; + } + + var value = !flags.strings[key] && isNumber(val) + ? Number(val) : val + ; + setKey(argv, key.split('.'), value); + + (aliases[key] || []).forEach(function (x) { + setKey(argv, x.split('.'), value); + }); + } + + function setKey (obj, keys, value) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + if (o[key] === undefined) o[key] = {}; + o = o[key]; + }); + + var key = keys[keys.length - 1]; + if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { + o[key] = value; + } + else if (Array.isArray(o[key])) { + o[key].push(value); + } + else { + o[key] = [ o[key], value ]; + } + } + + function aliasIsBoolean(key) { + return aliases[key].some(function (x) { + return flags.bools[x]; + }); + } + + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + if (/^--.+=/.test(arg)) { + // Using [\s\S] instead of . because js doesn't support the + // 'dotall' regex modifier. See: + // http://stackoverflow.com/a/1068308/13216 + var m = arg.match(/^--([^=]+)=([\s\S]*)$/); + var key = m[1]; + var value = m[2]; + if (flags.bools[key]) { + value = value !== 'false'; + } + setArg(key, value, arg); + } + else if (/^--no-.+/.test(arg)) { + var key = arg.match(/^--no-(.+)/)[1]; + setArg(key, false, arg); + } + else if (/^--.+/.test(arg)) { + var key = arg.match(/^--(.+)/)[1]; + var next = args[i + 1]; + if (next !== undefined && !/^-/.test(next) + && !flags.bools[key] + && !flags.allBools + && (aliases[key] ? !aliasIsBoolean(key) : true)) { + setArg(key, next, arg); + i++; + } + else if (/^(true|false)$/.test(next)) { + setArg(key, next === 'true', arg); + i++; + } + else { + setArg(key, flags.strings[key] ? '' : true, arg); + } + } + else if (/^-[^-]+/.test(arg)) { + var letters = arg.slice(1,-1).split(''); + + var broken = false; + for (var j = 0; j < letters.length; j++) { + var next = arg.slice(j+2); + + if (next === '-') { + setArg(letters[j], next, arg) + continue; + } + + if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) { + setArg(letters[j], next.split('=')[1], arg); + broken = true; + break; + } + + if (/[A-Za-z]/.test(letters[j]) + && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { + setArg(letters[j], next, arg); + broken = true; + break; + } + + if (letters[j+1] && letters[j+1].match(/\W/)) { + setArg(letters[j], arg.slice(j+2), arg); + broken = true; + break; + } + else { + setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg); + } + } + + var key = arg.slice(-1)[0]; + if (!broken && key !== '-') { + if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1]) + && !flags.bools[key] + && (aliases[key] ? !aliasIsBoolean(key) : true)) { + setArg(key, args[i+1], arg); + i++; + } + else if (args[i+1] && /true|false/.test(args[i+1])) { + setArg(key, args[i+1] === 'true', arg); + i++; + } + else { + setArg(key, flags.strings[key] ? '' : true, arg); + } + } + } + else { + if (!flags.unknownFn || flags.unknownFn(arg) !== false) { + argv._.push( + flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) + ); + } + if (opts.stopEarly) { + argv._.push.apply(argv._, args.slice(i + 1)); + break; + } + } + } + + Object.keys(defaults).forEach(function (key) { + if (!hasKey(argv, key.split('.'))) { + setKey(argv, key.split('.'), defaults[key]); + + (aliases[key] || []).forEach(function (x) { + setKey(argv, x.split('.'), defaults[key]); + }); + } + }); + + if (opts['--']) { + argv['--'] = new Array(); + notFlags.forEach(function(key) { + argv['--'].push(key); + }); + } + else { + notFlags.forEach(function(key) { + argv._.push(key); + }); + } + + return argv; +}; + +function hasKey (obj, keys) { + var o = obj; + keys.slice(0,-1).forEach(function (key) { + o = (o[key] || {}); + }); + + var key = keys[keys.length - 1]; + return key in o; +} + +function isNumber (x) { + if (typeof x === 'number') return true; + if (/^0x[0-9a-f]+$/i.test(x)) return true; + return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); +} diff --git a/Build/Scripts/Windows/CompileAndroid.bat b/Build/Scripts/Windows/CompileAndroid.bat index c88d8f2dd2..8fd0a6c414 100644 --- a/Build/Scripts/Windows/CompileAndroid.bat +++ b/Build/Scripts/Windows/CompileAndroid.bat @@ -1,3 +1,3 @@ SET PATH=%ANDROID_NDK%\prebuilt\windows\bin\;%PATH% -cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../../../Build/CMake/Toolchains/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release ../../../ +cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../../../Build/CMake/Toolchains/android.toolchain.cmake -DCMAKE_BUILD_TYPE=%1 ../../../ %ANDROID_NDK%\prebuilt\windows\bin\make.exe -j4 diff --git a/Build/Scripts/Windows/CompileAtomicEditorPhase1.bat b/Build/Scripts/Windows/CompileAtomicEditorPhase1.bat new file mode 100644 index 0000000000..bf4aa8907f --- /dev/null +++ b/Build/Scripts/Windows/CompileAtomicEditorPhase1.bat @@ -0,0 +1,3 @@ +call "%VS140COMNTOOLS%..\..\VC\bin\amd64\vcvars64.bat" +cmake ..\\..\\..\\ -DATOMIC_DEV_BUILD=0 -G "Visual Studio 14 2015 Win64" +msbuild /m Atomic.sln /t:AtomicNETNative /p:Configuration=%1 /p:Platform=x64 diff --git a/Build/Scripts/Windows/CompileAtomicEditorPhase2.bat b/Build/Scripts/Windows/CompileAtomicEditorPhase2.bat new file mode 100644 index 0000000000..e647f96512 --- /dev/null +++ b/Build/Scripts/Windows/CompileAtomicEditorPhase2.bat @@ -0,0 +1,2 @@ +call "%VS140COMNTOOLS%..\..\VC\bin\amd64\vcvars64.bat" +msbuild /m Atomic.sln /t:AtomicEditor /t:AtomicPlayer /p:Configuration=%1 /p:Platform=x64 diff --git a/Build_AtomicEditor.bat b/Build_AtomicEditor.bat index ef81fac815..e0ecd687bb 100644 --- a/Build_AtomicEditor.bat +++ b/Build_AtomicEditor.bat @@ -1,37 +1,2 @@ @echo OFF -setlocal enabledelayedexpansion - -set ATOMICEDITOR_BUILD_CMD=Build\Windows\node\node.exe Build\node_modules\jake\bin\cli.js -f ./Build/Scripts/Bootstrap.js build:atomiceditor - -for %%a in (%*) do ( - if /I "%%a"=="--with-android" (set ATOMICEDITOR_ANDROID=YES) -) - -:: If we're building in android support, make sure ANDROID_NDK is defined -if "%ATOMICEDITOR_ANDROID%" == "YES" ( - - if "%ANDROID_NDK%" == "" ( - @echo: - echo ANDROID_NDK not set, exiting - @echo: - exit /B - ) - - @echo: - echo Building Atomic Editor with Android support - @echo: - set ATOMICEDITOR_BUILD_CMD=!ATOMICEDITOR_BUILD_CMD![android] -) - -@echo: -@echo: -ECHO Building Atomic Editor, this process will take a few minutes -@echo: -@echo: -PAUSE -%ATOMICEDITOR_BUILD_CMD% -@echo: -@echo: -PAUSE - -endlocal +Build\Windows\node\node.exe ./Build/Scripts/Bootstrap.js buildeditor %* diff --git a/Build_AtomicEditor.sh b/Build_AtomicEditor.sh index 7a92db3e46..edca5ae51e 100755 --- a/Build_AtomicEditor.sh +++ b/Build_AtomicEditor.sh @@ -1,23 +1,9 @@ #!/usr/bin/env sh -buildcmd="build:atomiceditor" - -for var in "$@" -do - if [ $var == "--with-android" ]; then - if [ "$ANDROID_NDK" == "" ]; then - echo "\n\nANDROID_NDK environment variable not set, exiting\n\n" - exit 1 - fi - echo "\n\nBuilding Atomic Editor with Android support\n\n" - buildcmd+="[android]" - fi -done - if [ "$(uname)" = "Darwin" ]; then - ./Build/Mac/node/node ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js $buildcmd + ./Build/Mac/node/node ./Build/Scripts/Bootstrap.js buildeditor "$@" elif [ "$(expr substr $(uname -s) 1 5)" = "Linux" ]; then - ./Build/Linux/node/node ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js $buildcmd + ./Build/Linux/node/node ./Build/Scripts/Bootstrap.js buildeditor "$@" elif [ "$(expr substr $(uname -s) 1 7)" = "MSYS_NT" ]; then - ./Build/Windows/node/node.exe ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js $buildcmd + ./Build/Windows/node/node.exe ./Build/Scripts/Bootstrap.js buildeditor "$@" fi diff --git a/Script/AtomicNET/AtomicNET/Application/Application.cs b/Script/AtomicNET/AtomicNET/Application/Application.cs index 9a59d7b3e4..5dc45b4be5 100644 --- a/Script/AtomicNET/AtomicNET/Application/Application.cs +++ b/Script/AtomicNET/AtomicNET/Application/Application.cs @@ -28,7 +28,14 @@ public static int Run(Type appDelegateType, string[] args) app = NETIPCPlayerApp.Create(args); #endif -#if ATOMIC_ANDROID +#if ATOMIC_IOS + // On iOS, we need to set main ready as main() isn't being called + SDLEvents.SetMainReady(); +#endif + + +#if ATOMIC_ANDROID || ATOMIC_IOS + app = NETAtomicPlayer.Create(args); var renderer = AtomicNET.GetSubsystem(); diff --git a/Script/AtomicNET/AtomicNET/Core/AtomicNET.cs b/Script/AtomicNET/AtomicNET/Core/AtomicNET.cs index f5ee5612cb..15b8fe3471 100644 --- a/Script/AtomicNET/AtomicNET/Core/AtomicNET.cs +++ b/Script/AtomicNET/AtomicNET/Core/AtomicNET.cs @@ -77,11 +77,7 @@ public static void Initialize() PlayerModule.Initialize(); - coreDelegates = new CoreDelegates(); - coreDelegates.eventDispatch = NativeCore.EventDispatch; - coreDelegates.updateDispatch = NativeCore.UpdateDispatch; - - IntPtr coreptr = csi_Atomic_NETCore_Initialize(ref coreDelegates); + IntPtr coreptr = csi_Atomic_NETCore_Initialize(NativeCore.EventDispatch, NativeCore.UpdateDispatch); NETCore core = (coreptr == IntPtr.Zero ? null : NativeCore.WrapNative(coreptr)); @@ -102,10 +98,9 @@ public static void Initialize() } [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] - private static extern IntPtr csi_Atomic_NETCore_Initialize(ref CoreDelegates delegates); + private static extern IntPtr csi_Atomic_NETCore_Initialize(EventDispatchDelegate eventDispatch, UpdateDispatchDelegate updateDispatch); private static Context context; - private static CoreDelegates coreDelegates; private static Dictionary subSystems = new Dictionary(); } diff --git a/Script/AtomicNET/AtomicNET/Core/Constants.cs b/Script/AtomicNET/AtomicNET/Core/Constants.cs index dd017905bd..f86c1cbbbd 100644 --- a/Script/AtomicNET/AtomicNET/Core/Constants.cs +++ b/Script/AtomicNET/AtomicNET/Core/Constants.cs @@ -4,7 +4,9 @@ namespace AtomicEngine public static partial class Constants { -#if __MonoCS__ +#if ATOMIC_IOS + public const string LIBNAME = "@rpath/AtomicNETNative.framework/AtomicNETNative"; +#elif __MonoCS__ public const string LIBNAME = "AtomicNETNative"; #else public const string LIBNAME = "AtomicNETNative.dll"; diff --git a/Script/AtomicNET/AtomicNET/Core/NativeCore.cs b/Script/AtomicNET/AtomicNET/Core/NativeCore.cs index e346603352..4501730e71 100644 --- a/Script/AtomicNET/AtomicNET/Core/NativeCore.cs +++ b/Script/AtomicNET/AtomicNET/Core/NativeCore.cs @@ -5,9 +5,19 @@ using System.Linq; using static System.Reflection.IntrospectionExtensions; +#if ATOMIC_IOS +using ObjCRuntime; +#endif + namespace AtomicEngine { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void EventDispatchDelegate(IntPtr sender, uint eventType, IntPtr eventData); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void UpdateDispatchDelegate(float timeStep); + public class NativeType { @@ -124,6 +134,26 @@ internal static void Initialize() svm[i] = new ScriptVariantMap(); } + + static float expireDelta = 0.0f; + + // called ahead of E_UPDATE event +#if ATOMIC_IOS + [MonoPInvokeCallback(typeof(UpdateDispatchDelegate))] +#endif + public static void UpdateDispatch(float timeStep) + { + expireDelta += timeStep; + if (expireDelta > 2.0f) + { + expireDelta = 0.0f; + ExpireNatives(); + } + } + + #if ATOMIC_IOS + [MonoPInvokeCallback(typeof(EventDispatchDelegate))] + #endif public static void EventDispatch(IntPtr sender, uint eventType, IntPtr eventData) { List eventReceivers; @@ -240,19 +270,6 @@ static void ExpireNatives() } - static float expireDelta = 0.0f; - - // called ahead of E_UPDATE event - public static void UpdateDispatch(float timeStep) - { - expireDelta += timeStep; - if (expireDelta > 2.0f) - { - expireDelta = 0.0f; - ExpireNatives(); - } - } - // register a newly created native public static IntPtr RegisterNative(IntPtr native, RefCounted r) { diff --git a/Script/AtomicNET/AtomicNET/Core/NativeEvents.cs b/Script/AtomicNET/AtomicNET/Core/NativeEvents.cs index b241d68cde..a89f2f1d75 100644 --- a/Script/AtomicNET/AtomicNET/Core/NativeEvents.cs +++ b/Script/AtomicNET/AtomicNET/Core/NativeEvents.cs @@ -3,28 +3,10 @@ namespace AtomicEngine { - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void EventDispatchDelegate(IntPtr sender, uint eventType, IntPtr eventData); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void UpdateDispatchDelegate(float timeStep); - public delegate void EventDelegate(uint eventType, ScriptVariantMap eventData); public delegate void SenderEventDelegate(AObject sender, uint eventType, ScriptVariantMap eventData); - public delegate void HandleUpdateDelegate(float timeStep); - - [StructLayout(LayoutKind.Sequential)] - public struct CoreDelegates - { - [MarshalAs(UnmanagedType.FunctionPtr)] - public EventDispatchDelegate eventDispatch; - - [MarshalAs(UnmanagedType.FunctionPtr)] - public UpdateDispatchDelegate updateDispatch; - } - public partial class ScriptVariantMap { public void CopyVariantMap(IntPtr vm) diff --git a/Script/AtomicNET/AtomicNET/Core/SDLEvents.cs b/Script/AtomicNET/AtomicNET/Core/SDLEvents.cs new file mode 100644 index 0000000000..91f4d7ee82 --- /dev/null +++ b/Script/AtomicNET/AtomicNET/Core/SDLEvents.cs @@ -0,0 +1,144 @@ +using System; +using System.Runtime.InteropServices; + +namespace AtomicEngine +{ + public static class SDLEvents + { + [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl)] + static extern int SDL_SendWindowEvent(IntPtr window, byte windowevent, int data1, int data2); + + [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl)] + static extern int SDL_SendAppEvent(byte eventType); + + [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl)] + static extern void SDL_SetMainReady(); + + public static void SetMainReady() => SDL_SetMainReady(); + + public static void SendWindowEvent(SdlWindowEvent wndEvent, int data1 = 0, int data2 = 0) + { + var graphics = AtomicNET.GetSubsystem(); + SDL_SendWindowEvent(graphics.SDLWindow, (byte) wndEvent, data1, data2); + } + + public static void SendAppEvent(SdlEventType eventType) => SDL_SendAppEvent((byte)eventType); + } + + //see SDL_Video.h + public enum SdlWindowEvent + { + SDL_WINDOWEVENT_NONE, /* Never used */ + SDL_WINDOWEVENT_SHOWN, /* Window has been shown */ + SDL_WINDOWEVENT_HIDDEN, /* Window has been hidden */ + SDL_WINDOWEVENT_EXPOSED, /* Window has been exposed and should be redrawn */ + SDL_WINDOWEVENT_MOVED, /* Window has been moved to data1, data2 */ + SDL_WINDOWEVENT_RESIZED, /* Window has been resized to data1xdata2 */ + SDL_WINDOWEVENT_SIZE_CHANGED, /* The window size has changed, either as a result of an API call or through the system or user changing the window size. */ + SDL_WINDOWEVENT_MINIMIZED, /* Window has been minimized */ + SDL_WINDOWEVENT_MAXIMIZED, /* Window has been maximized */ + SDL_WINDOWEVENT_RESTORED, /* Window has been restored to normal size and position */ + SDL_WINDOWEVENT_ENTER, /* Window has gained mouse focus */ + SDL_WINDOWEVENT_LEAVE, /* Window has lost mouse focus */ + SDL_WINDOWEVENT_FOCUS_GAINED, /* Window has gained keyboard focus */ + SDL_WINDOWEVENT_FOCUS_LOST, /* Window has lost keyboard focus */ + SDL_WINDOWEVENT_CLOSE /* The window manager requests that the window be closed */ + } + + //see SDL_Events.h + public enum SdlEventType + { + SDL_FIRSTEVENT = 0, /**< Unused (do not remove) */ + + /* Application events */ + SDL_QUIT = 0x100, /**< User-requested quit */ + + /* These application events have special meaning on iOS, see README-ios.txt for details */ + SDL_APP_TERMINATING, /**< The application is being terminated by the OS + Called on iOS in applicationWillTerminate() + Called on Android in onDestroy() + */ + SDL_APP_LOWMEMORY, /**< The application is low on memory, free memory if possible. + Called on iOS in applicationDidReceiveMemoryWarning() + Called on Android in onLowMemory() + */ + SDL_APP_WILLENTERBACKGROUND, /**< The application is about to enter the background + Called on iOS in applicationWillResignActive() + Called on Android in onPause() + */ + SDL_APP_DIDENTERBACKGROUND, /**< The application did enter the background and may not get CPU for some time + Called on iOS in applicationDidEnterBackground() + Called on Android in onPause() + */ + SDL_APP_WILLENTERFOREGROUND, /**< The application is about to enter the foreground + Called on iOS in applicationWillEnterForeground() + Called on Android in onResume() + */ + SDL_APP_DIDENTERFOREGROUND, /**< The application is now interactive + Called on iOS in applicationDidBecomeActive() + Called on Android in onResume() + */ + + /* Window events */ + SDL_WINDOWEVENT = 0x200, /**< Window state change */ + SDL_SYSWMEVENT, /**< System specific event */ + + /* Keyboard events */ + SDL_KEYDOWN = 0x300, /**< Key pressed */ + SDL_KEYUP, /**< Key released */ + SDL_TEXTEDITING, /**< Keyboard text editing (composition) */ + SDL_TEXTINPUT, /**< Keyboard text input */ + + /* Mouse events */ + SDL_MOUSEMOTION = 0x400, /**< Mouse moved */ + SDL_MOUSEBUTTONDOWN, /**< Mouse button pressed */ + SDL_MOUSEBUTTONUP, /**< Mouse button released */ + SDL_MOUSEWHEEL, /**< Mouse wheel motion */ + + /* Joystick events */ + SDL_JOYAXISMOTION = 0x600, /**< Joystick axis motion */ + SDL_JOYBALLMOTION, /**< Joystick trackball motion */ + SDL_JOYHATMOTION, /**< Joystick hat position change */ + SDL_JOYBUTTONDOWN, /**< Joystick button pressed */ + SDL_JOYBUTTONUP, /**< Joystick button released */ + SDL_JOYDEVICEADDED, /**< A new joystick has been inserted into the system */ + SDL_JOYDEVICEREMOVED, /**< An opened joystick has been removed */ + + /* Game controller events */ + SDL_CONTROLLERAXISMOTION = 0x650, /**< Game controller axis motion */ + SDL_CONTROLLERBUTTONDOWN, /**< Game controller button pressed */ + SDL_CONTROLLERBUTTONUP, /**< Game controller button released */ + SDL_CONTROLLERDEVICEADDED, /**< A new Game controller has been inserted into the system */ + SDL_CONTROLLERDEVICEREMOVED, /**< An opened Game controller has been removed */ + SDL_CONTROLLERDEVICEREMAPPED, /**< The controller mapping was updated */ + + /* Touch events */ + SDL_FINGERDOWN = 0x700, + SDL_FINGERUP, + SDL_FINGERMOTION, + + /* Gesture events */ + SDL_DOLLARGESTURE = 0x800, + SDL_DOLLARRECORD, + SDL_MULTIGESTURE, + + /* Clipboard events */ + SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */ + + /* Drag and drop events */ + SDL_DROPFILE = 0x1000, /**< The system requests a file open */ + + /* Render events */ + SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset */ + + /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use, + * and should be allocated with SDL_RegisterEvents() + */ + SDL_USEREVENT = 0x8000, + + /** + * This last event is only for bounding internal arrays + */ + SDL_LASTEVENT = 0xFFFF + } +} diff --git a/Script/AtomicNET/AtomicNET/Graphics/Graphics.cs b/Script/AtomicNET/AtomicNET/Graphics/Graphics.cs index 96bec0e9c9..c914812d67 100644 --- a/Script/AtomicNET/AtomicNET/Graphics/Graphics.cs +++ b/Script/AtomicNET/AtomicNET/Graphics/Graphics.cs @@ -8,6 +8,14 @@ namespace AtomicEngine public partial class Graphics : AObject { + [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr csi_Atomic_Graphics_GetSDLWindow(); + + /// + /// Pointer to SDL window + /// + public IntPtr SDLWindow => csi_Atomic_Graphics_GetSDLWindow(); + // Shader Parameters public void SetShaderParameter(string param, Matrix3x4 matrix) diff --git a/Script/AtomicNET/AtomicNETProject.json b/Script/AtomicNET/AtomicNETProject.json index b01354877d..c6766492cf 100644 --- a/Script/AtomicNET/AtomicNETProject.json +++ b/Script/AtomicNET/AtomicNETProject.json @@ -101,6 +101,32 @@ "$ATOMIC_ROOT$/Script/AtomicNET/Platform/Android/" ] }, + { + "name": "AtomicNET.iOS", + "platforms" : ["ios"], + "outputType" : "Library", + "projectTypeGuids" :[ "8FFB629D-F513-41CE-95D2-7ECE97B6EEEC", "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC" ], + "defineConstants" : ["ATOMIC_IOS"], + "rootNamespace" : "AtomicGameEngine", + "assemblyName" : "AtomicNET", + "assemblyOutputPath" : "..\\..\\$ATOMIC_CONFIG$\\iOS\\", + "projectGuid" : "C74AB5E8-7517-11E6-AE3F-005056C00008", + "objcBindingApiDefinition" : "$ATOMIC_ROOT$/Script/AtomicNET/Platform/iOS/ApiDefinition/ApiDefinition.cs", + "references" : [ + "Xamarin.iOS", + "System", + "System.Core", + "System.Xml.Linq", + "System.Xml" + ], + "sharedReferences" : [ + "AtomicNET.Shared" + ], + "sources" : [ + "$ATOMIC_ROOT$/Script/AtomicNET/Platform/iOS/AtomicNET" + ], + "importProjects" : ["$(MSBuildExtensionsPath)\\Xamarin\\iOS\\Xamarin.iOS.ObjCBinding.CSharp.targets"] + }, { "name": "AtomicNETService", "platforms" : ["desktop"], diff --git a/Script/AtomicNET/AtomicNETService/Program.cs b/Script/AtomicNET/AtomicNETService/Program.cs index 7f97045a22..76202dbe78 100644 --- a/Script/AtomicNET/AtomicNETService/Program.cs +++ b/Script/AtomicNET/AtomicNETService/Program.cs @@ -1,11 +1,6 @@ using System; using AtomicEngine; -// net genproject C:\Dev\atomic\AtomicGameEngine\Script\AtomicNET\AtomicNETProject.json WINDOWS -// net parse C:\Dev\atomic\AtomicGameEngine\Artifacts\AtomicNET\Build\AtomicNETService\bin\Debug\AtomicNETService.exe -// net compile C:\Dev\atomic\AtomicGameEngine\Artifacts\AtomicNET\Build\AtomicNET.sln - - namespace AtomicTools { @@ -68,5 +63,3 @@ public static void Main(string[] args) } } } - - diff --git a/Script/AtomicNET/AtomicProject.json b/Script/AtomicNET/AtomicProject.json index 89f74a1a77..34e67592e1 100644 --- a/Script/AtomicNET/AtomicProject.json +++ b/Script/AtomicNET/AtomicProject.json @@ -84,6 +84,37 @@ "$ATOMIC_ROOT$/Script/AtomicNET/AtomicPlayer/AtomicPlayer.Common", "$ATOMIC_PROJECT_ROOT$/Project/AtomicNET/Platforms/Android" ] + }, + { + "name": "$ATOMIC_PROJECT_NAME$.iOS", + "platforms" : ["ios"], + "outputType" : "Exe", + "defineConstants" : ["ATOMIC_IOS"], + "rootNamespace" : "", + "assemblyName" : "$ATOMIC_PROJECT_NAME$", + "projectGuid" : "071BD84E-7518-11E6-C78E-005056C00008", + "projectTypeGuids" : ["FEACFBD2-3405-455C-9665-78FE426C6842", "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"], + "assemblyOutputPath" : "$ATOMIC_PROJECT_ROOT$\\AtomicNET\\$ATOMIC_CONFIG$\\Bin\\iOS", + "playerApplication" : true, + "codesignEntitlements" : "$ATOMIC_PROJECT_ROOT$/Project/AtomicNET/Platforms/iOS/Entitlements.plist", + "infoPList" : "$ATOMIC_PROJECT_ROOT$/Project/AtomicNET/Platforms/iOS/Info.plist", + "references" : [ + "Xamarin.iOS", + "System", + "System.Core", + "System.Xml.Linq", + "System.Xml", + "AtomicNET.iOS" + ], + "sharedReferences" : [ + "$ATOMIC_PROJECT_NAME$.Shared" + ], + "sources" : [ + "$ATOMIC_ROOT$/Script/AtomicNET/AtomicPlayer/AtomicPlayer.Common", + "$ATOMIC_PROJECT_ROOT$/Project/AtomicNET/Platforms/iOS" + ], + "importProjects" : ["$(MSBuildExtensionsPath)\\Xamarin\\iOS\\Xamarin.iOS.CSharp.targets"] } + ] } diff --git a/Script/AtomicNET/Platform/iOS/ApiDefinition/ApiDefinition.cs b/Script/AtomicNET/Platform/iOS/ApiDefinition/ApiDefinition.cs new file mode 100644 index 0000000000..4135e81f41 --- /dev/null +++ b/Script/AtomicNET/Platform/iOS/ApiDefinition/ApiDefinition.cs @@ -0,0 +1,10 @@ +using System; + +using UIKit; +using Foundation; +using ObjCRuntime; +using CoreGraphics; + +namespace AtomicGameEngine +{ +} diff --git a/Script/AtomicNET/Platform/iOS/AtomicNET/AtomicNETNative.framework.linkwith.cs b/Script/AtomicNET/Platform/iOS/AtomicNET/AtomicNETNative.framework.linkwith.cs new file mode 100644 index 0000000000..21a1889fe9 --- /dev/null +++ b/Script/AtomicNET/Platform/iOS/AtomicNET/AtomicNETNative.framework.linkwith.cs @@ -0,0 +1,3 @@ +using ObjCRuntime; + +[assembly: LinkWith ("AtomicNETNative.framework")] diff --git a/Source/AtomicNET/NETNative/CMakeLists.txt b/Source/AtomicNET/NETNative/CMakeLists.txt index 0455024fe7..44fbcc2c08 100644 --- a/Source/AtomicNET/NETNative/CMakeLists.txt +++ b/Source/AtomicNET/NETNative/CMakeLists.txt @@ -5,6 +5,12 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/Source/ThirdParty/FreeType/include ${CMAKE_SOURCE_DIR}/Source/ThirdParty/Box2D) +# TODO: Look into the application-extension flag for iOS +#if (IOS) +# set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fapplication-extension") +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fapplication-extension") +#endif() + set (CSATOMICDIR "${CMAKE_SOURCE_DIR}/Artifacts/Build/Source/Generated/CSharp/Packages/") file (GLOB CSHARP_BINDINGS_SOURCE ${CSATOMICDIR}/Atomic/Native/*.cpp ${CSATOMICDIR}/Atomic/Native/*.h @@ -44,6 +50,18 @@ if (APPLE) target_link_libraries( AtomicNETNative "-stdlib=libc++ -framework AudioUnit -framework Carbon -framework Cocoa -framework CoreAudio -framework CoreVideo -framework ForceFeedback -framework IOKit -framework OpenGL -framework CoreServices -framework Security") + else() + + set_target_properties(AtomicNETNative PROPERTIES + FRAMEWORK TRUE + MACOSX_FRAMEWORK_IDENTIFIER com.atomicgameengine.atomicnetframework + MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_SOURCE_DIR}/Build/CMake/IOS/AtomicNET.framework.plist + # PUBLIC_HEADER dynamicFramework.h + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer" + ) + + target_link_libraries( AtomicNETNative "-framework AudioToolbox -framework CoreAudio -framework CoreGraphics -framework Foundation -framework OpenGLES -framework QuartzCore -framework UIKit -framework CoreMotion -framework GameController") + endif() endif() @@ -64,10 +82,21 @@ endif() set (ATOMICNET_NATIVE_DIR "${CMAKE_SOURCE_DIR}/Artifacts/AtomicNET/$<$:Debug>$<$:Release>/Native/${ATOMICNET_NATIVE_PLATFORM}") +if (NOT IOS) + add_custom_command( TARGET AtomicNETNative POST_BUILD COMMAND "${CMAKE_COMMAND}" ARGS -E make_directory "\"${ATOMICNET_NATIVE_DIR}\"" COMMAND "${CMAKE_COMMAND}" ARGS -E copy_if_different \"$\" "\"${ATOMICNET_NATIVE_DIR}\"" ) +else() + + # iOS: We need to copy/zip the framework on iOS, the framework must also be code signed and POST_BUILD is triggered before this occurs, + # so handled in BuildIOS.js + add_custom_command( TARGET AtomicNETNative POST_BUILD + COMMAND install_name_tool -id @rpath/AtomicNETNative.framework/AtomicNETNative \"$\") + +endif() + if (MSVC) # Copy the D3D shader compiler (for pre-Windows 8) diff --git a/Source/AtomicNET/NETNative/NETAtomicPlayer.cpp b/Source/AtomicNET/NETNative/NETAtomicPlayer.cpp index c911c85ca1..4b051acdaf 100644 --- a/Source/AtomicNET/NETNative/NETAtomicPlayer.cpp +++ b/Source/AtomicNET/NETNative/NETAtomicPlayer.cpp @@ -38,7 +38,7 @@ #include #endif -// Android or iOS: use SDL_main +// Android: uses SDL_main, defined for IOS only to satifsy linker #if defined(__ANDROID__) || defined(IOS) typedef int(*sdl_entry_callback)(); @@ -50,14 +50,16 @@ extern "C" void RegisterSDLEntryCallback(sdl_entry_callback callback) sdlEntryCallback = callback; } -extern "C" int SDL_main(int argc, char** argv); -int SDL_main(int argc, char** argv) -{ - Atomic::ParseArguments(argc, argv); +extern "C" int SDL_main(int argc, char** argv); +int SDL_main(int argc, char** argv) +{ +#if defined(__ANDROID__) + Atomic::ParseArguments(argc, argv); if (sdlEntryCallback != 0) { return sdlEntryCallback(); } +#endif return 0; } #endif @@ -75,7 +77,7 @@ namespace Atomic { PlayerApp::Setup(); - engineParameters_["ResourcePaths"] = "AtomicResources"; + engineParameters_["ResourcePaths"] = "AtomicResources"; } int NETAtomicPlayer::Initialize() diff --git a/Source/AtomicNET/NETNative/NETCInterop.cpp b/Source/AtomicNET/NETNative/NETCInterop.cpp index d3bb25fc92..4b256645c1 100644 --- a/Source/AtomicNET/NETNative/NETCInterop.cpp +++ b/Source/AtomicNET/NETNative/NETCInterop.cpp @@ -22,6 +22,11 @@ namespace Atomic { +#ifdef ATOMIC_PLATFORM_IOS + static const char *sdlResourceDir = 0; + static const char *sdlDocumentsDir = 0; +#endif + extern "C" { @@ -60,10 +65,16 @@ namespace Atomic obj->SendEvent(eventType, vmap ? vmap->GetVariantMap() : obj->GetEventDataMap()); } - ATOMIC_EXPORT_API ClassID csi_Atomic_NETCore_Initialize(NETCoreDelegates* delegates) + ATOMIC_EXPORT_API ClassID csi_Atomic_NETCore_Initialize(NETCoreEventDispatchFunction eventDispatch, NETCoreUpdateDispatchFunction updateDispatch) { Context* context = new Context(); - NETCore* netCore = new NETCore(context, delegates); + + // NOTE: We don't simply marshal the NETCoreDelegates structure due to iOS "reverse callback" limitation + NETCoreDelegates delegates; + delegates.eventDispatch = eventDispatch; + delegates.updateDispatch = updateDispatch; + + NETCore* netCore = new NETCore(context, &delegates); context->RegisterSubsystem(netCore); return netCore; } @@ -123,6 +134,20 @@ namespace Atomic } + // Graphics + + ATOMIC_EXPORT_API void* csi_Atomic_Graphics_GetSDLWindow() + { + if (!NETCore::GetContext()) + return 0; + + if (!NETCore::GetContext()->GetSubsystem()) + return 0; + + return NETCore::GetContext()->GetSubsystem()->GetSDLWindow(); + + } + ATOMIC_EXPORT_API void* csi_Atomic_VertexBuffer_Lock(VertexBuffer* vb , unsigned start, unsigned count, bool discard) { if (!vb) @@ -140,9 +165,35 @@ namespace Atomic graphics->SetShaderParameter(param, *matrix); } +#ifdef ATOMIC_PLATFORM_IOS + ATOMIC_EXPORT_API void SDL_IOS_Init(const char *resourceDir, const char *documentsDir) + { + sdlResourceDir = resourceDir; + sdlDocumentsDir = documentsDir; + } +#endif + } } +#ifdef ATOMIC_PLATFORM_IOS + +//FileSystem.cpp uses these functions as external. +const char* SDL_IOS_GetResourceDir() +{ + return Atomic::sdlResourceDir; +} + +const char* SDL_IOS_GetDocumentsDir() +{ + return Atomic::sdlDocumentsDir; +} + +#endif + + + + diff --git a/Source/AtomicPlayer/Application/CMakeLists.txt b/Source/AtomicPlayer/Application/CMakeLists.txt index 23a4695831..66f2bbad29 100644 --- a/Source/AtomicPlayer/Application/CMakeLists.txt +++ b/Source/AtomicPlayer/Application/CMakeLists.txt @@ -55,7 +55,7 @@ if (APPLE) XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer" XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" XCODE_ATTRIBUTE_INFOPLIST_PREPROCESS YES - XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 9.2 + XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 9.3 XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" # iPhone/iPad XCODE_ATTRIBUTE_COMBINE_HIDPI_IMAGES NO ) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index fb6f821339..2d0b246a37 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -12,7 +12,7 @@ endif() add_subdirectory(AtomicPlayer) add_subdirectory(AtomicPlayerJS) -if (NOT IOS AND NOT EMSCRIPTEN) +if (NOT EMSCRIPTEN) add_subdirectory(AtomicApp) add_subdirectory(AtomicNET) endif() diff --git a/Source/ToolCore/Command/NETCmd.cpp b/Source/ToolCore/Command/NETCmd.cpp index c8d3686ab0..b16d23c906 100644 --- a/Source/ToolCore/Command/NETCmd.cpp +++ b/Source/ToolCore/Command/NETCmd.cpp @@ -67,11 +67,34 @@ bool NETCmd::Parse(const Vector& arguments, unsigned startIndex, String& return false; } + if (command_ == "compile" || command_ == "genresources") + { + for (unsigned i = startIndex + 3; i < arguments.Size(); i++) + { + if (arguments[i].Length() > 1 && arguments[i][0] == '-') + { + String argument = arguments[i].Substring(1).ToLower(); + String value = i + 1 < arguments.Size() ? arguments[i + 1] : String::EMPTY; + + if (argument == "platform" && !value.Empty()) + { + platforms_.Push(value); + i++; + } + else if (argument == "config" && !value.Empty()) + { + configurations_.Push(value); + i++; + } + } + } + } + if (command_ == "compile") { + // solution solutionPath_ = startIndex + 2 < arguments.Size() ? arguments[startIndex + 2] : String::EMPTY; - platform_ = startIndex + 3 < arguments.Size() ? arguments[startIndex + 3] : String::EMPTY; - configuration_ = startIndex + 4 < arguments.Size() ? arguments[startIndex + 4] : "Release"; + bool exists = false; @@ -87,19 +110,32 @@ bool NETCmd::Parse(const Vector& arguments, unsigned startIndex, String& return false; } - if (!platform_.Length()) + if (!platforms_.Size()) { errorMsg = "Platform not specified"; return false; } + if (!configurations_.Size()) + { + errorMsg = "configuration not specified"; + return false; + } + + return true; } else if (command_ == "genresources") { projectPath_ = startIndex + 2 < arguments.Size() ? arguments[startIndex + 2] : String::EMPTY; - platform_ = startIndex + 3 < arguments.Size() ? arguments[startIndex + 3] : String::EMPTY; requiresProjectLoad_ = true; + + if (!platforms_.Size()) + { + errorMsg = "Platform not specified"; + return false; + } + } else { @@ -136,8 +172,6 @@ void NETCmd::Run() if (command_ == "compile") { - FileSystem* fileSystem = GetSubsystem(); - NETBuildSystem* buildSystem = new NETBuildSystem(context_); context_->RegisterSubsystem(buildSystem); @@ -173,7 +207,7 @@ void NETCmd::Run() } // json project file - build = buildSystem->Build(solutionPath_, platform_, configuration_); + build = buildSystem->Build(solutionPath_, platforms_, configurations_); if (!build) { @@ -200,11 +234,11 @@ void NETCmd::Run() buildSystem->SetBuildPath(project->GetProjectPath() + "AtomicNET/Resources/"); - Platform* platform = toolSystem->GetPlatformByName(platform_); + Platform* platform = toolSystem->GetPlatformByName(platforms_[0]); if (!platform) { - Error(ToString("Unknown platform %s", platform_.CString())); + Error(ToString("Unknown platform %s", platforms_[0].CString())); Finished(); return; } diff --git a/Source/ToolCore/Command/NETCmd.h b/Source/ToolCore/Command/NETCmd.h index 0bf8e6abc6..0821a756db 100644 --- a/Source/ToolCore/Command/NETCmd.h +++ b/Source/ToolCore/Command/NETCmd.h @@ -64,8 +64,8 @@ class NETCmd: public Command // compile String solutionPath_; - String platform_; - String configuration_; + StringVector platforms_; + StringVector configurations_; bool requiresProjectLoad_; diff --git a/Source/ToolCore/NETTools/NETBuildSystem.cpp b/Source/ToolCore/NETTools/NETBuildSystem.cpp index 207efa2451..4d207a285c 100644 --- a/Source/ToolCore/NETTools/NETBuildSystem.cpp +++ b/Source/ToolCore/NETTools/NETBuildSystem.cpp @@ -41,14 +41,23 @@ namespace ToolCore { - NETBuild::NETBuild(Context* context, const String& solutionPath, const String& platform, const String& configuration) : + NETBuild::NETBuild(Context* context, const String& solutionPath, const StringVector& platforms, const StringVector& configurations) : Object(context), solutionPath_(solutionPath), - platform_(platform), - configuration_(configuration), status_(NETBUILD_PENDING) { + for (unsigned i = 0; i < platforms.Size() ; i++) + { + platforms_.Push(platforms[i].ToLower()); + } + for (unsigned i = 0; i < configurations.Size() ; i++) + { + String config = configurations[i]; + config.Replace("release", "Release"); + config.Replace("debug", "Debug"); + configurations_.Push(config); + } } NETBuildSystem::NETBuildSystem(Context* context) : @@ -187,15 +196,8 @@ namespace ToolCore { SharedPtr gen(new NETProjectGen(context_)); - StringVector platforms; - platforms.Push("desktop"); - - if (curBuild_->platform_.ToLower() == "android") - { - platforms.Push("android"); - } - - gen->SetSupportedPlatforms(platforms); + gen->SetSupportedPlatforms(curBuild_->platforms_); + gen->SetRewriteSolution(true); if (!gen->LoadJSONProject(solutionPath)) { @@ -229,7 +231,53 @@ namespace ToolCore return; } - const String configuration = curBuild_->configuration_; + StringVector stringVector; + String platforms; + String configs; + + for (unsigned i = 0; i < curBuild_->configurations_.Size(); i++) + { + stringVector.Push(ToString("/p:Configuration=%s", curBuild_->configurations_[i].CString())); + } + + configs = String::Joined(stringVector, " "); + stringVector.Clear(); + + for (unsigned i = 0; i < curBuild_->platforms_.Size(); i++) + { + // map platform + String platform = curBuild_->platforms_[i]; + + if (platform == "desktop" || platform == "android") + { + platform = "\"Any CPU\""; + } + else if (platform == "ios") + { + + platform = "\"Any CPU\""; + // TODO + // platform = "iPhone"; + } + else + { + ATOMIC_LOGERRORF("Unknown platform: %s, skipping", platform.CString()); + continue; + } + + platform = ToString("/p:Platform=%s", platform.CString()); + + if (stringVector.Contains(platform)) + { + // This can happen when specifying Desktop + Android for example + continue; + } + + stringVector.Push(platform); + } + + platforms = String::Joined(stringVector, " "); + stringVector.Clear(); Vector args; @@ -258,7 +306,7 @@ namespace ToolCore compile += ToString("&& \"%s\" restore \"%s\" ", nugetBinary.CString(), solutionPath.CString()); } - compile += ToString("&& msbuild \"%s\" /p:Configuration=%s /p:Platform=\"Any CPU\"\"", solutionPath.CString(), configuration.CString()); + compile += ToString("&& msbuild \"%s\" %s %s\"", solutionPath.CString(), platforms.CString(), configs.CString()); args.Push(compile); @@ -280,7 +328,7 @@ namespace ToolCore #endif } - compile += ToString("\"%s\" \"%s\" /p:Configuration=%s /p:Platform=\"Any CPU\"", xbuildBinary.CString(), solutionPath.CString(), configuration.CString()); + compile += ToString("\"%s\" \"%s\" %s %s", xbuildBinary.CString(), solutionPath.CString(), platforms.CString(), configs.CString()); args.Push(compile); @@ -291,6 +339,8 @@ namespace ToolCore SubprocessSystem* subs = GetSubsystem(); Subprocess* subprocess = nullptr; + ATOMIC_LOGINFOF("%s : %s", cmd.CString(), curBuild_->allArgs_.CString()); + try { subprocess = subs->Launch(cmd, args, ""); @@ -316,7 +366,7 @@ namespace ToolCore } - NETBuild* NETBuildSystem::GetBuild(const String& solutionPath, const String& platform, const String& configuration) + NETBuild* NETBuildSystem::GetBuild(const String& solutionPath, const StringVector& platforms, const StringVector& configurations) { List>::ConstIterator itr = builds_.Begin(); @@ -324,7 +374,7 @@ namespace ToolCore { NETBuild* build = *itr; - if (build->solutionPath_ == solutionPath && build->platform_ == platform && build->configuration_ == configuration) + if (build->solutionPath_ == solutionPath && build->platforms_ == platforms && build->configurations_ == configurations) return build; itr++; @@ -336,26 +386,20 @@ namespace ToolCore NETBuild* NETBuildSystem::BuildAtomicProject(Project* project) { - String platform; - String configuration; + StringVector platforms; + StringVector configurations; -#ifdef ATOMIC_PLATFORM_WINDOWS - platform = "WINDOWS"; -#elif ATOMIC_PLATFORM_OSX - platform = "MACOSX"; -#else - platform = "LINUX"; -#endif + platforms.Push("desktop"); #ifdef ATOMIC_DEBUG - configuration = "Debug"; + configurations.Push("Debug"); #else - configuration = "Release"; + configurations.Push("Release"); #endif String solutionPath = project->GetProjectPath() + "AtomicNET/Solution/" + project->GetProjectSettings()->GetName() + ".sln"; - NETBuild* build = Build(solutionPath, platform, configuration); + NETBuild* build = Build(solutionPath, platforms, configurations); if (build) { @@ -385,7 +429,7 @@ namespace ToolCore } - NETBuild* NETBuildSystem::Build(const String& solutionPath, const String& platform, const String& configuration) + NETBuild* NETBuildSystem::Build(const String& solutionPath, const StringVector& platforms, const StringVector& configurations) { FileSystem* fileSystem = GetSubsystem(); @@ -397,13 +441,13 @@ namespace ToolCore } // Get existing build - SharedPtr build(GetBuild(solutionPath, platform, configuration)); + SharedPtr build(GetBuild(solutionPath, platforms, configurations)); if (build.NotNull()) return build; // Create a new build - build = new NETBuild(context_, solutionPath, platform, configuration); + build = new NETBuild(context_, solutionPath, platforms, configurations); builds_.Push(build); diff --git a/Source/ToolCore/NETTools/NETBuildSystem.h b/Source/ToolCore/NETTools/NETBuildSystem.h index ddbb942dfb..b58cd0f997 100644 --- a/Source/ToolCore/NETTools/NETBuildSystem.h +++ b/Source/ToolCore/NETTools/NETBuildSystem.h @@ -58,14 +58,15 @@ namespace ToolCore public: - NETBuild(Context* context, const String& solutionPath, const String& platform, const String& configuration); + NETBuild(Context* context, const String& solutionPath, const StringVector& platforms, const StringVector& configurations); virtual ~NETBuild() {} private: /// .sln or .json configuration file String solutionPath_; - String configuration_; - String platform_; + StringVector configurations_; + StringVector platforms_; + NETBuildStatus status_; String allArgs_; String output_; @@ -85,7 +86,7 @@ namespace ToolCore virtual ~NETBuildSystem(); /// Build either a .sln or .json configuration file - NETBuild* Build(const String& solutionPath, const String& platform, const String& configuration = "Release"); + NETBuild* Build(const String& solutionPath, const StringVector &platforms, const StringVector &configurations); NETBuild* BuildAtomicProject(Project* project); @@ -93,7 +94,7 @@ namespace ToolCore void CurrentBuildError(String errorText); - NETBuild* GetBuild(const String& solutionPath, const String& platform, const String& configuration); + NETBuild* GetBuild(const String& solutionPath, const StringVector& platforms, const StringVector& configurations); void HandleBuildAtomicProject(StringHash eventType, VariantMap& eventData); void HandleToolUpdate(StringHash eventType, VariantMap& eventData); diff --git a/Source/ToolCore/NETTools/NETProjectGen.cpp b/Source/ToolCore/NETTools/NETProjectGen.cpp index e2cd26f292..4ea34d6edc 100644 --- a/Source/ToolCore/NETTools/NETProjectGen.cpp +++ b/Source/ToolCore/NETTools/NETProjectGen.cpp @@ -237,6 +237,12 @@ namespace ToolCore platform = "Android"; } + else if (SupportsPlatform("ios")) + { + ref = "AtomicNET"; + platform = "iOS"; + } + if (platform.Length()) { @@ -374,10 +380,23 @@ namespace ToolCore paths.Join(searchPaths, ";"); } + void NETCSProject::ProcessDefineConstants(StringVector& constants) + { + const Vector& globalConstants = projectGen_->GetGlobalDefineConstants(); + constants += globalConstants; + + if (constants.Contains("ATOMIC_IOS") || constants.Contains("ATOMIC_ANDROID")) + constants.Push("ATOMIC_MOBILE"); + } + void NETCSProject::CreateReleasePropertyGroup(XMLElement &projectRoot) { XMLElement pgroup = projectRoot.CreateChild("PropertyGroup"); - pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "); + + if (playerApplication_ && SupportsPlatform("ios")) + pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Release|iPhone' "); + else + pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "); pgroup.CreateChild("Optimize").SetValue("true"); @@ -391,8 +410,7 @@ namespace ToolCore constants += defineConstants_; - const Vector& globalConstants = projectGen_->GetGlobalDefineConstants(); - constants += globalConstants; + ProcessDefineConstants(constants); pgroup.CreateChild("DefineConstants").SetValue(String::Joined(constants, ";").CString()); pgroup.CreateChild("ErrorReport").SetValue("prompt"); @@ -429,16 +447,27 @@ namespace ToolCore } else { - pgroup.CreateChild("DebugType").SetValue("pdbonly"); - if (SupportsPlatform("android")) { + pgroup.CreateChild("DebugType").SetValue("pdbonly"); + if (outputType_.ToLower() != "library") { pgroup.CreateChild("AndroidUseSharedRuntime").SetValue("False"); pgroup.CreateChild("AndroidLinkMode").SetValue("SdkOnly"); } } + else if (playerApplication_ && SupportsPlatform("ios")) + { + pgroup.CreateChild("DebugType").SetValue("none"); + + pgroup.CreateChild("MtouchArch").SetValue("ARMv7, ARM64"); + pgroup.CreateChild("CodesignEntitlements").SetValue(GetSanitizedPath(codesignEntitlements_)); + pgroup.CreateChild("CodesignKey").SetValue("iPhone Developer"); + pgroup.CreateChild("MtouchDebug").SetValue("true"); + pgroup.CreateChild("MtouchOptimizePNGs").SetValue("False"); + } + } } @@ -446,7 +475,12 @@ namespace ToolCore void NETCSProject::CreateDebugPropertyGroup(XMLElement &projectRoot) { XMLElement pgroup = projectRoot.CreateChild("PropertyGroup"); - pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "); + + if (playerApplication_ && SupportsPlatform("ios")) + pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Debug|iPhone' "); + else + pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "); + pgroup.CreateChild("Optimize").SetValue("false"); @@ -460,9 +494,7 @@ namespace ToolCore constants.Push("TRACE"); constants += defineConstants_; - - const Vector& globalConstants = projectGen_->GetGlobalDefineConstants(); - constants += globalConstants; + ProcessDefineConstants(constants); pgroup.CreateChild("DefineConstants").SetValue(String::Joined(constants, ";").CString()); @@ -516,6 +548,17 @@ namespace ToolCore pgroup.CreateChild("AndroidEnableMultiDex").SetValue("False"); pgroup.CreateChild("AndroidSupportedAbis").SetValue("armeabi-v7a"); } + else if (playerApplication_ && SupportsPlatform("ios")) + { + pgroup.CreateChild("MtouchArch").SetValue("ARMv7, ARM64"); + pgroup.CreateChild("CodesignEntitlements").SetValue(GetSanitizedPath(codesignEntitlements_)); + pgroup.CreateChild("CodesignKey").SetValue("iPhone Developer"); + pgroup.CreateChild("MtouchDebug").SetValue("true"); + pgroup.CreateChild("MtouchFastDev").SetValue("true"); + pgroup.CreateChild("IpaPackageName").SetValue(""); + pgroup.CreateChild("OptimizePNGs").SetValue("false"); + pgroup.CreateChild("MtouchOptimizePNGs").SetValue("False"); + } } @@ -570,17 +613,69 @@ namespace ToolCore } else { - const String& projectPath = projectGen_->GetAtomicProjectPath(); + const String& projectPath = projectGen_->GetAtomicProjectPath(); if (!playerApplication_ || !projectPath.Length()) return; - XMLElement androidAsset = itemGroup.CreateChild("AndroidAsset"); - androidAsset.SetAttribute("Include", projectPath + "AtomicNET/Resources/AtomicResources.pak"); - androidAsset.CreateChild("Link").SetValue("Assets\\AtomicResources.pak"); + if (androidApplication_) + { + XMLElement androidAsset = itemGroup.CreateChild("AndroidAsset"); + androidAsset.SetAttribute("Include", projectPath + "AtomicNET/Resources/AtomicResources.pak"); + androidAsset.CreateChild("Link").SetValue("Assets\\AtomicResources.pak"); + } + else + { + XMLElement bundleResource = itemGroup.CreateChild("BundleResource"); + bundleResource.SetAttribute("Include", projectPath + "AtomicNET/Resources/AtomicResources.pak"); + bundleResource.CreateChild("Link").SetValue("Resources\\AtomicResources.pak"); + bundleResource.CreateChild("CopyToOutputDirectory").SetValue("PreserveNewest"); + } } } + void NETCSProject::CreateIOSItems(XMLElement &projectRoot) + { + XMLElement iosGroup = projectRoot.CreateChild("ItemGroup"); + + if (objcBindingApiDefinition_.Length()) + { + iosGroup.CreateChild("ObjcBindingApiDefinition").SetAttribute("Include", GetSanitizedPath(objcBindingApiDefinition_)); + } + + if (name_ == "AtomicNET.iOS") + { + ToolEnvironment* tenv = GetSubsystem(); + +#ifdef ATOMIC_DEBUG + String config = "Debug"; +#else + String config = "Release"; +#endif + + String nativePath = AddTrailingSlash(tenv->GetAtomicNETRootDir()) + config + "/Native/iOS/AtomicNETNative.framework"; + iosGroup.CreateChild("ObjcBindingNativeFramework").SetAttribute("Include", GetSanitizedPath(nativePath)); + + // framework copy + XMLElement none = iosGroup.CreateChild("None"); + none.SetAttribute("Include", nativePath + ".zip"); + none.CreateChild("Link").SetValue("AtomicNETNative.framework.zip"); + none.CreateChild("CopyToOutputDirectory").SetValue("Always"); + + } + else if (playerApplication_) + { + XMLElement plist = iosGroup.CreateChild("None"); + plist.SetAttribute("Include", GetSanitizedPath(infoPList_)); + plist.CreateChild("Link").SetValue("Info.plist"); + + XMLElement entitlements = iosGroup.CreateChild("Content"); + entitlements.SetAttribute("Include", GetSanitizedPath(codesignEntitlements_)); + entitlements.CreateChild("Link").SetValue("Entitlements.plist"); + } + + } + void NETCSProject::CreateAndroidItems(XMLElement &projectRoot) { @@ -729,8 +824,11 @@ namespace ToolCore // Platform XMLElement platform = pgroup.CreateChild("Platform"); - platform.SetAttribute("Condition", " '$(Platform)' == '' "); - platform.SetValue("AnyCPU"); + platform.SetAttribute("Condition", " '$(Platform)' == '' "); + if (playerApplication_ && SupportsPlatform("ios")) + platform.SetValue("iPhone"); + else + platform.SetValue("AnyCPU"); // ProjectGuid XMLElement guid = pgroup.CreateChild("ProjectGuid"); @@ -766,7 +864,14 @@ namespace ToolCore pgroup.CreateChild("ProductVersion").SetValue("8.0.30703"); pgroup.CreateChild("SchemaVersion").SetValue("2.0"); - pgroup.CreateChild("TargetFrameworkVersion").SetValue("v6.0"); + if (SupportsPlatform("ios")) + { + pgroup.CreateChild("IPhoneResourcePrefix").SetValue("Resources"); + } + else + { + pgroup.CreateChild("TargetFrameworkVersion").SetValue("v6.0"); + } if (SupportsPlatform("android")) { @@ -945,6 +1050,12 @@ namespace ToolCore CreateAndroidItems(project); } + if (SupportsPlatform("ios")) + { + CreateIOSItems(project); + } + + if (SupportsDesktop() && !GetIsPCL()) project.CreateChild("Import").SetAttribute("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"); @@ -1213,6 +1324,16 @@ namespace ToolCore targetFrameworkProfile_ = root["targetFrameworkProfile"].GetString(); + // iOS + objcBindingApiDefinition_ = root["objcBindingApiDefinition"].GetString(); + ReplacePathStrings(objcBindingApiDefinition_); + + codesignEntitlements_ = root["codesignEntitlements"].GetString(); + ReplacePathStrings(codesignEntitlements_); + + infoPList_ = root["infoPList"].GetString(); + ReplacePathStrings(infoPList_); + return true; } @@ -1327,7 +1448,9 @@ namespace ToolCore source += " GlobalSection(SolutionConfigurationPlatforms) = preSolution\n"; source += " Debug|Any CPU = Debug|Any CPU\n"; - source += " Release|Any CPU = Release|Any CPU\n"; + source += " Release|Any CPU = Release|Any CPU\n"; + source += " Debug|iPhone = Debug|iPhone\n"; + source += " Release|iPhone = Release|iPhone\n"; source += " EndGlobalSection\n"; source += " GlobalSection(ProjectConfigurationPlatforms) = postSolution\n"; @@ -1338,10 +1461,22 @@ namespace ToolCore if (p->outputType_ == "Shared") continue; - source += ToString(" {%s}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n", p->GetProjectGUID().CString()); - source += ToString(" {%s}.Debug|Any CPU.Build.0 = Debug|Any CPU\n", p->GetProjectGUID().CString()); - source += ToString(" {%s}.Release|Any CPU.ActiveCfg = Release|Any CPU\n", p->GetProjectGUID().CString()); - source += ToString(" {%s}.Release|Any CPU.Build.0 = Release|Any CPU\n", p->GetProjectGUID().CString()); + String cpu = "Any CPU"; + if (p->GetIsPlayerApp() && p->SupportsPlatform("ios")) + cpu = "iPhone"; + + source += ToString(" {%s}.Debug|%s.ActiveCfg = Debug|%s\n", p->GetProjectGUID().CString(), cpu.CString(), cpu.CString()); + source += ToString(" {%s}.Debug|%s.Build.0 = Debug|%s\n", p->GetProjectGUID().CString(), cpu.CString(), cpu.CString()); + source += ToString(" {%s}.Release|%s.ActiveCfg = Release|%s\n", p->GetProjectGUID().CString(), cpu.CString(), cpu.CString()); + source += ToString(" {%s}.Release|%s.Build.0 = Release|%s\n", p->GetProjectGUID().CString(), cpu.CString(), cpu.CString()); + + if (cpu != "iPhone" && (p->SupportsPlatform("ios", false))) + { + source += ToString(" {%s}.Debug|iPhone.ActiveCfg = Debug|Any CPU\n", p->GetProjectGUID().CString()); + source += ToString(" {%s}.Debug|iPhone.Build.0 = Debug|Any CPU\n", p->GetProjectGUID().CString()); + source += ToString(" {%s}.Release|iPhone.ActiveCfg = Release|Any CPU\n", p->GetProjectGUID().CString()); + source += ToString(" {%s}.Release|iPhone.Build.0 = Release|Any CPU\n", p->GetProjectGUID().CString()); + } } source += " EndGlobalSection\n"; @@ -1563,7 +1698,6 @@ namespace ToolCore bool NETProjectGen::LoadAtomicProject(const String& atomicProjectPath) { - FileSystem* fileSystem = GetSubsystem(); ToolEnvironment* tenv = GetSubsystem(); ToolSystem* tsystem = GetSubsystem(); @@ -1589,7 +1723,7 @@ namespace ToolCore { // Nope, load them up projectSettings_ = SharedPtr(new ProjectSettings(context_)); - projectSettings_->Load(atomicProjectPath_ + "Settings/Platforms.json"); + projectSettings_->Load(atomicProjectPath_ + "Settings/Project.json"); } #ifdef ATOMIC_DEV_BUILD diff --git a/Source/ToolCore/NETTools/NETProjectGen.h b/Source/ToolCore/NETTools/NETProjectGen.h index 7c8d5a81da..13c468afd5 100644 --- a/Source/ToolCore/NETTools/NETProjectGen.h +++ b/Source/ToolCore/NETTools/NETProjectGen.h @@ -76,6 +76,10 @@ namespace ToolCore bool GetIsPCL() const { return projectTypeGuids_.Contains("{786C830F-07A1-408B-BD7F-6EE04809D6DB}"); } + bool GetIsPlayerApp() const { return playerApplication_; } + bool SupportsDesktop() const; + bool SupportsPlatform(const String& platform, bool explicitCheck = true) const; + bool Generate(); private: @@ -99,12 +103,13 @@ namespace ToolCore void CreateApplicationItems(XMLElement &projectRoot); void CreateAndroidItems(XMLElement &projectRoot); + void CreateIOSItems(XMLElement &projectRoot); void CreateAssemblyInfo(); void GetAssemblySearchPaths(String& paths); - bool SupportsDesktop() const; - bool SupportsPlatform(const String& platform, bool explicitCheck = true) const; + void ProcessDefineConstants(StringVector& constants); + String name_; String projectGuid_; @@ -138,6 +143,12 @@ namespace ToolCore // Android bool androidApplication_; + + // iOS + String objcBindingApiDefinition_; + String codesignEntitlements_; + String infoPList_; + }; diff --git a/Source/ToolCore/Project/ProjectSettings.cpp b/Source/ToolCore/Project/ProjectSettings.cpp index 4df083028e..41a71c707b 100644 --- a/Source/ToolCore/Project/ProjectSettings.cpp +++ b/Source/ToolCore/Project/ProjectSettings.cpp @@ -89,6 +89,7 @@ namespace ToolCore if (!fileSystem->FileExists(path)) { + ATOMIC_LOGERRORF("No platform settings specified, using default: %s", path.CString()); SetDefault(); return true; } @@ -144,7 +145,7 @@ namespace ToolCore if (!platforms_.Size()) { - ATOMIC_LOGERRORF("No valif platforms defined in platform settings: %s, using default", path.CString()); + ATOMIC_LOGERRORF("No valid platforms defined in platform settings: %s, using default", path.CString()); SetDefault(); }