Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ set(CMAKE_RELWITHDEBINFO_POSTFIX "")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_SKIP_RPATH ON)

add_executable(${PROJECT_NAME})
if(ANDROID)
add_library(${PROJECT_NAME} SHARED)
else()
add_executable(${PROJECT_NAME})
endif()

if(MSVC)
add_definitions(-D_USE_MATH_DEFINES)
Expand Down Expand Up @@ -59,6 +63,12 @@ elseif(IOS)
MACOSX_BUNDLE_BUNDLE_VERSION 1
MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer")
elseif(ANDROID)
# Android build configuration
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
# Build as shared library for Android
set_target_properties(${PROJECT_NAME} PROPERTIES
LIBRARY_OUTPUT_NAME "opengothic")
elseif(APPLE)
enable_language(OBJCXX)
endif()
Expand Down Expand Up @@ -96,6 +106,12 @@ endif()

if(WIN32)
target_link_libraries(${PROJECT_NAME} shlwapi DbgHelp)
elseif(ANDROID)
# Add android_native_app_glue
set(ANDROID_NATIVE_APP_GLUE_DIR "${ANDROID_NDK}/sources/android/native_app_glue")
target_sources(${PROJECT_NAME} PRIVATE "${ANDROID_NATIVE_APP_GLUE_DIR}/android_native_app_glue.c")
target_include_directories(${PROJECT_NAME} PRIVATE "${ANDROID_NATIVE_APP_GLUE_DIR}")
target_link_libraries(${PROJECT_NAME} android log)
elseif(UNIX)
target_link_libraries(${PROJECT_NAME} -lpthread -ldl)
endif()
Expand Down
27 changes: 26 additions & 1 deletion game/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,32 @@ void Camera::changeZoom(int delta) {

void Camera::setViewport(uint32_t w, uint32_t h) {
const float fov = Gothic::options().cameraFov;
proj.perspective(fov, float(w)/float(h), zNear(), zFar());

// On Android, we may need to swap width/height for projection matrix due to Vulkan transform issues
uint32_t projW = w, projH = h;

#if defined(__ANDROID__)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but hacks in camera code for specific OS is not acceptable - just use auto-rotation.

// Check if we're in landscape mode and if Vulkan transform might be incorrect
if(w > h) {
// Landscape mode - Vulkan transform might be ROTATE_90 when it should be IDENTITY
// We'll use the actual window dimensions for correct aspect ratio
Tempest::Log::i("Camera::setViewport: Android landscape mode detected");
projW = w;
projH = h;
} else {
// Portrait mode
Tempest::Log::i("Camera::setViewport: Android portrait mode detected");
projW = w;
projH = h;
}
#endif

float aspectRatio = float(projW)/float(projH);
proj.perspective(fov, aspectRatio, zNear(), zFar());

// Log viewport changes for rotation debugging
const char* orientation = (w > h) ? "LANDSCAPE" : "PORTRAIT";
Tempest::Log::i("Camera::setViewport: ", w, "x", h, " (", orientation, ") aspect=", aspectRatio);

// NOTE: usually depth bouds are from 0.95 to 1.0, resilting into ~805675 discrete values
static float l = 0.951978f, r = 1;
Expand Down
35 changes: 33 additions & 2 deletions game/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@
#include <Tempest/MetalApi>
#endif

#if defined(__IOS__)
#if defined(__IOS__) || defined(__ANDROID__)
#include "utils/installdetect.h"
#endif

#if defined(__ANDROID__)
#include <android_native_app_glue.h>
#include <android/log.h>
extern "C" void tempest_android_main(struct android_app* app);
static struct android_app* g_android_app = nullptr;
int main(int argc, const char** argv);
#endif

#include "utils/crashlog.h"
#include "mainwindow.h"
#include "gothic.h"
Expand Down Expand Up @@ -53,7 +61,7 @@ std::unique_ptr<Tempest::AbstractGraphicsApi> mkApi(const CommandLine& g) {
break;
#endif
case CommandLine::Vulkan:
#if !defined(__APPLE__)
#if !defined(__APPLE__) || defined(__ANDROID__)
return std::make_unique<Tempest::VulkanApi>(flg);
#else
break;
Expand All @@ -67,12 +75,35 @@ std::unique_ptr<Tempest::AbstractGraphicsApi> mkApi(const CommandLine& g) {
#endif
}

#if defined(__ANDROID__)
extern "C" void android_main(struct android_app* app) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to move into Tempest, as it's an implementation detail.

g_android_app = app;
tempest_android_main(app);

// Set up working directory
auto appdir = InstallDetect::applicationSupportDirectory();
if(!appdir.empty()) {
std::filesystem::current_path(appdir);
}

const char* argv[] = {"opengothic", nullptr};
main(1, argv);
}
#endif

int main(int argc,const char** argv) {
#if defined(__IOS__)
{
auto appdir = InstallDetect::applicationSupportDirectory();
std::filesystem::current_path(appdir);
}
#elif defined(__ANDROID__)
{
auto appdir = InstallDetect::applicationSupportDirectory();
if(!appdir.empty()) {
std::filesystem::current_path(appdir);
}
}
#endif

try {
Expand Down
12 changes: 12 additions & 0 deletions game/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,17 @@ void MainWindow::paintEvent(PaintEvent& event) {
void MainWindow::resizeEvent(SizeEvent&) {
for(auto& i:fence)
i.wait();

auto rectBefore = SystemApi::windowClientRect(hwnd());
Tempest::Log::i("MainWindow::resizeEvent: Starting resize - window: ", rectBefore.w, "x", rectBefore.h);

swapchain.reset();
renderer.resetSwapchain();

auto rectAfter = SystemApi::windowClientRect(hwnd());
Tempest::Log::i("MainWindow::resizeEvent: After swapchain reset - window: ", rectAfter.w, "x", rectAfter.h);
Tempest::Log::i("MainWindow::resizeEvent: Swapchain size: ", swapchain.w(), "x", swapchain.h());

if(auto camera = Gothic::inst().camera())
camera->setViewport(swapchain.w(),swapchain.h());

Expand All @@ -291,6 +300,8 @@ void MainWindow::resizeEvent(SizeEvent&) {
setCursorPosition(rect.w/2,rect.h/2);
setCursorShape(fs ? CursorShape::Hidden : CursorShape::Arrow);
dMouse = Point();

Tempest::Log::i("MainWindow::resizeEvent: Resize completed");
}

void MainWindow::mouseDownEvent(MouseEvent &event) {
Expand Down Expand Up @@ -519,6 +530,7 @@ void MainWindow::keyUpEvent(KeyEvent &event) {
if(auto pl = Gothic::inst().player())
rootMenu.setPlayer(*pl);
clearInput();
//event.accept();
}
else if(act==KeyCodec::Inventory && !dialogs.isActive()) {
if(inventory.isActive()) {
Expand Down
4 changes: 2 additions & 2 deletions game/utils/crashlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <stacktrace>
#endif

#if defined(__LINUX__) || defined(__APPLE__)
#if (defined(__LINUX__) || defined(__APPLE__)) && !defined(__ANDROID__)
#include <execinfo.h> // backtrace
#include <dlfcn.h> // dladdr
#include <cxxabi.h> // __cxa_demangle
Expand Down Expand Up @@ -167,7 +167,7 @@ void CrashLog::tracebackStd(std::ostream &out) {
}

void CrashLog::tracebackLinux(std::ostream &out) {
#if defined(__LINUX__) || defined(__APPLE__)
#if (defined(__LINUX__) || defined(__APPLE__)) && !defined(__ANDROID__)
// inspired by https://gist.github.com/fmela/591333/36faca4c2f68f7483cd0d3a357e8a8dd5f807edf (BSD)
void *callstack[64] = {};
char **symbols = nullptr;
Expand Down
33 changes: 31 additions & 2 deletions game/utils/installdetect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
#include "shlwapi.h"
#endif

#ifdef __ANDROID__
#include <android_native_app_glue.h>
extern "C" struct android_app* tempest_android_get_app();
#endif

#include <cstring>
#include "utils/fileutil.h"

Expand All @@ -16,7 +21,7 @@ InstallDetect::InstallDetect() {
pfiles = programFiles(false);
pfilesX86 = programFiles(true);
#endif
#if defined(__OSX__) || defined(__IOS__)
#if defined(__OSX__) || defined(__IOS__) || defined(__ANDROID__)
appDir = applicationSupportDirectory();
#endif
}
Expand All @@ -27,7 +32,7 @@ std::u16string InstallDetect::detectG2() {
if(ret.empty())
ret = detectG2(pfilesX86);
return ret;
#elif defined(__OSX__) || defined(__IOS__)
#elif defined(__OSX__) || defined(__IOS__) || defined(__ANDROID__)
if(FileUtil::exists(appDir))
return appDir;
return u"";
Expand Down Expand Up @@ -62,3 +67,27 @@ std::u16string InstallDetect::programFiles(bool x86) {
return ret;
}
#endif

#ifdef __ANDROID__
std::u16string InstallDetect::applicationSupportDirectory() {
struct android_app* app = tempest_android_get_app();
if(app == nullptr || app->activity == nullptr)
return u"";

// Prefer external data path (accessible without root)
const char* path = app->activity->externalDataPath;
if(path == nullptr)
path = app->activity->internalDataPath;
if(path == nullptr)
return u"";

// Convert UTF-8 to UTF-16
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tempest::TextCodec::toUtf16

std::u16string ret;
size_t len = std::strlen(path);
ret.reserve(len);
for(size_t i = 0; i < len; ++i) {
ret.push_back(static_cast<char16_t>(static_cast<unsigned char>(path[i])));
}
return ret;
}
#endif
4 changes: 2 additions & 2 deletions game/utils/installdetect.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class InstallDetect final {
InstallDetect();

std::u16string detectG2();
#if defined(__OSX__) || defined(__IOS__)
#if defined(__OSX__) || defined(__IOS__) || defined(__ANDROID__)
static std::u16string applicationSupportDirectory();
#endif

Expand All @@ -20,7 +20,7 @@ class InstallDetect final {
std::u16string pfiles, pfilesX86;
#endif

#if defined(__OSX__) || defined(__IOS__)
#if defined(__OSX__) || defined(__IOS__) || defined(__ANDROID__)
std::u16string appDir;
#endif
};