Commits

Jason McKesson committed 1e728a7

Tutorial 6: Hierarchy code finished.

Comments (0)

Files changed (7)

Documents/Positioning/Tutorial 06.xml

         <para>This is functional, but not particularly flexible; the series of transforms is baked
             into the shader. It is also not particularly fast, what with having to do four matrix
             multiplications, per vertex.</para>
-        <para>Matrix math gives us an opportunity, however. Matrix multiplication is not
-            commutative, so the order of operations cannot be changed. The usual grouping is this: <inlineequation>
+        <para>Matrix math gives us an optimization. Matrix math is not commutative: <inlineequation>
+                <mathphrase>S*R</mathphrase>
+            </inlineequation> is not the same as <inlineequation>
+                <mathphrase>R*S</mathphrase>
+            </inlineequation>. However, it <emphasis>is</emphasis> associative: <inlineequation>
+                <mathphrase>(S*R)*T</mathphrase>
+            </inlineequation> is the same as <inlineequation>
+                <mathphrase>S*(R*T)</mathphrase>
+            </inlineequation>. The usual grouping for vertex transformation is this: <inlineequation>
                 <mathphrase>Final = C*(S*(R*(T*position)))</mathphrase>
             </inlineequation>. But this can easily be regrouped as: <inlineequation>
                 <mathphrase>Final = (((C*S)*R)*T)*position</mathphrase>
             </inlineequation>.</para>
         <para>This would in fact be slower for the shader to compute, since full matrix-to-matrix
-            multiplication is quite slow. But the quantity <inlineequation>
+            multiplication is much slower than matrix-to-vector multiplication. But the combined
+            matrix <inlineequation>
                 <mathphrase>(((C*S)*R)*T)</mathphrase>
             </inlineequation> is <emphasis>fixed</emphasis> for all of a given object's vertices.
             This can be computed on the CPU, and all we have to do is upload a single matrix to
-            OpenGL.</para>
+            OpenGL. And since we're already uploading a matrix to OpenGL for each object we render,
+            this changes nothing about the overall performance characteristics of the
+            rendering.</para>
         <para><emphasis>This</emphasis> is one of the main reasons matrices are used. You can have a
             transformation sequence with dozens of component transformations, and yet all it takes
             for the GPU to process this is a single vector/matrix multiplication.</para>
         <section>
             <title>Order of Transforms</title>
             <para>As previously stated, matrix multiplication is not commutative. This means that
-                the combined transform S*T is not the same as T*S. Let us explore this further. This
-                is what these two composite transform matrices look like:</para>
+                the combined transform <inlineequation>
+                    <mathphrase>S*T</mathphrase>
+                </inlineequation> is not the same as <inlineequation>
+                    <mathphrase>T*S</mathphrase>
+                </inlineequation>. Let us explore this further. This is what these two composite
+                transform matrices look like:</para>
             <!--TODO: Show T, S, S*T and T*S.-->
-            <para>The transform S*T actually scales the translation part of the resulting matrix.
-                This means that the vertices will not just get farther from each other, but farther
+            <para>The transform <inlineequation>
+                    <mathphrase>S*T</mathphrase>
+                </inlineequation> actually scales the translation part of the resulting matrix. This
+                means that the vertices will not just get farther from each other, but farther
                     <emphasis>from the origin</emphasis> of the destination space. It is the
                 difference between these two transforms:</para>
             <!--TODO: Show what the two transforms actually look like.-->
             <para>If you think about the order of operations, this makes sense. Even though one can
-                think of the combined transform S*T as a single transform, it is ultimately a
-                composite operation. The transformation T happens first; the object is translated
-                into a new position.</para>
+                think of the combined transform <inlineequation>
+                    <mathphrase>S*T</mathphrase>
+                </inlineequation> as a single transform, it is ultimately a composite operation. The
+                transformation T happens first; the object is translated into a new position.</para>
             <para>What you must understand is that something special happens between S and T.
                 Namely, that S is now being applied to positions that are not from model space (the
                 space the original vertices were in), but are in <emphasis>post translation
                 Remember: a matrix, even a translation matrix, defines a full-fledged coordinate
                 system.</para>
             <para>So S now acts on the T-space position of the vertices. T-space has an origin,
-                defined by the matrix T. So the scaling matrix S will scale the points away from the
-                origin point in T-space. Since what you (probably) actually wanted was to scale the
-                points away from the origin point in <emphasis>model space</emphasis>, S needs to
-                come first.</para>
+                defined by the matrix T. A scaling transformation matrix performs scaling based on
+                the origin point in the space of the vertices being scaled. So the scaling matrix S
+                will scale the points away from the origin point in T-space. Since what you
+                (probably) actually wanted was to scale the points away from the origin point in
+                    <emphasis>model space</emphasis>, S needs to come first.</para>
             <para>Rotation (orientation) matrices have the same issue. The orientation is always
                 local to the origin in the current space of the positions. So a rotation matrix must
                 happen before the translation matrix. Scales generally should happen before
                 orientation; if they happen afterwards, then the scale will be relative to the
                     <emphasis>new</emphasis> axis orientation, not the model-space one. This is fine
                 if it is a uniform scale, but a non-uniform scale will be problematic.</para>
