Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Create Choreographer #11

Merged
merged 13 commits into from
Feb 23, 2024
2 changes: 2 additions & 0 deletions package/android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_library(
../cpp/FilamentProxy.cpp
../cpp/Surface.cpp
../cpp/SurfaceProvider.cpp
../cpp/Choreographer.cpp
../cpp/Listener.cpp
../cpp/jsi/HybridObject.cpp
../cpp/jsi/Promise.cpp
Expand All @@ -34,6 +35,7 @@ add_library(
src/main/cpp/JNISharedPtr.cpp
src/main/cpp/FilamentInstaller.cpp
src/main/cpp/java-bindings/JFilamentProxy.cpp
src/main/cpp/java-bindings/JChoreographer.cpp
src/main/cpp/java-bindings/JFilamentView.cpp
src/main/cpp/java-bindings/JSurfaceProvider.cpp
)
Expand Down
4 changes: 4 additions & 0 deletions package/android/src/main/cpp/AndroidFilamentProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ std::shared_ptr<FilamentView> AndroidFilamentProxy::findFilamentView(int id) {
return _proxy->cthis()->findFilamentView(id);
}

std::shared_ptr<Choreographer> AndroidFilamentProxy::createChoreographer() {
return _proxy->cthis()->createChoreographer();
}

} // namespace margelo
1 change: 1 addition & 0 deletions package/android/src/main/cpp/AndroidFilamentProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class AndroidFilamentProxy : public FilamentProxy {
// TODO(hanno): implement
int loadModel(std::string path) override;
std::shared_ptr<FilamentView> findFilamentView(int id) override;
std::shared_ptr<Choreographer> createChoreographer() override;

private:
jni::global_ref<JFilamentProxy::javaobject> _proxy;
Expand Down
2 changes: 2 additions & 0 deletions package/android/src/main/cpp/Filament.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "FilamentInstaller.h"
#include "JChoreographer.h"
#include "JFilamentProxy.h"
#include "JFilamentView.h"
#include "JSurfaceProvider.h"
Expand All @@ -11,5 +12,6 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
margelo::JFilamentProxy::registerNatives();
margelo::JSurfaceProvider::registerNatives();
margelo::JFilamentView::registerNatives();
margelo::JChoreographer::registerNatives();
});
}
37 changes: 37 additions & 0 deletions package/android/src/main/cpp/java-bindings/JChoreographer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Created by Marc Rousavy on 23.02.24.
//

#include "JChoreographer.h"
#include <android/choreographer.h>

namespace margelo {

void JChoreographer::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", JChoreographer::initHybrid),
makeNativeMethod("onFrame", JChoreographer::onFrameLong),
});
}

JChoreographer::JChoreographer(const jni::alias_ref<jhybridobject>& javaThis) : _javaPart(jni::make_global(javaThis)) {}

jni::local_ref<JChoreographer::jhybriddata> JChoreographer::initHybrid(jni::alias_ref<jhybridobject> javaThis) {
return makeCxxInstance(javaThis);
}

void JChoreographer::onFrameLong(jlong timestamp) {
onFrame(static_cast<double>(timestamp));
}

void JChoreographer::start() {
static const auto method = javaClassLocal()->getMethod<void()>("start");
method(_javaPart);
}

void JChoreographer::stop() {
static const auto method = javaClassLocal()->getMethod<void()>("stop");
method(_javaPart);
}

} // namespace margelo
33 changes: 33 additions & 0 deletions package/android/src/main/cpp/java-bindings/JChoreographer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Created by Marc Rousavy on 23.02.24.
//

#pragma once

#include "Choreographer.h"
#include <fbjni/fbjni.h>

namespace margelo {

using namespace facebook;

class JChoreographer : public jni::HybridClass<JChoreographer>, public Choreographer {
public:
static void registerNatives();

void start() override;
void stop() override;
void onFrameLong(jlong timestamp);

private:
friend HybridBase;
jni::global_ref<JChoreographer::javaobject> _javaPart;
static auto constexpr TAG = "JChoreographer";
static auto constexpr kJavaDescriptor = "Lcom/margelo/filament/FilamentChoreographer;";

private:
explicit JChoreographer(const jni::alias_ref<jhybridobject>& javaThis);
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject> javaThis);
};

} // namespace margelo
9 changes: 9 additions & 0 deletions package/android/src/main/cpp/java-bindings/JFilamentProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//

