//****************************************************************************//
//***************** Matrix Stack Basics - January 14th, 2019 ***************//
//**************************************************************************//

- Paper handouts? In this digital age?! MADNESS!!!
- On the intro project: ...well, it looks like luckily I did it correctly, so yay?
---------------------------------------------------------------

- Alright, first things first, let's talk about OpenGL - "the library that Processing, and many other apps, use to draw things"
    - You'll be creating your own basic implementation of this (and the matrix stack) for project 1 - so pay attention!

- Let's say we want to draw a simple line - how'll we do this? Well, we'll start off doing this:

        glBeginShape(GL_LINES);

        // place the endpoints of the line
        glVertex(100.0, 400.0);
        glVertex(100.0, 100.0);

        glEnd(); // more important for filling the shape later on

    - We can use this same strategy to draw more complicated shapes; for instance, to draw two CONNECTED lines:

        glBeginShape(GL_LINES);
        glVertex(100.0, 400.0);
        glVertex(100.0, 100.0);
        //if we add more lines, because of the GL_LINES param, it'll draw a DIFFERENT line between the 3rd/4th vertex, 5th/6th, etc., so we need to put another vertex on top of the previous one to connect them
        glVertex(100.0, 400.0);
        glVertex(400.0, 400.0);
        glEnd();

    - And here's how we would draw a circle (basically: little lines):

        void unitCircle() {
            glBeginShape(GL_LINES);
            xOld = 1, yOld = 0;
            int numVertices = 20;
            for (int i = 1, i <= numVertices, i++) {
                theta = 2*PI* i / ((float) numVertices);
                int x = cos(theta), y = sin(theta);

                gtVertex(x, y);
                gtVertex(xOld, yOld);

                xOld = x;
                yOld = y;
            }
            glEnd();
        }

- "But this unit circle would be 2 pixels across - that's tiny! You can't even see it!"
    - So, to fix this problem, we'll use something called the matrix stack

- The MATRIX STACK, basically, lets us perform different transformations on things and work with them in a translated state
    - It has a few different components:
        - The "current transformation matrix" - CTM - represents the current topmost transformation that's applied to what we're drawing
        - glPushMatrix() copies the CTM and pushes the copy onto the top of the stack
        - glPopMatrix() will pop off the top of the matrix stack - we just throw the removed matrix away
            - "You should always have 1 push for each pop - no more, no less. They're like parentheses that way; they have to be balanced."
        - glTranslate(x, y, z) - translates the component
        - glTranslate(x, y, z) - scales the component
        - glRotate(?) - ...for now, just pretend this rotates by some angle
            - "Each of these 3 commands creates a transformation matrix AND multiplies it on the right-hand side of the CTM"
        - glVertex(x, y) - position multiplied by the CTM before drawing
    
    - e.g. to translate our line combination, we'd say:

        glPushMatrix();
        glTranslate(200, 0);
        glBeginShape();
        (...do our vertex placing...)
        glEnd();
        glPopMatrix();

    - "Why didn't we just add to the X and Y coordinates?" In this example, we could've done that - but for more complicated operations, we want the matrix stack to handle all that for us
        - For instance:

            void circleImage() {            // 1
                glPushMatrix();             // 2
                glTranslate(0.5, 0.5);      // 3
                glScale(0.5, 0.5);          // 4
                circle();
                glPopMatrix();
                
                glPushMatrix(); // Now, we're altering our ORIGINAL matrix stack, since popping reset the stack
                glTranslate(0.5, 0.25);
                glScale(0.5, 0.5);
                circle();
                glPopMatrix();
            }

        - What does the stack actually look like after first calling "pushMatrix" and Translate/Scale, then?

        1)              -----------------
              CTM       |Identity Matrix|      =>

        2)              -----------------
              CTM       |Identity Matrix|
                        -----------------
                        |Identity Matrix|      =>

        3)              -----------------
              CTM       |I * Translate  |
                        -----------------
                        |Identity Matrix|      =>

        4)              -----------------
              CTM       |I*T * Scale    |
                        -----------------
                        |Identity Matrix|

    - "So, push says that we're getting ready to transform things; it creates a fresh copy of the current state for us to work with, so that when we pop, the stack goes back to the original state!"
        - A quick side-note: Professor Turk likes giving matrix stack traces/drawing the matrix stack as exam problems, so be aware!

- So, there are 3 big uses for a matrix stack:
    1) Changing the coordinate system we're using
    2) Instantiation (object re-use, basically)
    3) Hierarchy creation (i.e. objects composed of sub-objects)
        - ...this is what our next example illustrates:
        - Let's say we want to draw a stick figure with OpenGL, with a torso, two arms, a hand for each arm, and two fingers for each hand
            - You can view this as a dependency tree, where our overall "stick figure" object is the parent of the torso, the torso is the parent of 2 arms, each of which is the parent of a hand, each of which is the parent of 2 fingers
        - "The source code for this is given in the handout/on Canvas, so make sure you look at that!"
            - Here, we have a "square" command that just draws a box centered at the origin - but by using the matrix stack, we can translate, scale, and rotate this square to draw all of our stick figure's components!
                - And since the matrix stack is persistent, we can then push, say, a rotation on the stack, then call a "drawHand()" method, and all of its drawing methods will be rotated accordingly!
                    - So, we can rotate the whole component thanks to the MS without having to change our original methods!
            - e.g.:

                void drawHand() {
                    pushMatrix();
                    rotate(PI/4.0);
                    scale(1.0, 0.25);
                    translate(1.0, 0.0);
                    drawBox();
                    popMatrix();
                }

- Okay, we'll finish this example (and keep pushing on) on Wednesday.