+            <para>There are reasons to put a translation matrix first. If the model-space origin is
+                not the point that you wish to rotate or scale around, then you will need to perform
+                the translation first, then apply a scale or rotation. Doing this multiple times can
+                allow you to scale and rotate about two completely different points. However, this
+                gets progressively more difficult, as each new translation needs to be based on the
+                space of the rotated or scaled points.</para>
         </section>
         <section>
             <title>Hierarchical Models</title>
-            <para/>
+            <para>Successive transforms allow us to create a hierarchy of transformations </para>
+        </section>
+    </section>
+    <section>
+        <title>In Review</title>
+        <para/>
+        <section>
+            <title>Further Study</title>
+            <para>Try doing these things with the given programs.</para>
+            <itemizedlist>
+                <listitem>
+                    <para>Reverse the order of rotations on the wrist in the Hierarchy tutorial.
+                        Note how this affects the ability to adjust the wrist.</para>
+                </listitem>
+            </itemizedlist>
         </section>
     </section>
     <section>

Documents/Tutorial Documents.xpr

                         <scenarioAssociation-array>
                             <scenarioAssociation>
                                 <field name="name">
-                                    <String xml:space="preserve">Tutorial to Printable PDF</String>
+                                    <String xml:space="preserve">Docbook HTML</String>
                                 </field>
                                 <field name="type">
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">Tutorials.xml</String>
+                                    <String xml:space="preserve">Positioning/Tutorial%2006.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">Tutorials.html</String>
+                                    <String xml:space="preserve">Positioning/Tutorial%2004.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Tutorial to HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">Basics/Tutorial%2000.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF Printable</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Writing/KotoRII/Adventures%20of%20Bastila%20and%20Mira/Chapter%201.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF Printable</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Writing/KotoRII/Adventures%20of%20Bastila%20and%20Mira/Chapter%202.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF Printable</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Design/RenderToDo.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Programming/InternalExes/FoMaker/design/FoLoadCodeGen.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">file:/G:/Program%20Files/XMLmind_XML_Editor/demo/docbook-modular-book/chapter.xml</String>
+                                    <String xml:space="preserve">file:/../Programming/ExternalExes/doxygen%20development/Design/ProgDocSchema.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Writing/KotoRII/Novelization/Episode%20II/Chapter1.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Programming/ExternalExes/doxygen%20development/Design/OldData/DoxyFormat.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Programming/ExternalExes/doxygen%20development/Design/DoxyFormat.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Projects/DuelingCircle/DC21.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Critiques/Past%20Mistakes%20Prologue.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../Critiques/Past%20Mistakes%201%20Trouble.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/../WritingDesign/TacticalD20/Anime_d20_SRD_v1.0_-_Chap01-12/DocBook/CharacterCreation.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook HTML</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/H:/SM/KotoRII/BasicOutline.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">file:/H:/SM/KotoRII/FirstBook.xml</String>
+                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Chapter1.xml</String>
+                                </field>
+                            </scenarioAssociation>
+                            <scenarioAssociation>
+                                <field name="name">
+                                    <String xml:space="preserve">Docbook PDF</String>
+                                </field>
+                                <field name="type">
+                                    <String xml:space="preserve">XSL</String>
+                                </field>
+                                <field name="url">
+                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Chapter3.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Chapter2.xml</String>
+                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Episode%20I.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Episode%20I.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook PDF</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Chapter3.xml</String>
+                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Chapter2.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">file:/H:/SM/KotoRII/Episode%20I/Chapter1.xml</String>
+                                    <String xml:space="preserve">file:/H:/SM/KotoRII/FirstBook.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">file:/H:/SM/KotoRII/BasicOutline.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook HTML</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../WritingDesign/TacticalD20/Anime_d20_SRD_v1.0_-_Chap01-12/DocBook/CharacterCreation.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook HTML</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Critiques/Past%20Mistakes%201%20Trouble.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook HTML</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Critiques/Past%20Mistakes%20Prologue.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook PDF</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Projects/DuelingCircle/DC21.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook HTML</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Programming/ExternalExes/doxygen%20development/Design/DoxyFormat.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook HTML</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Programming/ExternalExes/doxygen%20development/Design/OldData/DoxyFormat.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook HTML</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Writing/KotoRII/Novelization/Episode%20II/Chapter1.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook HTML</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Programming/ExternalExes/doxygen%20development/Design/ProgDocSchema.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook PDF</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Programming/InternalExes/FoMaker/design/FoLoadCodeGen.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook PDF Printable</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Design/RenderToDo.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook PDF Printable</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Writing/KotoRII/Adventures%20of%20Bastila%20and%20Mira/Chapter%202.xml</String>
-                                </field>
-                            </scenarioAssociation>
-                            <scenarioAssociation>
-                                <field name="name">
-                                    <String xml:space="preserve">Docbook PDF Printable</String>
-                                </field>
-                                <field name="type">
-                                    <String xml:space="preserve">XSL</String>
-                                </field>
-                                <field name="url">
-                                    <String xml:space="preserve">file:/../Writing/KotoRII/Adventures%20of%20Bastila%20and%20Mira/Chapter%201.xml</String>
+                                    <String xml:space="preserve">file:/G:/Program%20Files/XMLmind_XML_Editor/demo/docbook-modular-book/chapter.xml</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">Basics/Tutorial%2000.xml</String>
+                                    <String xml:space="preserve">Tutorials.html</String>
                                 </field>
                             </scenarioAssociation>
                             <scenarioAssociation>
                                 <field name="name">
