3.3. C# Scripts Overview

The important overall picture is covered here, for more detailed notes about the implementation see the code itself, Crl + Q with Rider or generate the doxygen documentation locally with CMake.

In the Scripts folder, the subfolders correspond to the namespaces. Beware that Editor folders are treated specially by Unity and will not be included in a build.

  • Libigl - This is where most of the interesting code is: modifying/updating the geometry, making calls to C++, threading, anything related to the meshes.

    • Editor - Scripts related to importing and pre-processing models so that we can modify them with libigl.

  • XrInput - This is where interface with the controllers is, reading values, setting up controllers when detected, note setting up tracking is done in the scene with the XR Interaction Toolkit components

  • UI - This is about the 2D user interfaces. How to generate the UI panels, update them and defining the click behaviour.

    • Components - This contains lots of smaller scripts to define the behaviour of a generated component. See Assets/Prefabs/UI.

    • Hints - Behaviour and data related to displaying 2D UI hints over the controllers to show what each button does. This is quite context sensitive for each tool and sub-state. Uses ScriptableObjects so that we can enter the data in the Unity Editor.

  • Util - Some helper scripts

  • Testing - Scripts here are not used but might be of interest to see how the Unity APIs work (particularly the mesh API).

Warning

The C# code documentation is ‘custom’ made. If something is displayed completely incorrectly, please create an issue so it can be fixed. You can always see the doxygen documentation locally or view the code comments themselves in the IDE.

3.3.1. Libigl Overview

namespace Libigl
class DirtyFlag

Marks which data has changed in UMeshData as a bitmask and needs to be applied to the mesh.

This is used to selectively update the Unity mesh and is only for data that Unity requires. Use these constants along with the bitwise operators.

class LibiglBehaviour : public IDisposable

This is where the behaviour that interfaces with libigl is. It follows a Pre/Post/Execute threading pattern. This is a partial class, meaning it is split between several files.

Input: This handles collecting data from the main thread for the worker thread. It sets up the MeshInputState for the Actions. This is where we decide what to execute on the worker thread.

Actions: This handles executing things on the worker thread. Actions, in this context, are things that can be executed on the worker thread. They are the entry points to the C++ code (mostly). These actions correspond to the Do* variables in the MeshInputState

Transform: This handles anything related to transformations of the mesh or selections. This is only used for calculating which transformation to do for the selections. The code for applying the transformation to selections is in Actions

See also Libigl.LibiglMesh which handles the threading and calls the Pre/Post/Execute callbacks.

class LibiglMesh : public MonoBehaviour

This component needs to be attached to any GameObject that you want to modify with libigl.

Any libigl related code is defined in the LibiglBehaviour class. This class only handles the threading and connection with the Unity Mesh components.

struct MeshInputState

Struct for storing the current input for a mesh. (This is a value type so assigning will copy). Anything that may change as we are executing should be in the InputState, as it is copied in PreExecute. Anything that is the same between all meshes may be put into the InputState. Anything related to what should be executed on the worker thread should be put here (e.g. DoSelect).

Variables that correspond to triggering Actions start with Do e.g. DoSelect

class MeshManager : public MonoBehaviour

Handles loading EditableMeshes and stores references, notably to the ActiveMesh.

struct MeshState

The C++ state for a mesh in column major. This is linked to Unity and the RowMajor version via UMeshData. It stores only pointers to the Eigen data so this can be shared between C++ and C#. The mesh data is allocated in C++ during the Native.InitializeMesh function using UMeshDataNative.

The DirtyState indicates what has been changed and needs to be applied to the Unity mesh.

