mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-12-13 19:49:36 +00:00
Emscripten port
This commit is contained in:
3
AerofoilWeb/.gitignore
vendored
Normal file
3
AerofoilWeb/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
obj
|
||||
res
|
||||
bin
|
||||
4
AerofoilWeb/AerofoilWeb_Combined.cpp
Normal file
4
AerofoilWeb/AerofoilWeb_Combined.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "GpFileSystem_Web.cpp"
|
||||
#include "GpLogDriver_Web.cpp"
|
||||
#include "GpMain_SDL_Web.cpp"
|
||||
#include "GpSystemServices_Web.cpp"
|
||||
15
AerofoilWeb/AerofoilWeb_Resources.cpp
Normal file
15
AerofoilWeb/AerofoilWeb_Resources.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "GpFileSystem_Web_Resources.h"
|
||||
|
||||
namespace GpFileSystem_Web_Resources
|
||||
{
|
||||
namespace ApplicationData
|
||||
{
|
||||
#include "res/ApplicationData.h"
|
||||
}
|
||||
namespace GameData
|
||||
{
|
||||
#include "res/GameData.h"
|
||||
}
|
||||
}
|
||||
7
AerofoilWeb/BuildAerofoilSDL.bat
Normal file
7
AerofoilWeb/BuildAerofoilSDL.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
set INPUT_DIR=../AerofoilSDL
|
||||
set OUTPUT_DIR=obj
|
||||
set FLAGS=-s USE_SDL=2 -flto -I../GpCommon/ -I../PortabilityLayer/ -I../Common/ -s ASYNCIFY -O0 -DGP_DEBUG_CONFIG=0
|
||||
|
||||
emcc -c %INPUT_DIR%/AerofoilSDL_Combined.cpp -o %OUTPUT_DIR%/AerofoilSDL_Combined.o %FLAGS%
|
||||
|
||||
pause
|
||||
7
AerofoilWeb/BuildAerofoilWeb.bat
Normal file
7
AerofoilWeb/BuildAerofoilWeb.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
set INPUT_DIR=.
|
||||
set OUTPUT_DIR=obj
|
||||
set FLAGS=-s USE_SDL=2 -flto -I../GpCommon/ -I../PortabilityLayer/ -I../Common/ -I../GpShell/ -s ASYNCIFY -O3 -DGP_DEBUG_CONFIG=0
|
||||
|
||||
emcc -c %INPUT_DIR%/AerofoilWeb_Combined.cpp -o %OUTPUT_DIR%/AerofoilWeb_Combined.o %FLAGS%
|
||||
|
||||
pause
|
||||
7
AerofoilWeb/BuildGpApp.bat
Normal file
7
AerofoilWeb/BuildGpApp.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
set INPUT_DIR=../GpApp
|
||||
set OUTPUT_DIR=obj
|
||||
set FLAGS=-s USE_SDL=2 -flto -I../GpCommon/ -I../PortabilityLayer/ -I../Common/ -s ASYNCIFY -O0 -DGP_DEBUG_CONFIG=0
|
||||
|
||||
emcc -c %INPUT_DIR%/GpApp_Combined.cpp -o %OUTPUT_DIR%/GpApp_Combined.o %FLAGS%
|
||||
|
||||
pause
|
||||
7
AerofoilWeb/BuildGpShell.bat
Normal file
7
AerofoilWeb/BuildGpShell.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
set INPUT_DIR=../GpShell
|
||||
set OUTPUT_DIR=obj
|
||||
set FLAGS=-s USE_SDL=2 -flto -I../GpCommon/ -I../PortabilityLayer/ -I../Common/ -s ASYNCIFY -O0 -DGP_DEBUG_CONFIG=0
|
||||
|
||||
emcc -c %INPUT_DIR%/GpShell_Combined.cpp -o %OUTPUT_DIR%/GpShell_Combined.o %FLAGS%
|
||||
|
||||
pause
|
||||
7
AerofoilWeb/BuildMacRomanConversion.bat
Normal file
7
AerofoilWeb/BuildMacRomanConversion.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
set INPUT_DIR=../MacRomanConversion
|
||||
set OUTPUT_DIR=obj
|
||||
set FLAGS=-flto -I../MacRomanConversion/ -s ASYNCIFY -O3
|
||||
|
||||
emcc -c %INPUT_DIR%/MacRomanConversion.cpp -o %OUTPUT_DIR%/MacRomanConversion.o %FLAGS%
|
||||
|
||||
pause
|
||||
7
AerofoilWeb/BuildPortabilityLayer.bat
Normal file
7
AerofoilWeb/BuildPortabilityLayer.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
set INPUT_DIR=../PortabilityLayer
|
||||
set OUTPUT_DIR=obj
|
||||
set FLAGS=-s USE_ZLIB=1 -flto -I../GpCommon/ -I../Common/ -I../PortabilityLayer/ -I../rapidjson/include/ -I../MacRomanConversion/ -I../stb/ -s ASYNCIFY -O3 -DGP_DEBUG_CONFIG=0 -Wno-tautological-constant-out-of-range-compare
|
||||
|
||||
emcc -c %INPUT_DIR%/PortabilityLayer_Combined.cpp -o %OUTPUT_DIR%/PortabilityLayer_Combined.o %FLAGS%
|
||||
|
||||
pause
|
||||
10
AerofoilWeb/BuildResources.bat
Normal file
10
AerofoilWeb/BuildResources.bat
Normal file
@@ -0,0 +1,10 @@
|
||||
..\x64\Release\bin2h.exe ..\Packaged res\ApplicationData.h
|
||||
..\x64\Release\bin2h.exe ..\Packaged\Houses res\GameData.h
|
||||
|
||||
set INPUT_DIR=.
|
||||
set OUTPUT_DIR=obj
|
||||
set FLAGS=-flto -O3 -DGP_DEBUG_CONFIG=0
|
||||
|
||||
emcc -c %INPUT_DIR%/AerofoilWeb_Resources.cpp -o %OUTPUT_DIR%/AerofoilWeb_Resources.o %FLAGS%
|
||||
|
||||
pause
|
||||
651
AerofoilWeb/GpFileSystem_Web.cpp
Normal file
651
AerofoilWeb/GpFileSystem_Web.cpp
Normal file
@@ -0,0 +1,651 @@
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include "GpFileSystem_Web.h"
|
||||
#include "GpIOStream.h"
|
||||
#include "IGpDirectoryCursor.h"
|
||||
#include "IGpSystemServices.h"
|
||||
#include "IGpMutex.h"
|
||||
#include "VirtualDirectory.h"
|
||||
|
||||
#include "PLDrivers.h"
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
#include "SDL2/SDL_rwops.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "UTF8.h"
|
||||
|
||||
#if defined(__CYGWIN__) || defined(__EMSCRIPTEN__)
|
||||
typedef off_t off64_t;
|
||||
#define fstat64 fstat
|
||||
#define fseek64 fseek
|
||||
#define ftruncate64 ftruncate
|
||||
#define stat64 stat
|
||||
#endif
|
||||
|
||||
|
||||
class GpFileStream_Web_StaticMemFile final : public GpIOStream
|
||||
{
|
||||
public:
|
||||
GpFileStream_Web_StaticMemFile(const unsigned char *bytes, size_t size);
|
||||
~GpFileStream_Web_StaticMemFile();
|
||||
|
||||
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;
|
||||
GpUFilePos_t Size() const override;
|
||||
GpUFilePos_t Tell() const override;
|
||||
void Close() override;
|
||||
void Flush() override;
|
||||
|
||||
private:
|
||||
const unsigned char *m_bytes;
|
||||
size_t m_offset;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
GpFileStream_Web_StaticMemFile::GpFileStream_Web_StaticMemFile(const unsigned char *bytes, size_t size)
|
||||
: m_bytes(bytes)
|
||||
, m_size(size)
|
||||
, m_offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
GpFileStream_Web_StaticMemFile::~GpFileStream_Web_StaticMemFile()
|
||||
{
|
||||
}
|
||||
|
||||
size_t GpFileStream_Web_StaticMemFile::Read(void *bytesOut, size_t size)
|
||||
{
|
||||
size_t available = m_size - m_offset;
|
||||
size = std::min(size, available);
|
||||
|
||||
memcpy(bytesOut, m_bytes + m_offset, size);
|
||||
m_offset += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t GpFileStream_Web_StaticMemFile::Write(const void *bytes, size_t size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_StaticMemFile::IsSeekable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_StaticMemFile::IsReadOnly() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_StaticMemFile::IsWriteOnly() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_StaticMemFile::SeekStart(GpUFilePos_t loc)
|
||||
{
|
||||
if (loc > m_size)
|
||||
return false;
|
||||
|
||||
m_offset = static_cast<size_t>(loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_StaticMemFile::SeekCurrent(GpFilePos_t loc)
|
||||
{
|
||||
GpFilePos_t minOffset = -static_cast<GpFilePos_t>(m_offset);
|
||||
GpFilePos_t maxOffset = static_cast<GpFilePos_t>(m_size - m_offset);
|
||||
|
||||
if (loc < minOffset || loc > maxOffset)
|
||||
return false;
|
||||
|
||||
m_offset = static_cast<size_t>(static_cast<GpFilePos_t>(m_offset) + loc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_StaticMemFile::SeekEnd(GpUFilePos_t loc)
|
||||
{
|
||||
if (loc > m_size)
|
||||
{
|
||||
fprintf(stderr, "SeekEnd failed: Loc %i size %i\n", static_cast<int>(loc), static_cast<int>(m_size));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offset = m_size - loc;
|
||||
return true;
|
||||
}
|
||||
|
||||
GpUFilePos_t GpFileStream_Web_StaticMemFile::Size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
GpUFilePos_t GpFileStream_Web_StaticMemFile::Tell() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
void GpFileStream_Web_StaticMemFile::Close()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void GpFileStream_Web_StaticMemFile::Flush()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
class GpFileStream_Web_File final : public GpIOStream
|
||||
{
|
||||
public:
|
||||
GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly);
|
||||
~GpFileStream_Web_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;
|
||||
GpUFilePos_t Size() const override;
|
||||
GpUFilePos_t Tell() const override;
|
||||
void Close() override;
|
||||
void Flush() override;
|
||||
|
||||
private:
|
||||
FILE *m_f;
|
||||
bool m_seekable;
|
||||
bool m_isReadOnly;
|
||||
bool m_isWriteOnly;
|
||||
};
|
||||
|
||||
|
||||
GpFileStream_Web_File::GpFileStream_Web_File(FILE *f, bool readOnly, bool writeOnly)
|
||||
: m_f(f)
|
||||
, m_isReadOnly(readOnly)
|
||||
, m_isWriteOnly(writeOnly)
|
||||
{
|
||||
m_seekable = (fseek(m_f, 0, SEEK_CUR) == 0);
|
||||
}
|
||||
|
||||
GpFileStream_Web_File::~GpFileStream_Web_File()
|
||||
{
|
||||
fclose(m_f);
|
||||
}
|
||||
|
||||
size_t GpFileStream_Web_File::Read(void *bytesOut, size_t size)
|
||||
{
|
||||
if (m_isWriteOnly)
|
||||
return 0;
|
||||
return fread(bytesOut, 1, size, m_f);
|
||||
}
|
||||
|
||||
size_t GpFileStream_Web_File::Write(const void *bytes, size_t size)
|
||||
{
|
||||
if (m_isReadOnly)
|
||||
return 0;
|
||||
return fwrite(bytes, 1, size, m_f);
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_File::IsSeekable() const
|
||||
{
|
||||
return m_seekable;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_File::IsReadOnly() const
|
||||
{
|
||||
return m_isReadOnly;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_File::IsWriteOnly() const
|
||||
{
|
||||
return m_isWriteOnly;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_File::SeekStart(GpUFilePos_t loc)
|
||||
{
|
||||
if (!m_seekable)
|
||||
return false;
|
||||
|
||||
fflush(m_f);
|
||||
return fseek64(m_f, static_cast<off64_t>(loc), SEEK_SET) >= 0;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_File::SeekCurrent(GpFilePos_t loc)
|
||||
{
|
||||
if (!m_seekable)
|
||||
return false;
|
||||
|
||||
fflush(m_f);
|
||||
return fseek64(m_f, static_cast<off64_t>(loc), SEEK_CUR) >= 0;
|
||||
}
|
||||
|
||||
bool GpFileStream_Web_File::SeekEnd(GpUFilePos_t loc)
|
||||
{
|
||||
if (!m_seekable)
|
||||
return false;
|
||||
|
||||
fflush(m_f);
|
||||
return fseek64(m_f, -static_cast<off64_t>(loc), SEEK_END) >= 0;
|
||||
}
|
||||
|
||||
GpUFilePos_t GpFileStream_Web_File::Size() const
|
||||
{
|
||||
fflush(m_f);
|
||||
|
||||
struct stat64 s;
|
||||
if (fstat64(fileno(m_f), &s) < 0)
|
||||
return 0;
|
||||
|
||||
return static_cast<GpUFilePos_t>(s.st_size);
|
||||
}
|
||||
|
||||
GpUFilePos_t GpFileStream_Web_File::Tell() const
|
||||
{
|
||||
return static_cast<GpUFilePos_t>(ftell(m_f));
|
||||
}
|
||||
|
||||
void GpFileStream_Web_File::Close()
|
||||
{
|
||||
this->~GpFileStream_Web_File();
|
||||
free(this);
|
||||
}
|
||||
|
||||
void GpFileStream_Web_File::Flush()
|
||||
{
|
||||
fflush(m_f);
|
||||
}
|
||||
|
||||
bool GpFileSystem_Web::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution)
|
||||
{
|
||||
const char *prefsAppend = nullptr;
|
||||
|
||||
switch (virtualDirectory)
|
||||
{
|
||||
case PortabilityLayer::VirtualDirectories::kApplicationData:
|
||||
resolution = std::string("Packaged");
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kGameData:
|
||||
resolution = std::string("Packaged/Houses");
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kFonts:
|
||||
resolution = std::string("Resources");
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kHighScores:
|
||||
prefsAppend = "HighScores";
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kUserData:
|
||||
prefsAppend = "Houses";
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kUserSaves:
|
||||
prefsAppend = "SavedGames";
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kPrefs:
|
||||
prefsAppend = "Prefs";
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kFontCache:
|
||||
prefsAppend = "FontCache";
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
|
||||
if (prefsAppend)
|
||||
resolution = m_prefsPath + prefsAppend;
|
||||
else
|
||||
resolution = m_basePath + resolution;
|
||||
|
||||
for (size_t i = 0; i < numPaths; i++)
|
||||
{
|
||||
resolution += "/";
|
||||
resolution += paths[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GpFileSystem_Web::GpFileSystem_Web()
|
||||
: m_delayCallback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
GpFileSystem_Web::~GpFileSystem_Web()
|
||||
{
|
||||
}
|
||||
|
||||
void GpFileSystem_Web::Init()
|
||||
{
|
||||
char *prefsDir = SDL_GetPrefPath("aerofoil", "aerofoil");
|
||||
m_prefsPath = prefsDir;
|
||||
|
||||
char *baseDir = SDL_GetBasePath();
|
||||
m_basePath = baseDir;
|
||||
SDL_free(baseDir);
|
||||
|
||||
char baseDirSeparator = m_basePath[m_basePath.size() - 1];
|
||||
if (m_basePath.size() >= 4 && m_basePath.substr(m_basePath.size() - 4, 3) == "bin")
|
||||
m_basePath = m_basePath.substr(0, m_basePath.size() - 4) + "lib" + baseDirSeparator + "aerofoil" + baseDirSeparator;
|
||||
|
||||
const char *extensions[] = { "HighScores", "Houses", "SavedGames", "Prefs", "FontCache" };
|
||||
for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++)
|
||||
{
|
||||
std::string prefsPath = std::string(prefsDir) + extensions[i];
|
||||
int created = mkdir(prefsPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
}
|
||||
SDL_free(prefsDir);
|
||||
}
|
||||
|
||||
bool GpFileSystem_Web::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path)
|
||||
{
|
||||
if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory))
|
||||
{
|
||||
for (size_t i = 0; i < catalog->m_numEntries; i++)
|
||||
{
|
||||
const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i];
|
||||
if (!strcmp(path, entry.m_fileName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string resolvedPath;
|
||||
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath))
|
||||
return false;
|
||||
|
||||
struct stat s;
|
||||
return stat(resolvedPath.c_str(), &s) == 0;
|
||||
}
|
||||
|
||||
bool GpFileSystem_Web::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists)
|
||||
{
|
||||
fprintf(stderr, "FileLocked %s\n", path);
|
||||
if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory))
|
||||
{
|
||||
for (size_t i = 0; i < catalog->m_numEntries; i++)
|
||||
{
|
||||
const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i];
|
||||
if (!strcmp(path, entry.m_fileName))
|
||||
{
|
||||
exists = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
exists = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string resolvedPath;
|
||||
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath))
|
||||
{
|
||||
if (exists)
|
||||
exists = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int permissions = access(resolvedPath.c_str(), W_OK | F_OK);
|
||||
exists = ((permissions & F_OK) != 0);
|
||||
return ((permissions & W_OK) != 0);
|
||||
}
|
||||
|
||||
GpIOStream *GpFileSystem_Web::OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition)
|
||||
{
|
||||
fprintf(stderr, "OpenFileNested %i %s subPaths %i\n", static_cast<int>(virtualDirectory), subPaths[0], static_cast<int>(numSubPaths));
|
||||
if (numSubPaths == 1)
|
||||
{
|
||||
fprintf(stderr, "Only one subpath\n");
|
||||
if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory))
|
||||
{
|
||||
fprintf(stderr, "Catalog matched. %i entries. %i size %i size0\n", static_cast<int>(catalog->m_numEntries), static_cast<int>(catalog->m_size), static_cast<int>(catalog->m_size0));
|
||||
for (size_t i = 0; i < catalog->m_numEntries; i++)
|
||||
{
|
||||
const GpFileSystem_Web_Resources::FileCatalogEntry &entry = catalog->m_entries[i];
|
||||
fprintf(stderr, "Comparing '%s' to '%s'\n", subPaths[0], entry.m_fileName);
|
||||
if (!strcmp(subPaths[0], entry.m_fileName))
|
||||
{
|
||||
fprintf(stderr, "File name matched\n");
|
||||
return new GpFileStream_Web_StaticMemFile(entry.m_data, entry.m_size);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Catalog had no match\n");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "More paths, falling through...\n");
|
||||
|
||||
const char *mode = nullptr;
|
||||
bool canWrite = false;
|
||||
bool needResetPosition = false;
|
||||
|
||||
switch (createDisposition)
|
||||
{
|
||||
case GpFileCreationDispositions::kCreateOrOverwrite:
|
||||
mode = "wb";
|
||||
break;
|
||||
case GpFileCreationDispositions::kCreateNew:
|
||||
mode = "x+b";
|
||||
break;
|
||||
case GpFileCreationDispositions::kCreateOrOpen:
|
||||
mode = "a+b";
|
||||
needResetPosition = true;
|
||||
break;
|
||||
case GpFileCreationDispositions::kOpenExisting:
|
||||
mode = writeAccess ? "r+b" : "rb";
|
||||
break;
|
||||
case GpFileCreationDispositions::kOverwriteExisting:
|
||||
mode = "r+b";
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
if (virtualDirectory == PortabilityLayer::VirtualDirectories::kSourceExport)
|
||||
return nullptr;
|
||||
|
||||
std::string resolvedPath;
|
||||
if (!ResolvePath(virtualDirectory, subPaths, numSubPaths, resolvedPath))
|
||||
return nullptr;
|
||||
|
||||
void *objStorage = malloc(sizeof(GpFileStream_Web_File));
|
||||
if (!objStorage)
|
||||
return nullptr;
|
||||
|
||||
FILE *f = fopen(resolvedPath.c_str(), mode);
|
||||
if (!f)
|
||||
{
|
||||
free(objStorage);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (needResetPosition)
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (createDisposition == GpFileCreationDispositions::kOverwriteExisting)
|
||||
{
|
||||
if (ftruncate64(fileno(f), 0) < 0)
|
||||
{
|
||||
free(objStorage);
|
||||
fclose(f);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return new (objStorage) GpFileStream_Web_File(f, !writeAccess, false);
|
||||
}
|
||||
|
||||
bool GpFileSystem_Web::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed)
|
||||
{
|
||||
fprintf(stderr, "Delete file %s\n", path);
|
||||
if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory))
|
||||
return false;
|
||||
|
||||
std::string resolvedPath;
|
||||
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath))
|
||||
{
|
||||
existed = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unlink(resolvedPath.c_str()) < 0)
|
||||
{
|
||||
existed = (errno != ENOENT);
|
||||
return false;
|
||||
}
|
||||
existed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GpFileSystem_Web::ValidateFilePath(const char *path, size_t length) const
|
||||
{
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
const char c = path[i];
|
||||
if (c >= '0' && c <= '9')
|
||||
continue;
|
||||
|
||||
if (c == '_' || c == '.' || c == '\'' || c == '!')
|
||||
continue;
|
||||
|
||||
if (c == ' ' && i != 0 && i != length - 1)
|
||||
continue;
|
||||
|
||||
if (c >= 'a' && c <= 'z')
|
||||
continue;
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GpFileSystem_Web::ValidateFilePathUnicodeChar(uint32_t c) const
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return true;
|
||||
|
||||
if (c == '_' || c == '\'')
|
||||
return true;
|
||||
|
||||
if (c == ' ')
|
||||
return true;
|
||||
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return true;
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GpFileSystem_Web::SetDelayCallback(DelayCallback_t delayCallback)
|
||||
{
|
||||
m_delayCallback = delayCallback;
|
||||
}
|
||||
|
||||
GpFileSystem_Web *GpFileSystem_Web::GetInstance()
|
||||
{
|
||||
return &ms_instance;
|
||||
}
|
||||
|
||||
class GpDirectoryCursor_StringList final : public IGpDirectoryCursor
|
||||
{
|
||||
public:
|
||||
explicit GpDirectoryCursor_StringList(std::vector<std::string> &paths);
|
||||
~GpDirectoryCursor_StringList();
|
||||
|
||||
bool GetNext(const char *&outFileName) override;
|
||||
void Destroy() override;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_paths;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
GpDirectoryCursor_StringList::GpDirectoryCursor_StringList(std::vector<std::string> &paths)
|
||||
: m_index(0)
|
||||
{
|
||||
std::swap(paths, m_paths);
|
||||
}
|
||||
|
||||
GpDirectoryCursor_StringList::~GpDirectoryCursor_StringList()
|
||||
{
|
||||
}
|
||||
|
||||
bool GpDirectoryCursor_StringList::GetNext(const char *&outFileName)
|
||||
{
|
||||
if (m_index == m_paths.size())
|
||||
return false;
|
||||
outFileName = m_paths[m_index].c_str();
|
||||
m_index++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GpDirectoryCursor_StringList::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
IGpDirectoryCursor *GpFileSystem_Web::ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths)
|
||||
{
|
||||
if (const GpFileSystem_Web_Resources::FileCatalog *catalog = GetCatalogForVirtualDirectory(virtualDirectory))
|
||||
return ScanCatalog(*catalog);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GpFileSystem_Web_Resources::FileCatalog *GpFileSystem_Web::GetCatalogForVirtualDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory)
|
||||
{
|
||||
if (virtualDirectory == PortabilityLayer::VirtualDirectories::kApplicationData)
|
||||
{
|
||||
fprintf(stderr, "%i == %i\n", static_cast<int>(virtualDirectory), static_cast<int>(PortabilityLayer::VirtualDirectories::kApplicationData));
|
||||
fprintf(stderr, "%i size\n", GpFileSystem_Web_Resources::ApplicationData::GetCatalog().m_size);
|
||||
fprintf(stderr, "First name: %s\n", GpFileSystem_Web_Resources::ApplicationData::GetCatalog().m_entries[0].m_fileName);
|
||||
return &GpFileSystem_Web_Resources::ApplicationData::GetCatalog();
|
||||
}
|
||||
fprintf(stderr, "%i != %i\n", static_cast<int>(virtualDirectory), static_cast<int>(PortabilityLayer::VirtualDirectories::kApplicationData));
|
||||
|
||||
if (virtualDirectory == PortabilityLayer::VirtualDirectories::kGameData)
|
||||
{
|
||||
fprintf(stderr, "%i == %i\n", static_cast<int>(virtualDirectory), static_cast<int>(PortabilityLayer::VirtualDirectories::kGameData));
|
||||
return &GpFileSystem_Web_Resources::GameData::GetCatalog();
|
||||
}
|
||||
fprintf(stderr, "%i != %i\n", static_cast<int>(virtualDirectory), static_cast<int>(PortabilityLayer::VirtualDirectories::kGameData));
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IGpDirectoryCursor *GpFileSystem_Web::ScanCatalog(const GpFileSystem_Web_Resources::FileCatalog &catalog)
|
||||
{
|
||||
std::vector<std::string> paths;
|
||||
for (size_t i = 0; i < catalog.m_numEntries; i++)
|
||||
paths.push_back(std::string(catalog.m_entries[i].m_fileName));
|
||||
|
||||
return new GpDirectoryCursor_StringList(paths);
|
||||
}
|
||||
|
||||
|
||||
GpFileSystem_Web GpFileSystem_Web::ms_instance;
|
||||
62
AerofoilWeb/GpFileSystem_Web.h
Normal file
62
AerofoilWeb/GpFileSystem_Web.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "IGpFileSystem.h"
|
||||
#include "GpFileSystem_Web_Resources.h"
|
||||
|
||||
#include "GpCoreDefs.h"
|
||||
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
|
||||
struct IGpMutex;
|
||||
|
||||
class GpFileSystem_Web final : public IGpFileSystem
|
||||
{
|
||||
public:
|
||||
GpFileSystem_Web();
|
||||
~GpFileSystem_Web();
|
||||
|
||||
void Init();
|
||||
|
||||
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
|
||||
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &exists) override;
|
||||
GpIOStream *OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) override;
|
||||
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override;
|
||||
IGpDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) override;
|
||||
|
||||
bool ValidateFilePath(const char *path, size_t pathLen) const override;
|
||||
bool ValidateFilePathUnicodeChar(uint32_t ch) const override;
|
||||
|
||||
void SetDelayCallback(DelayCallback_t delayCallback) override;
|
||||
|
||||
static GpFileSystem_Web *GetInstance();
|
||||
|
||||
private:
|
||||
struct ScanDirectoryNestedContext
|
||||
{
|
||||
GpFileSystem_Web *m_this;
|
||||
|
||||
IGpDirectoryCursor *m_returnValue;
|
||||
PortabilityLayer::VirtualDirectory_t m_virtualDirectory;
|
||||
char const *const *m_paths;
|
||||
size_t m_numPaths;
|
||||
};
|
||||
|
||||
static void ScanDirectoryNestedThunk(void *context);
|
||||
IGpDirectoryCursor *ScanDirectoryNestedInternal(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths);
|
||||
|
||||
IGpDirectoryCursor *ScanDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths);
|
||||
|
||||
static const GpFileSystem_Web_Resources::FileCatalog *GetCatalogForVirtualDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory);
|
||||
|
||||
static IGpDirectoryCursor *ScanCatalog(const GpFileSystem_Web_Resources::FileCatalog &catalog);
|
||||
|
||||
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution);
|
||||
|
||||
DelayCallback_t m_delayCallback;
|
||||
|
||||
std::string m_prefsPath;
|
||||
std::string m_basePath;
|
||||
|
||||
static GpFileSystem_Web ms_instance;
|
||||
};
|
||||
28
AerofoilWeb/GpFileSystem_Web_Resources.h
Normal file
28
AerofoilWeb/GpFileSystem_Web_Resources.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
namespace GpFileSystem_Web_Resources
|
||||
{
|
||||
struct FileCatalogEntry
|
||||
{
|
||||
const char *m_fileName;
|
||||
const unsigned char *m_data;
|
||||
const unsigned int m_size;
|
||||
};
|
||||
|
||||
struct FileCatalog
|
||||
{
|
||||
const FileCatalogEntry *m_entries;
|
||||
const unsigned int m_numEntries;
|
||||
const unsigned int m_size;
|
||||
const unsigned int m_size0;
|
||||
};
|
||||
|
||||
namespace ApplicationData
|
||||
{
|
||||
const FileCatalog &GetCatalog();
|
||||
}
|
||||
namespace GameData
|
||||
{
|
||||
const FileCatalog &GetCatalog();
|
||||
}
|
||||
}
|
||||
89
AerofoilWeb/GpLogDriver_Web.cpp
Normal file
89
AerofoilWeb/GpLogDriver_Web.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "GpLogDriver_Web.h"
|
||||
#include "GpFileSystem_Web.h"
|
||||
|
||||
#include "GpApplicationName.h"
|
||||
#include "GpIOStream.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <cstring>
|
||||
|
||||
GpLogDriver_Web::GpLogDriver_Web()
|
||||
{
|
||||
}
|
||||
|
||||
void GpLogDriver_Web::Init()
|
||||
{
|
||||
ms_instance.InitInternal();
|
||||
}
|
||||
|
||||
void GpLogDriver_Web::VPrintf(Category category, const char *fmt, va_list args)
|
||||
{
|
||||
size_t fmtSize = 0;
|
||||
bool hasFormatting = false;
|
||||
for (const char *fmtCheck = fmt; *fmtCheck; fmtCheck++)
|
||||
{
|
||||
if (*fmtCheck == '%')
|
||||
hasFormatting = true;
|
||||
|
||||
fmtSize++;
|
||||
}
|
||||
|
||||
time_t t = time(nullptr);
|
||||
struct tm sysTime = *localtime(&t);
|
||||
|
||||
char timestampBuffer[64];
|
||||
sprintf(timestampBuffer, "[%02d:%02d:%02d] ", sysTime.tm_hour, sysTime.tm_min, sysTime.tm_sec);
|
||||
|
||||
const char *debugTag = "";
|
||||
|
||||
switch (category)
|
||||
{
|
||||
case Category_Warning:
|
||||
debugTag = "[WARNING] ";
|
||||
break;
|
||||
case Category_Error:
|
||||
debugTag = "[ERROR] ";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
int formattedSize = vsnprintf(nullptr, 0, fmt, args);
|
||||
if (formattedSize <= 0)
|
||||
return;
|
||||
|
||||
char *charBuff = static_cast<char*>(malloc(formattedSize + 1));
|
||||
if (!charBuff)
|
||||
return;
|
||||
|
||||
vsnprintf(charBuff, formattedSize + 1, fmt, args);
|
||||
|
||||
fprintf(stderr, "%s%s%s\n", timestampBuffer, debugTag, charBuff);
|
||||
fflush(stderr);
|
||||
|
||||
free(charBuff);
|
||||
}
|
||||
|
||||
void GpLogDriver_Web::Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
GpLogDriver_Web *GpLogDriver_Web::GetInstance()
|
||||
{
|
||||
return &ms_instance;
|
||||
}
|
||||
|
||||
void GpLogDriver_Web::InitInternal()
|
||||
{
|
||||
time_t t = time(nullptr);
|
||||
struct tm utcTime = *gmtime(&t);
|
||||
|
||||
this->Printf(IGpLogDriver::Category_Information, GP_APPLICATION_NAME " build " __TIMESTAMP__);
|
||||
#if !GP_DEBUG_CONFIG
|
||||
this->Printf(IGpLogDriver::Category_Information, "Configuration: Release");
|
||||
#else
|
||||
this->Printf(IGpLogDriver::Category_Information, "Configuration: Debug");
|
||||
#endif
|
||||
}
|
||||
|
||||
GpLogDriver_Web GpLogDriver_Web::ms_instance;
|
||||
25
AerofoilWeb/GpLogDriver_Web.h
Normal file
25
AerofoilWeb/GpLogDriver_Web.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "IGpLogDriver.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class GpIOStream;
|
||||
|
||||
class GpLogDriver_Web : public IGpLogDriver
|
||||
{
|
||||
public:
|
||||
GpLogDriver_Web();
|
||||
|
||||
static void Init();
|
||||
|
||||
void VPrintf(Category category, const char *fmt, va_list args) override;
|
||||
void Shutdown() override;
|
||||
|
||||
static GpLogDriver_Web *GetInstance();
|
||||
|
||||
private:
|
||||
void InitInternal();
|
||||
|
||||
static GpLogDriver_Web ms_instance;
|
||||
};
|
||||
91
AerofoilWeb/GpMain_SDL_Web.cpp
Normal file
91
AerofoilWeb/GpMain_SDL_Web.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include <SDL.h>
|
||||
#include "SDL_main.h"
|
||||
|
||||
#include "GpMain.h"
|
||||
#include "GpAudioDriverFactory.h"
|
||||
#include "GpDisplayDriverFactory.h"
|
||||
#include "GpGlobalConfig.h"
|
||||
#include "GpFileSystem_Web.h"
|
||||
#include "GpLogDriver_Web.h"
|
||||
#include "GpFontHandlerFactory.h"
|
||||
#include "GpInputDriverFactory.h"
|
||||
#include "GpAppInterface.h"
|
||||
#include "GpSystemServices_Web.h"
|
||||
#include "GpVOSEvent.h"
|
||||
#include "GpX.h"
|
||||
|
||||
#include "IGpFileSystem.h"
|
||||
#include "IGpThreadEvent.h"
|
||||
#include "IGpVOSEventQueue.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
GpXGlobals g_gpXGlobals;
|
||||
|
||||
extern "C" IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties);
|
||||
|
||||
IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties);
|
||||
IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties);
|
||||
IGpInputDriver *GpDriver_CreateInputDriver_SDL2_Gamepad(const GpInputDriverProperties &properties);
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
GpLogDriver_Web::Init();
|
||||
IGpLogDriver *logger = GpLogDriver_Web::GetInstance();
|
||||
|
||||
#if GP_ASYNCIFY_PARANOID
|
||||
SDL_SetHint(SDL_HINT_EMSCRIPTEN_ASYNCIFY, "0");
|
||||
#endif
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0)
|
||||
return -1;
|
||||
|
||||
if (logger)
|
||||
logger->Printf(IGpLogDriver::Category_Information, "Starting filesystem...");
|
||||
|
||||
GpFileSystem_Web::GetInstance()->Init();
|
||||
|
||||
GpDriverCollection *drivers = GpAppInterface_Get()->PL_GetDriverCollection();
|
||||
|
||||
if (logger)
|
||||
logger->Printf(IGpLogDriver::Category_Information, "Setting up drivers...");
|
||||
|
||||
drivers->SetDriver<GpDriverIDs::kFileSystem>(GpFileSystem_Web::GetInstance());
|
||||
drivers->SetDriver<GpDriverIDs::kSystemServices>(GpSystemServices_Web::GetInstance());
|
||||
drivers->SetDriver<GpDriverIDs::kLog>(GpLogDriver_Web::GetInstance());
|
||||
|
||||
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2;
|
||||
|
||||
g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_SDL2;
|
||||
|
||||
g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_None;
|
||||
|
||||
EGpInputDriverType inputDrivers[] =
|
||||
{
|
||||
EGpInputDriverType_SDL2_Gamepad
|
||||
};
|
||||
|
||||
g_gpGlobalConfig.m_inputDriverTypes = inputDrivers;
|
||||
g_gpGlobalConfig.m_numInputDrivers = sizeof(inputDrivers) / sizeof(inputDrivers[0]);
|
||||
|
||||
g_gpGlobalConfig.m_osGlobals = &g_gpXGlobals;
|
||||
g_gpGlobalConfig.m_logger = logger;
|
||||
g_gpGlobalConfig.m_systemServices = GpSystemServices_Web::GetInstance();
|
||||
|
||||
GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2);
|
||||
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL);
|
||||
GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_SDL2_Gamepad, GpDriver_CreateInputDriver_SDL2_Gamepad);
|
||||
|
||||
if (logger)
|
||||
logger->Printf(IGpLogDriver::Category_Information, "SDL environment configured, starting up");
|
||||
|
||||
int returnCode = GpMain::Run();
|
||||
|
||||
if (logger)
|
||||
logger->Printf(IGpLogDriver::Category_Information, "SDL environment exited with code %i, cleaning up", returnCode);
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
206
AerofoilWeb/GpSystemServices_Web.cpp
Normal file
206
AerofoilWeb/GpSystemServices_Web.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include "GpSystemServices_Web.h"
|
||||
|
||||
#include "IGpClipboardContents.h"
|
||||
#include "IGpThreadEvent.h"
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
class GpMutex_Web_Null final : public IGpMutex
|
||||
{
|
||||
public:
|
||||
void Destroy() override;
|
||||
|
||||
void Lock() override;
|
||||
void Unlock() override;
|
||||
|
||||
static IGpMutex *GetInstance();
|
||||
|
||||
private:
|
||||
static GpMutex_Web_Null ms_instance;
|
||||
};
|
||||
|
||||
void GpMutex_Web_Null::Destroy()
|
||||
{
|
||||
}
|
||||
|
||||
void GpMutex_Web_Null::Lock()
|
||||
{
|
||||
}
|
||||
|
||||
void GpMutex_Web_Null::Unlock()
|
||||
{
|
||||
}
|
||||
|
||||
IGpMutex *GpMutex_Web_Null::GetInstance()
|
||||
{
|
||||
return &ms_instance;
|
||||
}
|
||||
|
||||
GpMutex_Web_Null GpMutex_Web_Null::ms_instance;
|
||||
|
||||
|
||||
class GpThreadEvent_Web_Null final : public IGpThreadEvent
|
||||
{
|
||||
public:
|
||||
void Wait() override;
|
||||
bool WaitTimed(uint32_t msec) override;
|
||||
void Signal() override;
|
||||
void Destroy() override;
|
||||
|
||||
static IGpThreadEvent *GetInstance();
|
||||
|
||||
private:
|
||||
static GpThreadEvent_Web_Null ms_instance;
|
||||
};
|
||||
|
||||
void GpThreadEvent_Web_Null::Wait()
|
||||
{
|
||||
}
|
||||
|
||||
bool GpThreadEvent_Web_Null::WaitTimed(uint32_t msec)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void GpThreadEvent_Web_Null::Signal()
|
||||
{
|
||||
}
|
||||
|
||||
void GpThreadEvent_Web_Null::Destroy()
|
||||
{
|
||||
}
|
||||
|
||||
IGpThreadEvent *GpThreadEvent_Web_Null::GetInstance()
|
||||
{
|
||||
return &ms_instance;
|
||||
}
|
||||
|
||||
|
||||
GpSystemServices_Web::GpSystemServices_Web()
|
||||
: m_textInputEnabled(false)
|
||||
, m_clipboardContents(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
int64_t GpSystemServices_Web::GetTime() const
|
||||
{
|
||||
time_t t = time(nullptr);
|
||||
return static_cast<int64_t>(t) - 2082844800;
|
||||
}
|
||||
|
||||
void GpSystemServices_Web::GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const
|
||||
{
|
||||
time_t t = time(nullptr);
|
||||
tm *tmObject = localtime(&t);
|
||||
year = static_cast<unsigned int>(tmObject->tm_year);
|
||||
month = static_cast<unsigned int>(tmObject->tm_mon + 1);
|
||||
hour = static_cast<unsigned int>(tmObject->tm_hour);
|
||||
minute = static_cast<unsigned int>(tmObject->tm_min);
|
||||
second = static_cast<unsigned int>(tmObject->tm_sec);
|
||||
}
|
||||
|
||||
IGpMutex *GpSystemServices_Web::CreateMutex()
|
||||
{
|
||||
return GpMutex_Web_Null::GetInstance();
|
||||
}
|
||||
|
||||
IGpMutex *GpSystemServices_Web::CreateRecursiveMutex()
|
||||
{
|
||||
return GpMutex_Web_Null::GetInstance();
|
||||
}
|
||||
|
||||
IGpThreadEvent *GpSystemServices_Web::CreateThreadEvent(bool autoReset, bool startSignaled)
|
||||
{
|
||||
return GpThreadEvent_Web_Null::GetInstance();
|
||||
}
|
||||
|
||||
uint64_t GpSystemServices_Web::GetFreeMemoryCosmetic() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
GpSystemServices_Web::~GpSystemServices_Web()
|
||||
{
|
||||
if (m_clipboardContents)
|
||||
m_clipboardContents->Destroy();
|
||||
}
|
||||
|
||||
void *GpSystemServices_Web::CreateThread(ThreadFunc_t threadFunc, void *context)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GpSystemServices_Web::Beep() const
|
||||
{
|
||||
}
|
||||
|
||||
bool GpSystemServices_Web::IsTouchscreen() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GpSystemServices_Web::IsUsingMouseAsTouch() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GpSystemServices_Web::IsTextInputObstructive() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GpSystemServices_Web::IsFullscreenPreferred() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GpSystemServices_Web::IsFullscreenOnStartup() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int GpSystemServices_Web::GetCPUCount() const
|
||||
{
|
||||
return SDL_GetCPUCount();
|
||||
}
|
||||
|
||||
void GpSystemServices_Web::SetTextInputEnabled(bool isEnabled)
|
||||
{
|
||||
m_textInputEnabled = isEnabled;
|
||||
}
|
||||
|
||||
bool GpSystemServices_Web::IsTextInputEnabled() const
|
||||
{
|
||||
return m_textInputEnabled;
|
||||
}
|
||||
|
||||
bool GpSystemServices_Web::AreFontResourcesSeekable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
IGpClipboardContents *GpSystemServices_Web::GetClipboardContents() const
|
||||
{
|
||||
return m_clipboardContents;
|
||||
}
|
||||
|
||||
void GpSystemServices_Web::SetClipboardContents(IGpClipboardContents *contents)
|
||||
{
|
||||
if (contents != m_clipboardContents)
|
||||
{
|
||||
if (m_clipboardContents)
|
||||
m_clipboardContents->Destroy();
|
||||
|
||||
m_clipboardContents = contents;
|
||||
}
|
||||
}
|
||||
|
||||
GpSystemServices_Web *GpSystemServices_Web::GetInstance()
|
||||
{
|
||||
return &ms_instance;
|
||||
}
|
||||
|
||||
GpSystemServices_Web GpSystemServices_Web::ms_instance;
|
||||
41
AerofoilWeb/GpSystemServices_Web.h
Normal file
41
AerofoilWeb/GpSystemServices_Web.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "IGpSystemServices.h"
|
||||
#include "GpCoreDefs.h"
|
||||
|
||||
struct IGpClipboardContents;
|
||||
|
||||
class GpSystemServices_Web final : public IGpSystemServices
|
||||
{
|
||||
public:
|
||||
GpSystemServices_Web();
|
||||
~GpSystemServices_Web();
|
||||
|
||||
void *CreateThread(ThreadFunc_t threadFunc, void *context) override;
|
||||
void Beep() const override;
|
||||
bool IsTouchscreen() const override;
|
||||
bool IsUsingMouseAsTouch() const override;
|
||||
bool IsTextInputObstructive() const override;
|
||||
bool IsFullscreenPreferred() const override;
|
||||
bool IsFullscreenOnStartup() const override;
|
||||
unsigned int GetCPUCount() const override;
|
||||
void SetTextInputEnabled(bool isEnabled) override;
|
||||
bool IsTextInputEnabled() const override;
|
||||
bool AreFontResourcesSeekable() const override;
|
||||
IGpClipboardContents *GetClipboardContents() const override;
|
||||
void SetClipboardContents(IGpClipboardContents *contents) override;
|
||||
int64_t GetTime() const override;
|
||||
void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override;
|
||||
IGpMutex *CreateMutex() override;
|
||||
IGpMutex *CreateRecursiveMutex() override;
|
||||
IGpThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) override;
|
||||
uint64_t GetFreeMemoryCosmetic() const override;
|
||||
|
||||
static GpSystemServices_Web *GetInstance();
|
||||
|
||||
private:
|
||||
static GpSystemServices_Web ms_instance;
|
||||
|
||||
IGpClipboardContents *m_clipboardContents;
|
||||
bool m_textInputEnabled;
|
||||
};
|
||||
5
AerofoilWeb/Link.bat
Normal file
5
AerofoilWeb/Link.bat
Normal file
@@ -0,0 +1,5 @@
|
||||
set INPUT_DIR=.
|
||||
set OUTPUT_DIR=bin
|
||||
set FLAGS=-flto -O0 -g -s USE_SDL=2 -s USE_ZLIB=1 -s ASYNCIFY -s ASYNCIFY_IGNORE_INDIRECT -s INITIAL_MEMORY=33554432 -s ASYNCIFY_ADVISE
|
||||
|
||||
emcc obj/AerofoilWeb_Combined.o obj/AerofoilWeb_Resources.o obj/GpShell_Combined.o obj/AerofoilSDL_Combined.o obj/GpApp_Combined.o obj/PortabilityLayer_Combined.o obj/MacRomanConversion.o -o %OUTPUT_DIR%/aerofoil.html %FLAGS%
|
||||
18
AerofoilWeb/LinkLog.txt
Normal file
18
AerofoilWeb/LinkLog.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
|
||||
d:\src\GlidePort\AerofoilWeb>
|
||||
3
AerofoilWeb/MakeBuildDirs.bat
Normal file
3
AerofoilWeb/MakeBuildDirs.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
mkdir obj
|
||||
mkdir bin
|
||||
mkdir res
|
||||
9
AerofoilWeb/Rebuild.bat
Normal file
9
AerofoilWeb/Rebuild.bat
Normal file
@@ -0,0 +1,9 @@
|
||||
call MakeBuildDirs.bat
|
||||
call BuildAerofoilSDL.bat
|
||||
call BuildAerofoilWeb.bat
|
||||
call BuildGpApp.bat
|
||||
call BuildGpShell.bat
|
||||
call BuildMacRomanConversion.bat
|
||||
call BuildPortabilityLayer.bat
|
||||
call BuildResources.bat
|
||||
call Link.bat
|
||||
1
AerofoilWeb/Run.bat
Normal file
1
AerofoilWeb/Run.bat
Normal file
@@ -0,0 +1 @@
|
||||
emrun bin/aerofoil.html
|
||||
13128
AerofoilWeb/aerofoil.wat
Normal file
13128
AerofoilWeb/aerofoil.wat
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user