-                                    <String xml:space="preserve">Tutorial to HTML</String>
+                                    <String xml:space="preserve">Tutorial to Printable PDF</String>
                                 </field>
                                 <field name="type">
                                     <String xml:space="preserve">XSL</String>
                                 </field>
                                 <field name="url">
-                                    <String xml:space="preserve">Positioning/Tutorial%2004.xml</String>
+                                    <String xml:space="preserve">Tutorials.xml</String>
                                 </field>
                             </scenarioAssociation>
                         </scenarioAssociation-array>

Documents/cssDoc.txt

     code.varname: Used for variable names.
     code.filename: Used for filenames.
     code.literal: Used for various kinds of literals in code.
+    code.classname: Used for classes.
     span.type: Used for the types of things.
+    span.mathphrase: Used for math phrases.
     
     div.example: Stores the entire example.
         p.title: The title of the example.

Tut 06 Objects in Motion/Hierarchy.cpp

 #include <string>
 #include <vector>
+#include <stack>
 #include <math.h>
 #include <glloader/gl_3_2_comp.h>
 #include <GL/freeglut.h>
 	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
 	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
 
-	float fzNear = 1.0f; float fzFar = 61.0f;
+	float fzNear = 1.0f; float fzFar = 100.0f;
 
 	cameraToClipMatrix[0].x = fFrustumScale;
 	cameraToClipMatrix[1].y = fFrustumScale;
 	glUseProgram(0);
 }
 
-const int numberOfVertices = 8;
+const int numberOfVertices = 24;
 
+#define RED_COLOR 1.0f, 0.0f, 0.0f, 1.0f
 #define GREEN_COLOR 0.0f, 1.0f, 0.0f, 1.0f
 #define BLUE_COLOR 	0.0f, 0.0f, 1.0f, 1.0f
-#define RED_COLOR 1.0f, 0.0f, 0.0f, 1.0f
-#define GREY_COLOR 0.8f, 0.8f, 0.8f, 1.0f
-#define BROWN_COLOR 0.5f, 0.5f, 0.0f, 1.0f
+
+#define YELLOW_COLOR 1.0f, 1.0f, 0.0f, 1.0f
+#define CYAN_COLOR 0.0f, 1.0f, 1.0f, 1.0f
+#define MAGENTA_COLOR 	1.0f, 0.0f, 1.0f, 1.0f
 
 const float vertexData[] =
 {
+	//Front
 	+1.0f, +1.0f, +1.0f,
+	+1.0f, -1.0f, +1.0f,
 	-1.0f, -1.0f, +1.0f,
+	-1.0f, +1.0f, +1.0f,
+
+	//Top
+	+1.0f, +1.0f, +1.0f,
+	-1.0f, +1.0f, +1.0f,
 	-1.0f, +1.0f, -1.0f,
+	+1.0f, +1.0f, -1.0f,
+
+	//Left
+	+1.0f, +1.0f, +1.0f,
+	+1.0f, +1.0f, -1.0f,
+	+1.0f, -1.0f, -1.0f,
+	+1.0f, -1.0f, +1.0f,
+
+	//Back
+	+1.0f, +1.0f, -1.0f,
+	-1.0f, +1.0f, -1.0f,
+	-1.0f, -1.0f, -1.0f,
 	+1.0f, -1.0f, -1.0f,
 
+	//Bottom
+	+1.0f, -1.0f, +1.0f,
+	+1.0f, -1.0f, -1.0f,
 	-1.0f, -1.0f, -1.0f,
-	+1.0f, +1.0f, -1.0f,
-	+1.0f, -1.0f, +1.0f,
+	-1.0f, -1.0f, +1.0f,
+
+	//Right
 	-1.0f, +1.0f, +1.0f,
+	-1.0f, -1.0f, +1.0f,
+	-1.0f, -1.0f, -1.0f,
+	-1.0f, +1.0f, -1.0f,
+
 
 	GREEN_COLOR,
+	GREEN_COLOR,
+	GREEN_COLOR,
+	GREEN_COLOR,
+
 	BLUE_COLOR,
+	BLUE_COLOR,
+	BLUE_COLOR,
+	BLUE_COLOR,
+
 	RED_COLOR,
-	BROWN_COLOR,
+	RED_COLOR,
+	RED_COLOR,
+	RED_COLOR,
 
-	GREEN_COLOR,
-	BLUE_COLOR,
-	RED_COLOR,
-	BROWN_COLOR,
+	YELLOW_COLOR,
+	YELLOW_COLOR,
+	YELLOW_COLOR,
+	YELLOW_COLOR,
+
+	CYAN_COLOR,
+	CYAN_COLOR,
+	CYAN_COLOR,
+	CYAN_COLOR,
+
+	MAGENTA_COLOR,
+	MAGENTA_COLOR,
+	MAGENTA_COLOR,
+	MAGENTA_COLOR,
 };
 
 const GLshort indexData[] =
 {
 	0, 1, 2,
-	1, 0, 3,
 	2, 3, 0,
-	3, 2, 1,
 
-	5, 4, 6,
-	4, 5, 7,
-	7, 6, 4,
-	6, 7, 5,
+	4, 5, 6,
+	6, 7, 4,
+
+	8, 9, 10,
+	10, 11, 8,
+
+	12, 13, 14,
+	14, 15, 12,
+
+	16, 17, 18,
+	18, 19, 16,
+
+	20, 21, 22,
+	22, 23, 20,
 };
 
 GLuint vertexBufferObject;
 GLuint indexBufferObject;
 GLuint vao;
 
