diff --git a/Aerofoil/GpSystemServices_Win32.cpp b/Aerofoil/GpSystemServices_Win32.cpp index 2824dc0..0e52b22 100644 --- a/Aerofoil/GpSystemServices_Win32.cpp +++ b/Aerofoil/GpSystemServices_Win32.cpp @@ -10,6 +10,7 @@ #endif GpSystemServices_Win32::GpSystemServices_Win32() + : m_isTouchscreenSimulation(false) { } @@ -84,6 +85,20 @@ void GpSystemServices_Win32::Beep() const MessageBeep(MB_OK); } +bool GpSystemServices_Win32::IsTouchscreen() const +{ + return m_isTouchscreenSimulation; +} + +bool GpSystemServices_Win32::IsUsingMouseAsTouch() const +{ + return m_isTouchscreenSimulation; +} + +void GpSystemServices_Win32::SetTouchscreenSimulation(bool isTouchscreenSimulation) +{ + m_isTouchscreenSimulation = isTouchscreenSimulation; +} GpSystemServices_Win32 *GpSystemServices_Win32::GetInstance() { diff --git a/Aerofoil/GpSystemServices_Win32.h b/Aerofoil/GpSystemServices_Win32.h index 934783e..945fafe 100644 --- a/Aerofoil/GpSystemServices_Win32.h +++ b/Aerofoil/GpSystemServices_Win32.h @@ -22,10 +22,16 @@ public: PortabilityLayer::HostThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) override; uint64_t GetFreeMemoryCosmetic() const override; void Beep() const override; + bool IsTouchscreen() const override; + bool IsUsingMouseAsTouch() const override; + + void SetTouchscreenSimulation(bool isTouchscreenSimulation); static GpSystemServices_Win32 *GetInstance(); private: + bool m_isTouchscreenSimulation; + static GpSystemServices_Win32 ms_instance; }; diff --git a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp index 02c3008..9b9a9b5 100644 --- a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp +++ b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.cpp @@ -1,4 +1,268 @@ +#define _LARGEFILE64_SOURCE #include "GpFileSystem_Android.h" +#include "GpIOStream.h" +#include "VirtualDirectory.h" + +#include "SDL_rwops.h" + +#include +#include +#include +#include + + + +class GpFileStream_SDLRWops final : public GpIOStream +{ +public: + GpFileStream_SDLRWops(SDL_RWops *f, bool readOnly, bool writeOnly); + ~GpFileStream_SDLRWops(); + + size_t Read(void *bytesOut, size_t size) override; + size_t Write(const void *bytes, size_t size) override; + bool IsSeekable() const override; + bool IsReadOnly() const override; + bool IsWriteOnly() const override; + bool SeekStart(GpUFilePos_t loc) override; + bool SeekCurrent(GpFilePos_t loc) override; + bool SeekEnd(GpUFilePos_t loc) override; + bool Truncate(GpUFilePos_t loc) override; + GpUFilePos_t Size() const override; + GpUFilePos_t Tell() const override; + void Close() override; + void Flush() override; + +private: + SDL_RWops *m_rw; + bool m_isReadOnly; + bool m_isWriteOnly; +}; + + +GpFileStream_SDLRWops::GpFileStream_SDLRWops(SDL_RWops *f, bool readOnly, bool writeOnly) + : m_rw(f) + , m_isReadOnly(readOnly) + , m_isWriteOnly(writeOnly) +{ +} + + +GpFileStream_SDLRWops::~GpFileStream_SDLRWops() +{ + m_rw->close(m_rw); +} + +size_t GpFileStream_SDLRWops::Read(void *bytesOut, size_t size) +{ + return m_rw->read(m_rw, bytesOut, 1, size); +} + +size_t GpFileStream_SDLRWops::Write(const void *bytes, size_t size) +{ + return m_rw->write(m_rw, bytes, 1, size); +} + +bool GpFileStream_SDLRWops::IsSeekable() const +{ + return true; +} + +bool GpFileStream_SDLRWops::IsReadOnly() const +{ + return m_isReadOnly; +} + +bool GpFileStream_SDLRWops::IsWriteOnly() const +{ + return m_isWriteOnly; +} + +bool GpFileStream_SDLRWops::SeekStart(GpUFilePos_t loc) +{ + return m_rw->seek(m_rw, static_cast(loc), RW_SEEK_SET) >= 0; +} + +bool GpFileStream_SDLRWops::SeekCurrent(GpFilePos_t loc) +{ + return m_rw->seek(m_rw, static_cast(loc), RW_SEEK_CUR) >= 0; +} + +bool GpFileStream_SDLRWops::SeekEnd(GpUFilePos_t loc) +{ + return m_rw->seek(m_rw, -static_cast(loc), RW_SEEK_END) >= 0; +} + +bool GpFileStream_SDLRWops::Truncate(GpUFilePos_t loc) +{ + return false; +} + +GpUFilePos_t GpFileStream_SDLRWops::Size() const +{ + return m_rw->size(m_rw); +} + +GpUFilePos_t GpFileStream_SDLRWops::GpFileStream_SDLRWops::Tell() const +{ + return SDL_RWtell(m_rw); +} + +void GpFileStream_SDLRWops::Close() +{ + this->~GpFileStream_SDLRWops(); + free(this); +} + +void GpFileStream_SDLRWops::Flush() +{ +} + +class GpFileStream_Android_File final : public GpIOStream +{ +public: + GpFileStream_Android_File(FILE *f, int fd, bool readOnly, bool writeOnly); + ~GpFileStream_Android_File(); + + size_t Read(void *bytesOut, size_t size) override; + size_t Write(const void *bytes, size_t size) override; + bool IsSeekable() const override; + bool IsReadOnly() const override; + bool IsWriteOnly() const override; + bool SeekStart(GpUFilePos_t loc) override; + bool SeekCurrent(GpFilePos_t loc) override; + bool SeekEnd(GpUFilePos_t loc) override; + bool Truncate(GpUFilePos_t loc) override; + GpUFilePos_t Size() const override; + GpUFilePos_t Tell() const override; + void Close() override; + void Flush() override; + +private: + FILE *m_f; + int m_fd; + bool m_seekable; + bool m_isReadOnly; + bool m_isWriteOnly; +}; + +GpFileStream_Android_File::GpFileStream_Android_File(FILE *f, int fd, bool readOnly, bool writeOnly) + : m_f(f) + , m_fd(fd) + , m_isReadOnly(readOnly) + , m_isWriteOnly(writeOnly) +{ + m_seekable = (fseek(m_f, 0, SEEK_CUR) == 0); +} + +GpFileStream_Android_File::~GpFileStream_Android_File() +{ + fclose(m_f); +} + +size_t GpFileStream_Android_File::Read(void *bytesOut, size_t size) +{ + if (m_isWriteOnly) + return 0; + return fread(bytesOut, 1, size, m_f); +} + +size_t GpFileStream_Android_File::Write(const void *bytes, size_t size) +{ + if (m_isReadOnly) + return 0; + return fwrite(bytes, 1, size, m_f); +} + +bool GpFileStream_Android_File::IsSeekable() const +{ + return m_seekable; +} + +bool GpFileStream_Android_File::IsReadOnly() const +{ + return m_isReadOnly; +} + +bool GpFileStream_Android_File::IsWriteOnly() const +{ + return m_isWriteOnly; +} + +bool GpFileStream_Android_File::SeekStart(GpUFilePos_t loc) +{ + if (!m_seekable) + return false; + + return lseek64(m_fd, static_cast(loc), SEEK_SET) >= 0; +} + +bool GpFileStream_Android_File::SeekCurrent(GpFilePos_t loc) +{ + if (!m_seekable) + return false; + + return lseek64(m_fd, static_cast(loc), SEEK_CUR) >= 0; +} + +bool GpFileStream_Android_File::SeekEnd(GpUFilePos_t loc) +{ + if (!m_seekable) + return false; + + return lseek64(m_fd, -static_cast(loc), SEEK_END) >= 0; +} + +bool GpFileStream_Android_File::Truncate(GpUFilePos_t loc) +{ + return ftruncate64(m_fd, static_cast(loc)) >= 0; +} + +GpUFilePos_t GpFileStream_Android_File::Size() const +{ + struct stat64 s; + if (fstat64(m_fd, &s) < 0) + return 0; + + return static_cast(s.st_size); +} + +GpUFilePos_t GpFileStream_Android_File::Tell() const +{ + return static_cast(ftell(m_f)); +} + +void GpFileStream_Android_File::Close() +{ + this->~GpFileStream_Android_File(); + free(this); +} + +void GpFileStream_Android_File::Flush() +{ + fflush(m_f); +} + +static bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, std::string &resolution, bool &isAsset) +{ + isAsset = false; + switch (virtualDirectory) + { + case PortabilityLayer::VirtualDirectories::kApplicationData: + resolution = std::string("Packaged/") + path; + isAsset = true; + return true; + case PortabilityLayer::VirtualDirectories::kGameData: + resolution = std::string("Packaged/Houses/") + path; + isAsset = true; + return true; + case PortabilityLayer::VirtualDirectories::kFonts: + resolution = std::string("Resources/") + path; + isAsset = true; + return true; + default: + return false; + }; +} GpFileSystem_Android::GpFileSystem_Android() { @@ -6,23 +270,138 @@ GpFileSystem_Android::GpFileSystem_Android() bool GpFileSystem_Android::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) { - return false; + std::string resolvedPath; + bool isAsset; + if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset)) + return false; + + if (isAsset) + { + SDL_RWops *rw = SDL_RWFromFile(resolvedPath.c_str(), "rb"); + if (!rw) + return false; + SDL_RWclose(rw); + } + + struct stat s; + return stat(resolvedPath.c_str(), &s) == 0; } bool GpFileSystem_Android::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists) { - return false; + std::string resolvedPath; + bool isAsset; + if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset)) + { + *exists = false; + return false; + } + + if (isAsset) + return true; + + int permissions = access(resolvedPath.c_str(), W_OK | F_OK); + *exists = ((permissions & F_OK) != 0); + return ((permissions & W_OK) != 0); } GpIOStream *GpFileSystem_Android::OpenFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool writeAccess, GpFileCreationDisposition_t createDisposition) { - return nullptr; + const char *mode = nullptr; + bool canWrite = false; + + switch (createDisposition) { + case GpFileCreationDispositions::kCreateOrOverwrite: + mode = "w+b"; + break; + case GpFileCreationDispositions::kCreateNew: + mode = "x+b"; + break; + case GpFileCreationDispositions::kCreateOrOpen: + mode = "c+b"; + break; + case GpFileCreationDispositions::kOpenExisting: + mode = writeAccess ? "r+b" : "rb"; + break; + case GpFileCreationDispositions::kOverwriteExisting: + mode = "r+b"; + break; + default: + return nullptr; + }; + + std::string resolvedPath; + bool isAsset; + if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset)) + return nullptr; + + if (isAsset) + { + if (createDisposition == GpFileCreationDispositions::kOverwriteExisting || writeAccess) + return nullptr; + + void *objStorage = malloc(sizeof(GpFileStream_SDLRWops)); + if (!objStorage) + return nullptr; + + SDL_RWops *rw = SDL_RWFromFile(resolvedPath.c_str(), mode); + if (!rw) + { + free(objStorage); + return nullptr; + } + + return new (objStorage) GpFileStream_SDLRWops(rw, true, false); + } + else + { + void *objStorage = malloc(sizeof(GpFileStream_Android_File)); + if (!objStorage) + return nullptr; + + FILE *f = fopen(resolvedPath.c_str(), mode); + if (!f) + { + free(objStorage); + return nullptr; + } + + int fd = fileno(f); + + if (createDisposition == GpFileCreationDispositions::kOverwriteExisting) + { + if (ftruncate64(fd, 0) < 0) + { + free(objStorage); + fclose(f); + return nullptr; + } + } + + return new (objStorage) GpFileStream_Android_File(f, fd, !writeAccess, false); + } } bool GpFileSystem_Android::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) { - existed = false; - return false; + std::string resolvedPath; + bool isAsset; + if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset)) + { + existed = false; + return false; + } + + if (isAsset) + return false; + + if (unlink(resolvedPath.c_str()) < 0) + { + existed = (errno != ENOENT); + return false; + } + existed = true; + return true; } PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory) diff --git a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h index fb34d69..3a58b46 100644 --- a/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h +++ b/AerofoilAndroid/app/jni/main/GpFileSystem_Android.h @@ -21,7 +21,5 @@ public: static GpFileSystem_Android *GetInstance(); private: - bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, wchar_t *outPath); - static GpFileSystem_Android ms_instance; }; diff --git a/AerofoilAndroid/app/src/main/.gitignore b/AerofoilAndroid/app/src/main/.gitignore deleted file mode 100644 index c7ed3c8..0000000 --- a/AerofoilAndroid/app/src/main/.gitignore +++ /dev/null @@ -1 +0,0 @@ -assets diff --git a/AerofoilAndroid/app/src/main/assets/.gitignore b/AerofoilAndroid/app/src/main/assets/.gitignore new file mode 100644 index 0000000..8075e75 --- /dev/null +++ b/AerofoilAndroid/app/src/main/assets/.gitignore @@ -0,0 +1,2 @@ +Packaged +Resources diff --git a/AerofoilAndroid/make_symlinks.bat b/AerofoilAndroid/make_symlinks.bat index ac3508d..ab38b63 100644 --- a/AerofoilAndroid/make_symlinks.bat +++ b/AerofoilAndroid/make_symlinks.bat @@ -17,6 +17,7 @@ mklink /D app\jni\zlib ..\..\..\zlib mklink /D app\jni\rapidjson ..\..\..\rapidjson mklink /D app\jni\MacRomanConversion ..\..\..\MacRomanConversion mklink /D app\jni\stb ..\..\..\stb -mklink /D app\src\main\assets ..\..\..\..\Packaged +mklink /D app\src\main\assets\Packaged ..\..\..\..\..\Packaged +mklink /D app\src\main\assets\Resources ..\..\..\..\..\Resources pause diff --git a/AerofoilAndroid/remove_symlinks.bat b/AerofoilAndroid/remove_symlinks.bat index 8d3e7ae..e49eaa2 100644 --- a/AerofoilAndroid/remove_symlinks.bat +++ b/AerofoilAndroid/remove_symlinks.bat @@ -14,4 +14,5 @@ rmdir app\jni\zlib rmdir app\jni\rapidjson rmdir app\jni\MacRomanConversion rmdir app\jni\stb -rmdir app\src\main\assets \ No newline at end of file +rmdir app\src\main\assets\Packaged +rmdir app\src\main\assets\Resources diff --git a/AerofoilSDL/GpMain_SDL_Win32.cpp b/AerofoilSDL/GpMain_SDL_Win32.cpp index 0f51ded..6b56965 100644 --- a/AerofoilSDL/GpMain_SDL_Win32.cpp +++ b/AerofoilSDL/GpMain_SDL_Win32.cpp @@ -50,6 +50,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine { if (!wcscmp(cmdLineArgs[i], L"-diagnostics")) GpLogDriver_Win32::Init(); + + if (!wcscmp(cmdLineArgs[i], L"-touchscreensimulation")) + GpSystemServices_Win32::GetInstance()->SetTouchscreenSimulation(true); } IGpLogDriver *logger = GpLogDriver_Win32::GetInstance(); diff --git a/ApplicationResourcePatches/PICT/1973.bmp b/ApplicationResourcePatches/PICT/1973.bmp new file mode 100644 index 0000000..956f29a Binary files /dev/null and b/ApplicationResourcePatches/PICT/1973.bmp differ diff --git a/ApplicationResourcePatches/PICT/1974.bmp b/ApplicationResourcePatches/PICT/1974.bmp new file mode 100644 index 0000000..3942532 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1974.bmp differ diff --git a/ApplicationResourcePatches/PICT/1975.bmp b/ApplicationResourcePatches/PICT/1975.bmp new file mode 100644 index 0000000..6f8f76f Binary files /dev/null and b/ApplicationResourcePatches/PICT/1975.bmp differ diff --git a/ApplicationResourcePatches/PICT/1976.bmp b/ApplicationResourcePatches/PICT/1976.bmp new file mode 100644 index 0000000..d1527ef Binary files /dev/null and b/ApplicationResourcePatches/PICT/1976.bmp differ diff --git a/ApplicationResourcePatches/PICT/1977.bmp b/ApplicationResourcePatches/PICT/1977.bmp new file mode 100644 index 0000000..13154a6 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1977.bmp differ diff --git a/ApplicationResourcePatches/PICT/1978.bmp b/ApplicationResourcePatches/PICT/1978.bmp new file mode 100644 index 0000000..20a8406 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1978.bmp differ diff --git a/ApplicationResourcePatches/PICT/1979.bmp b/ApplicationResourcePatches/PICT/1979.bmp new file mode 100644 index 0000000..d380910 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1979.bmp differ diff --git a/ApplicationResourcePatches/PICT/1980.bmp b/ApplicationResourcePatches/PICT/1980.bmp new file mode 100644 index 0000000..6e9888e Binary files /dev/null and b/ApplicationResourcePatches/PICT/1980.bmp differ diff --git a/ApplicationResourcePatches/PICT/1981.bmp b/ApplicationResourcePatches/PICT/1981.bmp new file mode 100644 index 0000000..b527b67 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1981.bmp differ diff --git a/ApplicationResourcePatches/PICT/1982.bmp b/ApplicationResourcePatches/PICT/1982.bmp new file mode 100644 index 0000000..cc99675 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1982.bmp differ diff --git a/ApplicationResourcePatches/PICT/1983.bmp b/ApplicationResourcePatches/PICT/1983.bmp new file mode 100644 index 0000000..dc8cb9f Binary files /dev/null and b/ApplicationResourcePatches/PICT/1983.bmp differ diff --git a/ApplicationResourcePatches/PICT/1984.bmp b/ApplicationResourcePatches/PICT/1984.bmp new file mode 100644 index 0000000..732abb4 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1984.bmp differ diff --git a/ApplicationResourcePatches/PICT/1985.bmp b/ApplicationResourcePatches/PICT/1985.bmp new file mode 100644 index 0000000..3b46ba7 Binary files /dev/null and b/ApplicationResourcePatches/PICT/1985.bmp differ diff --git a/ApplicationResourcePatches/PICT/1986.bmp b/ApplicationResourcePatches/PICT/1986.bmp new file mode 100644 index 0000000..1d9926e Binary files /dev/null and b/ApplicationResourcePatches/PICT/1986.bmp differ diff --git a/ApplicationResourcePatches/PICT/1987.bmp b/ApplicationResourcePatches/PICT/1987.bmp new file mode 100644 index 0000000..cfcd74e Binary files /dev/null and b/ApplicationResourcePatches/PICT/1987.bmp differ diff --git a/ApplicationResourcePatches/manifest.json b/ApplicationResourcePatches/manifest.json index df473e1..4047566 100644 --- a/ApplicationResourcePatches/manifest.json +++ b/ApplicationResourcePatches/manifest.json @@ -6,7 +6,22 @@ "DITL/2001.json" : "ApplicationResourcePatches/DITL/2001.json", "DITL/2002.json" : "ApplicationResourcePatches/DITL/2002.json", "DITL/2003.json" : "ApplicationResourcePatches/DITL/2003.json", - "DITL/2004.json" : "ApplicationResourcePatches/DITL/2004.json" + "DITL/2004.json" : "ApplicationResourcePatches/DITL/2004.json", + "PICT/1973.bmp" : "ApplicationResourcePatches/PICT/1973.bmp", + "PICT/1974.bmp" : "ApplicationResourcePatches/PICT/1974.bmp", + "PICT/1975.bmp" : "ApplicationResourcePatches/PICT/1975.bmp", + "PICT/1976.bmp" : "ApplicationResourcePatches/PICT/1976.bmp", + "PICT/1977.bmp" : "ApplicationResourcePatches/PICT/1977.bmp", + "PICT/1978.bmp" : "ApplicationResourcePatches/PICT/1978.bmp", + "PICT/1979.bmp" : "ApplicationResourcePatches/PICT/1979.bmp", + "PICT/1980.bmp" : "ApplicationResourcePatches/PICT/1980.bmp", + "PICT/1981.bmp" : "ApplicationResourcePatches/PICT/1981.bmp", + "PICT/1982.bmp" : "ApplicationResourcePatches/PICT/1982.bmp", + "PICT/1983.bmp" : "ApplicationResourcePatches/PICT/1983.bmp", + "PICT/1984.bmp" : "ApplicationResourcePatches/PICT/1984.bmp", + "PICT/1985.bmp" : "ApplicationResourcePatches/PICT/1985.bmp", + "PICT/1986.bmp" : "ApplicationResourcePatches/PICT/1986.bmp", + "PICT/1987.bmp" : "ApplicationResourcePatches/PICT/1987.bmp" }, "delete" : [ diff --git a/GpApp/AnimCursor.cpp b/GpApp/AnimCursor.cpp index dea8562..ee6dbab 100644 --- a/GpApp/AnimCursor.cpp +++ b/GpApp/AnimCursor.cpp @@ -265,6 +265,9 @@ Boolean GetColorCursors (acurHandle ballCursH, compiledAcurHandle compiledBallCu void InitAnimatedCursor (acurHandle ballCursH) { + if (thisMac.isTouchscreen) + return; + compiledAcurHandle compiledBallCursorH; if (ballCursH == nil) @@ -275,7 +278,6 @@ void InitAnimatedCursor (acurHandle ballCursH) if (!compiledBallCursorH) RedAlert(kErrFailedResourceLoad); - GetColorCursors(ballCursH, compiledBallCursorH); DisposCursors(); animCursorH = ballCursH; @@ -335,8 +337,9 @@ void IncrementCursor (void) InitAnimatedCursor(nil); if (animCursorH) { - (*animCursorH)->index++; - (*animCursorH)->index %= (*animCursorH)->n; + acurRec *acur = *animCursorH; + acur->index++; + acur->index %= acur->n; PortabilityLayer::HostDisplayDriver::GetInstance()->SetCursor((*compiledAnimCursorH)->frame[(*animCursorH)->index].hwCursor); } diff --git a/GpApp/Environ.cpp b/GpApp/Environ.cpp index 5bc9abf..62c13a2 100644 --- a/GpApp/Environ.cpp +++ b/GpApp/Environ.cpp @@ -301,6 +301,9 @@ void CheckOurEnvirons (void) thisMac.numScreens = HowManyUsableScreens(false, true, true); thisMac.isResolutionDirty = true; + thisMac.isTouchscreen = PortabilityLayer::HostSystemServices::GetInstance()->IsTouchscreen(); + thisMac.isMouseTouchscreen = PortabilityLayer::HostSystemServices::GetInstance()->IsUsingMouseAsTouch(); + FlushResolutionChange(); } diff --git a/GpApp/Environ.h b/GpApp/Environ.h index f596c92..ccaf2c3 100644 --- a/GpApp/Environ.h +++ b/GpApp/Environ.h @@ -29,6 +29,8 @@ typedef struct Boolean hasQT; Boolean hasDrag; Boolean isResolutionDirty; + Boolean isTouchscreen; + Boolean isMouseTouchscreen; } macEnviron; diff --git a/GpApp/GliderStructs.h b/GpApp/GliderStructs.h index 64d89e2..2b9c8b8 100644 --- a/GpApp/GliderStructs.h +++ b/GpApp/GliderStructs.h @@ -362,4 +362,72 @@ typedef struct short object; } retroLink, *retroLinkPtr; +namespace TouchScreenCtrlIDs +{ + enum TouchScreenCtrlID + { + None, + MoveLeft, + MoveRight, + Flip, + Bands, + BatteryHelium, + + Count, + }; +}; + +typedef TouchScreenCtrlIDs::TouchScreenCtrlID TouchScreenCtrlID_t; + +typedef struct +{ + int fingerID; + Point point; + TouchScreenCtrlID_t capturingControl; +} touchScreenFingerState; + +typedef struct +{ + Rect graphicRect; + Rect touchRect; + Boolean isEnabled; +} touchScreenControl; + +namespace touchScreenControlGraphics +{ + enum touchScreenControlGraphic + { + BandsDisabled, + BandsActive, + BandsIdle, + FlipActive, + FlipIdle, + MoveRightActive, + MoveRightIdle, + MoveLeftActive, + MoveLeftIdle, + HeliumDisabled, + HeliumActive, + HeliumIdle, + BatteryDisabled, + BatteryActive, + BatteryIdle, + + Count, + }; + + static const int kTouchScreenGraphicStartID = 1973; +} + +typedef touchScreenControlGraphics::touchScreenControlGraphic touchScreenControlGraphic_t; + +typedef struct +{ + static const int kMaxFingers = 4; + + touchScreenControl controls[TouchScreenCtrlIDs::Count]; + touchScreenFingerState fingers[kMaxFingers]; + + DrawSurface *graphics[touchScreenControlGraphics::Count]; +} touchScreenControlState, *touchScreenControlStatePtr; diff --git a/GpApp/Play.cpp b/GpApp/Play.cpp index 58d3012..e07322d 100644 --- a/GpApp/Play.cpp +++ b/GpApp/Play.cpp @@ -13,9 +13,12 @@ #include "Environ.h" #include "House.h" #include "MainWindow.h" +#include "PLEventQueue.h" +#include "PLTimeTaggedVOSEvent.h" #include "RectUtils.h" #include "ResolveCachingColor.h" #include "Scoreboard.h" +#include "Utilities.h" #define kHouseBannerAlert 1009 @@ -42,8 +45,6 @@ void HandleRoomVisitation (void); void SetObjectsToDefaults (void); void InitTelephone (void); void HandleTelephone (void); -Boolean DoesStarCodeExist (short); -short GetNumStarsRemaining (short, short); phoneType thePhone, theChimes; @@ -55,11 +56,14 @@ short batteryTotal, bandsTotal, foilTotal, mortals; Boolean playing, evenFrame, twoPlayerGame, showFoil, demoGoing; Boolean doBackground, playerSuicide, phoneBitSet, tvOn; +touchScreenControlState touchScreen; + extern VFileSpec *theHousesSpecs; extern demoPtr demoData; extern gameType smallGame; extern Rect gliderSrc[kNumGliderSrcRects]; extern Rect boardDestRect, boardSrcRect; +extern Rect localRoomsDest[]; extern long incrementModeTime; extern short numBands, otherPlayerEscaped, demoIndex, demoHouseIndex; extern short splashOriginH, splashOriginV, countDown, thisHouseIndex; @@ -384,15 +388,215 @@ void HandleGameResolutionChange(void) DumpScreenOn(&justRoomsRect, true); } +//-------------------------------------------------------------- HandleTouchUp + +void HandleTouchUp(int fingerID) +{ + for (int i = 0; i < touchScreenControlState::kMaxFingers; i++) + { + if (touchScreen.fingers[i].fingerID == fingerID) + { + touchScreen.fingers[i].fingerID = -1; + touchScreen.fingers[i].capturingControl = TouchScreenCtrlIDs::None; + return; + } + } +} + +//-------------------------------------------------------------- HandleTouchMove + +void HandleTouchMove(int fingerID, const Point &pt) +{ + for (int i = 0; i < touchScreenControlState::kMaxFingers; i++) + { + if (touchScreen.fingers[i].fingerID == fingerID) + { + touchScreen.fingers[i].point = pt; + return; + } + } +} + +//-------------------------------------------------------------- HandleTouchDown + +void HandleTouchDown(int fingerID, const Point &pt) +{ + int freeFingerIndex = -1; + + for (int i = 0; i < touchScreenControlState::kMaxFingers; i++) + { + if (touchScreen.fingers[i].fingerID == fingerID) + { + // Finger is already considered down, something weird happened + HandleTouchMove(fingerID, pt); + return; + } + else if (touchScreen.fingers[i].fingerID < 0) + freeFingerIndex = i; + } + + if (freeFingerIndex < 0) + return; + + touchScreenFingerState &fingerState = touchScreen.fingers[freeFingerIndex]; + + for (int j = 0; j < TouchScreenCtrlIDs::Count; j++) + { + if (touchScreen.controls[j].isEnabled) + { + if (touchScreen.controls[j].touchRect.Contains(pt)) + { + fingerState.fingerID = fingerID; + fingerState.capturingControl = static_cast(j); + fingerState.point = pt; + return; + } + } + } + +} + +//-------------------------------------------------------------- HandleTouchLeave + +void HandleTouchLeave(int fingerID) +{ + for (int i = 0; i < touchScreenControlState::kMaxFingers; i++) + { + if (touchScreen.fingers[i].fingerID == fingerID) + { + touchScreen.fingers[i].fingerID = -1; + touchScreen.fingers[i].capturingControl = TouchScreenCtrlIDs::None; + return; + } + } +} + +//-------------------------------------------------------------- HandleInGameEvents + +void HandleInGameEvents(void) +{ + PortabilityLayer::EventQueue *queue = PortabilityLayer::EventQueue::GetInstance(); + + TimeTaggedVOSEvent evt; + while (queue->Dequeue(&evt)) + { + if (thisMac.isTouchscreen) + { + if (thisMac.isMouseTouchscreen && evt.m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput) + { + const GpMouseInputEvent &mouseInput = evt.m_vosEvent.m_event.m_mouseInputEvent; + + const Point mousePt = mainWindow->MouseToLocal(mouseInput); + + switch (mouseInput.m_eventType) + { + case GpMouseEventTypes::kDown: + if (mouseInput.m_button == GpMouseButtons::kLeft) + HandleTouchDown(0, mousePt); + break; + case GpMouseEventTypes::kLeave: + HandleTouchLeave(0); + break; + case GpMouseEventTypes::kUp: + HandleTouchMove(0, mousePt); + HandleTouchUp(0); + break; + case GpMouseEventTypes::kMove: + HandleTouchMove(0, mousePt); + break; + default: + break; + }; + } + } + } +} + +//-------------------------------------------------------------- ResetTouchScreenControlBounds + +static int16_t touchScreenControlSize = 32; + +void ResetTouchScreenControlBounds (void) +{ + if (!thisMac.isTouchscreen) + return; + + + const Rect centerRoomRect = localRoomsDest[kCentralRoom]; + + int16_t touchScreenControlInterSpacing = 16; + int16_t touchScreenControlEdgeSpacing = 24; + + Point points[TouchScreenCtrlIDs::Count]; + Point sizes[TouchScreenCtrlIDs::Count]; + + points[TouchScreenCtrlIDs::MoveLeft] = Point::Create(mainWindowRect.left + touchScreenControlEdgeSpacing, mainWindowRect.bottom - touchScreenControlEdgeSpacing - touchScreenControlSize); + points[TouchScreenCtrlIDs::MoveRight] = points[TouchScreenCtrlIDs::MoveLeft] + Point::Create(touchScreenControlInterSpacing + touchScreenControlSize, 0); + + points[TouchScreenCtrlIDs::BatteryHelium] = Point::Create(mainWindowRect.right - touchScreenControlEdgeSpacing - touchScreenControlSize, mainWindowRect.bottom - touchScreenControlEdgeSpacing - touchScreenControlSize); + points[TouchScreenCtrlIDs::Flip] = points[TouchScreenCtrlIDs::BatteryHelium] + Point::Create(0, -touchScreenControlInterSpacing - touchScreenControlSize); + points[TouchScreenCtrlIDs::Bands] = points[TouchScreenCtrlIDs::BatteryHelium] + Point::Create(-touchScreenControlInterSpacing - touchScreenControlSize, 0); + + for (int i = 0; i < TouchScreenCtrlIDs::Count; i++) + sizes[i] = Point::Create(touchScreenControlSize, touchScreenControlSize); + + for (int i = 0; i < TouchScreenCtrlIDs::Count; i++) + { + Point lowerRight = points[i] + sizes[i]; + touchScreen.controls[i].graphicRect = Rect::Create(points[i].v, points[i].h, lowerRight.v, lowerRight.h); + touchScreen.controls[i].touchRect = touchScreen.controls[i].graphicRect.Inset(-(touchScreenControlInterSpacing / 2), -(touchScreenControlInterSpacing / 2)); + } + + // Clear all active touches + for (int i = 0; i < touchScreenControlState::kMaxFingers; i++) + { + touchScreen.fingers[i].fingerID = -1; + touchScreen.fingers[i].capturingControl = TouchScreenCtrlIDs::None; + } +} + +//-------------------------------------------------------------- InitTouchScreenControlState + +void InitTouchScreenControlState(void) +{ + if (!thisMac.isTouchscreen) + return; + + ResetTouchScreenControlBounds(); + + for (int i = 0; i < touchScreenControlGraphics::Count; i++) + { + if (touchScreen.graphics[i] != nil) + continue; + + int resID = touchScreenControlGraphics::kTouchScreenGraphicStartID + i; + + Rect resRect = Rect::Create(0, 0, touchScreenControlSize, touchScreenControlSize); + (void)CreateOffScreenGWorld(&touchScreen.graphics[i], &resRect); + LoadGraphic(touchScreen.graphics[i], resID); + } +} + //-------------------------------------------------------------- PlayGame void PlayGame (void) { + InitTouchScreenControlState(); + + touchScreen.controls[TouchScreenCtrlIDs::MoveLeft].isEnabled = true; + touchScreen.controls[TouchScreenCtrlIDs::MoveRight].isEnabled = true; + touchScreen.controls[TouchScreenCtrlIDs::Flip].isEnabled = true; + touchScreen.controls[TouchScreenCtrlIDs::Bands].isEnabled = true; + touchScreen.controls[TouchScreenCtrlIDs::BatteryHelium].isEnabled = true; + while ((playing) && (!quitting)) { + HandleInGameEvents(); + if (thisMac.isResolutionDirty) { HandleGameResolutionChange(); + ResetTouchScreenControlBounds(); } gameFrame++; diff --git a/GpApp/Render.cpp b/GpApp/Render.cpp index bafafe6..5248394 100644 --- a/GpApp/Render.cpp +++ b/GpApp/Render.cpp @@ -29,6 +29,7 @@ void RenderSparkles (void); void RenderStars (void); void RenderBands (void); void RenderShreds (void); +void RenderTouchScreenControls (void); void CopyRectsQD (void); @@ -55,6 +56,7 @@ extern short numBands, numStars, numShredded; extern short numSparkles, numFlyingPts, numPendulums, clockFrame; extern short numFlames, numSavedMaps, numTikiFlames, numCoals; extern Boolean evenFrame, shadowVisible, twoPlayerGame, tvOn; +extern touchScreenControlState touchScreen; //============================================================== Functions @@ -604,6 +606,66 @@ void RenderShreds (void) } } +//-------------------------------------------------------------- RenderTouchScreenControls + +void RenderTouchScreenControls (void) +{ + DrawSurface *ctrlGraphics[TouchScreenCtrlIDs::Count]; + + for (int i = 0; i < TouchScreenCtrlIDs::Count; i++) + ctrlGraphics[i] = nullptr; + + ctrlGraphics[TouchScreenCtrlIDs::MoveLeft] = touchScreen.graphics[touchScreenControlGraphics::MoveLeftIdle]; + ctrlGraphics[TouchScreenCtrlIDs::MoveRight] = touchScreen.graphics[touchScreenControlGraphics::MoveRightIdle]; + ctrlGraphics[TouchScreenCtrlIDs::Flip] = touchScreen.graphics[touchScreenControlGraphics::FlipIdle]; + ctrlGraphics[TouchScreenCtrlIDs::Bands] = touchScreen.graphics[touchScreenControlGraphics::BandsDisabled]; + ctrlGraphics[TouchScreenCtrlIDs::BatteryHelium] = touchScreen.graphics[touchScreenControlGraphics::BatteryDisabled]; + + if (batteryTotal < 0) + ctrlGraphics[TouchScreenCtrlIDs::BatteryHelium] = touchScreen.graphics[touchScreenControlGraphics::HeliumIdle]; + else if (batteryTotal > 0) + ctrlGraphics[TouchScreenCtrlIDs::BatteryHelium] = touchScreen.graphics[touchScreenControlGraphics::BatteryIdle]; + + if (bandsTotal > 0) + ctrlGraphics[TouchScreenCtrlIDs::Bands] = touchScreen.graphics[touchScreenControlGraphics::BandsIdle]; + + for (int i = 0; i < touchScreenControlState::kMaxFingers; i++) + { + if (touchScreen.fingers[i].capturingControl == TouchScreenCtrlIDs::BatteryHelium) + { + if (batteryTotal < 0) + ctrlGraphics[TouchScreenCtrlIDs::BatteryHelium] = touchScreen.graphics[touchScreenControlGraphics::HeliumActive]; + else if (batteryTotal > 0) + ctrlGraphics[TouchScreenCtrlIDs::BatteryHelium] = touchScreen.graphics[touchScreenControlGraphics::BandsActive]; + } + else if (touchScreen.fingers[i].capturingControl == TouchScreenCtrlIDs::Bands) + { + if (bandsTotal > 0) + ctrlGraphics[TouchScreenCtrlIDs::Bands] = touchScreen.graphics[touchScreenControlGraphics::BandsActive]; + } + else if (touchScreen.fingers[i].capturingControl == TouchScreenCtrlIDs::Flip) + ctrlGraphics[TouchScreenCtrlIDs::Flip] = touchScreen.graphics[touchScreenControlGraphics::FlipActive]; + else if (touchScreen.fingers[i].capturingControl == TouchScreenCtrlIDs::MoveLeft) + ctrlGraphics[TouchScreenCtrlIDs::MoveLeft] = touchScreen.graphics[touchScreenControlGraphics::MoveLeftActive]; + else if (touchScreen.fingers[i].capturingControl == TouchScreenCtrlIDs::MoveRight) + ctrlGraphics[TouchScreenCtrlIDs::MoveRight] = touchScreen.graphics[touchScreenControlGraphics::MoveRightActive]; + } + + for (int i = 0; i < TouchScreenCtrlIDs::Count; i++) + { + DrawSurface *graphic = ctrlGraphics[i]; + if (!graphic) + continue; + + const Rect sourceRect = ctrlGraphics[i]->m_port.GetRect(); + Rect destRect = touchScreen.controls[i].graphicRect; + + CopyMask(*GetGWorldPixMap(ctrlGraphics[i]), *GetGWorldPixMap(ctrlGraphics[i]), *GetGWorldPixMap(workSrcMap), &sourceRect, &sourceRect, &destRect); + AddRectToBackRects(&destRect); + AddRectToWorkRects(&destRect); + } +} + //-------------------------------------------------------------- CopyRectsQD void CopyRectsQD (void) @@ -655,6 +717,7 @@ void RenderFrame (void) RenderGlider(&theGlider2, false); RenderShreds(); RenderBands(); + RenderTouchScreenControls(); while (TickCount() < nextFrame) { diff --git a/PortabilityLayer/Android.mk b/PortabilityLayer/Android.mk index fab13a1..2b3eeb4 100644 --- a/PortabilityLayer/Android.mk +++ b/PortabilityLayer/Android.mk @@ -109,4 +109,4 @@ LOCAL_SRC_FILES := \ LOCAL_STATIC_LIBRARIES := zlib MacRomanConversion stb -include $(BUILD_SHARED_LIBRARY) +include $(BUILD_STATIC_LIBRARY) diff --git a/PortabilityLayer/HostSystemServices.h b/PortabilityLayer/HostSystemServices.h index 29fe479..e0f6124 100644 --- a/PortabilityLayer/HostSystemServices.h +++ b/PortabilityLayer/HostSystemServices.h @@ -23,6 +23,8 @@ namespace PortabilityLayer virtual HostThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) = 0; virtual uint64_t GetFreeMemoryCosmetic() const = 0; // Returns free memory in bytes, does not have to be accurate virtual void Beep() const = 0; + virtual bool IsTouchscreen() const = 0; + virtual bool IsUsingMouseAsTouch() const = 0; static void SetInstance(HostSystemServices *instance); static HostSystemServices *GetInstance(); diff --git a/PortabilityLayer/MacBinary2.h b/PortabilityLayer/MacBinary2.h index d21cfb4..758414d 100644 --- a/PortabilityLayer/MacBinary2.h +++ b/PortabilityLayer/MacBinary2.h @@ -1,19 +1,19 @@ -#pragma once - -#ifndef __PL_MACBINARY2_H__ +#pragma once + +#ifndef __PL_MACBINARY2_H__ #define __PL_MACBINARY2_H__ - -class GpIOStream; - -namespace PortabilityLayer -{ - class MacFileMem; - - namespace MacBinary2 - { - void WriteBin(const MacFileMem *file, GpIOStream *stream); - MacFileMem *ReadBin(GpIOStream *stream); - }; -} - -#endif + +class GpIOStream; + +namespace PortabilityLayer +{ + class MacFileMem; + + namespace MacBinary2 + { + void WriteBin(const MacFileMem *file, GpIOStream *stream); + MacFileMem *ReadBin(GpIOStream *stream); + }; +} + +#endif