Skip to content

Commit

Permalink
Initial Android build
Browse files Browse the repository at this point in the history
  • Loading branch information
justindriggers committed Feb 21, 2024
1 parent 7d05cbc commit d9381dd
Show file tree
Hide file tree
Showing 53 changed files with 1,171 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ elseif (EMSCRIPTEN)
add_subdirectory(pesto)
add_subdirectory("${AUDIO_DIR}/openal")
add_subdirectory("${RENDERERS_DIR}/opengl")
elseif (ANDROID)
add_subdirectory(carbonara)
add_subdirectory("${AUDIO_DIR}/openal")
add_subdirectory("${RENDERERS_DIR}/opengl")
endif()

add_subdirectory(linguine)
4 changes: 0 additions & 4 deletions audio/openal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,3 @@ target_include_directories(openal PUBLIC include)
target_include_directories(openal PRIVATE src)

target_link_libraries(openal PRIVATE linguine)

find_package(OpenAL REQUIRED)
target_link_libraries(openal PRIVATE ${OPENAL_LIBRARIES})
target_include_directories(openal PRIVATE ${OPENAL_INCLUDE_DIR})
15 changes: 15 additions & 0 deletions carbonara/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
23 changes: 23 additions & 0 deletions carbonara/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
project(carbonara)

add_library(carbonara SHARED
app/src/main/cpp/ApplicationAdapter.cpp
app/src/main/cpp/main.cpp
app/src/main/cpp/platform/AndroidInputManager.cpp
app/src/main/cpp/platform/AndroidLogger.cpp
app/src/main/cpp/platform/AndroidOpenGLFileLoader.cpp
app/src/main/cpp/platform/AndroidTimeManager.cpp
)

find_package(game-activity REQUIRED CONFIG)

target_link_libraries(carbonara PRIVATE
linguine opengl
game-activity::game-activity_static
EGL GLESv3 jnigraphics
android log
)

# https://developer.android.com/games/agdk/game-activity/migrate-native-activity#issue
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u \
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")
1 change: 1 addition & 0 deletions carbonara/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
51 changes: 51 additions & 0 deletions carbonara/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}

android {
namespace = "com.justindriggers.carbonara"
compileSdk = 34

defaultConfig {
applicationId = "com.justindriggers.carbonara"
minSdk = 30
targetSdk = 34
versionCode = 1
versionName = "1.0"
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
signingConfig = signingConfigs.getByName("debug")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
prefab = true
}
externalNativeBuild {
cmake {
path = file("../../CMakeLists.txt")
version = "3.22.1"
}
}
}

dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.games:games-activity:1.2.2")
}
21 changes: 21 additions & 0 deletions carbonara/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
27 changes: 27 additions & 0 deletions carbonara/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.NoActionBar"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<meta-data
android:name="android.app.lib_name"
android:value="carbonara" />
</activity>
</application>

</manifest>
123 changes: 123 additions & 0 deletions carbonara/app/src/main/cpp/ApplicationAdapter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include "ApplicationAdapter.h"

#include "OpenGLRenderer.h"
#include "platform/AndroidAudioManager.h"
#include "platform/AndroidInputManager.h"
#include "platform/AndroidLeaderboardManager.h"
#include "platform/AndroidLifecycleManager.h"
#include "platform/AndroidLogger.h"
#include "platform/AndroidOpenGLFileLoader.h"
#include "platform/AndroidSaveManager.h"
#include "platform/AndroidTimeManager.h"

namespace linguine::carbonara {

ApplicationAdapter::ApplicationAdapter(android_app& app) {
constexpr EGLint attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_NONE
};

auto display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, nullptr, nullptr);

EGLint numConfigs;
eglChooseConfig(display, attribs, nullptr, 0, &numConfigs);

std::unique_ptr<EGLConfig[]> supportedConfigs(new EGLConfig[numConfigs]);
eglChooseConfig(display, attribs, supportedConfigs.get(), numConfigs, &numConfigs);

auto config = *std::find_if(
supportedConfigs.get(),
supportedConfigs.get() + numConfigs,
[&display](const EGLConfig &config) {
EGLint red, green, blue, depth;

if (eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red)
&& eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green)
&& eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue)
&& eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depth)) {
return red == 8 && green == 8 && blue == 8 && depth == 24;
}

return false;
});

EGLint format;
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
EGLSurface surface = eglCreateWindowSurface(display, config, app.window, nullptr);