-
-void InitializeVertexBuffer()
+void InitializeVAO()
 {
 	glGenBuffers(1, &vertexBufferObject);
 
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
 	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_STATIC_DRAW);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-}
-
-float CalcLerpFactor(float fElapsedTime, float fLoopDuration)
-{
-	float fValue = fmodf(fElapsedTime, fLoopDuration) / fLoopDuration;
-	if(fValue > 0.5f)
-		fValue = 1.0f - fValue;
-
-	return fValue * 2.0f;
-}
-
-glm::mat3 NullRotation(float fElapsedTime)
-{
-	return glm::mat3(1.0f);
-}
-
-float ComputeAngleRad(float fElapsedTime, float fLoopDuration)
-{
-	const float fScale = 3.14159f * 2.0f / fLoopDuration;
-	float fCurrTimeThroughLoop = fmodf(fElapsedTime, fLoopDuration);
-	return fCurrTimeThroughLoop * fScale;
-}
-
-glm::mat3 RotateX(float fElapsedTime)
-{
-	float fAngRad = ComputeAngleRad(fElapsedTime, 3.0);
-	float fCos = cosf(fAngRad);
-	float fSin = sinf(fAngRad);
-
-	glm::mat3 theMat(1.0f);
-	theMat[1].y = fCos; theMat[2].y = -fSin;
-	theMat[1].z = fSin; theMat[2].z = fCos;
-	return theMat;
-}
-
-glm::mat3 RotateY(float fElapsedTime)
-{
-	float fAngRad = ComputeAngleRad(fElapsedTime, 2.0);
-	float fCos = cosf(fAngRad);
-	float fSin = sinf(fAngRad);
-
-	glm::mat3 theMat(1.0f);
-	theMat[0].x = fCos; theMat[2].x = fSin;
-	theMat[0].z = -fSin; theMat[2].z = fCos;
-	return theMat;
-}
-
-glm::mat3 RotateZ(float fElapsedTime)
-{
-	float fAngRad = ComputeAngleRad(fElapsedTime, 2.0);
-	float fCos = cosf(fAngRad);
-	float fSin = sinf(fAngRad);
-
-	glm::mat3 theMat(1.0f);
-	theMat[0].x = fCos; theMat[1].x = -fSin;
-	theMat[0].y = fSin; theMat[1].y = fCos;
-	return theMat;
-}
-
-glm::mat3 RotateAxis(float fElapsedTime)
-{
-	float fAngRad = ComputeAngleRad(fElapsedTime, 2.0);
-	float fCos = cosf(fAngRad);
-	float fInvCos = 1.0f - fCos;
-	float fSin = sinf(fAngRad);
-	float fInvSin = 1.0f - fSin;
-
-	glm::vec3 axis(1.0f, 1.0f, 1.0f);
-	axis = glm::normalize(axis);
-
-	glm::mat3 theMat(1.0f);
-	theMat[0].x = (axis.x * axis.x) + ((1 - axis.x * axis.x) * fCos);
-	theMat[1].x = axis.x * axis.y * (fInvCos) - (axis.z * fSin);
-	theMat[2].x = axis.x * axis.z * (fInvCos) + (axis.y * fSin);
-
-	theMat[0].y = axis.x * axis.y * (fInvCos) + (axis.z * fSin);
-	theMat[1].y = (axis.y * axis.y) + ((1 - axis.y * axis.y) * fCos);
-	theMat[2].y = axis.y * axis.z * (fInvCos) - (axis.x * fSin);
-
-	theMat[0].z = axis.x * axis.z * (fInvCos) - (axis.y * fSin);
-	theMat[1].z = axis.y * axis.z * (fInvCos) + (axis.x * fSin);
-	theMat[2].z = (axis.z * axis.z) + ((1 - axis.z * axis.z) * fCos);
-	return theMat;
-}
-
-glm::vec3 DynamicNonUniformScale(float fElapsedTime)
-{
-	const float fXLoopDuration = 3.0f;
-	const float fZLoopDuration = 5.0f;
-
-	return glm::vec3(glm::mix(1.0f, 0.5f, CalcLerpFactor(fElapsedTime, fXLoopDuration)),
-		1.0f,
-		glm::mix(1.0f, 10.0f, CalcLerpFactor(fElapsedTime, fZLoopDuration)));
-}
-
-struct Instance
-{
-	typedef glm::mat3(*RotationFunc)(float);
-
-	RotationFunc CalcRotation;
-	glm::vec3 offset;
-
-	glm::mat4 ConstructMatrix(float fElapsedTime)
-	{
-		const glm::mat3 &rotMatrix = CalcRotation(fElapsedTime);
-		glm::mat4 theMat(rotMatrix);
-		theMat[3] = glm::vec4(offset, 1.0f);
-
-		return theMat;
-	}
-};
-
-Instance g_instanceList[] =
-{
-	{NullRotation,				glm::vec3(0.0f, 0.0f, -25.0f)},
-	{RotateX,					glm::vec3(-5.0f, -5.0f, -25.0f)},
-	{RotateY,					glm::vec3(-5.0f, 5.0f, -25.0f)},
-	{RotateZ,					glm::vec3(5.0f, 5.0f, -25.0f)},
-	{RotateAxis,				glm::vec3(5.0f, -5.0f, -25.0f)},
-};
-
-//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
-void init()
-{
-	InitializeProgram();
-	InitializeVertexBuffer();
 
 	glGenVertexArrays(1, &vao);
 	glBindVertexArray(vao);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
 
 	glBindVertexArray(0);
+}
+
+inline float DegToRad(float fAngDeg)
+{
+	const float fDegToRad = 3.14159f * 2.0f / 360.0f;
+	return fAngDeg * fDegToRad;
+}
+
+inline float Clamp(float fValue, float fMinValue, float fMaxValue)
+{
+	if(fValue < fMinValue)
+		return fMinValue;
+
+	if(fValue > fMaxValue)
+		return fMaxValue;
+
+	return fValue;
+}
+
+glm::mat3 RotateX(float fAngDeg)
+{
+	float fAngRad = DegToRad(fAngDeg);
+	float fCos = cosf(fAngRad);
+	float fSin = sinf(fAngRad);
+
+	glm::mat3 theMat(1.0f);
+	theMat[1].y = fCos; theMat[2].y = -fSin;
+	theMat[1].z = fSin; theMat[2].z = fCos;
+	return theMat;
+}
+
+glm::mat3 RotateY(float fAngDeg)
+{
+	float fAngRad = DegToRad(fAngDeg);
+	float fCos = cosf(fAngRad);
+	float fSin = sinf(fAngRad);
+
+	glm::mat3 theMat(1.0f);
+	theMat[0].x = fCos; theMat[2].x = fSin;
+	theMat[0].z = -fSin; theMat[2].z = fCos;
+	return theMat;
+}
+
+glm::mat3 RotateZ(float fAngDeg)
+{
+	float fAngRad = DegToRad(fAngDeg);
+	float fCos = cosf(fAngRad);
+	float fSin = sinf(fAngRad);
+
+	glm::mat3 theMat(1.0f);
+	theMat[0].x = fCos; theMat[1].x = -fSin;
+	theMat[0].y = fSin; theMat[1].y = fCos;
+	return theMat;
+}
+
+class MatrixStack
+{
+public:
+	glm::mat4 Top()
+	{
+		if(m_matrices.empty())
+		{
+			m_matrices.push(glm::mat4(1.0f));
+		}
+
+		return m_matrices.top();
+	}
+
+	void RotateX(float fAngDeg)
+	{
+		const glm::mat4 &top = Top();
+		m_matrices.pop();
+		m_matrices.push(top * glm::mat4(::RotateX(fAngDeg)));
+	}
+
+	void RotateY(float fAngDeg)
+	{
+		const glm::mat4 &top = Top();
+		m_matrices.pop();
+		m_matrices.push(top * glm::mat4(::RotateY(fAngDeg)));
+	}
+
+	void RotateZ(float fAngDeg)
+	{
+		const glm::mat4 &top = Top();
+		m_matrices.pop();
+		m_matrices.push(top * glm::mat4(::RotateZ(fAngDeg)));
+	}
+
+	void Scale(const glm::vec3 &scaleVec)
+	{
+		glm::mat4 scaleMat(1.0f);
+		scaleMat[0].x = scaleVec.x;
+		scaleMat[1].y = scaleVec.y;
+		scaleMat[2].z = scaleVec.z;
+
+		const glm::mat4 &top = Top();
+		m_matrices.pop();
+		m_matrices.push(top * scaleMat);
+	}
+
+	void Translate(const glm::vec3 &offsetVec)
+	{
+		glm::mat4 translateMat(1.0f);
+		translateMat[3] = glm::vec4(offsetVec, 1.0f);
+
+		const glm::mat4 &top = Top();
+		m_matrices.pop();
+		m_matrices.push(top * translateMat);
+	}
+
+	void Push()
+	{
+		m_matrices.push(Top());
+	}
+
+	void Pop()
+	{
+		m_matrices.pop();
+	}
+
+private:
+	std::stack<glm::mat4> m_matrices;
+};
+
+class Hierarchy
+{
+public:
+	Hierarchy()
+		: posBase(glm::vec3(3.0f, -5.0f, -40.0f))
+		, angBase(-45.0f)
+		, posBaseLeft(glm::vec3(2.0f, 0.0f, 0.0f))
+		, posBaseRight(glm::vec3(-2.0f, 0.0f, 0.0f))
+		, scaleBaseZ(3.0f)
+		, angUpperArm(-33.75f)
+		, sizeUpperArm(9.0f)
+		, posLowerArm(glm::vec3(0.0f, 0.0f, 8.0f))
+		, angLowerArm(146.25f)
+		, lenLowerArm(5.0f)
+		, widthLowerArm(1.5f)
+		, posWrist(glm::vec3(0.0f, 0.0f, 5.0f))
+		, angWristRoll(0.0f)
+		, angWristPitch(67.5f)
+		, lenWrist(2.0f)
+		, widthWrist(2.0f)
+		, posLeftFinger(glm::vec3(1.0f, 0.0f, 1.0f))
+		, posRightFinger(glm::vec3(-1.0f, 0.0f, 1.0f))
+		, angFingerOpen(180.0f)
+		, lenFinger(2.0f)
+		, widthFinger(0.5f)
+		, angLowerFinger(45.0f)
+	{}
+
+	void Draw()
+	{
+		MatrixStack modelToCameraStack;
+
+		glUseProgram(theProgram);
+		glBindVertexArray(vao);
+
+		modelToCameraStack.Translate(posBase);
+		modelToCameraStack.RotateY(angBase);
+
+		//Draw left base.
+		{
+			modelToCameraStack.Push();
+			modelToCameraStack.Translate(posBaseLeft);
+			modelToCameraStack.Scale(glm::vec3(1.0f, 1.0f, scaleBaseZ));
+			glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+			glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+			modelToCameraStack.Pop();
+		}
+
+		//Draw right base.
+		{
+			modelToCameraStack.Push();
+			modelToCameraStack.Translate(posBaseRight);
+			modelToCameraStack.Scale(glm::vec3(1.0f, 1.0f, scaleBaseZ));
+			glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+			glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+			modelToCameraStack.Pop();
+		}
+
+		//Draw main arm.
+		DrawUpperArm(modelToCameraStack);
+
+		glBindVertexArray(0);
+		glUseProgram(0);
+	}
+
+#define STANDARD_ANGLE_INCREMENT 11.25f
+#define SMALL_ANGLE_INCREMENT 9.0f
+
+	void AdjBase(bool bIncrement)
+	{
+		angBase += bIncrement ? STANDARD_ANGLE_INCREMENT : -STANDARD_ANGLE_INCREMENT;
+		angBase = fmodf(angBase, 360.0f);
+	}
+
+	void AdjUpperArm(bool bIncrement)
+	{
+		angUpperArm += bIncrement ? STANDARD_ANGLE_INCREMENT : -STANDARD_ANGLE_INCREMENT;
+		angUpperArm = Clamp(angUpperArm, -90.0f, 0.0f);
+	}
+
+	void AdjLowerArm(bool bIncrement)
+	{
+		angLowerArm += bIncrement ? STANDARD_ANGLE_INCREMENT : -STANDARD_ANGLE_INCREMENT;
+		angLowerArm = Clamp(angLowerArm, 0.0f, 146.25f);
+	}
+
+	void AdjWristPitch(bool bIncrement)
+	{
+		angWristPitch += bIncrement ? STANDARD_ANGLE_INCREMENT : -STANDARD_ANGLE_INCREMENT;
+		angWristPitch = Clamp(angWristPitch, 0.0f, 90.0f);
+	}
+
+	void AdjWristRoll(bool bIncrement)
+	{
+		angWristRoll += bIncrement ? STANDARD_ANGLE_INCREMENT : -STANDARD_ANGLE_INCREMENT;
+		angWristRoll = fmodf(angWristRoll, 360.0f);
+	}
+
+	void AdjFingerOpen(bool bIncrement)
+	{
+		angFingerOpen += bIncrement ? SMALL_ANGLE_INCREMENT : -SMALL_ANGLE_INCREMENT;
+		angFingerOpen = Clamp(angFingerOpen, 9.0f, 180.0f);
+	}
+
+	void WritePose()
+	{
+		printf("angBase:\t%f\n", angBase);
+		printf("angUpperArm:\t%f\n", angUpperArm);
+		printf("angLowerArm:\t%f\n", angLowerArm);
+		printf("angWristPitch:\t%f\n", angWristPitch);
+		printf("angWristRoll:\t%f\n", angWristRoll);
+		printf("angFingerOpen:\t%f\n", angFingerOpen);
+		printf("\n");
+	}
+
+private:
+	void DrawFingers(MatrixStack &modelToCameraStack)
+	{
+		//Draw left finger
+		modelToCameraStack.Push();
+		modelToCameraStack.Translate(posLeftFinger);
+		modelToCameraStack.RotateY(angFingerOpen);
+
+		modelToCameraStack.Push();
+		modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, lenFinger / 2.0f));
+		modelToCameraStack.Scale(glm::vec3(widthFinger / 2.0f, widthFinger/ 2.0f, lenFinger / 2.0f));
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+		modelToCameraStack.Pop();
+
+		{
+			//Draw left lower finger
+			modelToCameraStack.Push();
+			modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, lenFinger));
+			modelToCameraStack.RotateY(-angLowerFinger);
+
+			modelToCameraStack.Push();
+			modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, lenFinger / 2.0f));
+			modelToCameraStack.Scale(glm::vec3(widthFinger / 2.0f, widthFinger/ 2.0f, lenFinger / 2.0f));
+			glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+			glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+			modelToCameraStack.Pop();
+
+			modelToCameraStack.Pop();
+		}
+
+		modelToCameraStack.Pop();
+
+		//Draw right finger
+		modelToCameraStack.Push();
+		modelToCameraStack.Translate(posRightFinger);
+		modelToCameraStack.RotateY(-angFingerOpen);
+
+		modelToCameraStack.Push();
+		modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, lenFinger / 2.0f));
+		modelToCameraStack.Scale(glm::vec3(widthFinger / 2.0f, widthFinger/ 2.0f, lenFinger / 2.0f));
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+		modelToCameraStack.Pop();
+
+		{
+			//Draw right lower finger
+			modelToCameraStack.Push();
+			modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, lenFinger));
+			modelToCameraStack.RotateY(angLowerFinger);
+
+			modelToCameraStack.Push();
+			modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, lenFinger / 2.0f));
+			modelToCameraStack.Scale(glm::vec3(widthFinger / 2.0f, widthFinger/ 2.0f, lenFinger / 2.0f));
+			glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+			glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+			modelToCameraStack.Pop();
+
+			modelToCameraStack.Pop();
+		}
+
+		modelToCameraStack.Pop();
+	}
+
+	void DrawWrist(MatrixStack &modelToCameraStack)
+	{
+		modelToCameraStack.Push();
+		modelToCameraStack.Translate(posWrist);
+		modelToCameraStack.RotateZ(angWristRoll);
+		modelToCameraStack.RotateX(angWristPitch);
+
+		modelToCameraStack.Push();
+		modelToCameraStack.Scale(glm::vec3(widthWrist / 2.0f, widthWrist/ 2.0f, lenWrist / 2.0f));
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+		modelToCameraStack.Pop();
+
+		DrawFingers(modelToCameraStack);
+
+		modelToCameraStack.Pop();
+	}
+
+	void DrawLowerArm(MatrixStack &modelToCameraStack)
+	{
+		modelToCameraStack.Push();
+		modelToCameraStack.Translate(posLowerArm);
+		modelToCameraStack.RotateX(angLowerArm);
+
+		modelToCameraStack.Push();
+		modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, lenLowerArm / 2.0f));
+		modelToCameraStack.Scale(glm::vec3(widthLowerArm / 2.0f, widthLowerArm / 2.0f, lenLowerArm / 2.0f));
+		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+		modelToCameraStack.Pop();
+
+		DrawWrist(modelToCameraStack);
+
+		modelToCameraStack.Pop();
+	}
+
+	void DrawUpperArm(MatrixStack &modelToCameraStack)
+	{
+		modelToCameraStack.Push();
+		modelToCameraStack.RotateX(angUpperArm);
+
+		{
+			modelToCameraStack.Push();
+			modelToCameraStack.Translate(glm::vec3(0.0f, 0.0f, (sizeUpperArm / 2.0f) - 1.0f));
+			modelToCameraStack.Scale(glm::vec3(1.0f, 1.0f, sizeUpperArm / 2.0f));
+			glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(modelToCameraStack.Top()));
+			glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
+			modelToCameraStack.Pop();
+		}
+
+		DrawLowerArm(modelToCameraStack);
+
+		modelToCameraStack.Pop();
+	}
+
+	glm::vec3		posBase;
+	float			angBase;
+
+	glm::vec3		posBaseLeft, posBaseRight;
+	float			scaleBaseZ;
+
+	float			angUpperArm;
+	float			sizeUpperArm;
+
+	glm::vec3		posLowerArm;
+	float			angLowerArm;
+	float			lenLowerArm;
+	float			widthLowerArm;
+
+	glm::vec3		posWrist;
+	float			angWristRoll;
+	float			angWristPitch;
+	float			lenWrist;
+	float			widthWrist;
+
+	glm::vec3		posLeftFinger, posRightFinger;
+	float			angFingerOpen;
+	float			lenFinger;
+	float			widthFinger;
+	float			angLowerFinger;
+};
+
+
+Hierarchy g_armature;
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializeProgram();
+	InitializeVAO();
+
 
 	glEnable(GL_CULL_FACE);
 	glCullFace(GL_BACK);
 	glClearDepth(1.0f);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-	glUseProgram(theProgram);
