diff --git a/.gitignore b/.gitignore index beed7b4..0dbc27c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,7 @@ tt-test-* *.lib *.obj *.lst -*.sln \ No newline at end of file +*.sln + +.DS_Store + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0c8d396 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ios-libs/bindbc-sdl"] + path = ios/libs/bindbc-sdl + url = https://github.com/BindBC/bindbc-sdl.git diff --git a/dist/.gitignore b/dist/.gitignore new file mode 100644 index 0000000..d81c463 --- /dev/null +++ b/dist/.gitignore @@ -0,0 +1,2 @@ +/tt.app + diff --git a/dub.json b/dub.json index b023981..9caa9b8 100644 --- a/dub.json +++ b/dub.json @@ -15,8 +15,8 @@ { "name": "wasm_debug", "targetPath": "web", - "sourceFiles": [ - "src/**.d" + "sourcePaths": [ + "src" ], "dependencies": {"runtime": {"path": "runtime"}}, "dflags": ["-i=.", "-i=std"], @@ -29,8 +29,8 @@ { "name": "wasm", "targetPath": "web", - "sourceFiles": [ - "src/**.d" + "sourcePaths": [ + "src" ], "dependencies": {"runtime": {"path": "runtime"}}, "dflags": ["-i=.", "-i=std", "-L=-allow-undefined"], @@ -43,8 +43,10 @@ { "name": "win32", "platforms": ["windows-x86"], + "sourcePaths": [ + "src" + ], "sourceFiles": [ - "src/**.d", "resource/tt.res" ], "importPaths": [ @@ -73,6 +75,65 @@ "bindbc-opengl": "dynamicBC", "bindbc-sdl": "dynamicBC" } + }, + { + "name": "win64", + "platforms": ["windows-x86_64"], + "sourcePaths": [ + "src" + ], + "sourceFiles": [ + "resource/tt.res" + ], + "importPaths": [ + "lib" + ], + "copyFiles": [ + "lib/SDL2-2.0.12/lib/x64/SDL2.dll", + "lib/SDL2-2.0.12/README-SDL.txt", + "lib/SDL2_mixer-2.0.4/lib/x64/SDL2_mixer.dll", + "lib/SDL2_mixer-2.0.4/lib/x64/libvorbis-0.dll", + "lib/SDL2_mixer-2.0.4/lib/x64/libvorbisfile-3.dll", + "lib/SDL2_mixer-2.0.4/lib/x64/libogg-0.dll" + ], + "dependencies": { + "bindbc-opengl": "~>0.13.0", + "bindbc-sdl": "~>0.19.0" + }, + "versions": [ + "BindBC", + "GL_32", + "GL_Batching", + "SDL_Mixer", + "InputBackendSDL" + ], + "subConfigurations": { + "bindbc-opengl": "dynamicBC", + "bindbc-sdl": "dynamicBC" + } + }, + { + "name": "iOS", + "targetType": "staticLibrary", + "sourcePaths": [ + "src" + ], + "dependencies": { + "bindbc-sdl": "~>0.19.0" + }, + "versions": [ + "IOS", + "BindBC", + "GL_32", + "GL_Batching", + "SDL_2012", + "SDL_Mixer", + "InputBackendSDLTouch", + "BindGL_Static" + ], + "subConfigurations": { + "bindbc-sdl": "staticBC" + } } ] -} \ No newline at end of file +} diff --git a/ios/README.md b/ios/README.md new file mode 100644 index 0000000..940fa6d --- /dev/null +++ b/ios/README.md @@ -0,0 +1,42 @@ +# iOS build instructions + +## Prerequire + +* for building + * LDC2 (>=1.24.0) + * Xcode (>=12.3) + * Apple account registration for App signing. + * Git + * curl +* for running + * iPhone/iPad/iPod touch (>= iOS 14.3) + * iOS Simulator + +## Instructions + +### Download and build libraries + +Change directory to `libs/` and run follow shells. + +1. `00_copy_druntimes.sh` + * Copy druntime and phobos library files from LDC2 directory. +1. `01_download-and-build-SDL2.sh` + * Download a SDL2 source tarball and build using iOS configuration. +1. `02_download-and-build-SDL2_mixer.sh` + * Download a SDL2_mixer source tarball and build using iOS configuration. +1. `03_build-bindbc-sdl.sh` + * Update bindbc-sdl from Github repository and build with patching to dub.sdl. + +### Build tt.app + +Change directory to this file directory. + +1. `build-ios.sh` + * Compile `libtt.a` object files. + * Merge dependency libraries. + * Build `project/build/tt.app` for iPhone simulator. +1. Build for real iOS devices using Xcode. + * Setting up signing capability in target configuration. + * It need Apple developer registration and private key for App signing. + * Build target `tt` for iOS arm64 architecture. + diff --git a/ios/build-ios.sh b/ios/build-ios.sh new file mode 100755 index 0000000..0807a5e --- /dev/null +++ b/ios/build-ios.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +cd `dirname $0` + +IOS_DIR=`pwd` +LIBS_DIR=${IOS_DIR}/libs +BUILD_DIR=${IOS_DIR}/project/build + +cd ../ + +DIST_DIR=`pwd`/dist + +dub build --compiler=ldc2 --arch=arm64-apple-ios --config=iOS || exit $? +libtool -static -o ${LIBS_DIR}/libtt-ios-arm64.a ${DIST_DIR}/libtt.a ${LIBS_DIR}/*-arm64.a &> /dev/null || exit $? + +dub build --compiler=ldc2 --arch=x86_64-apple-ios --config=iOS || exit $? +libtool -static -o ${LIBS_DIR}/libtt-ios-x86_64.a ${DIST_DIR}/libtt.a ${LIBS_DIR}/*-x86_64.a &> /dev/null || exit $? + +xcrun -sdk iphoneos lipo -create \ + ${LIBS_DIR}/libtt-ios-arm64.a \ + ${LIBS_DIR}/libtt-ios-x86_64.a \ + -output ${LIBS_DIR}/libtt-ios.a \ + &> /dev/null + +xcodebuild -project ${IOS_DIR}/project/tt.xcodeproj \ + -scheme tt \ + -sdk iphonesimulator \ + clean build \ + CONFIGURATION_BUILD_DIR=${BUILD_DIR} \ + ARCHS=x86_64 \ + ONLY_ACTIVE_ARCH=NO + diff --git a/ios/libs/.gitignore b/ios/libs/.gitignore new file mode 100644 index 0000000..415aab2 --- /dev/null +++ b/ios/libs/.gitignore @@ -0,0 +1,5 @@ +/SDL +/SDL2-* +/SDL2_mixer-* +/*.a + diff --git a/ios/libs/00_copy_druntimes.sh b/ios/libs/00_copy_druntimes.sh new file mode 100755 index 0000000..ec9ca39 --- /dev/null +++ b/ios/libs/00_copy_druntimes.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +cd `dirname $0` + +LIBS_DIR=`pwd` + +LDC2_HOME=`which ldc2` +LDC2_HOME=`dirname $LDC2_HOME` +LDC2_HOME=`dirname $LDC2_HOME` + +cp ${LDC2_HOME}/lib-ios-arm64/libdruntime-ldc.a ${LIBS_DIR}/libdruntime-ldc-arm64.a +cp ${LDC2_HOME}/lib-ios-x86_64/libdruntime-ldc.a ${LIBS_DIR}/libdruntime-ldc-x86_64.a + +cp ${LDC2_HOME}/lib-ios-arm64/libphobos2-ldc.a ${LIBS_DIR}/libphobos2-ldc-arm64.a +cp ${LDC2_HOME}/lib-ios-x86_64/libphobos2-ldc.a ${LIBS_DIR}/libphobos2-ldc-x86_64.a + diff --git a/ios/libs/01_download-and-build-SDL2.sh b/ios/libs/01_download-and-build-SDL2.sh new file mode 100755 index 0000000..f664d6a --- /dev/null +++ b/ios/libs/01_download-and-build-SDL2.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +cd `dirname $0` + +LIBS_DIR=`pwd` +SDL2_VERSION=2.0.12 +SDL2_BASE_NAME=SDL2-${SDL2_VERSION} + +curl -L -O https://www.libsdl.org/release/${SDL2_BASE_NAME}.tar.gz +tar xvzf ./${SDL2_BASE_NAME}.tar.gz +rm -f ./${SDL2_BASE_NAME}.tar.gz + +xcodebuild \ + -project ./${SDL2_BASE_NAME}/Xcode-iOS/SDL/SDL.xcodeproj \ + -scheme libSDL-iOS \ + -sdk iphoneos \ + clean build \ + CONFIGURATION_BUILD_DIR=${LIBS_DIR} \ + ARCHS=arm64 \ + ONLY_ACTIVE_ARCH=NO +mv ${LIBS_DIR}/libSDL2.a ${LIBS_DIR}/libSDL2-arm64.a + +xcodebuild \ + -project ./${SDL2_BASE_NAME}/Xcode-iOS/SDL/SDL.xcodeproj \ + -scheme libSDL-iOS \ + -sdk iphonesimulator \ + clean build \ + CONFIGURATION_BUILD_DIR=${LIBS_DIR} \ + ARCHS=x86_64 \ + ONLY_ACTIVE_ARCH=NO +mv ${LIBS_DIR}/libSDL2.a ${LIBS_DIR}/libSDL2-x86_64.a + +mkdir -p ./SDL/include +cp -r ./${SDL2_BASE_NAME}/include/* ./SDL/include + diff --git a/ios/libs/02_download-and-build-SDL2_mixer.sh b/ios/libs/02_download-and-build-SDL2_mixer.sh new file mode 100755 index 0000000..f7a9fec --- /dev/null +++ b/ios/libs/02_download-and-build-SDL2_mixer.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +cd `dirname $0` + +LIBS_DIR=`pwd` + +SDL2_MIXER_VERSION=2.0.4 +SDL2_MIXER_BASE_NAME=SDL2_mixer-${SDL2_MIXER_VERSION} + +curl -L -O https://www.libsdl.org/projects/SDL_mixer/release/${SDL2_MIXER_BASE_NAME}.tar.gz +tar xvzf ./${SDL2_MIXER_BASE_NAME}.tar.gz +rm -f ./${SDL2_MIXER_BASE_NAME}.tar.gz + +xcodebuild \ + -project ./${SDL2_MIXER_BASE_NAME}/Xcode-iOS/SDL_mixer.xcodeproj \ + -scheme libSDL_mixer-iOS \ + -sdk iphoneos \ + clean build \ + CONFIGURATION_BUILD_DIR=${LIBS_DIR} \ + ARCHS=arm64 \ + ONLY_ACTIVE_ARCH=NO +mv ${LIBS_DIR}/libSDL2_mixer.a ${LIBS_DIR}/libSDL2_mixer-arm64.a + +xcodebuild \ + -project ./${SDL2_MIXER_BASE_NAME}/Xcode-iOS/SDL_mixer.xcodeproj \ + -scheme libSDL_mixer-iOS \ + -sdk iphonesimulator \ + clean build \ + CONFIGURATION_BUILD_DIR=${LIBS_DIR} \ + ARCHS=x86_64 \ + ONLY_ACTIVE_ARCH=NO +mv ${LIBS_DIR}/libSDL2_mixer.a ${LIBS_DIR}/libSDL2_mixer-x86_64.a + diff --git a/ios/libs/03_build-bindbc-sdl.sh b/ios/libs/03_build-bindbc-sdl.sh new file mode 100755 index 0000000..6ef268d --- /dev/null +++ b/ios/libs/03_build-bindbc-sdl.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +cd `dirname $0` + +LIBS_DIR=`pwd` + +git submodule update + +cat >> ${LIBS_DIR}/bindbc-sdl/dub.sdl < + + + + diff --git a/ios/project/tt.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/project/tt.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/project/tt.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/project/tt/Assets.xcassets/AccentColor.colorset/Contents.json b/ios/project/tt/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/ios/project/tt/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..4955743 --- /dev/null +++ b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "filename" : "icon-40x40.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "icon-60x60.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "icon-58x58.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "icon-87x87.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "icon-80x80.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "icon-120x120.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "icon-120x120-1.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "icon-180x180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "icon-20x20.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "icon-40x40-1.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "icon-29x29.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "icon-58x58-1.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "icon-40x40-2.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "icon-80x80-1.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "icon-76x76.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "icon-152x152.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "icon-167x167.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "icon-1024x1024.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-1024x1024.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-1024x1024.png new file mode 100644 index 0000000..53235b8 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-1024x1024.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-120x120-1.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-120x120-1.png new file mode 100644 index 0000000..377378a Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-120x120-1.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-120x120.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-120x120.png new file mode 100644 index 0000000..377378a Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-120x120.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-152x152.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-152x152.png new file mode 100644 index 0000000..1e498ca Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-152x152.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-167x167.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-167x167.png new file mode 100644 index 0000000..3380b3a Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-167x167.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-180x180.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-180x180.png new file mode 100644 index 0000000..b33deb4 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-180x180.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-20x20.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-20x20.png new file mode 100644 index 0000000..da115d3 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-20x20.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-29x29.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-29x29.png new file mode 100644 index 0000000..dfd82d4 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-29x29.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40-1.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40-1.png new file mode 100644 index 0000000..8b3d3f9 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40-1.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40-2.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40-2.png new file mode 100644 index 0000000..8b3d3f9 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40-2.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40.png new file mode 100644 index 0000000..8b3d3f9 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-40x40.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-58x58-1.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-58x58-1.png new file mode 100644 index 0000000..d1b0db6 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-58x58-1.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-58x58.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-58x58.png new file mode 100644 index 0000000..d1b0db6 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-58x58.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-60x60.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-60x60.png new file mode 100644 index 0000000..750d7f0 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-60x60.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-76x76.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-76x76.png new file mode 100644 index 0000000..b900523 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-76x76.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-80x80-1.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-80x80-1.png new file mode 100644 index 0000000..f7bb387 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-80x80-1.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-80x80.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-80x80.png new file mode 100644 index 0000000..f7bb387 Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-80x80.png differ diff --git a/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-87x87.png b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-87x87.png new file mode 100644 index 0000000..7192aff Binary files /dev/null and b/ios/project/tt/Assets.xcassets/AppIcon.appiconset/icon-87x87.png differ diff --git a/ios/project/tt/Assets.xcassets/Contents.json b/ios/project/tt/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/ios/project/tt/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/project/tt/Info.plist b/ios/project/tt/Info.plist new file mode 100644 index 0000000..b9b054a --- /dev/null +++ b/ios/project/tt/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSupportsIndirectInputEvents + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ios/project/tt/main.m b/ios/project/tt/main.m new file mode 100644 index 0000000..7dbfbd4 --- /dev/null +++ b/ios/project/tt/main.m @@ -0,0 +1,7 @@ +#include "SDL.h" + +int ttStartup(int argc, char * argv[]); + +int main(int argc, char * argv[]) { + return ttStartup(argc, argv); +} diff --git a/ios/run-ios-simulator.sh b/ios/run-ios-simulator.sh new file mode 100755 index 0000000..bc3941c --- /dev/null +++ b/ios/run-ios-simulator.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +cd `dirname $0` + +APP_ID=com.example.tt +APP_BUNDLE_PATH=`pwd`/project/build/tt.app +DEVICE_ID="547B7D16-D2AA-40D1-A807-61D083A71CA8" + +xcrun simctl boot ${DEVICE_ID} +xcrun simctl install ${DEVICE_ID} ${APP_BUNDLE_PATH} +xcrun simctl launch --console ${DEVICE_ID} ${APP_ID} + diff --git a/ldc2.conf b/ldc2.conf index fe85114..e86a4bd 100644 --- a/ldc2.conf +++ b/ldc2.conf @@ -14,4 +14,49 @@ default: lib-dirs = []; // default rpath when linking against the shared default libs rpath = ""; -}; \ No newline at end of file +}; + +// for iOS configurations. + +"arm64-apple-ios": +{ + switches = [ + "-defaultlib=phobos2-ldc,druntime-ldc", + "-link-defaultlib-shared=false", + "-fvisibility=hidden", + "-Xcc=-target", + "-Xcc=arm64-apple-ios12.0", + "-Xcc=-miphoneos-version-min=12.0", + "-Xcc=-isysroot", + "-Xcc=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk", + ]; + post-switches = [ + "-I%%ldcbinarypath%%/../import", + ]; + lib-dirs = [ + "%%ldcbinarypath%%/../lib-ios-arm64", + ]; + rpath = "%%ldcbinarypath%%/../lib-ios-arm64"; +}; + +"x86_64-apple-ios": +{ + switches = [ + "-defaultlib=phobos2-ldc,druntime-ldc", + "-link-defaultlib-shared=false", + "-fvisibility=hidden", + "-Xcc=-target", + "-Xcc=x86_64-apple-ios12.0", + "-Xcc=-miphoneos-version-min=12.0", + "-Xcc=-isysroot", + "-Xcc=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk", + ]; + post-switches = [ + "-I%%ldcbinarypath%%/../import", + ]; + lib-dirs = [ + "%%ldcbinarypath%%/../lib-ios-x86_64", + ]; + rpath = "%%ldcbinarypath%%/../lib-ios-x86_64"; +}; + diff --git a/src/abagames/tt/boot.d b/src/abagames/tt/boot.d index 6d23987..f98c1d0 100644 --- a/src/abagames/tt/boot.d +++ b/src/abagames/tt/boot.d @@ -41,7 +41,28 @@ version(WASM) { } } -public int main(string[] args) { +version(IOS) { + import std.algorithm : map; + import std.array : array; + + alias extern(C) int function(char[][] args) MainFunc; + extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc); + + extern(C) int ttStartup(int argc, char** argv) { + return _d_run_main(argc, argv, &ttMainFunc); + } + + extern(C) int ttMainFunc(char[][] args) { + return ttMain(args.map!((s) => s.idup).array); + } + +} else { + public int main(string[] args) { + return ttMain(args); + } +} + +private int ttMain(string[] args) { screen = new Screen; pad = new RecordablePad(new InputBackendImpl()); gameManager = new GameManager; diff --git a/src/abagames/tt/gamemanager.d b/src/abagames/tt/gamemanager.d index aeb8495..e2b6258 100644 --- a/src/abagames/tt/gamemanager.d +++ b/src/abagames/tt/gamemanager.d @@ -32,6 +32,8 @@ import abagames.tt.title; import abagames.tt.soundmanager; import abagames.tt.replay; +import abagames.tt.virtualpad : VirtualPad; + /** * Manage the game state and actor pools. */ @@ -55,6 +57,7 @@ public class GameManager: abagames.util.sdl.gamemanager.GameManager { TitleState titleState; InGameState inGameState; bool escPressed; + VirtualPad virtualPad; public override void init() { BarrageManager.load(); @@ -106,6 +109,8 @@ public class GameManager: abagames.util.sdl.gamemanager.GameManager { pad, titleManager, passedEnemies, inGameState); inGameState.seed = rand.nextInt32(); ship.setGameState(inGameState); + + virtualPad = new VirtualPad(pad); } public override void start() { @@ -181,6 +186,7 @@ public class GameManager: abagames.util.sdl.gamemanager.GameManager { GL.popMatrix(); screen.viewOrthoFixed(); state.drawFront(); + virtualPad.draw(); screen.viewPerspective(); } } diff --git a/src/abagames/tt/virtualpad.d b/src/abagames/tt/virtualpad.d new file mode 100644 index 0000000..025b41d --- /dev/null +++ b/src/abagames/tt/virtualpad.d @@ -0,0 +1,154 @@ +/* + * virtualpad.d + * + * Copyright 2020 outlandkarasu. Some rights reserved. + * + * License: BSD-2-Clause + */ +module abagames.tt.virtualpad; + +import abagames.util.gl : GL; +import abagames.util.sdl.pad : Pad; +import abagames.tt.screen : Screen; + +public class VirtualPad { + + private Pad pad; + + this(Pad pad) { + this.pad = pad; + } + + version(InputBackendSDLTouch) { + + import abagames.util.sdl.input : Input, Backend = InputBackendSDLTouch; + + void draw() { + GL.pushMatrix(); + GL.lineWidth(4); + GL.color(1.0, 1.0, 1.0, 1.0); + + drawLeftWedge(); + drawRightWedge(); + drawUpWedge(); + drawDownWedge(); + + drawA(); + drawB(); + drawPause(); + + GL.lineWidth(1); + GL.popMatrix(); + } + + private: + + void drawLeftWedge() { + GL.pushMatrix(); + scaling(Backend.LEFT_WEDGE_RECT); + GL.begin(isDirPressing(Input.Dir.LEFT) ? GL.TRIANGLES : GL.LINE_LOOP); + GL.vertex( 0.5, 0.5, 0); + GL.vertex(-0.5, 0.0, 0); + GL.vertex( 0.5, -0.5, 0); + GL.end(); + GL.popMatrix(); + } + + void drawUpWedge() { + GL.pushMatrix(); + GL.begin(isDirPressing(Input.Dir.UP) ? GL.TRIANGLES : GL.LINE_LOOP); + scaling(Backend.UP_WEDGE_RECT); + GL.vertex( 0.0, -0.5, 0); + GL.vertex( 0.5, 0.5, 0); GL.vertex(-0.5, 0.5, 0); + GL.end(); + GL.popMatrix(); + } + + void drawRightWedge() { + GL.pushMatrix(); + scaling(Backend.RIGHT_WEDGE_RECT); + GL.begin(isDirPressing(Input.Dir.RIGHT) ? GL.TRIANGLES : GL.LINE_LOOP); + GL.vertex(-0.5, 0.5, 0); + GL.vertex( 0.5, 0.0, 0); + GL.vertex(-0.5, -0.5, 0); + GL.end(); + GL.popMatrix(); + } + + void drawDownWedge() { + GL.pushMatrix(); + scaling(Backend.DOWN_WEDGE_RECT); + GL.begin(isDirPressing(Input.Dir.DOWN) ? GL.TRIANGLES : GL.LINE_LOOP); + GL.vertex(-0.5, -0.5, 0); + GL.vertex( 0.5, -0.5, 0); + GL.vertex( 0.0, 0.5, 0); + GL.end(); + GL.popMatrix(); + } + + void drawA() { + GL.pushMatrix(); + scaling(Backend.A_BUTTON_RECT); + GL.begin(isButtonPressing(Input.Button.A) ? GL.TRIANGLES : GL.LINE_LOOP); + GL.vertex(-0.5, -0.5, 0); + GL.vertex( 0.5, 0.5, 0); + GL.vertex(-0.5, 0.5, 0); + GL.end(); + GL.popMatrix(); + } + + void drawB() { + GL.pushMatrix(); + scaling(Backend.B_BUTTON_RECT); + GL.begin(isButtonPressing(Input.Button.B) ? GL.TRIANGLES : GL.LINE_LOOP); + GL.vertex(-0.5, -0.5, 0); + GL.vertex( 0.5, 0.0, 0); + GL.vertex(-0.5, 0.0, 0); + GL.vertex(-0.5, 0.0, 0); + GL.vertex( 0.5, 0.5, 0); + GL.vertex(-0.5, 0.5, 0); + GL.end(); + GL.popMatrix(); + } + + void drawPause() { + GL.pushMatrix(); + scaling(Backend.PAUSE_BUTTON_RECT); + if (pad.getPauseState()) { + GL.begin(GL.TRIANGLES); + GL.vertex(-0.5, -0.5, 0); + GL.vertex( 0.5, -0.5, 0); + GL.vertex( 0.5, 0.5, 0); + GL.vertex(-0.5, -0.5, 0); + GL.vertex( 0.5, 0.5, 0); + GL.vertex(-0.5, 0.5, 0); + GL.end(); + } else { + GL.begin(GL.LINE_LOOP); + GL.vertex(-0.5, -0.5, 0); + GL.vertex( 0.5, -0.5, 0); + GL.vertex( 0.5, 0.5, 0); + GL.vertex(-0.5, 0.5, 0); + GL.end(); + } + GL.popMatrix(); + } + + void scaling(ref const(Backend.ButtonRect) rect) { + GL.translate(rect.x + rect.width / 2.0, rect.y + rect.height / 2.0, 0); + GL.scale(rect.width, rect.height, 1.0); + } + + bool isDirPressing(Input.Dir dir) { + return (pad.getDirState() & dir) != 0; + } + + bool isButtonPressing(Input.Button button) { + return (pad.getButtonState() & button) != 0; + } + + } else { + void draw() {} + } +} + diff --git a/src/abagames/util/bulletml/parser.d b/src/abagames/util/bulletml/parser.d index ccce760..a613292 100644 --- a/src/abagames/util/bulletml/parser.d +++ b/src/abagames/util/bulletml/parser.d @@ -59,7 +59,7 @@ protected: return false; } if (c != v) { - backup(idx + 1); + backup(cast(int)(idx + 1)); return false; } } @@ -202,4 +202,4 @@ public: } return 0; } -} \ No newline at end of file +} diff --git a/src/abagames/util/bulletml/xml.d b/src/abagames/util/bulletml/xml.d index 776fc0d..801eafc 100644 --- a/src/abagames/util/bulletml/xml.d +++ b/src/abagames/util/bulletml/xml.d @@ -47,7 +47,7 @@ Element[] parseXML(string s) { search: foreach (idx, c; value) { foreach (sc; space) { if (sc == c) { - spaceIndex = idx; + spaceIndex = cast(int) idx; break search; } } diff --git a/src/abagames/util/gl.d b/src/abagames/util/gl.d index 090f9e8..80a5934 100644 --- a/src/abagames/util/gl.d +++ b/src/abagames/util/gl.d @@ -1,7 +1,25 @@ module abagames.util.gl; import std.stdio; -version(BindBC) { import bindbc.opengl; } + +version(BindBC) +{ + version(BindGL_Static) { version = staticGL; } + else { import bindbc.opengl; } +} +else version(WASM) +{ + version = staticGL; +} + +version(WASM) +{ + version = GL_ES; +} +else version(IOS) +{ + version = GL_ES; +} import abagames.util.conv; import abagames.util.math; @@ -438,7 +456,7 @@ version(GL_Batching) { auto vsIndex = glCreateShader(GL.VERTEX_SHADER); { auto sourcePtr = cast(char*)vsSource.ptr; - int sourceLen = vsSource.length; + int sourceLen = cast(int) vsSource.length; glShaderSource(vsIndex, 1, &sourcePtr, &sourceLen); glCompileShader(vsIndex); glGetShaderiv(vsIndex, GL.COMPILE_STATUS, &status); @@ -451,7 +469,7 @@ version(GL_Batching) { auto fsIndex = glCreateShader(GL.FRAGMENT_SHADER); { auto sourcePtr = cast(char*)fsSource.ptr; - int sourceLen = fsSource.length; + int sourceLen = cast(int) fsSource.length; glShaderSource(fsIndex, 1, &sourcePtr, &sourceLen); glCompileShader(fsIndex); glGetShaderiv(fsIndex, GL.COMPILE_STATUS, &status); @@ -516,7 +534,7 @@ version(GL_Batching) { public: static void init() { - version(WASM) { + version(GL_ES) { program = compileProgram( ` precision mediump float; @@ -921,7 +939,7 @@ version(GL_Batching) { glBindVertexArray(triArrayIndex); glBindBuffer(GL.ARRAY_BUFFER, triBufferIndex); - int size = currentTriCount * Vertex.sizeof; + int size = cast(int)(currentTriCount * Vertex.sizeof); glBufferData(GL.ARRAY_BUFFER, size, null, GL.STREAM_DRAW); glBufferData(GL.ARRAY_BUFFER, size, triangles.ptr, GL.STREAM_DRAW); @@ -939,7 +957,7 @@ version(GL_Batching) { glBindVertexArray(lineArrayIndex); glBindBuffer(GL.ARRAY_BUFFER, lineBufferIndex); - int size = currentLineCount * Vertex.sizeof; + int size = cast(int)(currentLineCount * Vertex.sizeof); glBufferData(GL.ARRAY_BUFFER, size, null, GL.STREAM_DRAW); glBufferData(GL.ARRAY_BUFFER, size, lines.ptr, GL.STREAM_DRAW); @@ -996,7 +1014,7 @@ version(GL_Batching) { } } -version(WASM) { +version(staticGL) { extern (C) { version(X86) { int glGetAttribLocation(uint, const(char)*) { return 0; } @@ -1030,13 +1048,21 @@ version(WASM) { void glVertexAttribPointer(uint, int, uint, ubyte, int, const(void)*) {} void glViewport(int, int, int, int) {} } else { - int glGetAttribLocationWithLen(uint, const(char*), uint); - int glGetAttribLocation(uint p, string n) { - return glGetAttribLocationWithLen(p, n.ptr, n.length); + version(IOS) + { + int glGetAttribLocation(uint, const(char*)); + int glGetUniformLocation(uint, const(char*)); } - int glGetUniformLocationWithLen(uint, const(char*), uint); - int glGetUniformLocation(uint p, string n) { - return glGetUniformLocationWithLen(p, n.ptr, n.length); + else + { + int glGetAttribLocationWithLen(uint, const(char*), uint); + int glGetAttribLocation(uint p, string n) { + return glGetAttribLocationWithLen(p, n.ptr, n.length); + } + int glGetUniformLocationWithLen(uint, const(char*), uint); + int glGetUniformLocation(uint p, string n) { + return glGetUniformLocationWithLen(p, n.ptr, n.length); + } } uint glCreateProgram(); uint glCreateShader(uint); diff --git a/src/abagames/util/sdl/input.d b/src/abagames/util/sdl/input.d index 5ffd0f7..1c579ed 100644 --- a/src/abagames/util/sdl/input.d +++ b/src/abagames/util/sdl/input.d @@ -98,3 +98,137 @@ version(InputBackendWASM) { alias InputBackendImpl = InputBackendWASM; } + +version(InputBackendSDLTouch) { + public class InputBackendSDLTouch : InputBackend { + struct ButtonRect { + float x; + float y; + float width; + float height; + + bool isIn(float positionX, float positionY) const { + return (x <= positionX && positionX < x + width) + && (y <= positionY && positionY < y + height); + } + } + + struct Button { + ButtonRect rect; + int state; + } + + static { + // ortho screen is fixed size. + immutable SCREEN_WIDTH = 640; + immutable SCREEN_HEIGHT = 480; + + immutable WEDGES_POSITION_X = 15.0; + immutable WEDGES_POSITION_Y = 300.0; + immutable WEDGE_SIZE = 50.0; + + immutable LEFT_WEDGE_RECT = ButtonRect( + WEDGES_POSITION_X, + WEDGES_POSITION_Y + WEDGE_SIZE, + WEDGE_SIZE, + WEDGE_SIZE); + + immutable RIGHT_WEDGE_RECT = ButtonRect( + WEDGES_POSITION_X + WEDGE_SIZE * 2.0, + WEDGES_POSITION_Y + WEDGE_SIZE, + WEDGE_SIZE, + WEDGE_SIZE); + + immutable UP_WEDGE_RECT = ButtonRect( + WEDGES_POSITION_X + WEDGE_SIZE, + WEDGES_POSITION_Y, + WEDGE_SIZE, + WEDGE_SIZE); + + immutable DOWN_WEDGE_RECT = ButtonRect( + WEDGES_POSITION_X + WEDGE_SIZE, + WEDGES_POSITION_Y + WEDGE_SIZE * 2.0, + WEDGE_SIZE, + WEDGE_SIZE); + + immutable BUTTON_SIZE = 60.0; + immutable A_BUTTON_POSITION_X = 580.0; + immutable A_BUTTON_POSITION_Y = 300.0; + immutable B_BUTTON_POSITION_X = 580.0; + immutable B_BUTTON_POSITION_Y = A_BUTTON_POSITION_Y + BUTTON_SIZE + 20.0; + + immutable A_BUTTON_RECT = ButtonRect( + A_BUTTON_POSITION_X, + A_BUTTON_POSITION_Y, + BUTTON_SIZE, + BUTTON_SIZE); + + immutable B_BUTTON_RECT = ButtonRect( + B_BUTTON_POSITION_X, + B_BUTTON_POSITION_Y, + BUTTON_SIZE, + BUTTON_SIZE); + + immutable PAUSE_BUTTON_RECT = ButtonRect( + 20.0, 20.0, 30.0, 30.0); + + enum PAUSE_BUTTON_BIT = 1024; + + immutable BUTTONS = [ + Button(LEFT_WEDGE_RECT, Input.Dir.LEFT), + Button(UP_WEDGE_RECT, Input.Dir.UP), + Button(RIGHT_WEDGE_RECT, Input.Dir.RIGHT), + Button(DOWN_WEDGE_RECT, Input.Dir.DOWN), + Button(A_BUTTON_RECT, Input.Button.A), + Button(B_BUTTON_RECT, Input.Button.B), + Button(PAUSE_BUTTON_RECT, PAUSE_BUTTON_BIT), + ]; + } + + uint state = 0; + + public override void update() { + state = 0; + foreach (i; 0 .. SDL_GetNumTouchDevices()) { + immutable touchID = SDL_GetTouchDevice(i); + foreach (f; 0 .. SDL_GetNumTouchFingers(touchID)) { + const finger = SDL_GetTouchFinger(touchID, f); + if (!finger) continue; + state |= positionToButton( + finger.x, finger.y, SCREEN_WIDTH, SCREEN_HEIGHT); + } + } + } + + private static int positionToButton(float x, float y, int width, int height) { + immutable positionX = width * x; + immutable positionY = height * y; + int state = 0; + foreach (button; BUTTONS) { + if (button.rect.isIn(positionX, positionY)) { + state |= button.state; + } + } + return state; + } + + public override int getDirState() { + return state & 0xF; + } + + public override int getButtonState() { + return state & 0x30; + } + + public override bool getExitState() { + return false; + } + + public override bool getPauseState() { + return (state & PAUSE_BUTTON_BIT) != 0; + } + } + + alias InputBackendImpl = InputBackendSDLTouch; +} + diff --git a/src/abagames/util/sdl/screen3d.d b/src/abagames/util/sdl/screen3d.d index d78ba09..e114a44 100644 --- a/src/abagames/util/sdl/screen3d.d +++ b/src/abagames/util/sdl/screen3d.d @@ -10,7 +10,9 @@ version(BindBC) { import std.stdio; import std.string; import bindbc.sdl; - import bindbc.opengl; + + version(BindGL_Static) { } + else { import bindbc.opengl; } } import abagames.util.gl; import abagames.util.vector; @@ -39,9 +41,13 @@ public class Screen3D: Screen { protected abstract void init(); public void initWindow() { - if (loadSDL() != sdlSupport) { - throw new SDLInitFailedException("Unable to load SDL"); + version (BindSDL_Static) {} + else { + if (loadSDL() != sdlSupport) { + throw new SDLInitFailedException("Unable to load SDL"); + } } + // Initialize SDL. if (SDL_Init(SDL_INIT_VIDEO) < 0) { throw new SDLInitFailedException("Unable to initialize SDL: " ~ to!string(SDL_GetError())); @@ -64,11 +70,20 @@ version(GL_32) { throw new SDLInitFailedException("Unable to create SDL screen: " ~ to!string(SDL_GetError())); } context = SDL_GL_CreateContext(window); - auto glStatus = loadOpenGL(); - if (!isOpenGLLoaded) { - throw new SDLInitFailedException("Unable to load OpenGL"); + + version(BindGL_Static) {} + else { + auto glStatus = loadOpenGL(); + if (!isOpenGLLoaded) { + throw new SDLInitFailedException("Unable to load OpenGL"); + } + writeln("OpenGL Status: ", glStatus); } - writeln("OpenGL Status: ", glStatus); + + version(IOS) { + SDL_GetWindowSize(window, &width, &height); + } + GL.init(); GL.viewport(0, 0, width, height); GL.clearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -207,4 +222,4 @@ public class Screen3D: Screen { } } -} \ No newline at end of file +} diff --git a/src/abagames/util/sdl/sound.d b/src/abagames/util/sdl/sound.d index 6538cc2..81a0c94 100644 --- a/src/abagames/util/sdl/sound.d +++ b/src/abagames/util/sdl/sound.d @@ -32,19 +32,29 @@ public class SoundManager { public static void init() { if (noSound) return; - if (loadSDL() != sdlSupport) { - noSound = true; - return; + + version (BindSDL_Static) {} + else { + if (loadSDL() != sdlSupport) { + noSound = true; + return; + } } + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { noSound = true; throw new SDLInitFailedException ("Unable to initialize SDL_AUDIO: " ~ convString(SDL_GetError())); } - if (loadSDLMixer() != sdlMixerSupport) { - noSound = true; - return; + + version (BindSDL_Static) {} + else { + if (loadSDLMixer() != sdlMixerSupport) { + noSound = true; + return; + } } + int audio_rate = 44100; Uint16 audio_format = AUDIO_S16; int audio_channels = 1; @@ -223,4 +233,4 @@ public: } } -} \ No newline at end of file +}