EGLint contextAttribs[] = {
EGL_CONTEXT_MAJOR_VERSION, 3,
EGL_NONE
};

EGLContext context = eglCreateContext(display, config, nullptr, contextAttribs);
eglMakeCurrent(display, surface, surface, context);

_display = display;
_surface = surface;
_context = context;

auto logger = std::make_shared<AndroidLogger>();
auto audioManager = std::make_shared<AndroidAudioManager>();
auto inputManager = std::make_shared<AndroidInputManager>(app);
auto leaderboardManager = std::make_shared<AndroidLeaderboardManager>();
auto lifecycleManager = std::make_shared<AndroidLifecycleManager>();

auto renderer = std::shared_ptr<render::OpenGLRenderer>(
render::OpenGLRenderer::create(std::make_unique<AndroidOpenGLFileLoader>())
);

auto saveManager = std::make_shared<AndroidSaveManager>();
auto timeManager = std::make_shared<AndroidTimeManager>();

_engine = std::make_unique<Engine>(logger, audioManager, inputManager,
leaderboardManager, lifecycleManager,
renderer, saveManager, timeManager);
}

ApplicationAdapter::~ApplicationAdapter() {
if (_display != EGL_NO_DISPLAY) {
eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

if (_context != EGL_NO_CONTEXT) {
eglDestroyContext(_display, _context);
_context = EGL_NO_CONTEXT;
}

if (_surface != EGL_NO_SURFACE) {
eglDestroySurface(_display, _surface);
_surface = EGL_NO_SURFACE;
}

eglTerminate(_display);
_context = EGL_NO_DISPLAY;
}
}

void ApplicationAdapter::tick() {
EGLint width;
eglQuerySurface(_display, _surface, EGL_WIDTH, &width);

EGLint height;
eglQuerySurface(_display, _surface, EGL_HEIGHT, &height);

auto& renderer = _engine->get<Renderer>();
auto& viewport = renderer.getViewport();

if (width != viewport.getWidth() || height != viewport.getHeight()) {
renderer.resize(width, height);
}

_engine->tick();

eglSwapBuffers(_display, _surface);
}

} // namespace linguine::carbonara
27 changes: 27 additions & 0 deletions carbonara/app/src/main/cpp/ApplicationAdapter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <Engine.h>

#include <EGL/egl.h>

#include "platform/AndroidInputManager.h"

namespace linguine::carbonara {

class ApplicationAdapter {
public:
explicit ApplicationAdapter(android_app& app);

~ApplicationAdapter();

void tick();

private:
std::unique_ptr<Engine> _engine;

EGLDisplay _display = EGL_NO_DISPLAY;
EGLSurface _surface = EGL_NO_SURFACE;
EGLContext _context = EGL_NO_CONTEXT;
};

} // namespace linguine::carbonara
33 changes: 33 additions & 0 deletions carbonara/app/src/main/cpp/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "ApplicationAdapter.h"

using namespace linguine;
using namespace linguine::carbonara;

void handle_cmd(android_app* app, int32_t cmd) {
switch (cmd) {
case APP_CMD_INIT_WINDOW:
app->userData = new ApplicationAdapter(*app);
break;
case APP_CMD_TERM_WINDOW:
if (app->userData) {
auto* applicationAdapter = reinterpret_cast<ApplicationAdapter*>(app->userData);
app->userData = nullptr;
delete applicationAdapter;
}
break;
default:
break;
}
}

void android_main(struct android_app* app) {
app->onAppCmd = handle_cmd;

do {
if (app->userData) {
reinterpret_cast<ApplicationAdapter*>(app->userData)->tick();
} else {
AndroidInputManager::pollNativeEvents(*app);
}
} while (!app->destroyRequested);
}
32 changes: 32 additions & 0 deletions carbonara/app/src/main/cpp/platform/AndroidAudioManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <audio/AudioManager.h>

namespace linguine::carbonara {

class AndroidAudioManager : public AudioManager {
public:
~AndroidAudioManager() override = default;

void poll() override {}

void setMusicEnabled(bool enabled) override {}

void setSoundEffectsEnabled(bool enabled) override {}

void play(EffectType effectType) override {}

void play(SongType songType, Mode mode) override {}

[[nodiscard]] std::optional<SongType> getCurrentSongType() const override {
return {};
}

void stopSongs() override {}

void pause() override {}

void resume() override {}
};

} // namespace linguine::carbonara

0 comments on commit d9381dd

Please sign in to comment.