-
-	glBindVertexArray(vao);
-
-	float fElapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
-	for(int iLoop = 0; iLoop < ARRAY_COUNT(g_instanceList); iLoop++)
-	{
-		Instance &currInst = g_instanceList[iLoop];
-		const glm::mat4 &transformMatrix = currInst.ConstructMatrix(fElapsedTime);
-
-		glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(transformMatrix));
-		glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData), GL_UNSIGNED_SHORT, 0);
-	}
-
-	glBindVertexArray(0);
-	glUseProgram(0);
+	g_armature.Draw();
 
 	glutSwapBuffers();
 	glutPostRedisplay();
 	case 27:
 		glutLeaveMainLoop();
 		break;
+	case ',': g_armature.AdjBase(true); break;
+	case '/': g_armature.AdjBase(false); break;
+	case 'l': g_armature.AdjUpperArm(false); break;
+	case '.': g_armature.AdjUpperArm(true); break;
+	case 't': g_armature.AdjLowerArm(false); break;
+	case 'g': g_armature.AdjLowerArm(true); break;
+	case 'w': g_armature.AdjWristPitch(false); break;
+	case 's': g_armature.AdjWristPitch(true); break;
+	case 'a': g_armature.AdjWristRoll(true); break;
+	case 'd': g_armature.AdjWristRoll(false); break;
+
+	case 'q': g_armature.AdjFingerOpen(true); break;
+	case 'e': g_armature.AdjFingerOpen(false); break;
+	case 32: g_armature.WritePose(); break;
 	}
 }
 