#include "JFilamentProxy.h"
#include "JChoreographer.h"
#include "JFilamentView.h"
#include "JNISharedPtr.h"
#include <fbjni/fbjni.h>
Expand Down Expand Up @@ -32,6 +33,14 @@ std::shared_ptr<FilamentView> JFilamentProxy::findFilamentView(int id) {
return std::static_pointer_cast<FilamentView>(sharedRef);
}

std::shared_ptr<Choreographer> JFilamentProxy::createChoreographer() {
static const auto method = javaClassLocal()->getMethod<jni::alias_ref<JChoreographer::javaobject>()>("createChoreographer");
jni::local_ref<JChoreographer::javaobject> choreographer = method(_javaPart);
jni::global_ref<JChoreographer::javaobject> globalRef = jni::make_global(choreographer);
std::shared_ptr<JChoreographer> sharedRef = JNISharedPtr::make_shared_from_jni<JChoreographer>(globalRef);
return std::static_pointer_cast<Choreographer>(sharedRef);
}

jsi::Runtime& JFilamentProxy::getRuntime() {
if (_runtime == nullptr) {
[[unlikely]];
Expand Down
2 changes: 2 additions & 0 deletions package/android/src/main/cpp/java-bindings/JFilamentProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include "Choreographer.h"
#include "FilamentView.h"
#include <ReactCommon/CallInvokerHolder.h>
#include <fbjni/fbjni.h>
Expand All @@ -25,6 +26,7 @@ class JFilamentProxy : public jni::HybridClass<JFilamentProxy> {
// TODO(hanno): implement
int loadModel(const std::string& path);
std::shared_ptr<FilamentView> findFilamentView(int id);
std::shared_ptr<Choreographer> createChoreographer();

jsi::Runtime& getRuntime();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.margelo.filament;

import android.view.Choreographer;

import androidx.annotation.Keep;

import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;

/** @noinspection JavaJniMissingFunction*/
public class FilamentChoreographer {
/** @noinspection unused, FieldCanBeLocal */
@DoNotStrip
@Keep
private final HybridData mHybridData;
private final Choreographer choreographer;
private boolean isRunning;

public FilamentChoreographer() {
mHybridData = initHybrid();
choreographer = Choreographer.getInstance();
}

private void onFrameCallback(long timestamp) {
if (!isRunning) return;
onFrame(timestamp);
choreographer.postFrameCallback(this::onFrameCallback);
}

/** @noinspection unused */
@DoNotStrip
@Keep
private synchronized void start() {
if (!isRunning) {
isRunning = true;
choreographer.postFrameCallback(this::onFrameCallback);
}
}

/** @noinspection unused */
@DoNotStrip
@Keep
private synchronized void stop() {
if (isRunning) {
isRunning = false;
choreographer.removeFrameCallback(this::onFrameCallback);
}
}

private native HybridData initHybrid();
private native void onFrame(long timestamp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ class FilamentProxy {
reactContext = context;
}

/** @noinspection unused*/
@DoNotStrip
@Keep
FilamentChoreographer createChoreographer() {
return new FilamentChoreographer();
}

/** @noinspection unused*/
@DoNotStrip
@Keep
Expand Down
28 changes: 28 additions & 0 deletions package/cpp/Choreographer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Created by Marc Rousavy on 23.02.24.
//

#include "Choreographer.h"

namespace margelo {

void Choreographer::loadHybridMethods() {
registerHybridMethod("addOnFrameListener", &Choreographer::addOnFrameListener, this);
registerHybridMethod("start", &Choreographer::start, this);
registerHybridMethod("stop", &Choreographer::stop, this);
}

std::shared_ptr<Listener> Choreographer::addOnFrameListener(Choreographer::OnFrameCallback onFrameCallback) {
_callbacks.push_back(std::move(onFrameCallback));
return std::make_shared<Listener>([]() {
// TODO: Find a safe way to remove this listener from the vector.
});
}

void Choreographer::onFrame(double timestamp) {
for (const auto& callback : _callbacks) {
callback(timestamp);
}
}

} // namespace margelo
31 changes: 31 additions & 0 deletions package/cpp/Choreographer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Created by Marc Rousavy on 23.02.24.
//

#pragma once

#include "Listener.h"
#include "jsi/HybridObject.h"
#include <functional>

namespace margelo {

class Choreographer : public HybridObject {
public:
using OnFrameCallback = std::function<void(double timestamp)>;

std::shared_ptr<Listener> addOnFrameListener(OnFrameCallback onFrameCallback);

virtual void start() = 0;
virtual void stop() = 0;

protected:
void onFrame(double timestamp);

void loadHybridMethods() override;

private:
std::vector<OnFrameCallback> _callbacks;
};

} // namespace margelo
1 change: 1 addition & 0 deletions package/cpp/FilamentProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ void FilamentProxy::loadHybridMethods() {
registerHybridMethod("loadModel", &FilamentProxy::loadModel, this);
registerHybridMethod("findFilamentView", &FilamentProxy::findFilamentView, this);
registerHybridMethod("createTestObject", &FilamentProxy::createTestObject, this);
registerHybridMethod("createChoreographer", &FilamentProxy::createChoreographer, this);
}

} // namespace margelo
4 changes: 2 additions & 2 deletions package/cpp/FilamentProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@

#pragma once

#include <jsi/jsi.h>

#include <string>
#include <vector>

#include "Choreographer.h"
#include "FilamentView.h"
#include "jsi/HybridObject.h"
#include "test/TestHybridObject.h"
Expand All @@ -21,6 +20,7 @@ class FilamentProxy : public HybridObject {
private:
virtual int loadModel(std::string path) = 0;
virtual std::shared_ptr<FilamentView> findFilamentView(int id) = 0;
virtual std::shared_ptr<Choreographer> createChoreographer() = 0;

std::shared_ptr<TestHybridObject> createTestObject();

Expand Down
4 changes: 4 additions & 0 deletions package/cpp/Listener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@ void Listener::remove() {
_isRemoved = true;
}

void Listener::loadHybridMethods() {
registerHybridMethod("remove", &Listener::remove, this);
}

} // namespace margelo
6 changes: 5 additions & 1 deletion package/cpp/Listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@

#pragma once

#include "jsi/HybridObject.h"
#include <functional>

namespace margelo {

class Listener {
class Listener : public HybridObject {
public:
Listener(Listener&& listener) : _remove(std::move(listener._remove)), _isRemoved(listener._isRemoved) {}
explicit Listener(std::function<void()> remove);
~Listener();
void remove();

void loadHybridMethods() override;

private:
std::function<void()> _remove;
bool _isRemoved;
Expand Down
9 changes: 2 additions & 7 deletions package/cpp/SurfaceProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@ Listener SurfaceProvider::addOnSurfaceChangedListener(margelo::SurfaceProvider::
std::unique_lock lock(_mutex);

_callbacks.push_back(std::move(callback));
size_t index = _callbacks.size();

return Listener([weakThis = this, index]() {
if (weakThis != nullptr) {
std::unique_lock lock(weakThis->_mutex);
weakThis->_callbacks.erase(weakThis->_callbacks.begin() + index);
}
return Listener([]() {
// TODO: Find a safe way to remove this listener from the vector.
});
}

Expand Down
2 changes: 1 addition & 1 deletion package/cpp/core/EngineWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void EngineWrapper::setSurfaceProvider(std::shared_ptr<SurfaceProvider> surfaceP
Listener listener = surfaceProvider->addOnSurfaceChangedListener(
SurfaceProvider::Callback{.onSurfaceCreated = [=](std::shared_ptr<Surface> surface) { this->setSurface(surface); },
.onSurfaceDestroyed = [=](std::shared_ptr<Surface> surface) { this->destroySurface(); }});
_listener = std::make_unique<Listener>(std::move(listener));
_listener = std::make_shared<Listener>(std::move(listener));
}

void EngineWrapper::setSurface(std::shared_ptr<Surface> surface) {
Expand Down
2 changes: 1 addition & 1 deletion package/cpp/core/EngineWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class EngineWrapper : public HybridObject {
private:
std::shared_ptr<Engine> _engine;
std::shared_ptr<SurfaceProvider> _surfaceProvider;
std::unique_ptr<Listener> _listener;
std::shared_ptr<Listener> _listener;
};

} // namespace margelo
Loading
Loading