<!--
    This tutorial shows a basic sample of augmented reality.
    This exhibits:
      - how to detect an ArUco marker,
      - how to compute the pose of a marker,
      - how to make a basic augmented-reality render (we superimpose a cube onto the ArUco marker)
      - how to undistort a video according to the camera intrinsic parameters
      - how to distort a 3D render according to the camera intrinsic parameters
      - how to synchronize efficiently a video process pipeline with the video playback using signal_gate

    To use this application, you must open a calibration and a video. Samples are provided in the module folder
    of the application, `share/sight/tuto17_simple_ar` on Linux and `share\tuto17_simple_ar` on Windows:
      - calibration.xml
      - aruco_tag.m4v
-->
<plugin id="tuto17_simple_ar">
    <requirement id="sight::module::ui" />
    <requirement id="sight::module::viz::scene3d" />
    <requirement id="sight::module::ui::qt" />
    <requirement id="sight::module::service" />
    <requirement id="sight::module::ui" />

    <extension implements="sight::app::extension::config">
        <id>Tuto17SimpleAR_AppCfg</id>
        <config>
            <!-- ******************************* Objects declaration ****************************** -->

            <!-- Series of camera calibration -->
            <object uid="cameraSet" type="sight::data::camera_set" />
            <!-- Camera calibration, deferred because it is extracted from the series -->
            <object uid="camera" type="sight::data::camera" deferred="true" />
            <!-- Frame timeline used to buffer the output of the video grabber -->
            <object uid="frameTL" type="sight::data::frame_tl" />
            <!-- Video frame that is used for the current iteration -->
            <object uid="sourceFrame" type="sight::data::image" />
            <!-- Map containing all detected markers in the current frame -->
            <object uid="markerMap" type="sight::data::marker_map" />
            <!-- Marker matrix in the camera world -->
            <object uid="markerToCamera" type="sight::data::matrix4" />
            <!-- Camera matrix in the marker world -->
            <object uid="cameraToMarker" type="sight::data::matrix4" />
            <!-- Camera matrix in the marker world -->
            <object uid="cameraToMarkerDamped" type="sight::data::matrix4" />
            <!-- Cube superimposed on the video at the marker location -->
            <object uid="cubeMesh" type="sight::data::mesh" />
            <object uid="undistortMap" type="sight::data::image" />
            <object uid="distortMap" type="sight::data::image" />
            <object uid="cubeMaterial" type="sight::data::material" />

            <!-- Aruco tracker parameters -->
            <object uid="aruco_params" type="sight::data::map">
                <item key="debug_mode" type="sight::data::boolean" value="true" />
                <item key="corner_refinement" type="sight::data::boolean" value="true" />
                <item key="adaptive_th_win_size_min" type="sight::data::integer" value="3" />
                <item key="adaptive_th_win_size_max" type="sight::data::integer" value="23" />
                <item key="adaptive_th_win_size_step" type="sight::data::integer" value="10" />
                <item key="adaptive_th_constant" type="sight::data::real" value="7." />
                <item key="min_marker_perimeter_rate" type="sight::data::real" value="0.03" />
                <item key="max_marker_perimeter_rate" type="sight::data::real" value="4.0" />
                <item key="polygonal_approx_accuracy_rate" type="sight::data::real" value="0.03" />
                <item key="min_corner_distance_rate" type="sight::data::real" value="0.01" />
                <item key="minDistanceToBorder" type="sight::data::integer" value="1" />
                <item key="minMarkerDistanceRate" type="sight::data::real" value="0.0" />
                <item key="cornerRefinementWinSize" type="sight::data::integer" value="5" />
                <item key="cornerRefinementMaxIterations" type="sight::data::integer" value="30" />
                <item key="cornerRefinementMinAccuracy" type="sight::data::real" value="0.1" />
                <item key="markerBorderBits" type="sight::data::integer" value="1" />
                <item key="perspectiveRemovePixelPerCell" type="sight::data::integer" value="8" />
                <item key="perspectiveRemoveIgnoredMarginPerCell" type="sight::data::real" value="0.1" />
                <item key="maxErroneousBitsInBorderRate" type="sight::data::real" value="0.3" />
                <item key="minOtsuStdDev" type="sight::data::real" value="5.0" />
                <item key="errorCorrectionRate" type="sight::data::real" value="0.6" />
            </object>

            <!-- Damping parameters -->
            <object uid="damping_params" type="sight::data::map">
                <item key="enabled" type="sight::data::boolean" value="false" />
                <item key="weight" type="sight::data::real" value="0.6" />
            </object>

            <!-- Reprojection parameters -->
            <object uid="reprojection_params" type="sight::data::map">
                <item key="display" type="sight::data::boolean" value="true" />
                <item key="color" type="sight::data::color" value="#ffffff" />
            </object>

            <!-- ******************************* UI declaration *********************************** -->

            <!-- declaration of the views, menu and toolbar -->
            <service uid="mainFrame" type="sight::module::ui::frame">
                <gui>
                    <frame>
                        <name>tuto17_simple_ar</name>
                        <icon>tuto17_simple_ar/app.ico</icon>
                    </frame>
                    <toolbar />
                </gui>
                <registry>
                    <toolbar sid="toolbarView" start="true" />
                    <view sid="cameraView" start="true" />
                </registry>
            </service>

            <service uid="toolbarView" type="sight::module::ui::toolbar">
                <gui>
                    <layout>
                        <menuItem name="Load Calibration" icon="sight::module::ui::icons/calibration.svg" />
                        <editor />
                        <separator />
                        <menuItem name="Start" icon="sight::module::ui::icons/play.svg" shortcut="Space" />
                        <menuItem name="Pause" icon="sight::module::ui::icons/pause.svg" shortcut="Space" />
                        <menuItem name="Play" icon="sight::module::ui::icons/play.svg" shortcut="Space" />
                        <menuItem name="Stop" icon="sight::module::ui::icons/stop.svg" />
                        <menuItem name="Loop" icon="sight::module::ui::icons/loop.svg" style="check" />
                        <separator />
                        <menuItem name="Enable video image undistortion" icon="sight::module::ui::icons/barrel_distortion.svg" style="check" />
                        <menuItem name="Enable 3D rendering distortion" icon="sight::module::ui::icons/pincushion_distortion.svg" style="check" />
                        <separator />
                        <menuItem name="Show Mesh on tag" icon="sight::module::ui::icons/mesh.svg" style="check" />
                        <separator />
                        <menuItem name="Settings" icon="sight::module::ui::icons/gear.svg" style="check" />
                    </layout>
                </gui>
                <registry>
                    <menuItem sid="loadCalibAct" start="true" />
                    <editor sid="videoSelectorSrv" />
                    <menuItem sid="startVideoAct" start="true" />
                    <menuItem sid="pauseVideoAct" start="true" />
                    <menuItem sid="resumeVideoAct" start="true" />
                    <menuItem sid="stopVideoAct" start="true" />
                    <menuItem sid="loopVideoAct" start="true" />
                    <menuItem sid="startUndistortAct" start="true" />
                    <menuItem sid="startDistortAct" start="true" />
                    <menuItem sid="showMeshAct" start="true" />
                    <menuItem sid="showParametersAct" start="true" />
                </registry>
            </service>

            <service uid="cameraView" type="sight::module::ui::view">
                <gui>
                    <layout type="sight::ui::layout::line">
                        <orientation value="horizontal" />
                        <view proportion="1" />
                        <view proportion="0" backgroundColor="#36393E" />
                    </layout>
                </gui>
                <registry>
                    <view sid="videoView" start="true" />
                    <view sid="parametersView" start="true" />
                </registry>
            </service>

            <service uid="videoView" type="sight::module::ui::view">
                <gui>
                    <layout type="sight::ui::layout::line">
                        <orientation value="vertical" />
                        <view proportion="3" />
                        <view proportion="0" backgroundColor="#36393E" />
                    </layout>
                </gui>
                <registry>
                    <view sid="genericSceneSrv" />
                    <view sid="errorLabelSrv" start="true" />
                </registry>
            </service>

            <service uid="parametersView" type="sight::module::ui::view">
                <gui>
                    <layout type="sight::ui::layout::line">
                        <orientation value="vertical" />
                        <view proportion="3" />
                        <view proportion="2" />
                        <view proportion="1" />
                        <view proportion="1" />
                        <spacer />
                    </layout>
                </gui>
                <registry>
                    <view sid="aruco_parameters_srv" start="true" />
                    <view sid="reprojection_parameters_srv" start="true" />
                    <view sid="material_opacity_editor" start="true" />
                    <view sid="damping_parameters_srv" start="true" />
                </registry>
            </service>

            <!-- ************************************* Action ************************************ -->

            <!-- declaration of actions/slot callers -->
            <service uid="showParametersAct" type="sight::module::ui::modify_layout">
                <config>
                    <show_or_hide sid="parametersView" />
                </config>
            </service>

            <service uid="loadCalibAct" type="sight::module::ui::action" />

            <!-- Start the frame grabber -->
            <service uid="startVideoAct" type="sight::module::ui::action">
                <state enabled="false" />
            </service>

            <!-- Pause the frame grabber -->
            <service uid="pauseVideoAct" type="sight::module::ui::action">
                <state visible="false" />
            </service>

            <!-- Resume the frame grabber -->
            <service uid="resumeVideoAct" type="sight::module::ui::action">
                <state visible="false" />
            </service>

            <!-- Stop the frame grabber -->
            <service uid="stopVideoAct" type="sight::module::ui::action">
                <state enabled="false" />
            </service>

            <!-- Loop the frame grabber -->
            <service uid="loopVideoAct" type="sight::module::ui::action">
                <state enabled="false" />
            </service>

            <service uid="startUndistortAct" type="sight::module::ui::action" />

            <service uid="startDistortAct" type="sight::module::ui::action" />

            <service uid="showMeshAct" type="sight::module::ui::action">
                <state checked="true" />
            </service>

            <!-- ******************************* Begin Generic scene ******************************* -->

            <!-- scene in which the video and the 3D will be rendered -->
            <!-- In this tutorial, we move the camera and the marker mesh is fixed -->
            <service uid="genericSceneSrv" type="sight::viz::scene3d::render">
                <!-- It is essential to use the 'sync' mode when doing AR -->
                <!-- In this mode, the renderer will wait for a signal to trigger the rendering -->
                <scene renderMode="manual">
                    <background topColor="#36393E" bottomColor="#36393E" />

                    <layer id="video" order="1" compositors="Remap">
                        <adaptor uid="videoAdp" />
                        <adaptor uid="undistortAdp" />
                    </layer>

                    <layer id="default" order="3" compositors="Remap">
                        <adaptor uid="axisAdp" />
                        <adaptor uid="cameraAdp" />
                        <adaptor uid="materialAdp" />
                        <adaptor uid="cubeAdp" />
                        <adaptor uid="distortAdp" />
                    </layer>
                </scene>
            </service>

            <service uid="videoAdp" type="sight::module::viz::scene3d::adaptor::video">
                <in key="image" uid="sourceFrame" />
            </service>

            <service uid="undistortAdp" type="sight::module::viz::scene3d::adaptor::compositor_parameter" auto_connect="true">
                <inout key="parameter" uid="undistortMap" />
                <config compositorName="Remap" parameter="u_map" shaderType="fragment" visible="false" />
            </service>

            <service uid="axisAdp" type="sight::module::viz::scene3d::adaptor::axis">
                <config length="30" origin="true" label="false" />
            </service>

            <!-- Camera for the 3D layer -->
            <service uid="cameraAdp" type="sight::module::viz::scene3d::adaptor::camera">
                <inout key="transform" uid="cameraToMarkerDamped" />
                <in key="calibration" uid="camera" />
            </service>

            <service uid="materialAdp" type="sight::module::viz::scene3d::adaptor::material" auto_connect="true">
                <inout key="material" uid="cubeMaterial" />
                <config materialName="cube" />
            </service>

            <!-- Cube displayed on top of the marker plane -->
            <service uid="cubeAdp" type="sight::module::viz::scene3d::adaptor::mesh" auto_connect="true">
                <in key="mesh" uid="cubeMesh" />
                <config autoresetcamera="false" materialName="cube" />
            </service>

            <service uid="distortAdp" type="sight::module::viz::scene3d::adaptor::compositor_parameter" auto_connect="true">
                <inout key="parameter" uid="distortMap" />
                <config compositorName="Remap" parameter="u_map" shaderType="fragment" visible="false" />
            </service>

            <!-- ************************************* Services ************************************ -->

            <service uid="loadMeshSrv" type="sight::module::io::vtk::mesh_reader">
                <inout key="data" uid="cubeMesh" />
                <resource>tuto17_simple_ar/cube_60.vtk</resource>
            </service>

            <!-- hide axis adaptor until a marker is found -->
            <service uid="hideAxisSrv" type="sight::module::ui::action" />

            <!-- Calibration reader (here OpenCV's XML/YAML) -->
            <service uid="calibrationReaderSrv" type="sight::module::io::vision::open_cv_reader">
                <inout key="data" uid="cameraSet" />
            </service>

            <!-- extract the first sight::data::camera from the sight::data::camera_set -->
            <service uid="extractCameraSrv" type="sight::module::data::get_camera">
                <inout key="cameraSet" uid="cameraSet" />
                <out group="camera">
                    <key index="0" uid="camera" />
                </out>
            </service>

            <!-- GUI to handle aruco tracking parameters -->
            <service uid="aruco_parameters_srv" type="sight::module::ui::qt::settings">
                <inout key="map" uid="${aruco_params}" />
                <ui>
                    <item name="Show Marker" key="debug_mode" />
                    <item name="Corner refinement" key="corner_refinement" />
                    <item name="adpt. Threshold win size min" key="adaptive_th_win_size_min" widget="slider" min="3" max="100" />
                    <item name="adpt. Threshold win size max" key="adaptive_th_win_size_max" widget="slider" min="4" max="100" />
                    <item name="adpt. Threshold win size step" key="adaptive_th_win_size_step" widget="slider" min="1" max="100" />
                    <item name="adpt. threshold constant" key="adaptive_th_constant" min="0." max="30." />
                    <item name="Min. Marker Perimeter Rate" key="min_marker_perimeter_rate" min="0.01" max="1.0" />
                    <item name="Max. Marker Perimeter Rate" key="max_marker_perimeter_rate" min="1." max="10." />
                    <item name="Polygonal Approx. Accuracy Rate" key="polygonal_approx_accuracy_rate" min="0.01" max="1." />
                    <item name="Min. Corner Distance Rate" key="min_corner_distance_rate" min="0." max="1." />
                    <item name="Min. Distance to Border" key="minDistanceToBorder" widget="slider" min="0" max="10" />
                    <item name="Min. Marker Distance Rate" key="minMarkerDistanceRate" min="0." max="1." />
                    <item name="Corner Refinement Win. Size" key="cornerRefinementWinSize" widget="slider" min="1" max="100" />
                    <item name="Corner Refinement Max Iterations" key="cornerRefinementMaxIterations" widget="slider" min="1" max="10" />
                    <item name="Corner Refinement Min. Accuracy" key="cornerRefinementMinAccuracy" min="0.01" max="10." />
                    <item name="Marker Border Bits" key="markerBorderBits" widget="slider" min="1" max="100" />
                    <item name="Perspective Remove Pixel per Cell" key="perspectiveRemovePixelPerCell" widget="slider" min="1" max="32" />
                    <item name="Perspective Remove Ignored Margin Per Cell" key="perspectiveRemoveIgnoredMarginPerCell" min="0." max="1." />
                    <item name="Max. Erroneous Bits In Border Rate" key="maxErroneousBitsInBorderRate" min="0." max="1." />
                    <item name="Min. Otsu Std. Dev." key="minOtsuStdDev" min="0." max="100." />
                    <item name="Error Correction Rate" key="errorCorrectionRate" min="0." max="1." />
                </ui>
            </service>

            <service uid="reprojection_parameters_srv" type="sight::module::ui::qt::settings">
                <inout key="map" uid="${reprojection_params}" />
                <ui>
                    <item name="Show reprojection" key="display" />
                    <item name="Circle color" key="color" />
                </ui>
            </service>

            <service uid="damping_parameters_srv" type="sight::module::ui::qt::settings">
                <inout key="map" uid="${damping_params}" />
                <ui>
                    <item name="Damping" key="enabled" />
                    <item name="Weight" key="weight" min="0.1" max="1." widget="slider" />
                </ui>
            </service>

            <!-- Gui Service to display a value in a QLabel -->
            <service uid="errorLabelSrv" type="sight::module::ui::qt::text_status">
                <label>Reprojection error (RMSE)</label>
                <color>#D25252</color>
            </service>

            <!-- GUI to select camera (device, file, or stream) -->
            <service uid="videoSelectorSrv" type="sight::module::ui::qt::video::camera">
                <inout key="camera" uid="camera" />
                <videoSupport>true</videoSupport>
            </service>

            <!-- Grab image from camera device and fill a frame timeline -->
            <service uid="videoGrabberSrv" type="sight::module::io::video::frame_grabber">
                <in key="camera" uid="camera" />
                <inout key="frameTL" uid="frameTL" />
            </service>

            <!-- Consumes a frame in the timeline, picks the latest one to be processed -->
            <!-- It is overkill in this sample, but mandatory when we use multiple grabbers to synchronize them. -->
            <service uid="frameUpdaterSrv" type="sight::module::sync::synchronizer" auto_connect="false">
                <in group="frameTL">
                    <key uid="frameTL" />
                </in>
                <inout group="frames">
                    <key uid="sourceFrame" />
                </inout>
                <tolerance>100</tolerance>
            </service>

            <!-- Aruco tracker service -->
            <service uid="trackerSrv" type="sight::module::navigation::optics::aruco_tracker" worker="tracking" auto_connect="false">
                <in key="camera" uid="camera" />
                <inout key="frame" uid="sourceFrame" />
                <inout group="markerMap">
                    <!-- timeline of detected tag(s) -->
                    <key uid="markerMap" />
                </inout>
                <track>
                    <!-- list of tag's id -->
                    <marker id="101" />
                </track>
                <properties from="${aruco_params}" />
            </service>

            <!-- Computes the pose of the camera with tag(s) detected by aruco -->
            <service uid="registrationSrv" type="sight::module::geometry::vision::pose_from2d" worker="tracking">
                <in group="markerMap" auto_connect="true">
                    <key uid="markerMap" />
                </in>
                <in group="camera">
                    <key uid="camera" />
                </in>
                <inout group="matrix">
                    <key uid="markerToCamera" id="101" />
                </inout>
                <patternWidth>60</patternWidth>
            </service>

            <!-- Computes the reprojection error -->
            <service uid="errorSrv" type="sight::module::geometry::vision::reprojection_error" worker="error">
                <in group="matrix" auto_connect="true">
                    <key uid="markerToCamera" id="101" />
                </in>
                <in key="markerMap" uid="markerMap" />
                <in key="camera" uid="camera" />
                <inout key="frame" uid="sourceFrame" />
                <properties from="${reprojection_params}" pattern_width="60" />
            </service>

            <!-- Multiply matrices (here only used to inverse "markerToCamera") -->
            <service uid="matrixReverserSrv" type="sight::module::geometry::concatenate_matrices">
                <in group="matrix" auto_connect="false">
                    <key uid="markerToCamera" inverse="true" />
                </in>
                <inout key="output" uid="cameraToMarker" />
            </service>

            <service uid="undistorterSrv" type="sight::module::geometry::vision::distortion">
                <in key="camera" uid="camera" auto_connect="true" />
                <inout key="map" uid="undistortMap" />
                <mode>undistort</mode>
            </service>

            <service uid="distorterSrv" type="sight::module::geometry::vision::distortion">
                <in key="camera" uid="camera" auto_connect="true" />
                <inout key="map" uid="distortMap" />
                <mode>distort</mode>
            </service>

            <service uid="material_opacity_editor" type="sight::module::ui::qt::material_opacity_editor">
                <inout key="material" uid="cubeMaterial" />
                <label>Cube opacity</label>
            </service>

            <service uid="damp_matrix_srv" type="sight::module::geometry::weighted_mean_matrix" auto_connect="false">
                <in key="raw" uid="cameraToMarker" />
                <inout key="damped" uid="cameraToMarkerDamped" />
                <properties from="${damping_params}" />
            </service>

            <!-- ******************************* Connections ***************************************** -->

            <connect>
                <signal>showMeshAct/is_checked</signal>
                <slot>cubeAdp/update_visibility</slot>
            </connect>

            <connect>
                <signal>hideAxisSrv/is_checked</signal>
                <slot>axisAdp/update_visibility</slot>
            </connect>

            <connect>
                <signal>videoSelectorSrv/configured_file</signal>
                <signal>videoSelectorSrv/configured_stream</signal>
                <signal>videoSelectorSrv/configured_device</signal>
                <slot>startVideoAct/update</slot>
            </connect>

            <connect>
                <signal>videoGrabberSrv/camera_started</signal>
                <slot>pauseVideoAct/show</slot>
                <slot>startVideoAct/hide</slot>
                <slot>stopVideoAct/enable</slot>
                <slot>loopVideoAct/enable</slot>
            </connect>

            <connect>
                <signal>camera/id_modified</signal>
                <slot>videoGrabberSrv/stop_camera</slot>
            </connect>

            <connect>
                <signal>camera/modified</signal>
                <slot>startVideoAct/enable</slot>
                <slot>stopVideoAct/update</slot>
            </connect>

            <connect>
                <signal>errorSrv/error_computed</signal>
                <slot>errorLabelSrv/set_double_parameter</slot>
            </connect>

            <connect>
                <signal>cameraSet/modified</signal>
                <slot>extractCameraSrv/update</slot>
                <slot>errorSrv/update</slot>
            </connect>

            <connect>
                <signal>trackerSrv/marker_detected</signal>
                <slot>axisAdp/update_visibility</slot>
            </connect>

            <connect>
                <signal>loadCalibAct/updated</signal>
                <slot>calibrationReaderSrv/update</slot>
            </connect>

            <connect>
                <signal>startVideoAct/updated</signal>
                <slot>videoGrabberSrv/start_camera</slot>
                <slot>updater/start</slot>
            </connect>

            <connect>
                <signal>pauseVideoAct/updated</signal>
                <slot>updater/stop</slot>
                <slot>videoGrabberSrv/pause_camera</slot>
                <slot>resumeVideoAct/show</slot>
                <slot>pauseVideoAct/hide</slot>
            </connect>

            <connect>
                <signal>resumeVideoAct/updated</signal>
                <slot>videoGrabberSrv/pause_camera</slot>
                <slot>updater/start</slot>
                <slot>resumeVideoAct/hide</slot>
                <slot>pauseVideoAct/show</slot>
            </connect>

            <connect>
                <signal>stopVideoAct/updated</signal>
                <slot>videoGrabberSrv/stop_camera</slot>
                <slot>updater/stop</slot>
                <slot>startVideoAct/show</slot>
                <slot>resumeVideoAct/hide</slot>
                <slot>pauseVideoAct/hide</slot>
                <slot>stopVideoAct/disable</slot>
                <slot>loopVideoAct/disable</slot>
                <slot>loopVideoAct/uncheck</slot>
            </connect>

            <connect>
                <signal>loopVideoAct/updated</signal>
                <slot>videoGrabberSrv/loop_video</slot>
            </connect>

            <connect>
                <signal>startUndistortAct/checked</signal>
                <slot>undistortAdp/show</slot>
                <slot>startDistortAct/disable</slot>
            </connect>

            <connect>
                <signal>startUndistortAct/unchecked</signal>
                <slot>undistortAdp/hide</slot>
                <slot>startDistortAct/enable</slot>
            </connect>

            <connect>
                <signal>startDistortAct/checked</signal>
                <slot>distortAdp/show</slot>
                <slot>startUndistortAct/disable</slot>
            </connect>

            <connect>
                <signal>startDistortAct/unchecked</signal>
                <slot>distortAdp/hide</slot>
                <slot>startUndistortAct/enable</slot>
            </connect>

            <!-- ******************************* Start services ***************************************** -->

            <start uid="mainFrame" />
            <start uid="videoGrabberSrv" />
            <start uid="frameUpdaterSrv" />
            <start uid="registrationSrv" />
            <start uid="trackerSrv" />
            <start uid="calibrationReaderSrv" />
            <start uid="videoSelectorSrv" />
            <start uid="extractCameraSrv" />
            <start uid="matrixReverserSrv" />
            <start uid="errorSrv" />
            <start uid="hideAxisSrv" />
            <start uid="undistorterSrv" />
            <start uid="distorterSrv" />
            <start uid="loadMeshSrv" />
            <start uid="genericSceneSrv" />
            <start uid="materialAdp" />
            <start uid="videoAdp" />
            <start uid="undistortAdp" />
            <start uid="axisAdp" />
            <start uid="cameraAdp" />
            <start uid="cubeAdp" />
            <start uid="distortAdp" />
            <start uid="damp_matrix_srv" />

            <!-- ******************************* Update services ***************************************** -->

            <!-- At launch, enable the synchronization with the non-offscreen rendering -->
            <update>
                <service uid="showParametersAct" />
                <service uid="hideAxisSrv" />
                <service uid="loadMeshSrv" />

                <sequence uid="updater" loop="true">
                    <service uid="frameUpdaterSrv" />
                    <service uid="trackerSrv" />
                    <service uid="matrixReverserSrv" />
                    <service uid="damp_matrix_srv" />
                    <service uid="genericSceneSrv" />
                </sequence>
            </update>
        </config>
    </extension>
</plugin>