Tut 06 Objects in Motion/Rotations.cpp

 #define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
 
 GLuint theProgram;
-GLuint positionAttrib;
-GLuint colorAttrib;
 
 GLuint modelToCameraMatrixUnif;
 GLuint cameraToClipMatrixUnif;
 
 	theProgram = Framework::CreateProgram(shaderList);
 
-	positionAttrib = glGetAttribLocation(theProgram, "position");
-	colorAttrib = glGetAttribLocation(theProgram, "color");
-
 	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
 	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
 
 
 	size_t colorDataOffset = sizeof(float) * 3 * numberOfVertices;
 	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
-	glEnableVertexAttribArray(positionAttrib);
-	glEnableVertexAttribArray(colorAttrib);
-	glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
-	glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
+	glEnableVertexAttribArray(0);
+	glEnableVertexAttribArray(1);
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
 
 	glBindVertexArray(0);

Tut 06 Objects in Motion/Scale.cpp

 #define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
 
 GLuint theProgram;
-GLuint positionAttrib;
-GLuint colorAttrib;
 
 GLuint modelToCameraMatrixUnif;
 GLuint cameraToClipMatrixUnif;
 
 	theProgram = Framework::CreateProgram(shaderList);
 
-	positionAttrib = glGetAttribLocation(theProgram, "position");
-	colorAttrib = glGetAttribLocation(theProgram, "color");
-
 	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
 	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
 
 
 	size_t colorDataOffset = sizeof(float) * 3 * numberOfVertices;
 	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
-	glEnableVertexAttribArray(positionAttrib);
-	glEnableVertexAttribArray(colorAttrib);
-	glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
-	glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
+	glEnableVertexAttribArray(0);
+	glEnableVertexAttribArray(1);
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
 
 	glBindVertexArray(0);

Tut 06 Objects in Motion/Translation.cpp

 #define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
 
 GLuint theProgram;
-GLuint positionAttrib;
-GLuint colorAttrib;
 
 GLuint modelToCameraMatrixUnif;
 GLuint cameraToClipMatrixUnif;
 
 	theProgram = Framework::CreateProgram(shaderList);
 
-	positionAttrib = glGetAttribLocation(theProgram, "position");
-	colorAttrib = glGetAttribLocation(theProgram, "color");
-
 	modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
 	cameraToClipMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
 
 
 	size_t colorDataOffset = sizeof(float) * 3 * numberOfVertices;
 	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
-	glEnableVertexAttribArray(positionAttrib);
-	glEnableVertexAttribArray(colorAttrib);
-	glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
-	glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
+	glEnableVertexAttribArray(0);
+	glEnableVertexAttribArray(1);
+	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)colorDataOffset);
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
 
 	glBindVertexArray(0);