As this struct is shared between a managed (C#) and native (C++) context, you must consider Marshalling when adding new variables.

void* usually represents an Eigen matrix, but can be anything.

class Native

Contains all C++ function declarations. C# to C++

Handles initialization of the DLL and works with the UnityNativeTool for easy reloading/recompilation.

Convention: Pass the MeshState as the first argument if the function modifies a mesh.

class NativeCallbacks

Contains all callbacks from the native context. C++ to C#

Callbacks should be annotated with the MonoPInvokeCallbackAttribute so that IL2CPP builds will compile properly. Each callback needs to have a corresponding delegate (/type).

struct TransformDelta

Stores information about a single transformation.

class UMeshData : public IDisposable

Stores a copy of the Unity Mesh’s arrays. This is purely for the interface between the Libigl Mesh MeshState and the Unity Mesh / what will be rendered. Important: Uses RowMajor as that is how it is stored by Unity and on the GPU.

struct UMeshDataNative

Stores pointers to the native arrays in UMeshData so we can pass this to C++. Pointers are to the first element in the respective NativeArray.

Important: As Native arrays are not managed memory, the underlying array is fixed and will not move due to Garbage Collection. So an instance’s pointers will remain valid.

namespace Editor
class MeshImportPostprocessor : public AssetPostprocessor

Used for post-processing meshes after importing in the Editor. Only for file formats that Unity recognizes. Simplified version of OffMeshImporter

class OffMeshImporter : public ScriptedImporter

A custom importer for .off mesh files, which Unity does not recognize or know how to import by default. See tooltips.

3.3.2. XrInput Overview

namespace XrInput

Enums

enum ToolType

Which tool is being used, InputState.ActiveTool.

Values:

Transform
Select
enum ToolSelectMode

The sub-state of the Select tool.

Values:

Idle
Selecting
TransformingL
TransformingR
TransformingLr
enum ToolTransformMode

The sub-state of the Transform tool.

Values:

Idle
TransformingL
TransformingR
TransformingLr
enum SelectionMode

How to modify the selection.

Values:

Add
Subtract
Invert
enum PivotMode

How to rotate the mesh/selection.

Values:

Mesh
Hand
Selection
class InputManager : public MonoBehaviour

This script handles the controller input and is based on the Unity XR Interaction Toolkit. An important part is that this is where the InputState can be accessed and is updated.

struct InputState

This is the ‘shared’ input state. It is also where you can access the filtered controller input. Stores input that is shared between meshes as well as the raw input that has not been mapped to actions. Raw input has been filtered to prevent conflicts with UI and grabbables.

class XrBrush : public MonoBehaviour

Functionality related to the sphere ‘bubble’ brush. Currently handles resizing the brush, getting the center and finding overlapping bounding boxes via trigger colliders.

3.3.3. UI Overview

namespace UI
class Icons : public MonoBehaviour

Stores references to icon sprites. Names are mostly the same as the asset names.

class UiManager : public MonoBehaviour

Handles easy creation of operations to be done on a mesh and the user interaction (2D UI, speech, gestures) that comes with it.

class UiMeshDetails : public MonoBehaviour

Contains all functionality related to the mesh UI panel. There is one of these per LibiglMesh. Contains most UI generation.

namespace Components
class UiCollapsible : public MonoBehaviour

UI Component header that hides items when clicked/toggled.

class UiIconAction : public MonoBehaviour

UI Component with two buttons, one icon sized.

class UiPivotMode : public MonoBehaviour

Similar to UiSelectionMode, effectively an enum field.

class UiProgressIcon : public MonoBehaviour

Handles showing the progress icon and animating it based on the PreExecute and PostExecute. This indicates the state of the libigl thread.

class UiSelection : public MonoBehaviour

UI for one selection of a mesh (one row)

class UiSelectionMode : public MonoBehaviour

Handles the selection mode UI, onclick behaviour. There are several modes from SelectionMode as well as the newSelectionOnDrawBtn where a new selection is added on each stroke.

class UiToggleAction : public MonoBehaviour

A toggle and button UI element. The toggle and button are independent by default

namespace Hints
class UiInputHints : public MonoBehaviour

Defines the behaviour of the input hints of one hand. Important functions are: AddTooltip(GameObject, string), SetData and Repaint.

In short, tooltips can be added so when we hover over a UI element it displays some text. Repaint is called with the collection to set out the default hints for a particular state. This can then be overriden by scripting, e.g. see RepaintTriggerColor where we set the trigger hint color ot the active selection color.

class UiInputHintsData : public ScriptableObject

Data for one hand and one state of the ActiveTool. Used by the UiInputHints. We have one UiInputLabelData per button/axis.

class UiInputHintsDataCollection : public ScriptableObject

Stores the hints for all possible states of the ActiveTool and sub-states. These are stored as a hierarchy. UiInputHints.Repaint defines how this data is applied. There will be one instance for the left and one for the right hand.

class UiInputLabel : public MonoBehaviour

A label for a physical input button/axis to give a hint to what it does.

struct UiInputLabelData

Defines the content for a UiInputLabel.