How to use
In this section we will discuss how you can use ApertusVR's main features from Android and Java
Overview
The wrapper classes are placed in the org.apertusvr
package. For each ApertusVR entity type there's a corresponding Java wrapper class. Also there are a wrapper classes for the manager classes (e.g. ape::EventManager
, ape::SceneManager
)and ape::Event
and there are several supporting classes (e.g. apeColor
, apeVector3
). To be able to cast the interfaces, we ha a builder Java interface (apeBuilder
) too.
Event connection
Just like using the C++ interface, the user can connect to various events (fired by ApertusVR) from Java code. To do that, we need to implement the apeEventCallback
function:
We also have to create an instance of the MyEventCallback
class, e.g.
After instantiation, the connection works simply with the usage of apeManager
's connectEvent(...)
function. E.g., to be able to listen NODE
events, just type:
To get an insight of what actually happens here, let us discuss the details! When the user connects an event, the apeEventManager
(which is a static class) puts this eventCallback
into a map:
The app developer also creates a FrameCallback
class, which implements Android's built in Choreographer.FrameCallback
. Like in the following code block:
This will parse all the events fired in the C++ side, during the last frame. The ApertusJNI member function called processEventDoubleQueue()
is a JNI-function, which calls back to Java with apeEventManager
's fireEvent()
function, which will call the onEvent(apeEvent)
function of our apeEventCallback
implementation, if its instance is connected to the event's group (so the implementation object can be found under the apeEvent.Group.NODE
key in the map).
Entity wrappers
As it was written before, for each entity class in ApertusVR we have a corresponding Java class. The member functions and the class hierarchies on the Java side are the same, as they are on the C++ side. Therefore the API does not differ much, but there are tiny differences between the two. We will go through everything you need, to use ApertusVR entities from Java.
Getting access to entities
In C++, knowing the entity's name, we ask the ape::ISceneManager
to give us a weak pointer. Then we use the lock()
function to access it. After calling lock()
, we can also cast the resulted shared_ptr
to the proper type (ape::Entity::Type
), if we know what the entity's type should be.
When using ApertusVR from Java, we just use the interface's constructor to get access to an entity, then we check with the isValid()
function, that we can actually lock it in C++.
E.g. assume, that we want to access an apeFileGeometry
entity we know about, with the name of "FooBar"
, and our goal is to query its OwnerID
. The procedure goes something like on the following code example:
The following figure summarizes the procedure executed in the background:
This is the way in 90% of the cases. However, what if we don't know already the type of the entity, and only its name is given. In this case, we can use the apeSceneManager
interface:
Creating an entity
The next question is, how can we create entities in Java? Easy. Just use the apeSceneManager
interface!:
Okay, then how do we cast it to our needs? We wanted apeFileGeometry
interface, not apeEntity
.
This is where the apeBuilder
interface come in! The apeEntity
abstract class has a member function called cast
:
Providing a proper builder class (which implements the apeBuilder
interface), we can cast our apeEntity
to any given type extended from it. In the example, we just type:
Or an alternative way is to instance an other apeFileGeometry
entity with the apeEntity
's name you got from apeSceneManager
(like you saw it in the former sub-subsection).
Deleting entities
Deleting an entity in Java is the same as in C++, an example is presented below:
Writing an application
Now you know how to query events and handle them with entity usage, we can discuss how you can set up ApertusVR for your android application with the support of the JNI-plugin.
On Android, we build our applications from Activity classes, and each activity has its own lifecycle. To learn about activity lifecycles, see the Android guide on activity lifecycles. In code it appears as five function we have to override:
When the activity is launched (and the onCreate(...)
function is called) by Android , we have to do three things:
Get an instance from Android choreographer, and store it for later usages.
Start the ApertusVR system and optionally connect to a room.
Initialize the plug-ins for our application (more about it in the Plugins section).
The 1st is done by typing choreographer = Choreographer.getInstance()
. Not a big deal. The 2nd needs further explanation, and we will go through the 3rd in the next section.
Start ApertusVR
Before doing anything with ApertusVR, we have to call its C++ start method in the ape::System
namespace:
When we do that, we have to tell ApertusVR where it can find the apeCore.json file (configFolderPath
), which contains necessary informations. On Android it is stored in the assets folder of the given application. Therefore, when calling this method through the JNI-interface and the apeSystem
wrapper class, we type:
As you see, we have to provide the Android AssetManager (getAssets()
) for the start function. This will call the JNI-function startApertusVR(...),
which will call the actual ape::System::Start(...)
function.
For reading the asset folder from C++, the Android build has a shared library called apeAAssetOpen. The apeCoreConfig module, uses this shared library to open the asset folder. The JNI-method startApertusVR(...)
also initializes apeAAssetOpen library.
Connect to room
ApertusVR users on Android-Java can set the room they want to connect pre-runtime in the apeCore.json
, or runtime with the help of the apeSceneNetwork
wrapper. So basically everything goes like in the C++ case:
Plugins
In the ApertusVR C++ API plug-ins are implementations of the ape::IPlugin
interface. Developing on Android and Java, they have a different form. Our Java plug-ins are actually Android implementations of the AndroidLifecycleObserver
interface.
For being able to partition our application, Android provides us an interface called LifecycleObserver
. Classes implementing this interface (called lifecycle-aware components) can be attached to the activity's lifecycle as something which constantly observes its lifecycle, and respond to the events occouring during the activity's lifetime. To learn more about lifecycle-aware components, again please read the Android guide on the given topic.
As activities can select their lifecycle-aware components, it works kind of like a plug-in mechanism. Therefore the ApertusVR Android API contains an interface called apePlugin
, which only presents a LifecycleObserver
interface as it was a plug-in(ish thing):
So, in order to create a plug-in which works on Android and can respond to ApertusVR events from Java code, we need to implement this interface (or equivalently implement the "raw" LifecycleObserver
interface):
Then in our activity, when we want to start to use this example plug-in (e.g., when Android creates the activity), we create an instance of the plug-in, then attach it to the activity's lifecycle:
Not every Activity
subclass supports lifecycle-aware components. AppCompatActivity
specially supports it.
You can use configuration files for the plug-in if needed. Place the configuration file in the application's asset folder, then just query the path for the configuration file from the apeCoreCinfig.getConfigFolderPath()
.
Last updated