\hypertarget{datatypes_datatypes_intro}{}\section{Datatypes in Open\+Flipper}\label{datatypes_datatypes_intro}
Open\+Flipper supports a variety of datatypes. The default ones shipped with it are listed in the following section. It is also possible to extend Open\+Flipper with additional datatypes. this is described in the section \hyperlink{datatypes_adding_custom}{Adding custom datatypes}.\hypertarget{datatypes_datatypes_integrated}{}\section{Integrated data types}\label{datatypes_datatypes_integrated}
The following datatypes are available in Open\+Flipper\+:
\begin{DoxyItemize}
\item \hyperlink{polyMeshType}{Polygonal Meshes} 
\item \hyperlink{triMeshType}{Triangular Meshes} 
\item \hyperlink{skeletonType}{Skeletons} 
\item \hyperlink{planeType}{Planes} 
\item \hyperlink{sphereType}{Spheres} 
\item \hyperlink{splatType}{Point Splats} 
\item \hyperlink{BSplineCurveType}{B\+Spline\+Curves} 
\item \hyperlink{BSplineSurfaceType}{B\+Spline\+Surfaces} 
\item \hyperlink{polyLineType}{Polygonal Lines} 
\item \hyperlink{coordsysType}{Coordinate Systems} 
\item \hyperlink{CameraType}{Camera} 
\item \hyperlink{QtWidgetType}{Qt Widgets}
\end{DoxyItemize}

A description on how new data types can be added to Open\+Flipper can be found here\+: \hyperlink{datatypes_adding_custom}{Adding custom datatypes} \hypertarget{polyMeshType}{}\section{Polygonal Mesh (D\+A\+T\+A\+\_\+\+P\+O\+L\+Y\+\_\+\+M\+E\+SH)}\label{polyMeshType}
\hypertarget{polyMeshType_type_PolyMesh_info}{}\subsection{Datatype Information}\label{polyMeshType_type_PolyMesh_info}
Open\+Flipper includes a datatype for polygonal Meshes. The datastructure used to represent the Mesh is \hyperlink{OpenMeshDoc}{Open\+Mesh}. Open\+Mesh is a generic and efficient data structure for representing and manipulating polygonal meshes. You can directly use it inside of Open\+Flipper.~\newline
 The basic object type for handling polygonal meshes is the \hyperlink{classPolyMeshObject}{Poly\+Mesh\+Object}. This object manages rendering and data storage of a polygonal Open\+Mesh.~\newline
 To get the actual mesh you can call the \hyperlink{classMeshObject_a6c0369a82054030a178e0dd565739ccd}{Poly\+Mesh\+Object\+::mesh()} function which returns a pointer to the Open\+Mesh structure, which can be directly manipulated with the functions described in the \hyperlink{OpenMeshDoc}{Open\+Mesh Documentation}.~\newline
 Note\+: If you know that you only work on triangular meshes, use the \hyperlink{triMeshType}{Triangular Mesh datatype}.~\newline
\hypertarget{triMeshType}{}\section{Triangular Mesh (D\+A\+T\+A\+\_\+\+T\+R\+I\+A\+N\+G\+L\+E\+\_\+\+M\+E\+SH)}\label{triMeshType}
\hypertarget{triMeshType_type_TriMesh_info}{}\subsection{Datatype Information}\label{triMeshType_type_TriMesh_info}
Open\+Flipper includes a datatype for triangular Meshes. The datastructure used to represent the Mesh is \hyperlink{OpenMeshDoc}{Open\+Mesh}. Open\+Mesh is a generic and efficient data structure for representing and manipulating polygonal meshes. You can directly use it inside of Open\+Flipper.~\newline
 The basic object type for handling triangular meshes is the \hyperlink{classTriMeshObject}{Tri\+Mesh\+Object}. This object manages rendering and data storage of a triangular Open\+Mesh.~\newline
 To get the actual mesh you can call the \hyperlink{classMeshObject_a6c0369a82054030a178e0dd565739ccd}{Tri\+Mesh\+Object\+::mesh()} function which returns a pointer to the Open\+Mesh structure, which can be directly manipulated with the functions described in the \hyperlink{OpenMeshDoc}{Open\+Mesh Documentation}.~\newline
\hypertarget{skeletonType}{}\section{Skeleton (D\+A\+T\+A\+\_\+\+S\+K\+E\+L\+E\+T\+ON)}\label{skeletonType}
\hypertarget{skeletonType_skeletonStructure}{}\subsection{Skeleton Structure}\label{skeletonType_skeletonStructure}


A \hyperlink{classSkeletonT}{skeleton} represents a hierarchical tree structure of \hyperlink{classJointT}{joints}. The joints can be accessed through the skeleton. Therefore the skeleton class provides an \hyperlink{classSkeletonT_1_1Iterator}{iterator} over its joints. Additional ways to access joints from the skeleton are defined in the \hyperlink{classSkeletonT_JointAccess}{Joint Access Section}.~\newline
The \hyperlink{classJointT}{joint class} does not directly store information about the position and orientation of the joint, since this is dependent on the current pose. The joint class can be used to traverse from a joint to its neighbors in the tree structure and to set the selection state of a joint. Each joint is equipped with a unique id which is guaranteed to lie in a range between $[0,\cdots, (n-1)]$, where $ n $ is the number of joints. So when a joint is deleted from the skeleton the ids may change.\hypertarget{skeletonType_skeletonPoses}{}\subsection{Poses and Animations}\label{skeletonType_skeletonPoses}


A skeleton consists of a set of different poses. Initially a skeleton has only one attached pose. The so called reference pose. This pose defines the original position and orientation of each joint in the skeleton. For each animation defined on the skeleton poses store the position of joints in each frame of the animation. So for every frame of the animation we have an associated pose. ~\newline
 ~\newline
The \hyperlink{classSkeletonT_a089d5f7bae7aa66c5461d5e57a1f6358}{reference\+Pose()} can directly be accessed from the skeleton. In order to access specific poses from the animation we first have to get a handle for that pose. These handles are called \hyperlink{classAnimationHandle}{Animation\+Handles} and they store the index of an animation and index of a frame (or pose). All functions needed to access animations and poses from a skeleton are defined in the \hyperlink{classSkeletonT_AnimationAccess}{Animation Section}.\hypertarget{skeletonType_transformations}{}\subsection{Joint Transformations}\label{skeletonType_transformations}


