Actor components ================ An actor component encapsulates reusable functionality for actors. A component can only be attached to one actor at a time. Each component has a unique ID and a name (not necessarily unique) for identification in save files and the Met.3D UI. For example, the ``MTransformComponent`` provides position, rotation, and scale properties to its associated actor, along with an optional drag-and-drop gizmo for easy manipulation. This component operates independently from the actor's core functionality. In summary, if an actor's functionality can be modularized, it should be implemented as an actor component. Implementation -------------- The ``MActorComponent`` class defines the interface for all components, featuring virtual methods for resource initialization, rendering, intersection checking, and dragging. It also allows enabling or disabling the component and emits the ``actorComponentChanged`` signal to indicate when redrawing or changes are necessary. The ``MActor`` class manages actors and their components, storing them in an ID map. When adding a component, it is initialized, and its properties are integrated into the actor's property tree. Components are managed using ``std::shared_ptr``, ensuring automatic cleanup when references are cleared. Removing a component disconnects signal connections and removes its properties from the property tree, allowing for reuse or cleanup. Actors do not save their attached components during session or file saving, as this must be managed manually by the actors themselves, which may create default components in their constructor. Creating these default components while loading would duplicate them. This design choice allows actors to control component instantiation. Usage of existing components ---------------------------- Each instance of an actor component is created by the actor it is added to via the ``MActor::addActorComponentOfType(...)`` method. This method takes the component type as a type parameter and accepts constructor arguments for the component. It is important to note, that the first argument for all components constructors should be the actor that created it. This argument should not be passed to the ``MActor::addActorComponentOfType(...)`` method. It is provided by the actor. Implementing a new component ---------------------------- The new component must inherit from the ``MActorComponent`` class or its subclasses and implement a constructor with the first argument as a pointer to the ``MActor`` class. The component's interface can be customized as needed. For more details on the methods that can be implemented, refer to the :ref:`reference`. When using properties, it is recommended to group all component properties under a single group property and set its configuration group to the component's name. .. _reference: Reference --------- This contains the class reference of the ``MActorComponent`` class. * :code:`MActorComponent(MActor*, QString&)` — The constructor of the component. The first argument is mandatory for all child classes to also implement. * :code:`~MActorComponent()` — The destructor of the component. All resources the component uses should be cleaned up here. * :code:`getName()` — Returns the current name of the component. * :code:`setName(const QString&)` — Sets the current name of the component. * :code:`getParentActor()` — Returns the actor the component is attached to or nullptr, if it is orphaned. * :code:`isEnabled()` — Whether the component is currently enabled or disabled. * :code:`setEnabled(bool)` — Either enables or disables the component. A disabled component will not be interactable or rendered. * :code:`virtual onEnabled()` — Called when the component changes from disabled to enabled. * :code:`virtual onDisabled()` — Called when the component changes from enabled to disabled. * :code:`virtual onNameChanged()` — Called when the name of the component changes. Use this to update the configuration group of the component. * :code:`virtual initializeResources()` — Initialize the component and its GPU resources. * :code:`virtual reloadShaderEffects(bool)` — Reload all shaders used by the component and optionally force them to recompile. * :code:`virtual renderToCurrentContext(MSceneViewGLWidget*)` — Used to render the component as a 3D object in the scene. * :code:`virtual renderToUiLayer(MSceneViewGLWidget*)` — Used to render the component to the 2D UI layer. * :code:`virtual checkIntersectionWithHandle(MSceneViewGLWidget*, float, float)` — Used to check for intersections with the mouse and the component for interaction. * :code:`virtual dragEvent(MSceneViewGLWidget*, int, float, float)` — Called when the component is dragged after a successful intersection check. * :code:`virtual releaseEvent(MSceneViewGLWidget*, int)` — Called when the drag event ends and the component is released. * :code:`virtual addProperties(MProperty*)` — Used to add the component properties to the given property group. * :code:`virtual toggleProperties(bool)` — Used to disable all properties of the component. * :code:`virtual removeProperties(MProperty*)` — Used to remove the component properties from the given property group. * :code:`virtual saveConfiguration(QSettings*)` — Saves all non-property configuration to the given ``QSettings*`` object. * :code:`virtual loadConfiguration(QSettings*)` — Loads all non-property configuration from the given ``QSettings*`` object. * :code:`emitComponentChangedSignal()` — Emits the signal, that the component changed and the actor needs to react to those changes.