aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.vimrc1
-rw-r--r--.vscode/extensions.json1
-rw-r--r--.vscode/settings.json3
-rw-r--r--contributing.md6
-rw-r--r--example.tex22
-rw-r--r--figs.drawio761
-rw-r--r--glossary.bib24
-rw-r--r--img/.gitignore2
-rw-r--r--img/DecoratorDesignPattern.pngbin0 -> 13528 bytes
-rw-r--r--img/ECSBlockDiagram.pngbin0 -> 64822 bytes
-rw-r--r--img/ECSComponentManager.pngbin0 -> 247012 bytes
-rw-r--r--img/ExtensionObjects.jpgbin0 -> 48639 bytes
-rw-r--r--img/decorator-design-pattern.puml62
-rw-r--r--img/example.puml6
-rw-r--r--img/theme.ipuml9
-rw-r--r--latexmkrc72
-rw-r--r--makefile16
-rw-r--r--meta.tex10
-rw-r--r--plan.tex261
-rw-r--r--projdoc.cls166
-rw-r--r--readme.md46
-rw-r--r--reqs.toml86
-rw-r--r--requirements.tex42
-rw-r--r--research.tex354
-rw-r--r--scripts/.gitignore1
-rwxr-xr-xscripts/reqs2tex.py173
-rw-r--r--scripts/tex.py81
-rwxr-xr-xscripts/time2tex.py (renamed from time2tex.py)148
-rw-r--r--sources.bib183
-rw-r--r--style.md61
-rw-r--r--time.txt108
-rw-r--r--timerep.tex1
33 files changed, 2416 insertions, 293 deletions
diff --git a/.gitignore b/.gitignore
index efae07a..74caed0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,8 +29,7 @@
# output files
*.pdf
-!img/*.pdf
-img/*.puml.pdf
# generated files
time.tex
+reqs.tex
diff --git a/.vimrc b/.vimrc
index 382d2a0..1994b78 100644
--- a/.vimrc
+++ b/.vimrc
@@ -4,7 +4,6 @@ call vimtex#syntax#core#new_arg('texVerbZoneInline', {
\ 'contains': '',
\ 'matcher': 'start="{" end="}"'
\})
-" and \begin{blockcode} ... \end{blockcode}
call vimtex#syntax#core#new_env({
\ 'name': 'blockcode',
\ 'region': 'texVerbZone',
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index e2e2139..1ce5b20 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,5 +1,6 @@
{
"recommendations": [
+ "James-Yu.latex-workshop",
"EditorConfig.EditorConfig"
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 25effcc..4a05df8 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,7 +1,4 @@
{
- "editor.wordWrap": "wordWrapColumn",
- "editor.wrappingIndent": "same",
- "editor.wordWrapColumn": 85,
"files.trimTrailingWhitespace": true,
"latex-workshop.latex.recipe.default": "latexmk",
"latex-workshop.latex.tools": [
diff --git a/contributing.md b/contributing.md
index c11c834..46cfeca 100644
--- a/contributing.md
+++ b/contributing.md
@@ -2,10 +2,6 @@ This document is an extension of the [crêpe engine contribution
guidelines][crepe-engine-contrib]. Rules in this document override those in the
other document.
-# Versioning
-
-- TODO: discuss w/ group
-
# Code style
- Indent using tabs
@@ -21,6 +17,8 @@ other document.
- Only environments indent the LaTeX source code
- Insert a non-breaking space (`~`) after (Latin) abbreviations such as "i.e."
or "e.g.". Never place a comma after either of these.
+- Multiple references (both `\cref` and `\autocite`) should be done in a single
+ command (i.e. `\cref{fig:a,fig:b}` and `\autocite{source1,source2}`)
# Banned practices
diff --git a/example.tex b/example.tex
index ce45f6f..9f36f59 100644
--- a/example.tex
+++ b/example.tex
@@ -1,7 +1,6 @@
\documentclass{projdoc}
% if the document compiles too slow (likely due to many/large images), try compiling
% with the [draft] option. this replaces all images with placeholders.
-\input{meta.tex}
\title{Example Document}
@@ -35,7 +34,7 @@ These don't show up in the table of contents by default
\Cref{fig:example-a} definitely shows something. Referencing multiple things at once
is neatly handled by cleveref:
-\cref{fig:example-a,fig:example-b,fig:example-c,tab:gate-xor}.
+\cref{fig:example-a,fig:example-b,fig:example-puml,tab:gate-xor}.
\begin{figure}
\centering
@@ -46,15 +45,17 @@ is neatly handled by cleveref:
\begin{figure}
\begin{subfigure}{0.45\textwidth}%
+ \centering
\fitimg{\includegraphics{example-image-b}}
\caption{Example image B}
\label{fig:example-b}
\end{subfigure}%
\hfill
\begin{subfigure}{0.45\textwidth}%
- \fitimg{\includegraphics{example-image-c}}
- \caption{Example image C}
- \label{fig:example-c}
+ \centering
+ \includepumldiag{img/example.puml}
+ \caption{Example PlantUML diagram}
+ \label{fig:example-puml}
\end{subfigure}%
\caption{Subfigures}
\end{figure}
@@ -153,17 +154,24 @@ Description:
\con{Bad thing 2}
\end{comparison}
-\subsection{Citations}
+\subsection{References}
+
+\subsubsection{Citations}
Citations are inserted using the \codeinline{\autocite} command \autocite{rfc:3339}.
The bibliography is automatically printed after \codeinline{\end{document}}.
-\subsection{Glossary}
+\subsubsection{Glossary}
Glossary entries can be inserted using the \codeinline{\gls} commands. Example:
``\Gls{sdl2} handles \glspl{hid} as well!''. In following occurrences of acronyms,
only their short form is printed: `\gls{sdl2}' and `\gls{hid}'. All of these link to
the glossary that is automatically printed after \codeinline{\end{document}}.
+\subsubsection{Requirements}
+
+Requirements are referenced like \codeinline{\label}s:
+e.g.~\cref{req:audio:handle,req:audio:async-api}.
+
\end{document}
diff --git a/figs.drawio b/figs.drawio
new file mode 100644
index 0000000..7c961d1
--- /dev/null
+++ b/figs.drawio
@@ -0,0 +1,761 @@
+<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.8 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.8" pages="2">
+ <diagram id="C5RBs43oDa-KdzZeNtuy" name="Main diagram">
+ <mxGraphModel dx="2577" dy="1035" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
+ <root>
+ <mxCell id="WIyWlLk6GJQsqaUBKTNV-0" />
+ <mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" />
+ <mxCell id="zkfFHV4jXpPFQw0GAbJ--6" value="GameObject" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="320" y="540" width="160" height="153" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="zkfFHV4jXpPFQw0GAbJ--7" value="+name" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="zkfFHV4jXpPFQw0GAbJ--8" value="+tag" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-1" value="+active" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="60" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-2" value="+layer" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="77" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="zkfFHV4jXpPFQw0GAbJ--9" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="94" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="zkfFHV4jXpPFQw0GAbJ--11" value="+AddComponent()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=12;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="102" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-3" value="+IsActiveInWorld()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=12;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="119" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-4" value="+IsActiveSelf()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;fontSize=12;movable=0;resizable=0;deletable=0;editable=0;locked=1;connectable=0;" parent="zkfFHV4jXpPFQw0GAbJ--6" vertex="1">
+ <mxGeometry y="136" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-9" value="Scene" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="40" y="590" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-82" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-9" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-14" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-9" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-81" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-9" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-28" value="" style="endArrow=open;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-9" target="zkfFHV4jXpPFQw0GAbJ--6" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="260" y="580" as="sourcePoint" />
+ <mxPoint x="290" y="590" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="320" y="625" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-39" value="+contents" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-28" vertex="1" connectable="0">
+ <mxGeometry x="-0.1405" y="-1" relative="1" as="geometry">
+ <mxPoint y="-17" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-40" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-28" vertex="1" connectable="0">
+ <mxGeometry x="-0.7119" y="-1" relative="1" as="geometry">
+ <mxPoint y="14" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-41" value="*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-28" vertex="1" connectable="0">
+ <mxGeometry x="0.6214" y="-1" relative="1" as="geometry">
+ <mxPoint x="3" y="14" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-34" value="Camera" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="40" y="760" width="160" height="102" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-78" value="+backgroundColor" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-34" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-77" value="+ascpectWidth" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-34" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-35" value="+ascpectHeight" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-34" vertex="1">
+ <mxGeometry y="60" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-36" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-34" vertex="1">
+ <mxGeometry y="77" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-37" value="-" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-34" vertex="1">
+ <mxGeometry y="85" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-46" value="" style="endArrow=open;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-34" target="PVU13nk45NJB4w4DQgDw-9" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="210" y="635" as="sourcePoint" />
+ <mxPoint x="140" y="660" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-47" value="+renderScene" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-46" vertex="1" connectable="0">
+ <mxGeometry x="-0.1405" y="-1" relative="1" as="geometry">
+ <mxPoint x="-41" y="-6" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-48" value="1..*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-46" vertex="1" connectable="0">
+ <mxGeometry x="-0.7119" y="-1" relative="1" as="geometry">
+ <mxPoint x="-21" y="4" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-49" value="1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-46" vertex="1" connectable="0">
+ <mxGeometry x="0.6214" y="-1" relative="1" as="geometry">
+ <mxPoint x="9" y="-9" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-50" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-34" target="zkfFHV4jXpPFQw0GAbJ--6" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="130" y="770" as="sourcePoint" />
+ <mxPoint x="290" y="670" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-54" value="UIObject" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="320" y="740" width="160" height="85" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-86" value="+width" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-54" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-55" value="+height" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-54" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-56" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-54" vertex="1">
+ <mxGeometry y="60" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-85" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-54" vertex="1">
+ <mxGeometry y="68" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-58" value="Button" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="230" y="880" width="160" height="85" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-87" value="+interactable&#xa;" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-58" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-59" value="+onClick" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-58" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-60" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-58" vertex="1">
+ <mxGeometry y="60" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-83" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-58" vertex="1">
+ <mxGeometry y="68" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-62" value="Text" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="414" y="880" width="160" height="136" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-93" value="+text" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-62" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-92" value="+font: String" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-62" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-91" value="+size: int" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-62" vertex="1">
+ <mxGeometry y="60" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-90" value="+allignment" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-62" vertex="1">
+ <mxGeometry y="77" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-89" value="+color" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-62" vertex="1">
+ <mxGeometry y="94" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-64" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-62" vertex="1">
+ <mxGeometry y="111" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-84" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-62" vertex="1">
+ <mxGeometry y="119" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-66" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-54" target="zkfFHV4jXpPFQw0GAbJ--6" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="210" y="770" as="sourcePoint" />
+ <mxPoint x="330" y="678" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-67" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-58" target="PVU13nk45NJB4w4DQgDw-54" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="195" y="780" as="sourcePoint" />
+ <mxPoint x="384" y="810" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-68" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-62" target="PVU13nk45NJB4w4DQgDw-54" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="205" y="790" as="sourcePoint" />
+ <mxPoint x="350" y="698" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-102" value="" style="endArrow=open;html=1;rounded=0;strokeColor=default;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=11;fontColor=default;labelBackgroundColor=default;resizable=1;endFill=0;endSize=8;" parent="WIyWlLk6GJQsqaUBKTNV-1" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="480" y="640" as="sourcePoint" />
+ <mxPoint x="480" y="680" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="520" y="640" />
+ <mxPoint x="520" y="680" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-103" value="+parent &amp;gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-102" vertex="1" connectable="0">
+ <mxGeometry x="-0.719" y="3" relative="1" as="geometry">
+ <mxPoint x="13" y="-4" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-104" value="*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-102" vertex="1" connectable="0">
+ <mxGeometry x="-0.0905" y="1" relative="1" as="geometry">
+ <mxPoint x="-31" y="-5" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-105" value="0..1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="PVU13nk45NJB4w4DQgDw-102" vertex="1" connectable="0">
+ <mxGeometry y="1" relative="1" as="geometry">
+ <mxPoint x="-21" y="30" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-106" value="Transform" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="560" y="565.5" width="160" height="102" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-111" value="+position" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-106" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-110" value="+rotation" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-106" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-107" value="+scale" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-106" vertex="1">
+ <mxGeometry y="60" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-108" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-106" vertex="1">
+ <mxGeometry y="77" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-109" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-106" vertex="1">
+ <mxGeometry y="85" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-112" value="" style="endArrow=none;html=1;rounded=0;" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-106" edge="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="510" y="610" as="sourcePoint" />
+ <mxPoint x="560" y="560" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-113" value="iMouseListener" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="640" y="880" width="160" height="119" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-114" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-113" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-115" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-113" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-116" value="+OnMouseMoved()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-113" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-121" value="+OnMouseClicked()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-113" vertex="1">
+ <mxGeometry y="68" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-122" value="+OnMousePressed()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-113" vertex="1">
+ <mxGeometry y="85" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-123" value="+OnMouseReleased()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-113" vertex="1">
+ <mxGeometry y="102" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-117" value="iKeyListener" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="840" y="880" width="160" height="85" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-118" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-117" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-119" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-117" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-120" value="+OnKeyPressed()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-117" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-124" value="+OnKeyReleased()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-117" vertex="1">
+ <mxGeometry y="68" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-125" value="Color" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="-200" y="760" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-126" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-125" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-127" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-125" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-128" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-125" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-129" value="Point" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="-200" y="650" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-130" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-129" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-131" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-129" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-132" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-129" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-133" value="Debug" style="shape=folder;fontStyle=1;spacingTop=10;tabWidth=40;tabHeight=14;tabPosition=left;html=1;whiteSpace=wrap;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="-200" y="560" width="70" height="40" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-135" value="Time" style="shape=folder;fontStyle=1;spacingTop=10;tabWidth=40;tabHeight=14;tabPosition=left;html=1;whiteSpace=wrap;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="-200" y="490" width="70" height="40" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-136" value="Input" style="shape=folder;fontStyle=1;spacingTop=10;tabWidth=40;tabHeight=14;tabPosition=left;html=1;whiteSpace=wrap;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="-200" y="420" width="70" height="40" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-138" value="AudioSource" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="30" y="212" width="160" height="136" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-142" value="+audioClip: Resource* (was String)" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;fontColor=#ff0000;" parent="PVU13nk45NJB4w4DQgDw-138" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-143" value="+playOnAwake: Boolean" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-138" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-144" value="+loop: Boolean" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-138" vertex="1">
+ <mxGeometry y="60" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-145" value="+volume" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-138" vertex="1">
+ <mxGeometry y="77" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-140" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-138" vertex="1">
+ <mxGeometry y="94" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-141" value="+Play(looping)" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-138" vertex="1">
+ <mxGeometry y="102" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-150" value="+Stop()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-138" vertex="1">
+ <mxGeometry y="119" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-152" value="Collider" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="310" y="212" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-153" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-152" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-154" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-152" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-155" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-152" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-156" value="CircleCollider" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="220" y="318" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-157" value="+radius" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-156" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-158" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-156" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-159" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-156" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-160" value="BoxCollider" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="414" y="316" width="160" height="85" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-164" value="+width" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-160" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-161" value="+height" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-160" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-162" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-160" vertex="1">
+ <mxGeometry y="60" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-163" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-160" vertex="1">
+ <mxGeometry y="68" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-165" value="Component" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="410" y="82" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-166" value="+active: Boolean" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-165" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-167" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-165" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-168" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-165" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-169" value="Rigidbody" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="550" y="195" width="160" height="102" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-174" value="+mass" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-169" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-173" value="+gravityScale" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-169" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-170" value="+bodyType" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-169" vertex="1">
+ <mxGeometry y="60" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-171" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-169" vertex="1">
+ <mxGeometry y="77" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-172" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-169" vertex="1">
+ <mxGeometry y="85" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-175" value="BehaviourScript" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="690" y="316" width="160" height="85" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-176" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-175" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-177" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-175" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-178" value="+OnStart()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-175" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-179" value="+OnUpdate()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-175" vertex="1">
+ <mxGeometry y="68" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-180" value="Sprite" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="880" y="165" width="160" height="153" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-199" value="+sprite:Resource* (WasString)" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;fontColor=#ff0000;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-198" value="+color" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="43" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-197" value="+flipX" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="60" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-196" value="+flipY" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="77" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-195" value="+sortingLayer" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="94" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-181" value="+orderInLayer" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="111" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-182" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="128" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-183" value="+Render()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-180" vertex="1">
+ <mxGeometry y="136" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-185" value="Animator" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
+ <mxGeometry x="1050" y="318" width="160" height="85" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-186" value="+fps" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-185" vertex="1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-187" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" parent="PVU13nk45NJB4w4DQgDw-185" vertex="1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-188" value="+Play(looping)" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-185" vertex="1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="PVU13nk45NJB4w4DQgDw-189" value="+Stop()" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="PVU13nk45NJB4w4DQgDw-185" vertex="1">
+ <mxGeometry y="68" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-4" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-138">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="320" y="510" as="sourcePoint" />
+ <mxPoint x="160" y="400" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="320" y="520" />
+ <mxPoint x="110" y="520" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-9" value="*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-4">
+ <mxGeometry x="0.8037" y="-2" relative="1" as="geometry">
+ <mxPoint x="-16" y="-4" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-10" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-156">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="344" y="550" as="sourcePoint" />
+ <mxPoint x="179" y="358" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="330" y="490" />
+ <mxPoint x="300" y="490" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-11" value="*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-10">
+ <mxGeometry x="0.8037" y="-2" relative="1" as="geometry">
+ <mxPoint x="-16" y="-4" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-12" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-160">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="354" y="560" as="sourcePoint" />
+ <mxPoint x="189" y="368" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="470" y="440" />
+ <mxPoint x="494" y="440" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-13" value="*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-12">
+ <mxGeometry x="0.8037" y="-2" relative="1" as="geometry">
+ <mxPoint x="-16" y="-4" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-14" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-169">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="364" y="570" as="sourcePoint" />
+ <mxPoint x="199" y="378" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="500" y="460" />
+ <mxPoint x="630" y="460" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-15" value="*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-14">
+ <mxGeometry x="0.8037" y="-2" relative="1" as="geometry">
+ <mxPoint x="-16" y="-26" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-16" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-175">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="374" y="580" as="sourcePoint" />
+ <mxPoint x="209" y="388" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="520" y="480" />
+ <mxPoint x="770" y="480" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-17" value="*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-16">
+ <mxGeometry x="0.8037" y="-2" relative="1" as="geometry">
+ <mxPoint x="-12" y="-21" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-18" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-180">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="384" y="590" as="sourcePoint" />
+ <mxPoint x="219" y="398" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="540" y="500" />
+ <mxPoint x="960" y="500" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-19" value="0..1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-18">
+ <mxGeometry x="0.8037" y="-2" relative="1" as="geometry">
+ <mxPoint x="-16" y="-45" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-20" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="zkfFHV4jXpPFQw0GAbJ--6" target="PVU13nk45NJB4w4DQgDw-185">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="394" y="600" as="sourcePoint" />
+ <mxPoint x="229" y="408" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="560" y="520" />
+ <mxPoint x="1130" y="520" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-21" value="0..*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-20">
+ <mxGeometry x="0.8037" y="-2" relative="1" as="geometry">
+ <mxPoint x="-16" y="-50" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-24" value="" style="endArrow=open;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-185" target="PVU13nk45NJB4w4DQgDw-180">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="960" y="439.38" as="sourcePoint" />
+ <mxPoint x="1220" y="440" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="1130" y="240" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-26" value="0..1" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-24">
+ <mxGeometry x="-0.7119" y="-1" relative="1" as="geometry">
+ <mxPoint x="-21" y="14" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-27" value="1..*" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GgpaCZaR6PRI7i0rwrCe-24">
+ <mxGeometry x="0.6214" y="-1" relative="1" as="geometry">
+ <mxPoint x="3" y="14" as="offset" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-28" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-138" target="PVU13nk45NJB4w4DQgDw-165">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="203" y="770" as="sourcePoint" />
+ <mxPoint x="330" y="682" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="110" y="160" />
+ <mxPoint x="380" y="160" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-29" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-152" target="PVU13nk45NJB4w4DQgDw-165">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="380" y="358" as="sourcePoint" />
+ <mxPoint x="507" y="270" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-31" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-156" target="PVU13nk45NJB4w4DQgDw-152">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="250" y="358" as="sourcePoint" />
+ <mxPoint x="377" y="270" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-32" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-160" target="PVU13nk45NJB4w4DQgDw-152">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="320" y="460" as="sourcePoint" />
+ <mxPoint x="447" y="372" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-33" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-169" target="PVU13nk45NJB4w4DQgDw-165">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="510" y="348" as="sourcePoint" />
+ <mxPoint x="637" y="260" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-34" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-175" target="PVU13nk45NJB4w4DQgDw-165">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="600" y="436" as="sourcePoint" />
+ <mxPoint x="727" y="348" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="770" y="160" />
+ <mxPoint x="590" y="160" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-36" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="PVU13nk45NJB4w4DQgDw-180" target="PVU13nk45NJB4w4DQgDw-165">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="920" y="140" as="sourcePoint" />
+ <mxPoint x="570" y="124" as="targetPoint" />
+ <Array as="points">
+ <mxPoint x="960" y="116" />
+ </Array>
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-37" value="ParticelSystem" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
+ <mxGeometry x="950" y="620" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-38" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" vertex="1" parent="GgpaCZaR6PRI7i0rwrCe-37">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-39" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" vertex="1" parent="GgpaCZaR6PRI7i0rwrCe-37">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-40" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" vertex="1" parent="GgpaCZaR6PRI7i0rwrCe-37">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-45" value="PolygonCollider" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
+ <mxGeometry x="950" y="718" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-46" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" vertex="1" parent="GgpaCZaR6PRI7i0rwrCe-45">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-47" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" vertex="1" parent="GgpaCZaR6PRI7i0rwrCe-45">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="GgpaCZaR6PRI7i0rwrCe-48" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" vertex="1" parent="GgpaCZaR6PRI7i0rwrCe-45">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ </root>
+ </mxGraphModel>
+ </diagram>
+ <diagram id="YIiIl2IRF6RgPQzV_9jG" name="Example">
+ <mxGraphModel dx="1050" dy="621" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
+ <root>
+ <mxCell id="0" />
+ <mxCell id="1" parent="0" />
+ <mxCell id="rDWCdEblCpn9XmIhacVI-1" value="example&#xa;" style="swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;rounded=0;shadow=0;strokeWidth=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;direction=east;" vertex="1" parent="1">
+ <mxGeometry x="160" y="70" width="160" height="68" as="geometry">
+ <mxRectangle x="330" y="540" width="160" height="26" as="alternateBounds" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="rDWCdEblCpn9XmIhacVI-2" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" vertex="1" parent="rDWCdEblCpn9XmIhacVI-1">
+ <mxGeometry y="26" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="rDWCdEblCpn9XmIhacVI-3" value="" style="line;html=1;strokeWidth=1;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=1;labelPosition=right;points=[];portConstraint=eastwest;fontSize=12;perimeterSpacing=0;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;verticalLabelPosition=middle;" vertex="1" parent="rDWCdEblCpn9XmIhacVI-1">
+ <mxGeometry y="43" width="160" height="8" as="geometry" />
+ </mxCell>
+ <mxCell id="rDWCdEblCpn9XmIhacVI-4" style="text;align=left;verticalAlign=bottom;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=1;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rounded=0;shadow=0;html=0;strokeWidth=1;horizontal=1;movable=1;resizable=1;deletable=1;editable=1;locked=0;connectable=1;" vertex="1" parent="rDWCdEblCpn9XmIhacVI-1">
+ <mxGeometry y="51" width="160" height="17" as="geometry" />
+ </mxCell>
+ <mxCell id="INcigVm9b0TAH9v99pnO-1" value="" style="endArrow=block;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;strokeWidth=1;endSize=14;" edge="1" parent="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="200" y="200" as="sourcePoint" />
+ <mxPoint x="160" y="160" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="BdnN9X1UdPwwrvRyySie-1" value="" style="endArrow=none;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;startArrow=diamondThin;startFill=1;" edge="1" parent="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="280" y="200" as="sourcePoint" />
+ <mxPoint x="240" y="160" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="wr2JkJuTEkJ5C-UpQk8J-1" value="" style="endArrow=open;html=1;rounded=0;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;endFill=0;endSize=8;" edge="1" parent="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="360" y="200" as="sourcePoint" />
+ <mxPoint x="320" y="160" as="targetPoint" />
+ <Array as="points" />
+ </mxGeometry>
+ </mxCell>
+ <mxCell id="oRUFz-RLu-avQMRJHf4n-1" value="" style="endArrow=none;html=1;rounded=0;" edge="1" parent="1">
+ <mxGeometry width="50" height="50" relative="1" as="geometry">
+ <mxPoint x="440" y="200" as="sourcePoint" />
+ <mxPoint x="400" y="160" as="targetPoint" />
+ </mxGeometry>
+ </mxCell>
+ </root>
+ </mxGraphModel>
+ </diagram>
+</mxfile>
diff --git a/glossary.bib b/glossary.bib
index 4d02e4a..fda634f 100644
--- a/glossary.bib
+++ b/glossary.bib
@@ -28,3 +28,27 @@
description = {Graphics library developed by \hbox{Microsoft}},
}
+@acronym{api,
+ short = {API},
+ long = {Application Programming Interface},
+}
+
+@acronym{reqlabel-priority,
+ short = {pri},
+ long = {priority},
+}
+@acronym{reqlabel-description,
+ short = {req},
+ long = {requirement},
+}
+@acronym{reqlabel-done,
+ short = {DoD},
+ long = {definition of done},
+}
+
+@abbreviation{poc,
+ short = {POC},
+ long = {proof-of-concept},
+}
+
+
diff --git a/img/.gitignore b/img/.gitignore
new file mode 100644
index 0000000..60a51f5
--- /dev/null
+++ b/img/.gitignore
@@ -0,0 +1,2 @@
+!*.pdf
+*.eps
diff --git a/img/DecoratorDesignPattern.png b/img/DecoratorDesignPattern.png
new file mode 100644
index 0000000..8830a3d
--- /dev/null
+++ b/img/DecoratorDesignPattern.png
Binary files differ
diff --git a/img/ECSBlockDiagram.png b/img/ECSBlockDiagram.png
new file mode 100644
index 0000000..4d36afa
--- /dev/null
+++ b/img/ECSBlockDiagram.png
Binary files differ
diff --git a/img/ECSComponentManager.png b/img/ECSComponentManager.png
new file mode 100644
index 0000000..6602cd6
--- /dev/null
+++ b/img/ECSComponentManager.png
Binary files differ
diff --git a/img/ExtensionObjects.jpg b/img/ExtensionObjects.jpg
new file mode 100644
index 0000000..4807ff7
--- /dev/null
+++ b/img/ExtensionObjects.jpg
Binary files differ
diff --git a/img/decorator-design-pattern.puml b/img/decorator-design-pattern.puml
new file mode 100644
index 0000000..2bc406b
--- /dev/null
+++ b/img/decorator-design-pattern.puml
@@ -0,0 +1,62 @@
+@startuml
+!include theme.ipuml
+skinparam style strictuml
+skinparam Linetype ortho
+
+class Client
+class Component <<interface>> {
+ + execute()
+ --
+}
+class ConcComponent as "Concrete\nComponent" {
+ ...
+ --
+ + execute()
+}
+class BaseDecorator as "Base Decorator" {
+ - wrappee: Component
+ + BaseDecorator(c: Component)
+ + execute()
+}
+class ConcDecorator as "Concrete\nDecorators" {
+ ...
+ --
+ + execute()
+ + extra()
+}
+
+hide Client members
+hide circle
+
+Client --> Component
+Component <|.. ConcComponent
+Component <|.. BaseDecorator
+Component <--o BaseDecorator
+BaseDecorator <|-- ConcDecorator
+
+ConcComponent -right[hidden] BaseDecorator
+
+note right of Client
+ a = <b>new</b> ConcComponent()
+ b = <b>new</b> ConcDecorator1(a)
+ c = <b>new</b> ConcDecorator1(b)
+ c.execute()
+ // Decorator -> Decorator -> Component
+end note
+
+note right of BaseDecorator::BaseDecorator
+ wrappee = c
+end note
+
+note right of BaseDecorator::execute
+ wrappee.execute()
+end note
+
+note right of ConcDecorator::execute
+ super::execute()
+ extra()
+end note
+
+@enduml
+
+" referenced from <https://github.com/algamza/algamza.github.io>
diff --git a/img/example.puml b/img/example.puml
new file mode 100644
index 0000000..942dce2
--- /dev/null
+++ b/img/example.puml
@@ -0,0 +1,6 @@
+@startuml
+!include theme.ipuml
+
+Bob -> Alice : hello
+
+@enduml
diff --git a/img/theme.ipuml b/img/theme.ipuml
index 88d183a..4e3613e 100644
--- a/img/theme.ipuml
+++ b/img/theme.ipuml
@@ -1,5 +1,10 @@
!theme plain
-skinparam DefaultFontSize 14
+skinparam ClassAttributeIconSize 0
+skinparam ClassFontStyle bold
skinparam DefaultFontName Inter
+skinparam DefaultFontSize 14
+skinparam MaxMessageSize 200
+skinparam Nodesep 25
+skinparam Padding 2
+skinparam Ranksep 50
skinparam RoundCorner 0
-skinparam maxMessageSize 200
diff --git a/latexmkrc b/latexmkrc
index 66ed0d1..d2c3cdc 100644
--- a/latexmkrc
+++ b/latexmkrc
@@ -1,49 +1,41 @@
-$pdflatex = "xelatex %O %S";
+# https://nl.mirrors.cicku.me/ctan/support/latexmk/latexmk.pdf
+
+use File::Spec::Functions;
+
+$pdflatex = "xelatex --interaction=nonstopmode --shell-escape %O %S";
$pdf_mode = 1;
$dvi_mode = 0;
$postscript_mode = 0;
+$clean_ext .= ' %R.ist %R.xdy bbl run.xml';
+@default_files = (
+ 'example',
+ 'plan',
+ 'research',
+ 'timerep',
+);
-# https://tex.stackexchange.com/questions/400325/latexmkrc-for-bib2gls
-add_cus_dep('glo', 'gls', 0, 'run_makeglossaries');
-add_cus_dep('acn', 'acr', 0, 'run_makeglossaries');
-add_cus_dep('aux', 'glstex', 0, 'run_bib2gls');
-
-sub run_makeglossaries {
- if ( $silent ) {
- system "makeglossaries -q '$_[0]'";
- } else {
- system "makeglossaries '$_[0]'";
- };
+push @file_not_found, '^Package .* No file `([^\\\']*)\\\'';
+push @generated_exts, 'glo', 'gls', 'glg';
+add_cus_dep('aux', 'glstex', 0, 'bib2gls');
+sub bib2gls {
+ return Run_msg("bib2gls $_[0]");
}
-sub run_bib2gls {
- if ( $silent ) {
- my $ret = system "bib2gls --silent --group '$_[0]'";
- } else {
- my $ret = system "bib2gls --group '$_[0]'";
- };
- my ($base, $path) = fileparse( $_[0] );
- if ($path && -e "$base.glstex") {
- rename "$base.glstex", "$path$base.glstex";
- }
- # Analyze log file.
- local *LOG;
- $LOG = "$_[0].glg";
- if (!$ret && -e $LOG) {
- open LOG, "<$LOG";
- while (<LOG>) {
- if (/^Reading (.*\.bib)\s$/) {
- rdb_ensure_file( $rule, $1 );
- }
- }
- close LOG;
- }
- return $ret;
+add_cus_dep('puml', 'eps', 0, 'plantuml');
+sub plantuml {
+ return Run_msg("plantuml -teps $_[0].puml");
}
-push @file_not_found, '^Package .* No file `([^\\\']*)\\\'';
-push @generated_exts, 'glo', 'gls', 'glg';
-push @generated_exts, 'acn', 'acr', 'alg';
-$clean_ext .= ' %R.ist %R.xdy';
-$clean_ext .= ' bbl run.xml';
+add_cus_dep('txt', 'tex', 0, 'time2tex');
+sub time2tex {
+ return Run_msg("python3 @{[catfile('scripts', 'time2tex.py')]} $_[0].txt");
+}
+
+add_cus_dep('toml', 'tex', 0, 'reqs2tex');
+add_cus_dep('toml', 'aux', 0, 'reqs2tex');
+sub reqs2tex {
+ return Run_msg("python3 @{[catfile('scripts', 'reqs2tex.py')]} $_[0].toml");
+}
+
+# vim:ft=perl
diff --git a/makefile b/makefile
deleted file mode 100644
index 02c583e..0000000
--- a/makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-all: plan.pdf
-
-LATEXMKFLAGS += -cd
-LATEXMKFLAGS += -interaction=nonstopmode
-%.pdf: %.tex
- -latexmk $(LATEXMKFLAGS) $<
-
-%.puml.pdf: %.puml
- plantuml -tpdf $<
- mv $*.pdf $@
-
-%.tex: %.txt
- ./time2tex.py $< > $@
-
-timerep.pdf: time.tex
-
diff --git a/meta.tex b/meta.tex
deleted file mode 100644
index cad4b81..0000000
--- a/meta.tex
+++ /dev/null
@@ -1,10 +0,0 @@
-\organization{Avans University of Applied Sciences}
-\project{Project cr\^epe}
-\version{0.0}
-\author{%
- Loek Le Blansch\and%
- Wouter Boerenkamps\and%
- Jaro Rutjes\and%
- Max Smits\and%
- Niels Stunnebrink%
-}
diff --git a/plan.tex b/plan.tex
index 4ad9bad..a67598e 100644
--- a/plan.tex
+++ b/plan.tex
@@ -1,9 +1,264 @@
\documentclass{projdoc}
-\input{meta.tex}
\title{Project Plan}
\begin{document}
-hoi
-\end{document}
+\tablestables
+\newpage
+
+\section{Background}
+
+This project is part of the fourth-year minor `Systems Programming in C++'. The minor
+consists of several courses throughout 20 weeks, which create the basis for this
+project. The project focus is on building a game engine using the programming
+language C++. This document describes the plan of attack for the project.
+
+\section{Problem Definition}
+
+\subsection{Problem Analysis}
+
+CodedFun Games is a small, single-person game company looking to scale up. The owner,
+who is a game programmer, and graphical artist, has received government funding,
+which he wants to invest in a custom-built game engine. The owner has no interest in
+developing or maintaining a game engine himself, so he has hired a part-time engine
+programmer. This programmer does not have time to create an entire engine but is
+willing to maintain or expand an existing engine one day per week.
+
+The client seeks a custom game engine that is easy to maintain, easy to extend, and
+user-friendly. Additionally, the engine should be well-documented, which is
+considered an essential aspect of being user-friendly.
+
+So far, the client has made all his games in Unity and is very fond of the structure.
+Therefore, the client wants the new engine to adhere to a similar structure. A simple
+requirements document is defined to specify how strictly this structure should be
+followed.
+
+Finally, because the client does not want to dive deeply into the engine himself, he wants a secondary application (preferably a game) that can be used to test the engine's features. This is referred to as the \emph{validation application}.
+
+\subsection{Goal}
+
+The goal is to develop a custom game engine that meets the client's requirements for maintainability, extensibility, user-friendliness, and adherence to a Unity-like structure. The engine may integrate third-party software (as agreed with the client) to support specific features, such as audio, physics, and rendering. In addition, a \emph{validation application} is created to show and test the engine's features.
+
+\subsection{Scope}
+The requirements document \autocite{crepe:requirements} has several requirements with a MoSCoW `must', `should', `could' or `won't' priority to indicate the project's scope.
+
+\subsection{Result}
+
+The expected result is a well-documented, custom game engine that follows a structure similar to Unity. Additionally, a \emph{validation application} should be provided to test and showcase the engine's capabilities.
+
+\subsection{Validation Application}
+
+The \emph{validation application} \autocite{crepe:validation-application} is explained in a document where the features of the \emph{validation application} are linked to the user stories.
+
+\section{Planning}
+
+The customer specified multiple deliverables throughout the 20 weeks of this project. Despite the fact that 20 weeks have been reserved for this project, the game will be delivered in week 17. Any delay/resit will take place between weeks 17 and 20. A rough planning can be found in \cref{tab:planning}.
+
+\begin{table}
+ \begin{tabularx}{\linewidth}{lX}
+ \toprule
+ \textbf{Week\#} & \textbf{Deliverable}\\
+ \midrule
+ 4 & Project Plan\\
+ 7 & Some POCs\\
+ 10 & POCs and Design document\\
+ 17 & Game engine, \emph{validation application}\\
+ \bottomrule
+ \end{tabularx}
+ \caption{Planning}
+ \label{tab:planning}
+\end{table}
+
+\section{Risks}
+
+\subsection{Technical Risks}
+
+\begin{description}
+ \item[Multiplatform] The team works in both Linux and windows, which poses a risk
+ for the development if there is a platform dependency.
+ \item[Integration] Users can make a wrong integration causing for delay or risk of
+ losing code.
+\end{description}
+
+\subsection{Project Management Risks}
+
+\begin{description}
+ \item[Scope Expansion] There is a risk of creating a scope that is bigger than the
+ requirements. Lack of Team Collaboration: Insufficient collaboration among team
+ members may hinder progress.
+ \item[Lack of Team Collaboration] Within the team a lack of collaboration can result in miscommunication or delay in work.
+ \item[Falling out of specific team member] Within the team the scrum master and integrator have additional roles. If one or both members can not continue it can hinder progress of the project.
+\end{description}
+
+\subsection{Measures}
+
+\begin{description}
+ \item[Multiplatform] The team can switch any time to a single platform, so this
+ risk is mitigated.
+ \item[Integration] By following standards and having an integrator, which checks
+ every pull request, this risk is minimized.
+ \item[Scope Expansion] By writing detailed requirements and having weekly team
+ meetings, to check if the progress is within the scope, should be sufficient to
+ decrease the risk.
+ \item[Lack of Team Collaboration] Weekly team meetings will result in collaboration among team members and discussing what each other tasks is, will decease this risk.
+ \item[Falling out of specific team member] The scrum master can be taken over by any other team member. All tools (e.g. scrum board) are open to all members. The tasks of the integrator can be taken over by the team. Within GitHub the team as a whole has the same rights as the integrator.
+\end{description}
+
+\section{Documentation}
+
+This section describes the required documentation for the project, including the
+types of documents to be created and the standards they must adhere to.
+
+\subsection{Documents}
+
+This project consists of seven main documents:\noparbreak
+\begin{description}
+ \item[Project Plan] Contains all elements related to the organization of the
+ project, including timelines, milestones, roles, and responsibilities.
+ \item[Requirements] Details the requirements and user stories, including both
+ functional and non-functional requirements.
+ \item[Design] Describes the design choices, including architecture, user interface,
+ and system components.
+ \item[Working hours] A table which includes all working hours of each team member.
+ \item[API Reference] Details the available endpoints, request and response formats,
+ authentication methods, error codes, and examples for interacting with the
+ project's API.
+\end{description}
+
+\subsection{Documentation Standard}
+
+The documentation standard can be found in the contributing.md
+\autocite{crepe:docs-standard}.
+
+\section{Work Agreements}
+Work agreements are the expectations and commitments made by the team members. This
+section includes details on roles and responsibilities, documentation of work hours,
+protocols for handling absences or delays, guidelines for addressing inconsistent
+participation, and procedures for weekly updates and meetings. All team members
+reviewed and agreed to these terms.
+
+\subsection{Project Roles}
+
+\begin{description}
+ \item[Loek Le Blansch] Integrator
+ \item[Wouter Boerenkamps] Project Member
+ \item[Jaro Rutjes] Team Leader / Scrum Master
+ \item[Max Smits] Project Member / Product Owner
+ \item[Niels Stunnebrink] Project Member
+\end{description}
+
+\subsection{Work Hours}
+
+Each project member will keep track of their own working hours and add them to the
+`file'.
+
+\subsection{Absence or Delay}
+
+If a project member is going to be absent or delayed, they are required to
+notify the team through either WhatsApp or Outlook. Additionally, the teacher
+should be informed of the absence as well.
+
+\subsection{Inconsistent Participation}
+
+Inconsistent participation will be addressed in a structured manner:
+
+\begin{description}
+ \item[Initial Discussion] The team leader will first discuss the issue of
+ inconsistent participation with the individual team member.
+ \item [Team Discussion] If no improvement is observed, the issue will be brought up
+ with the entire team to seek a collective solution.
+ \item [Project Supervisor Involvement] Should the problem persist, despite these
+ efforts, it will be escalated to the project supervisor (Bob van der Putten) for
+ further action.
+\end{description}
+
+Valid reasons for absence or inconsistency will be considered, and no repercussions
+will be necessary in such cases. However, if the inconsistency is due to other
+factors, potential repercussions may include additional assignments or actions as
+determined by the project supervisor.
+
+A team member is considered to have inconsistent participation if their hours
+are significantly behind the team’s average or if tasks are not completed
+without valid reasons. It is essential that any concerns regarding a team
+member's performance, should be resolved through unanimous agreement within the team.
+
+\subsection{Weekly Update}
+
+Each team member is required to send their technical weekly update to Jaro Rutjes
+before 12:00 on Friday. Personal updates may also be included and will be
+confidential between the team member, the Team Leader, and/or the teacher, if
+requested.
+
+Jaro Rutjes will compile and send a team update to the project supervisor, Bob
+van der Putten, also by Friday. This update will include technical information
+on what has been accomplished, plans for upcoming work, and an overview of the
+team's overall progress.
+
+\subsection{Weekly Meetings}
+
+The project team will hold at least two meetings each week, with each meeting lasting
+a maximum of 30 minutes. Following these meetings, an additional one hour will be
+scheduled for discussions on the topics covered.
+
+Meetings will be planned and discussed one week in advance, with invitations sent via
+Outlook. Additional meetings may be scheduled if necessary to address issues or
+project needs.
+
+% Information about how and when Scrum will be used in this project (using Miro).
+\section{Scrum (Miro)}
+
+The team starts using scrum after the initial phase, of structuring the project, is finished. This phase is finished after a initial design of the product is made.
+
+\subsection{Scrum Board}
+
+The Scrum board \autocite{miro:scrum-board} will consist of the following tabs:
+
+\begin{description}
+ \item[Backlog] This tab contains a list of all tasks and user stories that are
+ planned for future sprints.
+ \item[Next Sprint] This tab includes tasks and user stories that have been selected
+ for the upcoming sprint.
+ \item[Current Sprint] This tab displays the tasks and user stories that are
+ actively being worked on in the current sprint.
+ \item[In Progress] Tasks that are actively being worked on are moved to this tab.
+ \item[Review] Completed tasks that are awaiting review or testing will be placed in
+ this tab.
+ \item[Done] Once tasks have been reviewed and are considered complete, they are
+ moved to the Done tab.
+ \item [Blocked] This tab is used for tasks that cannot proceed due to obstacles or
+ dependencies.
+\end{description}
+
+To manage tasks effectively:
+
+\begin{itemize}
+ \item A task from the \emph{Current Sprint} tab should be selected and moved to the
+ \emph{In Progress} tab when work begins.
+ \item The status of the task should be updated to \emph{In Progress} as soon as
+ work starts.
+ \item Once the task is completed and reviewed, it should be moved to the
+ \emph{Done} tab, and its status should be updated to \emph{Done}.
+\end{itemize}
+
+Each task or user story will be assigned user points, which indicate the relative size or complexity of the task. Examples of certain tasks will be available in the scrumboard.
+
+\subsection{Burn Down Chart}
+
+The Burn Down Chart will be generated using Excel from the Scrum board data every
+week. Each user story or task marked as done, will burn the chart downwards. This
+Burn Down Chart is shared in the weekly updates with the team.
+
+% Information regarding the git workflow of this project.
+\section{Git Workflow}
+
+GitHub is used for version management of both code \autocite{crepe:code-repo} and
+documentation \autocite{crepe:docs-repo}, each in its own respective repository. This
+keeps the documentation and code separate, resulting in ordered and manageable
+repositories.
+
+\subsection{Code Standard and Git Workflow}
+
+The code standard and the git workflow can be found in the contributing.md \autocite{crepe:code-standard}.
+
+\end{document}
diff --git a/projdoc.cls b/projdoc.cls
index 388f901..8a2c05d 100644
--- a/projdoc.cls
+++ b/projdoc.cls
@@ -1,6 +1,19 @@
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{projdoc}[2024-09-03 class projdoc]
+% project defaults
+\makeatletter
+\def\@project{Project cr\^epe}
+\def\@organization{Avans University of Applied Sciences}
+\def\@author{%
+ Loek Le Blansch\and%
+ Wouter Boerenkamps\and%
+ Jaro Rutjes\and%
+ Max Smits\and%
+ Niels Stunnebrink%
+}
+\makeatother
+
% based on article
\LoadClass{article}
@@ -40,6 +53,7 @@
\RequirePackage{tabularx}
\RequirePackage{booktabs}
\RequirePackage{needspace}
+\RequirePackage{xr-hyper}
\RequirePackage{hyperref}
\RequirePackage{microtype}
\RequirePackage{xcolor}
@@ -58,6 +72,7 @@
\RequirePackage{subcaption}
\RequirePackage{multicol}
\RequirePackage{comparison} % ./comparison.sty
+\RequirePackage{xstring}
% font style
\setmainfont{TeX Gyre Schola}
@@ -73,6 +88,9 @@
\bigskipamount=7mm
\medskipamount=4mm
+% number paragraphs by default
+\setcounter{secnumdepth}{4}
+
% section placement / appearance
\newlength{\sectionpenalty}
\newlength{\subsectionpenalty}
@@ -119,6 +137,23 @@
itemsep=\dimexpr\style@itemsep-\style@parsep\relax,
parsep=\style@parsep,
}
+\def\projdoc@description@before{%
+ \renewcommand\makelabel[1]{%
+ {\bfseries ##1}:%
+ }%
+}
+\newlength\projdoc@description@leftmargin%
+\projdoc@description@leftmargin=3em%
+\newlength\projdoc@description@labelindent%
+\projdoc@description@labelindent=3ex%
+\def\projdoc@setdescriptionstyle{%
+ \setdescription{
+ before={\projdoc@description@before},
+ leftmargin=\projdoc@description@leftmargin,
+ labelindent=\projdoc@description@labelindent,
+ }%
+}
+\projdoc@setdescriptionstyle%
\makeatother
% create a label using \customlabel[<creftype>]{<refname>}{<reftext>} that displays
@@ -126,24 +161,20 @@
% \cref{<refname>} is used
\makeatletter
\NewDocumentCommand{\customlabel}{omm}{%
- \begingroup
- \cref@constructprefix{#1}{\cref@result}%
- \protected@edef\@currentlabel{#3}%
- \protected@edef\@currentlabelname{#3}%
- \protected@edef\cref@currentlabel{[#1][][\cref@result]#3}
- \label[#1]{#2}%
- \endgroup
+ \begingroup
+ \cref@constructprefix{#1}{\cref@result}%
+ \protected@edef\@currentlabel{#3}%
+ \protected@edef\@currentlabelname{#3}%
+ \protected@edef\cref@currentlabel{[#1][][\cref@result]#3}
+ \label[#1]{#2}%
+ \endgroup
}
\makeatother
% \maketitle format
\makeatletter
-\let\@project\relax
\def\project#1{\def\@project{#1}}
-\let\@organization\relax
\def\organization#1{\def\@organization{#1}}
-\let\@version\relax
-\def\version#1{\def\@version{#1}}
\def\@maketitle{%
\centering%
\parskip=0pt%
@@ -173,8 +204,15 @@
}%
\vfill\flushright%
\par{%
- \par{\strut{}Version \@version\strut}%
\par{\strut\@date\strut}%
+ \begingroup%
+ \endlinechar=\m@ne\everyeof{\noexpand}%
+ \edef\x{%
+ \endgroup%
+ \def\noexpand\commit{\@@input|"git rev-parse --short HEAD" }%
+ }%
+ \x%
+ \par{\strut\footnotesize({\ttfamily\commit})\strut}%
}%
\par\vspace*{2in}%
}
@@ -196,6 +234,12 @@
selection={recorded and deps and see},
]
+% allow cross-references to requirements.pdf from all documents except
+% requirements.pdf itself
+\IfEq*{\jobname}{requirements}{}{
+ \externaldocument{reqs}[requirements.pdf]
+}
+
% default document header/trailer
\makeatletter
\def\projdoc@header{
@@ -206,19 +250,27 @@
\thispagestyle{empty}
\end{titlepage}
}
-\newbool{projdoc@cited}
-\apptocmd{\abx@aux@cite}{\global\booltrue{projdoc@cited}}{}{}
+\newbool{projdoc@used@cite}
+\newbool{projdoc@used@gls}
+\apptocmd{\abx@aux@cite}{\global\booltrue{projdoc@used@cite}}{}{}
+\apptocmd{\glsxtr@record}{\global\booltrue{projdoc@used@gls}}{}{}
\def\projdoc@trailer{
% bibliography (if citations used)
- \ifbool{projdoc@cited}{\printbibliography}{}%
+ \ifbool{projdoc@used@cite}{%
+ \hfuzz=50pt% reduce overfull hbox warnings for bibliography (mostly URLs)
+ \printbibliography%
+ }{}%
% glossary
- \ifcsundef{printunsrtglossary}{}{%
+ \ifbool{projdoc@used@gls}{%
+ \projdoc@description@leftmargin=2ex%
+ \projdoc@description@labelindent=0pt%
+ \projdoc@setdescriptionstyle%
\section*{Glossary}%
\begin{multicols}{2}%
\renewcommand{\glossarysection}[2][]{}%
\printunsrtglossary%
\end{multicols}%
- }%
+ }{}%
}
\AtBeginDocument{\projdoc@header}
\AtEndDocument{\projdoc@trailer}
@@ -266,8 +318,8 @@
\def\UrlRight{\hbox{\,}}%
}
\DefineVerbatimEnvironment{blockcode}{Verbatim}{
- tabsize=2,
- obeytabs,
+ tabsize=2,
+ obeytabs,
}
% scale down image if it exceeds page margins
@@ -277,7 +329,8 @@
% adjust scale for puml diagrams
\newcommand{\includepumldiag}[1]{%
- \fitimg{\includegraphics[scale=0.6]{#1}}%
+ \StrSubstitute{#1}{.puml}{.eps}[\filename]%
+ \fitimg{\includegraphics[scale=0.6]{\filename}}%
}
% prevent page break between two paragraphs
@@ -285,3 +338,76 @@
\newcommand\noparbreak{\par\nobreak\@afterheading}
\makeatother
+% cleveref extra types
+\crefname{paragraph}{paragraph}{paragraphs}
+\Crefname{paragraph}{Paragraph}{Paragraphs}
+\crefname{requirement}{requirement}{requirements}
+\Crefname{requirement}{Requirement}{Requirements}
+\crefname{test}{test}{tests}
+\Crefname{test}{Test}{Tests}
+
+% fix cleveref showing filename to external cross-reference
+% see <https://tex.stackexchange.com/a/708445/211562>
+% edited from cleveref source
+\makeatletter
+\def\cref@getref#1#2{%
+ \expandafter\let\expandafter#2\csname r@#1@cref\endcsname%
+ \expandafter\expandafter\expandafter\def%
+ \expandafter\expandafter\expandafter#2%
+ \expandafter\expandafter\expandafter{%
+ \expandafter\@firstoffive#2}}%
+\def\cpageref@getref#1#2{%
+ \expandafter\let\expandafter#2\csname r@#1@cref\endcsname%
+ \expandafter\expandafter\expandafter\def%
+ \expandafter\expandafter\expandafter#2%
+ \expandafter\expandafter\expandafter{%
+ \expandafter\@secondoffive#2}}%
+\AtBeginDocument{%
+ \def\label@noarg#1{%
+ \cref@old@label{#1}%
+ \@bsphack%
+ \edef\@tempa{{page}{\the\c@page}}%
+ \setcounter{page}{1}%
+ \edef\@tempb{\thepage}%
+ \expandafter\setcounter\@tempa%
+ \cref@constructprefix{page}{\cref@result}%
+ \protected@write\@auxout{}{%
+ \string\newlabel{#1@cref}{%
+ {\cref@currentlabel}%
+ {[\@tempb][\arabic{page}][\cref@result]\thepage}%
+ {}%
+ {}%
+ {}%
+ }%
+ }%
+ \@esphack%
+ }%
+ \def\label@optarg[#1]#2{%
+ \cref@old@label{#2}%
+ \@bsphack%
+ \edef\@tempa{{page}{\the\c@page}}%
+ \setcounter{page}{1}%
+ \edef\@tempb{\thepage}%
+ \expandafter\setcounter\@tempa%
+ \cref@constructprefix{page}{\cref@result}%
+ \protected@edef\cref@currentlabel{%
+ \expandafter\cref@override@label@type%
+ \cref@currentlabel\@nil{#1}%
+ }%
+ \protected@write\@auxout{}{%
+ \string\newlabel{#2@cref}{%
+ {\cref@currentlabel}%
+ {[\@tempb][\arabic{page}][\cref@result]\thepage}%
+ {}%
+ {}%
+ {}%
+ }%
+ }%
+ \@esphack%
+ }%
+}
+\makeatother
+
+% missing reference marker
+\def\mref{\textsuperscript{\textit{\,ref?}}}
+
diff --git a/readme.md b/readme.md
index 1375c5e..ece6512 100644
--- a/readme.md
+++ b/readme.md
@@ -3,29 +3,35 @@
systems programming in c++ minor project documentation
Please see [style.md](./style.md) for writing style and
-[contributing.md](./contributing.md) for coding and git standards.
+[contributing.md](./contributing.md) for coding and git standards. There is
+also [an example document](./example.tex) which may be used to copy/paste LaTeX
+snippets for specific formatting.
## Compilation
-- A `latexmkrc` file is provided for copmilation with `latexmk`. The documents
- should also compile under [Visual Studio Code][vscode] using the [LaTeX
- Workshop extension][latexworkshop], as well as [VimTeX][vimtex].
-- A [makefile](./makefile) is used to compile other files (e.g. plantuml
- diagrams, [time report](#time-report))
-- These documents use fonts loaded using `fontspec`, please see
- [style.md](./style.md) for download links.
-
-## Time report
-
-The time report document includes generated LaTeX code which can be compiled
-from [time.txt](./time.txt) using [time2tex.py](./time2tex.py). The
-[makefile](./makefile) includes a rule that does this, so `make timerep.pdf`
-should be used to compile this document specifically.
-
-## Requirements
-
-TODO: how to store + cross-reference requirements w/o extra latex compilation
-runs
+Prerequisites:
+- A LaTeX distribution that includes XeLaTeX and latexmk
+- PlantUML
+- Python 3
+- Fonts (see see [style.md](./style.md) for download links)
+
+All documents are compiled using latexmk, and this repository contains
+additional configuration files for the following editors:
+- [Visual Studio Code][vscode] + [LaTeX Workshop][latexworkshop]
+- (Neo)Vim + [VimTeX][vimtex] (source `.vimrc` to fix custom verb command
+ highlighting)
+
+## Special files
+
+- `time.txt` contains tracked time for each team member. This file is
+ automatically converted using [time2tex](scripts/time2tex.py) when compiling
+ [timerep.tex](./timerep.tex).
+- `reqs.toml` contains the project requirements. This file is converted using
+ [reqs2tex](scripts/reqs2tex.py) for [requirements.tex](./requirements.tex)
+ and also generates an `.aux` file for cross-referencing the requirements from
+ other documents.
+- `sources.bib` contains all bibliography entries / references
+- `glossary.bib` contains all glossary entries
[vscode]: https://code.visualstudio.com
[latexworkshop]: https://marketplace.visualstudio.com/items?itemName=James-Yu.latex-workshop
diff --git a/reqs.toml b/reqs.toml
new file mode 100644
index 0000000..ed0b451
--- /dev/null
+++ b/reqs.toml
@@ -0,0 +1,86 @@
+# This is a TOML file containing all project requirements. The reqs2tex script
+# can be used to generate the files necessary to compile requirements.tex and
+# cross-reference the requirements from other documents.
+
+# This is the requirement cross-reference ID. Requirements can be
+# (cross-)referenced from LaTeX by prefixing this ID with `req:` (i.e. this
+# requirement is referenced as \cref{req:audio}).
+[audio]
+# Requirement type ('system' | 'user')
+type = 'user'
+# MoSCoW priority ('must' | 'should' | 'could' | 'will not')
+priority = 'must'
+# Requirement body. Supports LaTeX formatting. (tip: use single quotes so
+# backslash doesn't act as an escape character)
+description = '''
+The engine allows the game programmer to easily start, pause and stop
+background music, while simultaniously playing sound effects.
+'''
+# Definition of done. If 'done' is a string, it is treated as LaTeX code, if it
+# is a list of strings, each item is treated as the ID of another requirement,
+# and the references are checked before LaTeX runs.
+done = [
+ 'audio:async-api',
+ 'audio:handle',
+ 'audio:stream-mix',
+ 'audio:volume',
+]
+#done = 'When I feel like it'
+# Requirements that are no longer applicable should set `deleted` to `true`.
+# This will make sure the requirements are numbered consistently across
+# different document revisions.
+#deleted = true
+
+[audio:async-api]
+type = 'system'
+priority = 'must'
+description = '''
+The public audio \gls{api} supports starting audio samples asynchronously
+(i.e.~fire and forget).
+'''
+
+[audio:handle]
+type = 'system'
+priority = 'must'
+description = '''
+The public audio \gls{api} allows the game programmer to control (i.e.~play,
+pause, resume and stop) audio samples after they are created/initialized.
+'''
+
+[audio:stream-mix]
+type = 'system'
+priority = 'must'
+description = '''
+The audio system supports playing multiple audio streams simultaniously.
+'''
+
+[audio:volume]
+type = 'system'
+priority = 'must'
+description = '''
+The public audio \gls{api} allows the game programmer to control the volume of
+audio samples.
+'''
+
+# TODO: audio encoding support?
+
+[lib:license]
+type = 'system'
+priority = 'must'
+description = '''
+External libraries must have a license that is MIT-compatible, or one that
+allows linking against MIT code.
+'''
+
+[lib:platform]
+type = 'system'
+priority = 'must'
+description = '''
+External libraries must have cross-platform support for at least Linux and
+Windows.
+'''
+
+# TODO: library popularity as quality factor?
+# TODO: library documentation as quality factor?
+# TODO: modularity over less libraries? (i.e. why don't we just SDL2 everything?)
+
diff --git a/requirements.tex b/requirements.tex
new file mode 100644
index 0000000..6b4a87a
--- /dev/null
+++ b/requirements.tex
@@ -0,0 +1,42 @@
+\documentclass{projdoc}
+
+\makeatletter
+\projdoc@description@leftmargin=2ex
+\projdoc@description@labelindent=0pt
+\projdoc@setdescriptionstyle
+\makeatother
+\setcounter{secnumdepth}{1}
+
+\makeatletter
+\def\reqlabel#1{\csuse{reqlabel@#1}}
+\def\reqlabelreset{%
+ \global\def\reqlabel@priority{%
+ \Glsdesc{reqlabel-priority}%
+ \global\def\reqlabel@priority{\Glstext{reqlabel-priority}}%
+ }%
+ \global\def\reqlabel@description{%
+ \Glsdesc{reqlabel-description}%
+ \global\def\reqlabel@description{\Glstext{reqlabel-description}}%
+ }%
+ \global\def\reqlabel@done{%
+ \Glsdesc{reqlabel-done}%
+ \global\def\reqlabel@done{\Glstext{reqlabel-done}}%
+ }%
+}
+% Abbreviate requirement field labels after first occurrence on every page
+\AtBeginShipout{\reqlabelreset}
+\makeatother
+
+\title{Requirements}
+
+\begin{document}
+\tablestables
+\newpage
+
+\section{Requirements}
+\begin{multicols}{2}
+\input{reqs.tex}
+\end{multicols}
+
+\end{document}
+
diff --git a/research.tex b/research.tex
index 8dfb2a6..4a65ec3 100644
--- a/research.tex
+++ b/research.tex
@@ -1,5 +1,4 @@
\documentclass{projdoc}
-\input{meta.tex}
\title{Research document}
@@ -24,7 +23,7 @@ A game engine is not the game itself but a platform with which games are built.
should provide the functionalities with which the game is constructed. The purpose of
a game engine is not to create data out of nothing. Instead, data is read, and the
correlating features and effects are generated. However, the engine is also used to
-create these files, referred to as ``assets.'' The game engine must be able to accept
+create these files, referred to as ``assets''. The game engine must be able to accept
a certain format of these assets---whether levels, sprites, or textures---and convert
them into usable data.
@@ -44,31 +43,194 @@ layers are divided into the following categories:\noparbreak
performance profiling.
\item[Scripting layer] Runs scripts, such as Lua or Python.
\item[Memory systems] Handles and monitors memory usage.
- \item[\gls{ecs}] Provides a modular way to create game objects, add physics, and
- define how the engine interacts with objects.
\item[Physics] Adds specific physics to objects.
\item[Audio] Processes audio.
\item[AI] Provides artificial inteligent behavior.
\end{description}
-\subsubsection{ECS}
-
-A game engine must have the ability to keep track and update several game objects. To
-do this most game engines employ an \gls{ecs} model which uses modulair components to
-give entities properties and features. The need for an entity component system arises
-because multiple game objects are required to create a scene in a game. These game
-objects exist within the scene and perform actions, such as a UI display for a score.
-This game object does not need to be rendered; it could be a script running in the
-background. It could also be a player sprite that is controlled. These entities need
-to be aware of other entities, for example, during collisions. For this to function,
-a scene is required to host all game objects. Within this scene, the game objects
-must be stored efficiently, and entities must be provided with the required behavior,
-such as audio, position, or physics. To create diverse entities with specific
-functions: A scene can contain many different kinds of entities, each with different
-properties and functions. But no matter how different each entity is, it remains an
-entity. To assign properties and functions to entities, components are used. Entt is
-an example of an \gls{ecs}.
-% TODO: ref?entt
+\subsubsection{Structures}
+
+The above mentioned layers should be structured, somehow. One of the requirements is
+that the game engine's API uses a so-called gameObject (with one or more
+component(s)). The gameObject is described in more detail at
+\cref{sec:Gameobjects/components}.
+
+There are multiple structures that could be used to structure a game engine. It's of
+course possible to use inheritance. A major disadvantages of inheritance is that it's
+not flexible. However, the provided class diagram of the game engine's API already
+specifies that composition should be used (in stead of inheritance). So, let's take a
+look at structures that use composition.
+
+The Decorator design pattern (as shown in \cref{fig:decorator}) could be used to
+structure the game engine. A gameObject's propperties/behavior is determined by one
+(or more) components. The Decorator design pattern allows to modify an object's
+propperties/behavior by adding one (or more) Decorators. The object that is modified,
+could be the gameObject and the components could be the Decorators. This is not
+exactly the same as the required API, but it's very close. A major disadvantage of
+such Decorator design pattern, is that the interface of all components should be the
+same (they should share the same methods), because the client (which is the scene in
+our case) can only call/reach the components through the interface. This would
+require very general methods (at the interface), which might make the programming
+harder \autocite{man:DecoratorDesignPattern}.
+
+\begin{figure}
+ \centering
+ \includegraphics[width=0.5\textwidth]{img/DecoratorDesignPattern.png}
+ \caption{Decorator design pattern}
+ Source: \autocite{img:Decorator}
+ \label{fig:decorator}
+\end{figure}
+
+The Extension Objects design pattern (as shown in \cref{fig:extension objects}) could
+also be used to structure the game engine. The Extension Objects design pattern
+allows to modify an object's propperties/behavior by adding one (or more) Extensions.
+The object that is modified, could be the gameObject and the components could be the
+Extensions. This is quite the same as the required API. An advantage is, that the
+client (which is the scene in our case) can call all kind of different Extension's
+methods (depending on the kind of Externsion, e.g.~the method \codeinline{render()}
+for the sprite Extension and the method \codeinline{update()} for the script
+Extension). In other words, the interfaces of the different Extensions should not be
+the same. This is way more flexible than the Decorator design pattern. A disadvantage
+is that the data and functionality are in the same class (namely inside the Extion's
+methods), so it's not sepperated. Another disadvantage is that the Extension Objects
+design pattern can be quite slow, because objects are scattered in memory (and it is
+very hard to quickly get their memory address)
+\autocite{man:ExtensionObjectDesignPattern, man:extionsionObjectsStackOverflow}.
+
+\begin{figure}
+ \centering
+ \includegraphics[width=0.5\textwidth]{img/ExtensionObjects.jpg}
+ \caption{Extension Objects design pattern}
+ Source: \autocite{img:extionsionObjects}
+ \label{fig:extension objects}
+\end{figure}
+
+Another (very popular) design pattern to structure the game engine, is the Entity
+Component System (\gls{ecs}) (as shown in \cref{fig:ECS Block Diagram}). The
+\gls{ecs} is made out of three main subsystems, namely entities, components and
+systems. Entities are just IDs. An entity is made out of a gameObject and one (or
+more) components. Components are the classes that hold the data. The components
+determine what kind of entity it is (e.g.~a sprite, audio, and so on). Systems take
+care of the behavior of the entities. Systems mainly read and write the enity's
+components data. The \gls{ecs} clearly distinguishes the data (components) from the
+functionality (systems), which is an advantage.
+
+\begin{figure}
+ \centering
+ \includegraphics[width=0.5\textwidth]{img/ECSBlockDiagram.png}
+ \caption{ECS design pattern}
+ Source: \autocite{img:ECSBlockDiagram}
+ \label{fig:ECS Block Diagram}
+\end{figure}
+
+The \gls{ecs} is normally equipped with a component manager (as shown in
+\cref{fig:ECS Component manager}). The component manager keeps track of the entities
+(Alien, Player, Target, etc in \cref{fig:ECS Component manager}) and the connected
+components (Position, Movement, Render, etc in \cref{fig:ECS Component manager}). The
+component manager stores two lists (key value pairs). The key of the first list is
+the ID of an entity, and the value of this list are the connected components. The key
+of the second list is the component, and the value of this list are the entities that
+have this component. These two lists make it possible to very quickly gather
+components or entities. This makes the \gls{ecs} very fast, which is of course an
+advantage \autocite{man:ECSComponentManager}.
+
+\begin{figure}
+ \centering
+ \includegraphics[width=0.5\textwidth]{img/ECSComponentManager.png}
+ \caption{ECS Component manager}
+ Source: \autocite{img:ECSComponentSystem}
+ \label{fig:ECS Component manager}
+\end{figure}
+
+Another aspect that makes the \gls{ecs} very fast, is that a system can handle all
+components (of the same type) together at once. This is possible because all entities
+are independent of each other.
+
+There are many ways of implementing the systems. Some say that each component type
+has their own system. This interpretation of the systems does not take the interplay
+of different component types, into account. A less restrictive approach is to let
+different systems deal with all components they should be concerned with. For
+instance a Physics Systems should be aware of Collision Components and Rigidbody
+Components, as both probably contain necessary information regarding physics
+simulation. It's best to see systems as ``closed environments''. That is, they do not
+take ownership of entities nor components. They do access them through independent
+manager objects, which in turn will take care of the entities and components
+life-cycle \autocite{man:ECSExplanation}.
+
+Sometimes systems, entities and even components need to cummincate with each other.
+This might be very hard because systems, entities and components are more or less
+independent. One option is to use an event systems. A system, entity and component
+can raise an event and other systems, entities and components can react to that
+event. This is what makes the \gls{ecs} a complicated system (disadvantage)
+\autocite{man:ECSExplanation}.
+
+There are many C/C++ libraries available, completely dedicated to \gls{ecs}. The most
+popular libraries are shown in \cref{tab:popularECSLibraries}. The popularity is
+based on the amount of stars on GitHub.
+
+\begin{table}
+ \centering
+ \begin{tabular}{ll@{\qquad}lr}
+ \toprule
+ \textbf{Name} & \textbf{Short Description} & \textbf{Stars} & \textbf{License}\\
+ \midrule
+ EnTT & Fast and reliable entity-component system & 10k & MIT\\
+ Flecs & A Multithreaded Entity Component System & 6.3k & MIT\\
+ EntityX & Fast, type-safe C++ entity component system & 2.2k & MIT\\
+ \bottomrule
+ \end{tabular}
+ \caption{Popular \gls{ecs} libraries}
+ Source: \autocite{github:awesome-ecs}
+ \label{tab:popularECSLibraries}
+\end{table}
+
+TODO: Add library benchmark to find the best library.
+
+It is, of course, not necessary to use a library to implement an \gls{ecs}
+architecture. However, it seems very hard to achieve the same performance as a
+library \autocite{github:ecsfaq}.
+
+\subsection{Conclusion}
+
+\section{Gameobjects/components}
+\label{sec:Gameobjects/components}
+
+\subsection{Introduction}
+
+One of the requirements of our customer, is that the game engine's structure is
+similar to Unity. The customer has created a class diagram of the game engine's API,
+which is (of course) very similar to Unity. One of the most important parts of the
+class diagram is a so-called gameObject (with several components). It's needed to
+understand the exact meaning/function of these gameObjects, that's why this research
+question arose.
+
+\subsection{Findings}
+
+A gameObject is the most important concept in Unity. Every object in a game is a
+GameObject, from characters and collectible items to the lights, cameras and special
+effects. However, a gameObject itself can't do anything on its own. A gameObject
+needs to be given properties before it can become a character, an envirnment, or a
+special effect. \autocite{man:unityGameobjects}
+
+A gameObject can be seen as a container for components. Components are the properties
+of the gameObject. A few examples of components are sprites, animators, audioSources,
+and so on. Multiple (different) components can be assigned to a single gameObject
+(e.g.~a sprite and an audioSource).
+
+Since we now know that a gameObject needs components to do something, it's obvious
+that there should be a way to add components to a gameObject. Some components
+(e.g.~the behaviorScript component) should also be able to reference to its
+gameObject.
+
+Each gameObject always has one transform class. The transform class describes the
+position, rotation, and scale within the scene. Some component use this information
+to e.g.~scale a sprite. Other components eddit this information to e.g.~model
+gravity. \autocite{man:unityTransformClass}
+
+A gameObject can have one (or multiple) children gameObject(s). All children
+gameObjects, of course, also have one transform class. However, the position,
+rotation, and scale of this class, is always the same as the child's parent. A child
+can not have more than one parent. \autocite{man:unityTransformClass}
\subsection{Conclusion}
@@ -103,23 +265,18 @@ software, emulators, and popular games, including Valve's award-winning catalog
many Humble Bundle games.''} \gls{sdl2} is written in the C programming language, and
therefore, structs and functions are used instead of objects and methods.
-The advantages of \gls{sdl2} are:\noparbreak
-\begin{itemize}
- \item Controller support is provided.
- \item 2D and 3D rendering are supported.
- \item Broad multiplatform support is offered, including older consoles such as the
- Wii.
- \item Low-level control is available.
- \item A large community ensures wide usage.
- \item Extended libraries can be used to add functionalities, such as SDL\_Mixer for
- sound.
-\end{itemize}
-
-The disadvantages of \gls{sdl2} are:\noparbreak
-\begin{itemize}
- \item A limited built-in 2D renderer is provided.
- \item Extended libraries require setup.
-\end{itemize}
+\begin{comparison}
+ \pro{Controller support is provided.}
+ \pro{2D and 3D rendering are supported.}
+ \pro{Broad multiplatform support is offered, including older consoles such as the
+ Wii.}
+ \pro{Low-level control is available.}
+ \pro{A large community ensures wide usage.}
+ \pro{Extended libraries can be used to add functionalities, such as SDL\_Mixer for
+ sound.}
+ \con{A limited built-in 2D renderer is provided.}
+ \con{Extended libraries require setup.}
+\end{comparison}
\paragraph{SFML}
@@ -127,24 +284,19 @@ The disadvantages of \gls{sdl2} are:\noparbreak
network, system, and window. This framework, written in C++, was designed to simplify
game development.
-The advantages of \gls{sfml} are:
-\begin{itemize}
- \item Object-oriented design is provided since it is written in C++.
- \item A built-in 2D renderer is available for ease of use.
- \item A built-in audio system is included.
- \item Cross-platform support is available for Linux, Windows, and macOS.
- \item Networking capabilities are provided for multiplayer or networked
- applications.
-\end{itemize}
-
-The disadvantages of \gls{sfml} are:
-\begin{itemize}
- \item The 2D rendering engine may experience performance issues in large-scale
- games.
- \item The community is smaller compared to \gls{sdl2}.
- \item No native 3D support is provided.
- \item Not all image formats are supported.
-\end{itemize}
+\begin{comparison}
+ \pro{Object-oriented design is provided since it is written in C++.}
+ \pro{A built-in 2D renderer is available for ease of use.}
+ \pro{A built-in audio system is included.}
+ \pro{Cross-platform support is available for Linux, Windows, and macOS.}
+ \pro{Networking capabilities are provided for multiplayer or networked
+ applications.}
+ \con{The 2D rendering engine may experience performance issues in large-scale
+ games.}
+ \con{The community is smaller compared to \gls{sdl2}.}
+ \con{No native 3D support is provided.}
+ \con{Not all image formats are supported.}
+\end{comparison}
\subsubsection{Audio}
@@ -152,7 +304,7 @@ for audio some options could be: FMOD, Wwise, or iirKlang
\subsection{Conclusion}
-\section{resource manager}
+\section{Resource manager}
\subsection{Introduction}
@@ -214,7 +366,7 @@ Unity supports many different image formats:
\subsection{Conclusion}
-\section{Event manager}
+\section{Event manager/game loop}
\subsection{Introduction}
@@ -222,15 +374,77 @@ Unity supports many different image formats:
\subsection{Conclusion}
-\section{Memory/debugging}
+% TODO: this entire section
+\section{Profiling and debugging}
+
+% Which profiling and debugging features are wanted?
+% How to provide those profiling and debugging features?
+% Can most of the profiling/debugging be handled by external tools?
+
+% Ideas:
+% - flame graph
+% - watchtable (combine w/ fps/speed control overlay?)
+% - debug printing utility functions
\subsection{Introduction}
\subsection{Findings}
+\subsubsection{Callgrind}
+
+\begin{comparison}
+ \pro{Source code does not need to be modified for profiling}
+ \con{Execution speed is severely impacted}
+\end{comparison}
+
+\subsection{Conclusion}
+
+\section{Audio}
+
+The game engine is required to have an audio system
+\autocite[\ref{req:audio}]{crepe:requirements}. Since writing a custom real-time
+audio mixing engine is outside the scope of this project\mref, this section compares
+various standalone audio libraries for suitability in the engine.
+
+\subsection{Libraries}
+\label{sec:audio:libs}
+
+After searching for libraries (search terms: `dynamic/adaptive audio', `real-time
+audio', `audio library', `game audio engine'), several libraries were found. These
+libraries were checked against the audio engine requirements
+\autocite{crepe:requirements} and then tested by writing the same benchmark-style
+\gls{poc} using the remaining qualifying libraries:\noparbreak
+\begin{enumerate}
+ \item Load a background track (Ogg Vorbis)
+ \item Load three short samples (WAV)
+ \item Start the background track
+ \item Play each sample sequentially while pausing and resuming the background track
+ \item Play all samples simultaniously
+ \item Stop all audio and exit
+\end{enumerate}
+
+Of these libraries the following were determined to be unsuitable for use in this
+project due to various reasons:\noparbreak
+\begin{description}
+ \item[FMOD \autocite{lib:fmod}] Is proprietary (violates \cref{req:lib:license})
+ \item[PortAudio \autocite{lib:portaudio}] Does not handle mixing
+ \item[miniaudio \autocite{lib:miniaudio}] With finished \gls{poc}, but dropped due
+ to very limited codec support (WAV, MP3 and FLAC only); Also does not have an
+ \gls{api} reference (only programming manual)
+ \item[YSE \autocite{lib:yse}] Attempted to write \gls{poc}, but CMake configuration
+ in repository is broken; This project seems to have been abandoned
+\end{description}
+
+The only library that remained after these tests is SoLoud \autocite{lib:soloud}. It
+is Zlib/LibPng licensed and provides a high-level object-oriented C++ \gls{api}.
+
\subsection{Conclusion}
+\label{sec:audio:conclusion}
+
+Due to a severe shortage of libraries that fit our requirements, SoLoud appears to be
+the most suitable (and only) audio library for use in this project.
-\section{Physics/scripting}
+\section{Physics}
\subsection{Introduction}
@@ -238,9 +452,15 @@ Unity supports many different image formats:
\subsection{Conclusion}
-\section{Conclusion}
+\section{Scripting}
-\section{Gameobjects/components}
+\subsection{Introduction}
+
+\subsection{Findings}
+
+\subsection{Conclusion}
+
+\section{Audio}
\subsection{Introduction}
@@ -248,6 +468,12 @@ Unity supports many different image formats:
\subsection{Conclusion}
-\section{Conclusion}
+\section{AI}
+
+\subsection{Introduction}
+
+\subsection{Findings}
+
+\subsection{Conclusion}
\end{document}
diff --git a/scripts/.gitignore b/scripts/.gitignore
new file mode 100644
index 0000000..bee8a64
--- /dev/null
+++ b/scripts/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/scripts/reqs2tex.py b/scripts/reqs2tex.py
new file mode 100755
index 0000000..2bab558
--- /dev/null
+++ b/scripts/reqs2tex.py
@@ -0,0 +1,173 @@
+#!/bin/python3
+import sys, tomllib, tex, re
+from enum import StrEnum
+
+def label2ref(*labels):
+ return ",".join(["req:" + label for label in labels])
+
+class KEY(StrEnum):
+ LABEL = 'label'
+ TYPE = 'type'
+ ID = 'id'
+ INDEX = 'index'
+ DELETED = 'deleted'
+ DONE = 'done'
+ DESCRIPTION = 'description'
+ PRIORITY = 'priority'
+
+REQ_TYPE = [
+ 'system',
+ 'user',
+]
+
+REQ_PRIORITY = [
+ 'must',
+ 'should',
+ 'could',
+ 'will not',
+]
+
+id_counter = 0
+def make_id(item):
+ global id_counter
+ id_counter += 1
+ return "{type_short}#{counter:03d}".format(
+ type_short = item[KEY.TYPE][0].upper(),
+ counter = id_counter,
+ )
+
+def sanitize(item, ids):
+ def die(msg):
+ print(f"[{item[KEY.LABEL]}]: {msg}")
+ exit(1)
+
+ # ensure properties
+ item[KEY.DESCRIPTION] = item.get(KEY.DESCRIPTION)
+ item[KEY.DONE] = item.get(KEY.DONE)
+ item[KEY.PRIORITY] = item.get(KEY.PRIORITY)
+ item[KEY.TYPE] = item.get(KEY.TYPE)
+
+ # type checks
+ if item[KEY.TYPE] not in REQ_TYPE:
+ die(f"unknown or missing requirement type: {repr(item[KEY.TYPE])}")
+ if item[KEY.PRIORITY] not in REQ_PRIORITY:
+ die(f"unknown or missing requirement priority: {repr(item[KEY.PRIORITY])}")
+
+ # conversions
+ if isinstance(item[KEY.DONE], list):
+ # safety check
+ if not set(item[KEY.DONE]).issubset(ids):
+ die("definition of done includes unknown requirement(s)")
+ item[KEY.DONE] = tex.cmd('Cref', label2ref(*item[KEY.DONE]))
+
+def convert(reqs):
+ all_ids = [item[KEY.LABEL] for item in reqs]
+ index = 0
+ for item in reqs:
+ item[KEY.ID] = tex.esc(make_id(item))
+ item[KEY.DELETED] = item.get(KEY.DELETED, False)
+ if item[KEY.DELETED]: continue
+ item[KEY.INDEX] = index
+ index += 1
+ sanitize(item, all_ids)
+
+ # skip deleted requirements (but process for make_id)
+ reqs = [item for item in reqs if item[KEY.DELETED] == False]
+
+ # sort by label
+ reqs = sorted(reqs, key=lambda item: item[KEY.LABEL])
+
+ return reqs
+
+def fmt_aux(data):
+ out = []
+ for item in data:
+ ref = label2ref(item[KEY.LABEL])
+ out += [
+ tex.cmd('newlabel', f"{ref}", tex.group(
+ item[KEY.ID],
+ '',
+ '',
+ ref,
+ '',
+ )),
+ tex.cmd('newlabel', f"{ref}@cref", tex.group(
+ f"[requirement][][]{item[KEY.ID]}",
+ '[][][]',
+ '',
+ '',
+ '',
+ )),
+ ]
+ return "\n".join(out)
+
+def fmt_tex(data):
+ out = ""
+ for item in data:
+ out += tex.join(
+ tex.cmd('subsection', f"{item[KEY.ID]}: {item[KEY.LABEL]}".upper()),
+ tex.withatletter(
+ tex.cmd('cref@constructprefix', 'requirement', r'\cref@result'),
+ tex.pedef('@currentlabel', item[KEY.ID]),
+ tex.pedef('@currentlabelname', item[KEY.ID]),
+ tex.pedef('cref@currentlabel', tex.group(['requirement'], [''], [r'\cref@result']) + item[KEY.ID]),
+ ),
+ tex.cmd('label', ['requirement'], label2ref(item[KEY.LABEL])),
+ tex.cmd('parbox', tex.cmd('linewidth'),
+ tex.env('description', tex.join(
+ tex.cmd('item', [tex.cmd('reqlabel', 'priority')]),
+ item[KEY.PRIORITY].title(),
+ tex.cmd('item', [tex.cmd('reqlabel', 'description')]),
+ item[KEY.DESCRIPTION],
+ *([
+ tex.cmd('item', [tex.cmd('reqlabel', 'done')]),
+ item[KEY.DONE]
+ ] if item[KEY.DONE] is not None else []),
+ )),
+ )
+ )
+ return out
+
+def tomlload(content):
+ # replace requirement labels with temp value
+ label_map = dict()
+ label_idx = 0
+ lines = content.split("\n")
+ for index, line in enumerate(lines):
+ match = re.search(r"^\s*\[(.+)\]", line)
+ if match is None: continue
+ lines[index] = f"[{label_idx}]"
+ label_map[str(label_idx)] = match.group(1)
+ label_idx += 1
+ content = "\n".join(lines)
+
+ # load TOML and replace temporary labels with real labels
+ data_dict = tomllib.loads(content)
+ data_list = []
+ for key, value in data_dict.items():
+ value[KEY.LABEL] = label_map[key]
+ data_list.append(value)
+
+ return data_list
+
+def main(input_file):
+ data = []
+ with open(input_file, "r") as file:
+ data = tomlload(file.read())
+
+ items = convert(data)
+
+ output_aux = input_file.removesuffix(".toml") + ".aux"
+ with open(output_aux, "w+") as file:
+ file.write(fmt_aux(items))
+
+ output_tex = input_file.removesuffix(".toml") + ".tex"
+ with open(output_tex, "w+") as file:
+ file.write(fmt_tex(items))
+
+if __name__ == "__main__":
+ if len(sys.argv) != 2:
+ print("usage: reqs2tex.py reqs.toml")
+ exit(1)
+ main(sys.argv[1])
+
diff --git a/scripts/tex.py b/scripts/tex.py
new file mode 100644
index 0000000..07d275a
--- /dev/null
+++ b/scripts/tex.py
@@ -0,0 +1,81 @@
+# utility function for converting latex code
+
+def group(*args):
+ out = ""
+ for arg in args:
+ if isinstance(arg, list):
+ out += "[" + arg[0] + "]"
+ if isinstance(arg, str):
+ out += "{" + arg + "}"
+ return out
+
+def join(*things):
+ return "".join(things)
+
+def string(content):
+ return r"\string" + content
+
+def cmd(*args):
+ name = args[0]
+ args = args[1:]
+ if len(args) == 0: args = [""]
+ return f"\\{name}" + group(*args)
+
+def pedef(*args):
+ return r"\protected@edef" + cmd(*args)
+
+def csdef(*args):
+ return r"\def" + cmd(*args)
+
+def auxout(*content):
+ return r"\write\@auxout" + group(join(*content))
+
+def scmd(*args):
+ return string(cmd(*args))
+
+def env(name, *args):
+ content = args[-1]
+ args = args[0:-1]
+ out = f"\\begin{{{name}}}"
+ if len(args) > 0:
+ out += group(*args)
+ out += content
+ out += f"\\end{{{name}}}"
+ return out
+
+def esc(plain):
+ plain = plain.replace("\\", "\\string\\")
+ plain = plain.replace("#", "\\#")
+ plain = plain.replace("$", "\\$")
+ plain = plain.replace("%", "\\%")
+ return plain
+
+def tabrule(*cells):
+ return "&".join(cells) + "\\\\"
+
+def withatletter(*content):
+ return join(
+ cmd('makeatletter'),
+ *content,
+ cmd('makeatother'),
+ )
+
+def explist(*items):
+ out = []
+ for item in items:
+ if isinstance(item, str) or not hasattr(item, '__iter__'):
+ out.append(item)
+ else:
+ out += explist(*item)
+ return out
+
+def sec(level, heading):
+ level = max(min(3, level), 0)
+ section = [
+ 'section',
+ 'subsection',
+ 'subsubsection',
+ 'paragraph',
+ ][level]
+ return cmd(section, heading)
+
diff --git a/time2tex.py b/scripts/time2tex.py
index fe3091f..a5d6802 100755
--- a/time2tex.py
+++ b/scripts/time2tex.py
@@ -1,5 +1,5 @@
#!/bin/python3
-import sys
+import sys, tex
from datetime import datetime, timedelta
def fmt_duration(sec):
@@ -19,46 +19,50 @@ def fmt_duration(sec):
return "\\,".join(out)
def fmt_percentage(fac):
- return f"{{\\footnotesize\\itshape({round(fac * 100)}\\%)}}"
+ return tex.group(
+ tex.cmd('footnotesize') +\
+ tex.cmd('itshape') +\
+ tex.esc(f"({round(fac * 100)}%)")
+ )
def fmt_member_overview(times):
# calculations
- out = ""
- members = {}
+ tracked = {}
total_time = 0
for time in times:
- if not time["name"] in members:
- members[time["name"]] = 0
- members[time["name"]] += time["duration"]
+ if not time["name"] in tracked:
+ tracked[time["name"]] = 0
+ tracked[time["name"]] += time["duration"]
total_time += time["duration"]
- # begin table
- out += r"\begin{table}\centering"
- out += r"\begin{tabular}{lr@{~}l}\toprule"
- out += r"\textbf{Member} & \textbf{Tracked} &\\\midrule{}"
-
- # member overview
- for name, tracked in members.items():
- out += f"{name} & {fmt_duration(tracked)} & {fmt_percentage(tracked / total_time)}\\\\"
- out += r"\midrule{}"
-
- # sum
- out += f"&{fmt_duration(total_time)}&\\\\"
-
- # end table
- out += r"\bottomrule\end{tabular}"
- out += r"\caption{Tracked time per group member}\label{tab:time-member}"
- out += r"\end{table}"
-
- return out
+ members = sorted(list(set(time["name"] for time in times)))
+ return tex.env('table', tex.join(
+ tex.cmd('centering'),
+ tex.env('tabular', 'lr@{~}l', tex.join(
+ tex.cmd('toprule'),
+ tex.tabrule(tex.cmd('textbf', 'Member'), tex.cmd('textbf', 'Tracked')),
+ tex.cmd('midrule'),
+ *[
+ tex.tabrule(
+ name,
+ fmt_duration(tracked[name]),
+ fmt_percentage(tracked[name] / total_time))
+ for name in members
+ ],
+ tex.cmd('midrule'),
+ tex.tabrule('', fmt_duration(total_time), ''),
+ tex.cmd('bottomrule'),
+ )),
+ tex.cmd('caption', 'Tracked time per group member'),
+ tex.cmd('label', 'tab:time-member'),
+ ))
def fmt_weekly_overview(times):
# calculations
- out = ""
weeks = []
member_totals = {}
total_time = sum(time["duration"] for time in times)
- members = list(set(time["name"] for time in times))
+ members = sorted(list(set(time["name"] for time in times)))
time_start = min(time["date"] for time in times)
time_end = max(time["date"] for time in times)
week_start = time_start - timedelta(days=time_start.weekday()) # round down to nearest monday
@@ -84,31 +88,40 @@ def fmt_weekly_overview(times):
for member in members:
member_totals[member] = sum(time["duration"] for time in times if time["name"] == member)
- # begin table
- out += r"\begin{table}\centering"
- out += f"\\begin{{tabular}}{{l{'r@{~}l' * len(members)}@{{\\qquad}}r}}\\toprule"
- out += r"\textbf{\#}"
- for member in members:
- out += f"&\\textbf{{{member}}}&"
- out += r"&\textbf{Subtotal}\\\midrule{}"
-
- for entry in weeks:
- out += f"{entry['num']}"
- for member in members:
- out += f"&{fmt_duration(entry['members'][member])}&{fmt_percentage(entry['members'][member] / entry['total'])}"
- out += f"&{fmt_duration(entry['total'])}\\\\"
-
- out += r"\midrule{}"
- for member in members:
- out += f"&{fmt_duration(member_totals[member])}&{fmt_percentage(member_totals[member] / total_time)}"
- out += f"&{fmt_duration(total_time)}\\\\"
-
- # end table
- out += r"\bottomrule\end{tabular}"
- out += r"\caption{Tracked time per week}\label{tab:time-weekly}"
- out += r"\end{table}"
-
- return out
+ return tex.env('table', tex.join(
+ tex.cmd('centering'),
+ tex.cmd('fitimg',
+ tex.env('tabular', r'l' + r'r@{~}l' * len(members) + r'@{\qquad}r', tex.join(
+ tex.cmd('toprule'),
+ tex.tabrule(*[
+ tex.cmd('textbf', cell)
+ for cell in [
+ tex.esc("#"),
+ *tex.explist([ member, "" ] for member in members),
+ "Subtotal",
+ ]
+ ]),
+ tex.cmd('midrule'),
+ *[
+ tex.tabrule(*[
+ str(entry['num']),
+ *tex.explist(
+ [
+ fmt_duration(entry['members'][member]),
+ fmt_percentage(entry['members'][member] / entry['total']),
+ ]
+ for member in members
+ ),
+ fmt_duration(entry['total']),
+ ])
+ for entry in weeks
+ ],
+ tex.cmd('bottomrule'),
+ )),
+ ),
+ tex.cmd('caption', 'Tracked time per week'),
+ tex.cmd('label', 'tab:time-weekly'),
+ ))
def duration2secs(duration):
out = 0 # output (seconds)
@@ -170,17 +183,15 @@ def parse(content):
return out
def fmt(times):
- # TODO: Task overview
- print(f"""
-\\section{{Overviews}}\n
-\\subsection{{Members}}\n
-{fmt_member_overview(times)}
-\\subsection{{Weekly}}\n
-{fmt_weekly_overview(times)}
-""")
-
-def main():
- input_file = sys.argv[1]
+ return tex.join(
+ tex.cmd('section', 'Overviews'),
+ tex.cmd('subsection', 'Members'),
+ fmt_member_overview(times),
+ tex.cmd('subsection', 'Weekly'),
+ fmt_weekly_overview(times),
+ )
+
+def main(input_file):
content = ""
with open(input_file, "r") as file:
content = file.read()
@@ -189,12 +200,15 @@ def main():
except Exception as e:
print(f"{input_file}: {e}")
exit(1)
+ output = fmt(parsed)
- fmt(parsed)
+ output_file = input_file.removesuffix(".txt") + ".tex"
+ with open(output_file, "w+") as file:
+ file.write(output)
if __name__ == "__main__":
if len(sys.argv) != 2:
- print("usage: time2tex <input>")
+ print("usage: time2tex.py time.txt")
exit(1)
- main()
+ main(sys.argv[1])
diff --git a/sources.bib b/sources.bib
index b088784..a34f739 100644
--- a/sources.bib
+++ b/sources.bib
@@ -12,3 +12,186 @@
institution = {RFC Editor},
}
+@misc{miro:scrum-board,
+ author = {Loek Le Blansch and Wouter Boerenkamps and Jaro Rutjes and Max Smits and Niels Stunnebrink},
+ title = {Scrum Board on Miro},
+ url = {https://miro.com/app/board/uXjVKjtdM64=/?share_link_id=303851465474},
+ date = {2024-09-10},
+}
+
+@misc{crepe:code-repo,
+ author = {Loek Le Blansch and Wouter Boerenkamps and Jaro Rutjes and Max Smits and Niels Stunnebrink},
+ title = {Crepe Code Repository},
+ url = {https://github.com/lonkaars/crepe},
+ date = {2024-09-10},
+}
+
+@misc{crepe:docs-repo,
+ author = {Loek Le Blansch and Wouter Boerenkamps and Jaro Rutjes and Max Smits and Niels Stunnebrink},
+ title = {Crepe Documentation Repository},
+ url = {https://github.com/lonkaars/crepe-docs},
+ date = {2024-09-10},
+}
+
+@misc{crepe:docs-standard,
+ author = {Loek Le Blansch and Wouter Boerenkamps and Jaro Rutjes and Max Smits and Niels Stunnebrink},
+ title = {Crepe Documentation Standard},
+ url = {https://github.com/lonkaars/crepe-docs/blob/master/contributing.md},
+ date = {2024-09-10},
+}
+
+@misc{crepe:code-standard,
+ author = {Loek Le Blansch and Wouter Boerenkamps and Jaro Rutjes and Max Smits and Niels Stunnebrink},
+ title = {Crepe Code Standard},
+ url = {https://github.com/lonkaars/crepe/blob/master/contributing.md},
+ date = {2024-09-10},
+}
+
+@online{lib:miniaudio,
+ title = {miniaudio - A single file audio playback and capture library.},
+ % author = {David Reid},
+ url = {https://miniaud.io/docs/manual/index.html},
+ urldate = {2024-09-22},
+}
+
+@online{lib:yse,
+ title = {YSE - cross-platform sound engine},
+ url = {https://www.attr-x.net/yse},
+ urldate = {2024-09-18},
+}
+
+@online{lib:soloud,
+ title = {SoLoud},
+ % author = {Jari Komppa},
+ url = {https://solhsa.com/soloud},
+ urldate = {2024-09-18},
+}
+
+@online{lib:fmod,
+ title = {FMOD},
+ url = {https://www.fmod.com},
+ urldate = {2024-09-18},
+}
+
+@online{lib:portaudio,
+ title = {PortAudio - an Open-Source Cross-Platform Audio API},
+ url = {https://www.portaudio.com},
+ urldate = {2024-09-18},
+}
+
+@online{tool:perf,
+ title = {\texttt{perf:} Linux profiling with performance counters},
+ url = {https://perf.wiki.kernel.org/index.php/Main_Page},
+ urldate = {2024-09-18},
+}
+
+@report{crepe:requirements,
+ author = {Loek Le Blansch and Wouter Boerenkamps and Jaro Rutjes and Max Smits and Niels Stunnebrink},
+ title = {Requirements},
+ date = {2024-09-18},
+}
+
+@misc{crepe:validation-application,
+ author = {Loek Le Blansch and Wouter Boerenkamps and Jaro Rutjes and Max Smits and Niels Stunnebrink},
+ title = {Validation Application},
+ date = {2024-09-10},
+}
+
+@misc{github:awesome-ecs,
+ author = {Sangjun Lee},
+ title = {Awesome Entity Component System},
+ url = {https://github.com/jslee02/awesome-entity-component-system?tab=readme-ov-file},
+ date = {2023}
+}
+
+@misc{github:ecsfaq,
+ author = {Sander Mertens},
+ title = {ECS FAQ},
+ url = {https://github.com/SanderMertens/ecs-faq?tab=readme-ov-file#should-i-write-my-own-ecs},
+ date = {2023}
+}
+
+@manual{man:unityGameobjects,
+ title = {GameObject},
+ author = {Unity Technologies},
+ organization = {Unity},
+ url = {https://docs.unity3d.com/Manual/GameObjects.html},
+ date = {2024}
+}
+
+@manual{man:unityTransformClass,
+ title = {Transform Class},
+ author = {Unity Technologies},
+ organization = {Unity},
+ url = {https://docs.unity3d.com/Manual/class-Transform.html},
+ date = {2024}
+}
+
+@misc{img:Decorator,
+ title = {Decorator Pattern Structure Diagram},
+ author = {Refactoring Guru},
+ url = {https://refactoring.guru/images/patterns/diagrams/decorator/structure.png},
+ date = {2024}
+}
+
+@manual{man:ExtensionObjectDesignPattern,
+ title = {Extension Object Design Pattern},
+ author = {James Fawcett},
+ organization = {Syracuse University},
+ url = {https://ecs.syr.edu/faculty/fawcett/handouts/CSE776/PatternPDFs/ExtensionObject.pdf},
+ date = {2024}
+}
+
+@manual{man:DecoratorDesignPattern,
+ title = {Decorator Design Pattern},
+ author = {Refactoring Guru},
+ organization = {Refactoring Guru},
+ url = {https://refactoring.guru/design-patterns/decorator},
+ date = {2024}
+}
+
+@misc{img:extionsionObjects,
+ title = {Extension Objects Diagram},
+ author = {stackoverflow},
+ url = {https://i.sstatic.net/GoIQ6.jpg},
+ date = {2024}
+}
+
+@manual{man:extionsionObjectsStackOverflow,
+ title = {Extension Object Design Pattern},
+ author = {Supun Wijerathne},
+ organization = {stackoverflow},
+ url = {https://stackoverflow.com/questions/39331752/what-is-the-difference-between-extension-objects-pattern-and-adapter-pattern},
+ date = {2016}
+}
+
+@misc{img:ECSBlockDiagram,
+ title = {ECS Diagram},
+ author = {Unity},
+ url = {https://docs.unity3d.com/Packages/com.unity.entities@0.1/manual/images/ECSBlockDiagram.png},
+ date = {2024}
+}
+
+@misc{img:ECSComponentSystem,
+ title = {ECS Component System},
+ author = {Joel van der Werf},
+ url = {https://i.imgur.com/VMQFIjW.png},
+ date = {2024}
+}
+
+@manual{man:ECSExplanation,
+ title = {The Entity Component System C++ Game Design Pattern - Part 1},
+ author = {GameDev.net},
+ organization = {GameDev.net},
+ url = {https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/the-entity-component-system-c-game-design-pattern-part-1-r4803/},
+ date = {2024}
+}
+
+@manual{man:ECSComponentManager,
+ title = {ECS Core API},
+ author = {Unity Technologies},
+ organization = {Unity},
+ url = {https://docs.unity3d.com/Packages/com.unity.entities@0.1/manual/ecs_core.html},
+ date = {2024}
+}
+
diff --git a/style.md b/style.md
index c518e7c..8dca81b 100644
--- a/style.md
+++ b/style.md
@@ -4,6 +4,28 @@ LaTeX commands and LaTeX source style requirements are detailed in
a number of frequently used snippets that may be used as a cheat-sheet style
reference.
+# General rules
+
+- All documentation is written in U.S. English
+- Section headers are in sentence case (i.e. only the first word and proper
+ nouns are capitalized)
+- Section headers should not contain punctuation (e.g. no question marks, "or"
+ instead of a slash, etc.)
+- Quotes are closed before punctuation marks.
+- Do not use contractions, modal adverbs or rhetorical questions.
+
+# References
+
+- Citations are inserted before the full stop at the end of a sentence.
+- When a library or piece of software is introduced in a document, reference
+ the project homepage using the bibliography.
+- Direct quotations or paraphased text must be cited.
+- Acronyms, abbreviations and jargon reference the glossary.
+- All figures and tables must be referenced in the body text. Don't write
+ paragraphs that 'lead up' to figures, as this forces LaTeX to not break the
+ page between the paragraph and figure.
+- Figures from third-party sources must be cited.
+
# Fonts
The documents use the following fonts. All of these are free and open source,
@@ -27,15 +49,18 @@ workshop and VimTeX.
[texgyreschola-math]: https://www.gust.org.pl/projects/e-foundry/tg-math/download/index_html#Schola_Math
[jetbrains-mono]: https://www.jetbrains.com/lp/mono
-# Spelling
+# Figures
-- All documentation is written in U.S. English
-- Section headers are in sentence case (i.e. only the first word and proper
- nouns are capitalized)
+Non-raster figures are preferred over rasterized figures (where applicable).
+Please note that LaTeX does not support SVG images, and these need to be
+converted to PDF (e.g. using `svg2pdf` on linux).
+
+Raster images should only be used when the source is already in a raster format
+(e.g. for photos) or when otherwise impractical.
-# Grammar
+# Specific rules
-## Comma And
+## Comma and
**In lists**, the last element is mentioned using the word 'and', *without* a
comma.
@@ -50,27 +75,3 @@ consistency.
>
> Action X was performed, and this had Y impact.
-# Figures
-
-Non-raster figures are preferred over rasterized figures (where applicable).
-Please note that LaTeX does not support SVG images, and these need to be
-converted to PDF (e.g. using `svg2pdf` on linux).
-
-Raster images should only be used when the source is already in a raster format
-(e.g. for photos) or when otherwise impractical.
-
-# References
-
-- When a library or piece of software is introduced in a document, reference
- the project homepage using the bibliography.
-- Direct quotations or paraphased text must be cited.
-- Acronyms, abbreviations and jargon reference the glossary.
-- All figures and tables must be referenced in the body text. Don't write
- paragraphs that 'lead up' to figures, as this forces LaTeX to not break the
- page between the paragraph and figure.
-
-# Document structure
-
-- Use `\section`, `\subsection`, `\subsubsection` and `\paragraph` to insert
- headings.
-
diff --git a/time.txt b/time.txt
index 4e5f2f6..c53b4e4 100644
--- a/time.txt
+++ b/time.txt
@@ -19,13 +19,66 @@ loek: 2024-09-10 25m briefing :: watch bob videos
loek: 2024-09-10 5m docs :: update readme
loek: 2024-09-10 12m docs :: add comparison package and more example latex code
loek: 2024-09-10 30m project meeting
+loek: 2024-09-11 1h40m research :: profiling and debugging
+loek: 2024-09-12 15m integration :: PR merge
+loek: 2024-09-12 30m research :: audio
+loek: 2024-09-13 1h10m project meeting
+loek: 2024-09-13 45m integration :: PR merge
+loek: 2024-09-14 45m refactoring :: clean up LaTeX build system
+loek: 2024-09-14 1h10m docs :: requirements
+loek: 2024-09-15 2h55m docs :: requirements
+loek: 2024-09-16 2h30m docs :: requirements
+loek: 2024-09-17 1h20m project meeting
+loek: 2024-09-17 55m bugs :: cross-platform latexmk filespec
+loek: 2024-09-17 2h25m docs :: requirements
+loek: 2024-09-18 2h20m docs :: requirements
+loek: 2024-09-18 1h50m research :: audio
+loek: 2024-09-18 1h05m integration :: PR merge
+loek: 2024-09-19 30m docs :: requirements
+loek: 2024-09-19 15m project meeting
+loek: 2024-09-19 1h30m project meeting
+loek: 2024-09-19 45m project meeting
+loek: 2024-09-19 15m docs :: remove versioning
+loek: 2024-09-19 30m PR merge and style guide update
+loek: 2024-09-22 2h15m docs :: research
+loek: 2024-09-24 1h45m project meeting
+loek: 2024-09-25 3h implementation :: audio facade and API
+loek: 2024-09-26 2h project meeting
+loek: 2024-09-25 1h20m implementation :: audio facade and API
-max: 2024-09-02 1h project meeting :: project kickoff
-max: 2024-09-02 45m project meeting
+max: 2024-09-02 1h project kickoff
+max: 2024-09-02 45m first project meeting
+max: 2024-09-03 1h30m first project lesson
max: 2024-09-04 1h30m installing and configuring latex
max: 2024-09-04 2h reading project info
max: 2024-09-05 20m discussing GitHub with Jaro
-max: 2024-09-05 1h30m first group meeting
+max: 2024-09-05 1h30m second project meeting
+max: 2024-09-06 45m writing email and fixing clang-format/-tidy
+max: 2024-09-09 3h10m investigating Unity (in relation to the class diagram)
+max: 2024-09-10 1h30m third project meeting
+max: 2024-09-10 20m discussing about class diagram
+max: 2024-09-10 40m second project lesson (one-to-one meeting with Bob)
+max: 2024-09-11 1h50m first review of Jaro's Plan document
+max: 2024-09-12 1h trying to fix LaTeX and VS code settings
+max: 2024-09-12 1h worked on gameObject research
+max: 2024-09-13 1h30m fourth project meeting
+max: 2024-09-16 1h researching self-made ECS possibilities
+max: 2024-09-16 1h30m researching ECS libraries
+max: 2024-09-17 1h30m fifth project meeting
+max: 2024-09-18 4h researching engine structure
+max: 2024-09-19 20m sixt project meeting (part one)
+max: 2024-09-19 1h30m third project lesson
+max: 2024-09-19 45m sixt project meeting (part two)
+max: 2024-09-19 20m researching facade design pattern
+max: 2024-09-20 1h30m checking PvA (and fixing LaTeX)
+max: 2024-09-20 3h researching engine structure
+max: 2024-09-24 2h seventh project meeting
+max: 2024-09-24 45m PvA review with Bob
+max: 2024-09-25 7h30m Creating EnTT POC and considering other ECS
+max: 2024-09-25 1h wrote email to Bob
+max: 2024-09-25 2h40m make my own ECS (homemade ECS)
+max: 2024-09-26 2h eight project meeting
+max: 2024-09-26 1h wrote email to Bob (after project meeting)
wouter: 2024-09-02 1h project meeting :: project kickoff
wouter: 2024-09-02 45m project meeting
@@ -35,6 +88,20 @@ wouter: 2024-09-04 1h30m researching 3rd party tools
wouter: 2024-09-05 1h30m first group meeting
wouter: 2024-09-05 20m setting up research document
wouter: 2024-09-05 1h researching game enigne
+wouter: 2024-09-06 3h researching game enigne
+wouter: 2024-09-09 2h researching SDL and SFML2
+wouter: 2024-09-10 1h30m third project meeting
+wouter: 2024-09-10 45m project videos
+wouter: 2024-09-10 40m second project lesson
+wouter: 2024-09-12 2h researching gameloops
+wouter: 2024-09-14 3h working on game loop poc
+wouter: 2024-09-16 4h working on gameloop poc
+wouter: 2024-09-17 1h30m fifth project meeting
+wouter: 2024-09-18 3h finishing gameloop poc and starting event manager
+wouter: 2024-09-19 15m project meeting
+wouter: 2024-09-19 1h30m project meeting
+wouter: 2024-09-19 45m project meeting
+wouter: 2024-09-19 15m docs :: remove versioning
niels: 2024-09-02 1h project meeting :: project kickoff
niels: 2024-09-02 45m project meeting
@@ -44,6 +111,23 @@ niels: 2024-09-04 2h setting up vimtex on neovim
niels: 2024-09-04 1h researching different code styles and c++ guidelines
niels: 2024-09-05 1h30m first group meeting
niels: 2024-09-06 2h added c++ guidelines in the contributing.md
+niels: 2024-09-09 1h adjusted code of conduct based on feedback
+niels: 2024-09-10 1h30m project meeting
+niels: 2024-09-10 45m project videos
+niels: 2024-09-10 40m second project lesson (one-to-one meeting with Bob)
+niels: 2024-09-11 3h researching the different resourches from unity
+niels: 2024-09-12 3h researching the best option for audio/sprites format and comparing it to sdl2 and sfml.
+niels: 2024-09-13 1h30m project meeting
+niels: 2024-09-13 10m weekly update
+niels: 2024-09-16 1h30m Discussing with jaro about resource manager
+niels: 2024-09-16 4h programming resource manager POC
+niels: 2024-09-17 1h30m project meeting
+niels: 2024-09-18 2h Continued with programming resource manager
+niels: 2024-09-19 15m project meeting
+niels: 2024-09-19 1h30m project meeting
+niels: 2024-09-19 45m project meeting
+niels: 2024-09-19 15m PvA reviewing
+niels: 2024-09-22 2h30m Adding spritesheet functionalities
jaro: 2024-09-02 1h project meeting :: project kickoff
jaro: 2024-09-02 45m project meeting
@@ -58,5 +142,23 @@ jaro: 2024-09-09 1h project plan
jaro: 2024-09-10 1h preparing meeting and project plan
jaro: 2024-09-10 1h30m project meeting
jaro: 2024-09-10 1h project disussing research
+jaro: 2024-09-10 45m project videos
+jaro: 2024-09-10 1h project plan research physics
+jaro: 2024-09-13 1h project preparing meeting and reading review project plan
+jaro: 2024-09-13 1h30m project meeting
+jaro: 2024-09-13 30m weekly update
+jaro: 2024-09-16 1h30m Meeting Niels resource manager
+jaro: 2024-09-16 2h requirements and sdl2 example
+jaro: 2024-09-16 30m requirements
+jaro: 2024-09-17 30m preparing meeting
+jaro: 2024-09-17 1h30m meeting
+jaro: 2024-09-17 30m requirements
+jaro: 2024-09-17 2h30m class diagram
+jaro: 2024-09-18 45m project plan (feedback)
+jaro: 2024-09-19 1h30m research physics
+jaro: 2024-09-19 30m project meeting
+jaro: 2024-09-19 1h30m project lesson
+jaro: 2024-09-19 1h project meeting
+jaro: 2024-09-19 30m project plan and class diagram
# vim:ft=cfg
diff --git a/timerep.tex b/timerep.tex
index 7590217..34a30ea 100644
--- a/timerep.tex
+++ b/timerep.tex
@@ -1,5 +1,4 @@
\documentclass{projdoc}
-\input{meta.tex}
\title{Time Report}