A \hyperlink{classPoseT}{pose} of the skeleton defines the skeleton configuration for one frame in the animation. Thus if we want to change the position of joints this is only meaningful when a pose is given. The \hyperlink{classPoseT}{Pose class} can then be used to alter the transformation of joints. Basically there are two $ 4 \times 4 $ matrices for every joint which store its alignment.~\newline
 ~\newline
 For every joint $ J_i $ in the skeleton we define a matrix $ G_i $ to prescribe the global position and orientation of the joint. Hence, $ G_i $ is also referred to as the global matrix\+: ~\newline
 \[ G_i = \left[ \begin{array}{cccc} & & & p_x\\ & r & & p_y\\ & & & p_z\\ 0 & 0 & 0 & 1\\ \end{array} \right] \] ~\newline
 ~\newline
 where $ r \in R^{3 \times 3} $ is a rotation matrix and $ p = (p_x,p_y,p_z)^\top $ denotes the global joint position. The global matrix can also be seen as a transformation for the change of a basis. The global matrix transforms points from the local coordinate frame of the joint to global Cartesian coordinates.~\newline
 ~\newline
 The representation of joints using global matrices is sufficient to represent the geometry of a skeleton, but for computational efficiency we add another representation. We also express the position and orientation of a joint relative to its parent joint. This local representation of the joints is also stored in matrices, yielding a local matrix $ L_i $ for every joint $ J_i $\+:~\newline
 \[ L_i = G_p^{-1} \cdot G_i \] ~\newline
 The functions to access and alter the transformations are defined in the \hyperlink{classPoseT_PoseEditing}{Pose Editing section} of the \hyperlink{classPoseT}{PoseT} class.~\newline
 ~\newline
{\bfseries Note\+:} When using the functions \hyperlink{classPoseT_a09a23fe006d4efaadc71d3e731a205a6}{Pose\+T\+::set\+Local\+Matrix} and \hyperlink{classPoseT_a7903b555811eafb67204e829bd286d95}{Pose\+T\+::set\+Local\+Translation} the second parameter \textquotesingle{}\+\_\+keep\+Local\+Child\+Positions\textquotesingle{} defines if a change of the local matrix, keeps the local matrices of the child joints and thus updates the global matrices of the child joints or vice versa.~\newline
 ~\newline
{\bfseries Note\+:} When using the functions \hyperlink{classPoseT_abb3b80190a71cedef449b0e28669de32}{Pose\+T\+::set\+Global\+Matrix} and \hyperlink{classPoseT_a4ea35b6a61485ed152ba2f3e9ca010d3}{Pose\+T\+::set\+Global\+Translation} the second parameter \textquotesingle{}\+\_\+keep\+Global\+Child\+Positions\textquotesingle{} defines if a change of the global matrix, keeps the global matrices of the child joints and thus updates the local matrices of the child joints or vice versa.~\newline
~\newline
The \hyperlink{classPoseT}{Pose class} also provides unified matrices. These matrices are stored to minimize computations since they are used often when the skeleton is equipped with a skin mesh. The unified matrix maps a point from global coordinates in the reference pose to global coordinates in another pose. If the global matrix of a joint in reference pose is denoted as $ G_0 $ and the global matrix in a target pose is denoted as $ G_f $ then the unified matrix $ U $ is given as\+:

\[ U = G_f \cdot G_0^{-1} \] ~\newline
 Functions to access the unified matrices of a pose are defined in the \hyperlink{classPoseT_UnifiedMatrices}{Unified Matrices section}.\hypertarget{skeletonType_skeleton_tutorial_1}{}\subsection{Skeleton Tutorial 1\+: Simple Skeletal Animation}\label{skeletonType_skeleton_tutorial_1}
This section shows and explains a sample code to construct a simple skeletal animation. Images from the resulting animation are shown below\+: 

To generate such an animation we first have to define the structure of the skeleton\+:


\begin{DoxyCode}
\textcolor{comment}{//add an empty skeleton in OpenFlipper}
\textcolor{keywordtype}{int} objectId = -1;

emit addEmptyObject( \hyperlink{Skeleton_8hh_a2212d910967b02f9b8710b04b1c58a12}{DATA\_SKELETON}, objectId );

\hyperlink{classSkeletonObject}{SkeletonObject}* \hyperlink{namespacePluginFunctions_a147bb3aa4dd7489885c58b2197904b27}{skeletonObject};
\textcolor{keywordflow}{if} ( !\hyperlink{namespacePluginFunctions_a457fae57adecd43d140a3328ee935df3}{PluginFunctions::getObject}(objectId, skeletonObject) ) \{
  emit log(\hyperlink{LoggingInterface_8hh_a595b2880f3ae74561ba390e3fd8c0e7ca39fe22d7b704805a8e30697a4a07d8fc}{LOGERR},\textcolor{stringliteral}{"Unable to create new Skeleton"});
  \textcolor{keywordflow}{return};
\}

\hyperlink{classSkeletonT}{Skeleton}* \hyperlink{namespacePluginFunctions_a72e0406882d6f951e3ff8999d664f461}{skeleton} = \hyperlink{namespacePluginFunctions_a72e0406882d6f951e3ff8999d664f461}{PluginFunctions::skeleton}(skeletonObject);

\textcolor{comment}{// setup the structure of the skeleton}
\textcolor{comment}{// we want to construct a row of 3 joints}
\hyperlink{classJointT}{Skeleton::Joint}* currentParent = 0;
\textcolor{keywordtype}{int} jointCount = 3;

\textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} i=0; i < jointCount; i++)\{
  std::string      jointName = QString(\textcolor{stringliteral}{"Joint"} + QString::number(i)).toStdString(); \textcolor{comment}{// name of the joint}
  \hyperlink{classJointT}{Skeleton::Joint}*  newJoint = \textcolor{keyword}{new} \hyperlink{classJointT}{Skeleton::Joint}(currentParent, jointName )
      ;      \textcolor{comment}{// create new joint object with a pointer to its parent joint object}

  skeleton->\hyperlink{classSkeletonT_a1631f74df397f87ec44b5afa5a339bf4}{addJoint}(currentParent, newJoint);                                      \textcolor{comment}{// and add it
       to the skeleton}
  currentParent = newJoint;
\}
\end{DoxyCode}


Now the structure of the skeleton is defined, but it does not have an animation and the position of all joints in the reference pose is $ p = (0,0,0)^\top $. In the next step we set the correct positions for the reference pose\+:


\begin{DoxyCode}
\textcolor{comment}{// set positions for the reference pose}
\hyperlink{classPoseT}{Skeleton::Pose}* refPose = skeleton->\hyperlink{classSkeletonT_a089d5f7bae7aa66c5461d5e57a1f6358}{referencePose}();
\textcolor{keywordtype}{double} xOffset = 0.0;

\textcolor{comment}{// iterate over all joints of the skeleton and set a new translation}
\textcolor{comment}{// the joints transformation matrix is initially the identity so changing}
\textcolor{comment}{// the translation yields the desired effect}
\textcolor{keywordflow}{for} (\hyperlink{classSkeletonT_1_1Iterator}{Skeleton::Iterator} it = skeleton->\hyperlink{classSkeletonT_a0fe6ab4ddb20601bfba4d195e4e3c780}{begin}(); it != skeleton->
      \hyperlink{classSkeletonT_ad5e80649bdb640885fd1b905896d6fbb}{end}(); ++it)\{
  refPose->\hyperlink{classPoseT_a4ea35b6a61485ed152ba2f3e9ca010d3}{setGlobalTranslation}( (*it)->id(), \hyperlink{namespaceACG_ae4a56bb6b65d7f966934982a1e370213}{ACG::Vec3d}(xOffset, 0.0, 0.0) )
      ;
  xOffset += 1.0;
\}
\end{DoxyCode}


The reference pose of the skeleton is now completely defined, but we still don\textquotesingle{}t have an animation. It is created and added to the skeleton as follows\+:


\begin{DoxyCode}
\textcolor{comment}{//add an animation}
\textcolor{keywordtype}{int} frameCount = 100;

\hyperlink{classFrameAnimationT}{FrameAnimationT<ACG::Vec3d>}* animation = \textcolor{keyword}{new} 
      \hyperlink{classFrameAnimationT}{FrameAnimationT<ACG::Vec3d>}(skeleton, frameCount);
\hyperlink{classAnimationHandle}{AnimationHandle} animHandle = skeleton->addAnimation(\textcolor{stringliteral}{"Rotation"}, animation);
skeleton->animation(animHandle)->setFps(25);
\end{DoxyCode}


We have added an animation with 100 frames and a playback rate of 25 frames per second. The transformations for every joint and every frame of the animation however is still an identity matrix and therefore only one point is visible when this animation is played. To change this we now have to change the transformations of all joints for the complete animation\+:


\begin{DoxyCode}
\textcolor{comment}{// set position in every pose/frame of the animation}
\textcolor{comment}{// joints are indexed 0,1,2 in our case. so 1 yields the middle joint}
\hyperlink{classJointT}{Skeleton::Joint}* middleJoint = skeleton->joint(1);

\textcolor{comment}{// for the two outer joints we just use the same translation}
\textcolor{comment}{// like in the reference pose, but for the middle joint we also}
\textcolor{comment}{// apply a rotation which is incremented from 0 to 90 degrees}
\hyperlink{classACG_1_1GLMatrixT}{ACG::GLMatrixd} rotationMatrix;
rotationMatrix.\hyperlink{classACG_1_1Matrix4x4T_a598f9a255f3aa4eab1f9e42f668cd375}{identity}();
\textcolor{keywordtype}{double} maxAngle = 90.0;
\hyperlink{classOpenMesh_1_1VectorT}{ACG::Vec3d} axis(0.0, 0.0, 1.0);

\textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} i=0; i < frameCount; i++)\{
  animHandle.setFrame(i);

  \hyperlink{classPoseT}{Skeleton::Pose}* pose = skeleton->\hyperlink{classFrameAnimationT_ae981361c6d29c0e0b6d3e0f4877c9561}{pose}(animHandle);

  \textcolor{comment}{// set the same translation like in the reference pose}
  \textcolor{keywordflow}{for} (\hyperlink{classSkeletonT_1_1Iterator}{Skeleton::Iterator} it = skeleton->begin(); it != skeleton->end(); ++it)
    pose->\hyperlink{classPoseT_a4ea35b6a61485ed152ba2f3e9ca010d3}{setGlobalTranslation}( (*it)->id(), refPose->
      \hyperlink{classPoseT_ac6c29e6e544e09a06a3ff17554125fe8}{globalTranslation}( (*it)->id() ) );

  \textcolor{comment}{// update the rotation matrix}
  rotationMatrix.\hyperlink{classACG_1_1GLMatrixT_a00a5672ec60726a386be957ee9bd4312}{rotate}( maxAngle / frameCount, axis);
  \textcolor{comment}{// copy the rotation matrix to the global matrix of the middle joint}
  pose->\hyperlink{classPoseT_abb3b80190a71cedef449b0e28669de32}{setGlobalMatrix}(     middleJoint->\hyperlink{classJointT_a3b474af6bb87baac7f6c920ab228e42f}{id}(), rotationMatrix, false );
  \textcolor{comment}{// since the translation is lost now..re-add it}
  pose->\hyperlink{classPoseT_a4ea35b6a61485ed152ba2f3e9ca010d3}{setGlobalTranslation}(middleJoint->\hyperlink{classJointT_a3b474af6bb87baac7f6c920ab228e42f}{id}(), refPose->
      \hyperlink{classPoseT_ac6c29e6e544e09a06a3ff17554125fe8}{globalTranslation}( middleJoint->\hyperlink{classJointT_a3b474af6bb87baac7f6c920ab228e42f}{id}() ), \textcolor{keyword}{false} );
\}
\end{DoxyCode}


Now the animation is complete. In order to use these code snippets two additional things are needed. For one we need two includes\+: 
\begin{DoxyCode}
\textcolor{preprocessor}{#include <ACG/Math/GLMatrixT.hh>}
\textcolor{preprocessor}{#include <\hyperlink{Skeleton_8hh}{ObjectTypes/Skeleton/Skeleton.hh}>}
\end{DoxyCode}


and after the animation is constructed we have to inform Open\+Flipper about the changes\+:


\begin{DoxyCode}
emit updatedObject(skeletonObject->\hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}(), \hyperlink{group__DefaultUpdateTypes_ga4ce39b8d60eb78ada5080d032c9463a8}{UPDATE\_ALL});
\hyperlink{namespacePluginFunctions_afb6ba50cd13b03ae5c8ed921b82f9157}{PluginFunctions::viewAll}();
\end{DoxyCode}
\hypertarget{skeletonType_skeleton_tutorial_2}{}\subsection{Skeleton Tutorial 2\+: Skinning}\label{skeletonType_skeleton_tutorial_2}
In this tutorial we extend the first tutorial by adding a mesh which deforms with the rotation of the skeleton. For simplicity we just construct a mesh without faces. Additionally, the skin weights for the points of the mesh are also computed using a very simple method and therefore the result does not look perfect. The result is shown below\+:



The first thing we need to do is to add a mesh object\+:


\begin{DoxyCode}
\textcolor{comment}{//add a mesh}
objectId = -1;
emit addEmptyObject( \hyperlink{TriangleMesh_8hh_a899767380abdeb71a7d93f1764e4c746}{DATA\_TRIANGLE\_MESH}, objectId );

\hyperlink{classTriMeshObject}{TriMeshObject}* meshObject;
\textcolor{keywordflow}{if} ( !\hyperlink{namespacePluginFunctions_a457fae57adecd43d140a3328ee935df3}{PluginFunctions::getObject}(objectId,meshObject) ) \{
  emit log(\hyperlink{LoggingInterface_8hh_a595b2880f3ae74561ba390e3fd8c0e7ca39fe22d7b704805a8e30697a4a07d8fc}{LOGERR},\textcolor{stringliteral}{"Unable to create new Mesh"});
  \textcolor{keywordflow}{return};
\}

TriMesh* mesh = \hyperlink{namespacePluginFunctions_a4797322b8169e91fd69c194b927b8aa8}{PluginFunctions::triMesh}(meshObject);
\end{DoxyCode}


The connection between joints of the skeleton and vertices of the mesh is stored in the skin weights. They describe the weighted influence of different joints on one vertex. The weights are stored as a mesh property and we need to add the property first\+:


\begin{DoxyCode}
\textcolor{comment}{//add skin-weights property on the mesh}
\hyperlink{structOpenMesh_1_1VPropHandleT}{OpenMesh::VPropHandleT< BaseSkin::SkinWeights >} propWeights;
mesh->add\_property(propWeights, SKIN\_WEIGHTS\_PROP);
\end{DoxyCode}


Now we can go on and add vertices to the mesh and set their skin weights. The points are added above and below the skeleton and we add 50 points between two joints both above and below\+:


\begin{DoxyCode}
\textcolor{keywordtype}{int} steps = 50; \textcolor{comment}{// number of intermediate points}

\textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} i=0; i < jointCount; i++)
\textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} j=0; j < steps;      j++)\{
  \textcolor{comment}{// intermediate position}
  \textcolor{keywordtype}{double} xPos = j / double(steps-1);

  \textcolor{comment}{// add vertices}
  \hyperlink{classOpenMesh_1_1PolyMeshT_a0fc18e13d70825938274e3faf7b55e01}{TriMesh::VertexHandle} vh1 = mesh->add\_vertex( \hyperlink{classOpenMesh_1_1VectorT}{ACG::Vec3d}(i + xPos,  0.1, 0
      .0) );
  \hyperlink{classOpenMesh_1_1PolyMeshT_a0fc18e13d70825938274e3faf7b55e01}{TriMesh::VertexHandle} vh2 = mesh->add\_vertex( \hyperlink{classOpenMesh_1_1VectorT}{ACG::Vec3d}(i + xPos, -0.1, 0
      .0) );

  \textcolor{comment}{// add a simple weighting from 1 directly at joint i down to 0}
  \textcolor{comment}{// at the position of the next joint}
  mesh->property(propWeights, vh1)[ i ] = 1.0 - xPos;
  mesh->property(propWeights, vh2)[ i ] = 1.0 - xPos;

  \textcolor{keywordflow}{if} ( i != 2 )\{
    \textcolor{comment}{// add an increasing weight for the next joint}
    \textcolor{comment}{// this weight starts with 0 near the joint i and increases}
    \textcolor{comment}{// to 1 near joint i+1}
    mesh->property(propWeights, vh1)[ i+1 ] = xPos;
    mesh->property(propWeights, vh2)[ i+1 ] = xPos;
  \} \textcolor{keywordflow}{else}
    \textcolor{keywordflow}{break}; \textcolor{comment}{// no intermediate points after the last joint}
\}
\end{DoxyCode}


This simple skin weight definition shifts the center of the rotation between the first and the second joint, but a \textquotesingle{}correct\textquotesingle{} weight computation would exceed the range of this tutorial. To run the code two more things have to be considered. First, we have to add an include for the skinweights\+:


\begin{DoxyCode}
\textcolor{preprocessor}{#include <ObjectTypes/Skeleton/BaseSkin.hh>}
\end{DoxyCode}


And additionally we have to inform Open\+Flipper about the changes that have been made\+:


\begin{DoxyCode}
\textcolor{comment}{// tell the skeletal animation plugin to attach the mesh to the skeleton}
RPC::callFunctionValue<bool, int, int>(\textcolor{stringliteral}{"skeletalanimation"}, \textcolor{stringliteral}{"attachSkin"}, skeletonObject->
      \hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}(), meshObject->\hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}());
\textcolor{comment}{// the mesh has been updated}
emit updatedObject(meshObject->\hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}(), \hyperlink{group__DefaultUpdateTypes_ga4ce39b8d60eb78ada5080d032c9463a8}{UPDATE\_ALL});
\textcolor{comment}{// switch to drawMode points because we have no faces in our mesh}
\hyperlink{namespacePluginFunctions_aa8a61acbaf42ab8649aec866b73e4c06}{PluginFunctions::setDrawMode}( 
      \hyperlink{namespaceACG_1_1SceneGraph_1_1DrawModes_a9c5f1ec0a64bebbfb0381f2a0edb34e1}{ACG::SceneGraph::DrawModes::POINTS} )
\end{DoxyCode}


{\bfseries Note\+:} The \hyperlink{namespaceRPC}{R\+PC} function call can be left out, but then the user has to connect skeleton and skin with the \textquotesingle{}Attach Skin to Skeleton\textquotesingle{} Button in the Skeletal Animation Toolbox.~\newline
~\newline
The complete sourcecode of this tutorial can be found \hyperlink{skeletonSource}{here}. \hypertarget{skeletonSource}{}\subsection{Skeleton Tutorial Source\+Code}\label{skeletonSource}

\begin{DoxyCode}
\textcolor{preprocessor}{#include <\hyperlink{TriangleMesh_8hh}{ObjectTypes/TriangleMesh/TriangleMesh.hh}>}
\textcolor{preprocessor}{#include <\hyperlink{PluginFunctions_8hh}{OpenFlipper/BasePlugin/PluginFunctions.hh}>}

\textcolor{preprocessor}{#include <ACG/Math/GLMatrixT.hh>}
\textcolor{preprocessor}{#include <\hyperlink{Skeleton_8hh}{ObjectTypes/Skeleton/Skeleton.hh}>}
\textcolor{preprocessor}{#include <ObjectTypes/Skeleton/BaseSkin.hh>}


\textcolor{keywordtype}{void} skeletonTutorial2() \{
  
  \textcolor{keywordtype}{int} objectId = -1;
  
  emit addEmptyObject( \hyperlink{Skeleton_8hh_a2212d910967b02f9b8710b04b1c58a12}{DATA\_SKELETON}, objectId );

  \hyperlink{classSkeletonObject}{SkeletonObject}* skeletonObject;
  \textcolor{keywordflow}{if} ( !\hyperlink{namespacePluginFunctions_a457fae57adecd43d140a3328ee935df3}{PluginFunctions::getObject}(objectId, skeletonObject) ) \{
    emit log(\hyperlink{LoggingInterface_8hh_a595b2880f3ae74561ba390e3fd8c0e7ca39fe22d7b704805a8e30697a4a07d8fc}{LOGERR},\textcolor{stringliteral}{"Unable to create new Skeleton"});
    \textcolor{keywordflow}{return};
  \}

  \hyperlink{classSkeletonT}{Skeleton}* skeleton = \hyperlink{namespacePluginFunctions_a72e0406882d6f951e3ff8999d664f461}{PluginFunctions::skeleton}(skeletonObject);

  \textcolor{comment}{//setup the topology}
  \hyperlink{classJointT}{Skeleton::Joint}* currentParent = 0;
  \textcolor{keywordtype}{int} jointCount = 3;

  \textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} i=0; i < jointCount; i++)\{
    std::string     jointName = QString(\textcolor{stringliteral}{"Joint"} + QString::number(i)).toStdString();
    \hyperlink{classJointT}{Skeleton::Joint}* newJoint = \textcolor{keyword}{new} \hyperlink{classJointT}{Skeleton::Joint}(currentParent, jointName 
      );
    skeleton->\hyperlink{classSkeletonT_a1631f74df397f87ec44b5afa5a339bf4}{addJoint}(currentParent, newJoint);
    currentParent = newJoint;
  \}
  
  \textcolor{comment}{//set positions for the reference pose}
  \hyperlink{classPoseT}{Skeleton::Pose}* refPose = skeleton->\hyperlink{classSkeletonT_a089d5f7bae7aa66c5461d5e57a1f6358}{referencePose}();
  \textcolor{keywordtype}{double} xOffset = 0.0;
  
  \textcolor{keywordflow}{for} (\hyperlink{classSkeletonT_1_1Iterator}{Skeleton::Iterator} it = skeleton->\hyperlink{classSkeletonT_a0fe6ab4ddb20601bfba4d195e4e3c780}{begin}(); it != skeleton->
      \hyperlink{classSkeletonT_ad5e80649bdb640885fd1b905896d6fbb}{end}(); ++it)\{
    refPose->\hyperlink{classPoseT_a4ea35b6a61485ed152ba2f3e9ca010d3}{setGlobalTranslation}( (*it)->id(), \hyperlink{namespaceACG_ae4a56bb6b65d7f966934982a1e370213}{ACG::Vec3d}(xOffset, 0.0, 0.0)
       );
    xOffset += 1.0;
  \}
  
  \textcolor{comment}{//add an animation}
  \textcolor{keywordtype}{int} frameCount = 100;
  
  \hyperlink{classFrameAnimationT}{FrameAnimationT<ACG::Vec3d>}* animation = \textcolor{keyword}{new} 
      \hyperlink{classFrameAnimationT}{FrameAnimationT<ACG::Vec3d>}(skeleton, frameCount);
  \hyperlink{classAnimationHandle}{AnimationHandle} animHandle = skeleton->addAnimation(\textcolor{stringliteral}{"Rotation"}, animation);
  skeleton->animation(animHandle)->setFps(25);
  
  \textcolor{comment}{//set position in every pose/frame of the animation}
  \hyperlink{classJointT}{Skeleton::Joint}* middleJoint = skeleton->joint(1);
  \hyperlink{classACG_1_1GLMatrixT}{ACG::GLMatrixd} rotationMatrix;
  
  rotationMatrix.\hyperlink{classACG_1_1Matrix4x4T_a598f9a255f3aa4eab1f9e42f668cd375}{identity}();
  \textcolor{keywordtype}{double} maxAngle = 90.0;
  \hyperlink{classOpenMesh_1_1VectorT}{ACG::Vec3d} axis(0.0, 0.0, 1.0);

  \textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} i=0; i < frameCount; i++)\{
    animHandle.setFrame(i);

    \hyperlink{classPoseT}{Skeleton::Pose}* pose = skeleton->\hyperlink{classFrameAnimationT_ae981361c6d29c0e0b6d3e0f4877c9561}{pose}(animHandle);

    \textcolor{keywordflow}{for} (\hyperlink{classSkeletonT_1_1Iterator}{Skeleton::Iterator} it = skeleton->begin(); it != skeleton->end(); ++it)
      pose->\hyperlink{classPoseT_a4ea35b6a61485ed152ba2f3e9ca010d3}{setGlobalTranslation}( (*it)->id(), refPose->
      \hyperlink{classPoseT_ac6c29e6e544e09a06a3ff17554125fe8}{globalTranslation}( (*it)->id() ) );

    rotationMatrix.\hyperlink{classACG_1_1GLMatrixT_a00a5672ec60726a386be957ee9bd4312}{rotate}( maxAngle / frameCount, axis);
    pose->\hyperlink{classPoseT_abb3b80190a71cedef449b0e28669de32}{setGlobalMatrix}(     middleJoint->\hyperlink{classJointT_a3b474af6bb87baac7f6c920ab228e42f}{id}(), rotationMatrix, false );
    pose->\hyperlink{classPoseT_a4ea35b6a61485ed152ba2f3e9ca010d3}{setGlobalTranslation}(middleJoint->\hyperlink{classJointT_a3b474af6bb87baac7f6c920ab228e42f}{id}(), refPose->
      \hyperlink{classPoseT_ac6c29e6e544e09a06a3ff17554125fe8}{globalTranslation}( middleJoint->\hyperlink{classJointT_a3b474af6bb87baac7f6c920ab228e42f}{id}() ), \textcolor{keyword}{false} );
  \}

  \textcolor{comment}{//add a mesh}
  objectId = -1;
  emit addEmptyObject( \hyperlink{TriangleMesh_8hh_a899767380abdeb71a7d93f1764e4c746}{DATA\_TRIANGLE\_MESH}, objectId );

  \hyperlink{classTriMeshObject}{TriMeshObject}* meshObject;
  \textcolor{keywordflow}{if} ( !\hyperlink{namespacePluginFunctions_a457fae57adecd43d140a3328ee935df3}{PluginFunctions::getObject}(objectId,meshObject) ) \{
    emit log(\hyperlink{LoggingInterface_8hh_a595b2880f3ae74561ba390e3fd8c0e7ca39fe22d7b704805a8e30697a4a07d8fc}{LOGERR},\textcolor{stringliteral}{"Unable to create new Mesh"});
    \textcolor{keywordflow}{return};
  \}

  TriMesh* mesh = \hyperlink{namespacePluginFunctions_a4797322b8169e91fd69c194b927b8aa8}{PluginFunctions::triMesh}(meshObject);
  
  \textcolor{comment}{//add skin-weights property on the mesh}
  \hyperlink{structOpenMesh_1_1VPropHandleT}{OpenMesh::VPropHandleT< BaseSkin::SkinWeights >} 
      propWeights;
  mesh->add\_property(propWeights, SKIN\_WEIGHTS\_PROP);

  \textcolor{keywordtype}{int} steps = 50;

  \textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} i=0; i < jointCount; i++)
  \textcolor{keywordflow}{for} (\textcolor{keywordtype}{int} j=0; j < steps;      j++)\{
    \textcolor{keywordtype}{double} xPos = (j / double(steps-1));
    \hyperlink{classOpenMesh_1_1PolyMeshT_a0fc18e13d70825938274e3faf7b55e01}{TriMesh::VertexHandle} vh1 = mesh->add\_vertex( 
      \hyperlink{classOpenMesh_1_1VectorT}{ACG::Vec3d}(i + xPos,  0.1, 0.0) );
    \hyperlink{classOpenMesh_1_1PolyMeshT_a0fc18e13d70825938274e3faf7b55e01}{TriMesh::VertexHandle} vh2 = mesh->add\_vertex( 
      \hyperlink{classOpenMesh_1_1VectorT}{ACG::Vec3d}(i + xPos, -0.1, 0.0) );

    mesh->property(propWeights, vh1)[ i ] = 1.0 - xPos;
    mesh->property(propWeights, vh2)[ i ] = 1.0 - xPos;

    \textcolor{keywordflow}{if} ( i != 2 )\{
      mesh->property(propWeights, vh1)[ i+1 ] = xPos;
      mesh->property(propWeights, vh2)[ i+1 ] = xPos;
    \} \textcolor{keywordflow}{else}
      \textcolor{keywordflow}{break};
  \}


  RPC::callFunctionValue<bool, int, int>(\textcolor{stringliteral}{"skeletalanimation"}, \textcolor{stringliteral}{"attachSkin"}, skeletonObject->
      \hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}(), meshObject->\hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}());

  emit updatedObject(skeletonObject->\hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}(), \hyperlink{group__DefaultUpdateTypes_ga4ce39b8d60eb78ada5080d032c9463a8}{UPDATE\_ALL});
  emit updatedObject(meshObject->\hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}(), \hyperlink{group__DefaultUpdateTypes_ga4ce39b8d60eb78ada5080d032c9463a8}{UPDATE\_ALL});
  \hyperlink{namespacePluginFunctions_aa8a61acbaf42ab8649aec866b73e4c06}{PluginFunctions::setDrawMode}( 
      \hyperlink{namespaceACG_1_1SceneGraph_1_1DrawModes_a9c5f1ec0a64bebbfb0381f2a0edb34e1}{ACG::SceneGraph::DrawModes::POINTS} );
  \hyperlink{namespacePluginFunctions_afb6ba50cd13b03ae5c8ed921b82f9157}{PluginFunctions::viewAll}();
\}
\end{DoxyCode}
 \hypertarget{planeType}{}\section{Plane (D\+A\+T\+A\+\_\+\+P\+L\+A\+NE)}\label{planeType}
 \hypertarget{sphereType}{}\section{Sphere (D\+A\+T\+A\+\_\+\+S\+P\+H\+E\+RE)}\label{sphereType}
 \hypertarget{splatType}{}\section{Point Splats (D\+A\+T\+A\+\_\+\+S\+P\+L\+A\+T\+C\+L\+O\+UD)}\label{splatType}
 \hypertarget{BSplineCurveType}{}\section{B-\/\+Spline Curve (D\+A\+T\+A\+\_\+\+B\+S\+P\+L\+I\+N\+E\+\_\+\+C\+U\+R\+VE)}\label{BSplineCurveType}
 \hypertarget{BSplineSurfaceType}{}\section{B-\/\+Spline Surface (D\+A\+T\+A\+\_\+\+B\+S\+P\+L\+I\+N\+E\+\_\+\+S\+U\+R\+F\+A\+CE)}\label{BSplineSurfaceType}
 \hypertarget{polyLineType}{}\section{Plane (D\+A\+T\+A\+\_\+\+P\+O\+L\+Y\+\_\+\+L\+I\+NE)}\label{polyLineType}
\hypertarget{polyLineType_type_PolyLine_info}{}\subsection{Datatype Information}\label{polyLineType_type_PolyLine_info}
Open\+Flipper includes a datatype for representing polygonal Lines. This type can handle projection to meshes, smoothing and various other interactions. It is implemented in the \hyperlink{classACG_1_1PolyLineT}{A\+C\+G\+::\+Poly\+LineT} class. \hypertarget{coordsysType}{}\section{Coordinate System (D\+A\+T\+A\+\_\+\+C\+O\+O\+R\+D\+S\+YS)}\label{coordsysType}
 \hypertarget{CameraType}{}\section{Camera (D\+A\+T\+A\+\_\+\+C\+A\+M\+E\+RA)}\label{CameraType}
\hypertarget{CameraType_type_Camera_info}{}\subsection{Camera Datatype Information}\label{CameraType_type_Camera_info}
Open\+Flipper includes a data type \char`\"{}\+D\+A\+T\+A\+\_\+\+C\+A\+M\+E\+R\+A\char`\"{} for visualizing cameras. A camera consists of the modelview and the projection matrix. Additionally it requires the aspect ratio and the near/far plane distances.\hypertarget{CameraType_type_camera_usage}{}\subsection{Usage}\label{CameraType_type_camera_usage}
To use the data\+Type, create an empty object of type D\+A\+T\+A\+\_\+\+C\+A\+M\+E\+RA


\begin{DoxyCode}
\textcolor{comment}{// Variable which will store the id of the newly created object.}
 \textcolor{keywordtype}{int} newObjectId = -1;

 \textcolor{comment}{// Emit the signal, that we want to create a new object of the specified type DATA\_CAMERA}
 emit addEmptyObject(\hyperlink{Camera_8hh_a15afd8b87261940137dea45196d99e45}{DATA\_CAMERA}, newObjectId);

 \textcolor{comment}{// Get the newly created object}
 \hyperlink{classCameraObject}{CameraObject}* \textcolor{keywordtype}{object} = \hyperlink{namespacePluginFunctions_a457fae57adecd43d140a3328ee935df3}{PluginFunctions::getObject}(newObjectId);

 \textcolor{keywordflow}{if}(\textcolor{keywordtype}{object}) \{

     \textcolor{comment}{// Get the node}
     \hyperlink{classACG_1_1SceneGraph_1_1CameraNode}{CameraNode}* \hyperlink{namespacePluginFunctions_a8632b4ade240db78dcd8ebedcd30083a}{cameraNode} = \textcolor{keywordtype}{object}->cameraNode();

     \textcolor{comment}{// ...}
       
 \} \textcolor{keywordflow}{else} \{
   \textcolor{comment}{// Something went wrong when creating the object.}
   std::cerr << \textcolor{stringliteral}{"Unable to create object"} << std::endl;
 \}
\end{DoxyCode}


Now that you have the camera node, you have to set some variables.
\begin{DoxyItemize}
\item Set the Modelview Matrix\+: \hyperlink{classACG_1_1SceneGraph_1_1CameraNode_a987ec2ddebc86b75a046e27a1b0449f4}{Camera\+Node\+::set\+Model\+View()}
\item Set the projection Matrix\+: \hyperlink{classACG_1_1SceneGraph_1_1CameraNode_a2974574e426660a0ed5d6751d670f2d6}{Camera\+Node\+::set\+Projection()}
\item Set near and far plane\+: \hyperlink{classACG_1_1SceneGraph_1_1CameraNode_adb5a088f195e227d27b1dacf7630e47e}{Camera\+Node\+::set\+Far\+Plane()}, \hyperlink{classACG_1_1SceneGraph_1_1CameraNode_a99bdc83d6d663d14f3661f695e0383da}{Camera\+Node\+::set\+Near\+Plane()}
\item Aspect ration of the setup\+: Camera\+Node\+::set\+Aspect\+Ration()
\end{DoxyItemize}

This will setup all required parameters of your camera. Don\textquotesingle{}t forget to call 
\begin{DoxyCode}
emit updatedObject(\hyperlink{namespacePluginFunctions_ab06976558ac267e42c0f230be3d2b59b}{cameraObject}->\hyperlink{classBaseObject_afcca102b4a943f6c836bcd2f4ff9a334}{id}(),\hyperlink{group__DefaultUpdateTypes_ga4ce39b8d60eb78ada5080d032c9463a8}{UPDATE\_ALL});
\end{DoxyCode}
 to make your changes visible. \hypertarget{QtWidgetType}{}\section{Qt\+Widget (D\+A\+T\+A\+\_\+\+Q\+T\+\_\+\+W\+I\+D\+G\+ET)}\label{QtWidgetType}
This type allows rendering Q\+Widgets directly into the scene using the shader pipline renderer. At this time, only the left button and Mouse\+Moveevents are supported since the right click is reserved for context menus. An example\+: 
\begin{DoxyCode}
\textcolor{comment}{//create your own QWidget}
\textcolor{comment}{//you can also use slots/signal to connect e.g. clicked() signal from the QPushButton}
QWidget* emptyWidget = \textcolor{keyword}{new} QWidget();
QBoxLayout* layout = \textcolor{keyword}{new} QBoxLayout(QBoxLayout::LeftToRight);
emptyWidget->setLayout(layout);

\textcolor{comment}{//create a QtWidgetType}
\textcolor{keywordtype}{int} id;
addEmptyObject(\hyperlink{QtWidget_8hh_a5535ce05db1f32d58fa5270afb0ebdbc}{DATA\_QT\_WIDGET},\textcolor{keywordtype}{id});
\hyperlink{classQtWidgetObject}{QtWidgetObject}* qtObj;
\hyperlink{namespacePluginFunctions_a457fae57adecd43d140a3328ee935df3}{PluginFunctions::getObject}(\textcolor{keywordtype}{id},qtObj);

\textcolor{comment}{//assign the QWidget to the QtWidgetType and update it}
qtObj->setWidget(emptyWidget);
emit updatedObject(\textcolor{keywordtype}{id});
\end{DoxyCode}


It is also possible to create a Qt\+Widget\+Node and assign it manually to one of you object. Ensure to inform the node about Mouse Events, when using the plain node. One example method is to pass the event directly to the node. Another method is to traverse the whole scenegraph like this\+: 
\begin{DoxyCode}
\textcolor{keywordtype}{void} PluginName::slotMouseEvent(QMouseEvent* \_event)
\{
  \hyperlink{classACG_1_1SceneGraph_1_1MouseEventAction}{ACG::SceneGraph::MouseEventAction} action(\_event,
      \hyperlink{namespacePluginFunctions_a341db97dfd8cf625b4d914481028c25a}{PluginFunctions::viewerProperties}().glState());
  \hyperlink{namespacePluginFunctions_a95bf07301b5f4e367e9d6909acbaf7fd}{PluginFunctions::traverse}(action);
\}
\end{DoxyCode}
 \hypertarget{datatypes_adding_custom}{}\section{Adding custom datatypes}\label{datatypes_adding_custom}
\hypertarget{datatypes_adding_custom_adding_custom_datatypes_overview}{}\subsection{Overview}\label{datatypes_adding_custom_adding_custom_datatypes_overview}
Open\+Flipper data types consist of several components.


\begin{DoxyItemize}
\item The underlying data type (like \hyperlink{namespaceOpenMesh}{Open\+Mesh} or a class or simply an array of points)
\item The rendering node that is used to display the data
\item The Object class which manages your data and rendering inside Open\+Flipper
\end{DoxyItemize}

Furthermore some plugins need to be added\+:


\begin{DoxyItemize}
\item A Type plugin that registers your type inside Open\+Flipper and creates raw objects of your new type
\item Possible file plugins to read or write data to disk
\end{DoxyItemize}\hypertarget{datatypes_adding_custom_objectTypeFileStructure}{}\subsection{File structure inside the Object\+Types directory}\label{datatypes_adding_custom_objectTypeFileStructure}
For this documentation we take the Plane data type as an example.\hypertarget{datatypes_adding_custom_objectTypeDataStorage}{}\subsubsection{Data storage type}\label{datatypes_adding_custom_objectTypeDataStorage}
The underlying data type is a simple class representing a plane. It is defined in the files \char`\"{}\+Plane\+Type.(hh/cc)\char`\"{}. The type could also be defined in an extra lib outside of Open\+Flipper if it is more complex (e.\+g. \hyperlink{namespaceOpenMesh}{Open\+Mesh}, C\+G\+AL,...). But for smaller types they should be inside the Object\+Type directory.\hypertarget{datatypes_adding_custom_objectTypeRenderingNodes}{}\subsubsection{Rendering nodes}\label{datatypes_adding_custom_objectTypeRenderingNodes}
The second set of files is the rendering node. The node usually takes a reference to the data type and renders the data via Open\+GL. For the Point\+Node the implementation can be found in \char`\"{}\+Plane\+Node.(hh/cc)\char`\"{}.\hypertarget{datatypes_adding_custom_objectTypeBaseTypeFile}{}\subsubsection{Base type file}\label{datatypes_adding_custom_objectTypeBaseTypeFile}
The required types are than collected in one types file which is called \char`\"{}\+Plane\+Types.\+hh\char`\"{}. This file includes the nodes used for rendering and the underlying data type. Here you can add additional typedefs (e.\+g. if the original type would be called \char`\"{}plane\+Data\+Type\char`\"{} you can typedef it to a simple \char`\"{}plane\char`\"{}) to make the code more readable.


\begin{DoxyCode}
\textcolor{preprocessor}{#include <ObjectTypes/Plane/PlaneType.hh>}
\textcolor{preprocessor}{#include <ObjectTypes/Plane/PlaneNode.hh>}
\end{DoxyCode}
\hypertarget{datatypes_adding_custom_objectTypeObjectTypeFile}{}\subsubsection{Object Type}\label{datatypes_adding_custom_objectTypeObjectTypeFile}
After the rendering and storage are defined, the actual object has to be implemented. This is done in the files \char`\"{}\+Plane\+Object.(hh/cc)\char`\"{}. The Object\+Type has to be derived from \hyperlink{classBaseObjectData}{Base\+Object\+Data} (if it will be rendered) or if there are no rendering nodes for that type and it is simply a storage it is derived from \hyperlink{classBaseObject}{Base\+Object}. The Object\+Type creates an instances of the data (in this case the plane) and the required rendering nodes. Additionally it has a function to copy the object, and handles the picking translation.\hypertarget{datatypes_adding_custom_objectTypePluginFunctionsFile}{}\subsubsection{Plugin\+Functions File}\label{datatypes_adding_custom_objectTypePluginFunctionsFile}
The last block of files are \char`\"{}\+Plugin\+Functions.(hh/cc)\char`\"{}. In these files the plugin functions for your type are implemented. They typically contain dynamic casts from the \hyperlink{classBaseObject}{Base\+Object} Type to your type and node. They are used in the plugins to quickly convert between the management base class and the real data objects.\hypertarget{datatypes_adding_custom_objectTypeFinalIncludeFile}{}\subsubsection{Final Include File}\label{datatypes_adding_custom_objectTypeFinalIncludeFile}
Finally one include file has to be created that Defines the name that is used in Open\+Flipper\+: 
\begin{DoxyCode}
\textcolor{preprocessor}{#define DATA\_PLANE typeId("Plane")}
\end{DoxyCode}


and includes the pluginfunctions ,object and type header\+:


\begin{DoxyCode}
\textcolor{preprocessor}{#include <\hyperlink{PlaneObject_8hh}{ObjectTypes/Plane/PlaneObject.hh}>}

\textcolor{preprocessor}{#include <\hyperlink{PluginFunctionsPlane_8hh}{ObjectTypes/Plane/PluginFunctionsPlane.hh}>}

\textcolor{preprocessor}{#include <\hyperlink{PlaneTypes_8hh}{ObjectTypes/Plane/PlaneTypes.hh}>}
\end{DoxyCode}
\hypertarget{datatypes_adding_custom_objectTypeTypePlugin}{}\subsection{The Type plugin}\label{datatypes_adding_custom_objectTypeTypePlugin}
After fully defining the data type, we need to create a plugin that manages the new type inside Open\+Flipper. The Type\+Plugin implements the \hyperlink{classTypeInterface}{Type\+Interface} (\hyperlink{typeInterfacePage}{Type Interface} ). The plugin will register the type in the Open\+Flipper core. Additionally the plugin will be used to generate new objects of your type.\hypertarget{datatypes_adding_custom_objectTypeFilePlugin}{}\subsection{The File Plugins}\label{datatypes_adding_custom_objectTypeFilePlugin}
File plugins load data from a file into your object (or save from object to file). You can write your own custom file plugins. Please look at the \hyperlink{classFileInterface}{File\+Interface} for further details (\hyperlink{fileInterfacePage}{File Interface} ). 