//****************************************************************************//
//************ Composing 2D Transformations- January 11th, 2019 *************//
//**************************************************************************//

- The 4th row in a class...it is a thing
---------------------------------------

- Okay, so on Wednesday we talked about the 3 major types of transformations: translation, scaling, and rotation
    - Translation, sadly, worked out to adding 2 vectors instead of multiplying matrices...but then we found out that we COULD express it as a matrix multiplication using "homogenous coordinates!"
        - "This is how graphic libraries handle transformations internally, as matrix multiplications"

- Now, let's suppose we have the following problem: we have a little picture of a house (represented by Mr. Pentagon), and we want to rotate our home by 90 degrees
    - If we just apply our rotation operation, we'd rotate about the origin
- But what if we want to rotate IN PLACE, so that we're rotating around the center of our object?
    - As it turns out, OpenGL has NO idea what we mean by the "center" of our object - so how do we do this?
    - Well, if WE know where our house's center is, we can do it by moving our house to the origin, rotating it, and then moving it back
        - i.e., we're TRANSLATING it!
- So, the process would look like:
    1) Translating our house so the center is at the origin (T1)
    2) Rotating our house however we want (R)
    3) Translating the house back to its original position (T2)
        - So, in matrix form, rotating our house around a point (a,b) by 90 degrees would look like:

            translate(-a,-b) -> rotate(pi/2) -> translate(a,b)

            T1 = [1 0 -a]   , R = [0 -1 0]  , T2 = [1 0 a]
                 [0 1 -b]         [1  0 0]         [0 1 b]
                 [0 0  1]         [0  0 1]         [0 0 1]

- However, REMEMBER that matrix multiplications happen right-to-left - so, we have to put the first operations at the END of the matrix multiplication
    - "Think of these as functions, and the idea of function composition - the innermost function will get called first!"
    - Therefore, to rotate our point P to its new home:

        P' = T2( R( T1(P) ) ) = (T2*R*T1)*P

        - "DON'T FORGET THIS; you should always read the matrix operations right-to-left, from the vector backwards"

- Notice here, though, that our matrix multiplications are associative - and, therefore, we can combine ALL of our operations into a single matrix just by multiplying them together!
    - "So, if we have a polygon with 5 million points or something, we don't have to do 3 separate intense calculations to rotate it - we can just do 3 quick matrix operations to combine our transformations, then do it once!"
- So, the key points to remember:
    1) Operation order matters
        - If we rotated before translating, we'd end up with a completely different result!
    2) We can combine/compose multiple operations into one

- So, going back to our triangle from yesteryear, how would we translate it 2 units to the left, and then double it in size? Well, it's a translation and a scaling - SO, writing out the handy-dandy matrices for these:

        T = [1 0 -2]      S = [2 0 0]
            [0 1  0]          [0 2 0]
            [0 0  1]          [0 0 1]

    - Combining them (don't forget to reverse the order, so translate happens first!),

        ST = [2 0 0] * [1 0 -2] = [2 0 -4]
             [0 2 0]   [0 1  0]   [0 2  0]
             [0 0 1]   [0 0  1]   [0 0  1]

    - Great! Now, let's apply our combined translation-scaling operation to each point in the tri-angled figure:

        [2 0 -4] * |  1| = | -2|
        [0 2  0]   |  1|   |  2|
        [0 0  1]   |{1}|   |{1}|

        (...do for the other 2 points...)

        - *had to add the 3rd coordinate to the vector to work w/ homogenous coordinates

- Doing this in the OpenGL API would look something like this:

        glScale(2.0, 2.0);
        glTranslate(-2.0, 0.0);
        draw_triangle()

    - "This looks backwards, because we have to call our functions in the SAME order as the matrix multiplications!" (i.e., the last-called operation is done first!)
        - Why doesn't the library just handle this re-ordering for us? We'll see an example on Monday where having control over this is useful

- Okay, we've established that in general, operations aren't commutative - but are ANY operations commutative with each other?
    - Well, translations DO commute with other translations (it's the same thing as commuting additions)
        - ...but translations don't commute with rotations, uniform scaling, or non-uniform scaling
            - all of these apply vice-versa as well (e.g. since translations don't commute with rotations, rotations obviously also don't commute with translations!)
    - Rotations commute with one another in 2D, and with uniform scaling!
        - ...but not with non-uniform scaling, and 3D rotations DON'T commute with one another!
            - Why doesn't it work in 3D? Imagine rotating 90 degrees around X, then Y, and vice versa - it just doesn't get you the same answer
    - Uniform scaling is really just multiplication, so it's commutative with itself AND non-uniform scaling
        - ...but not with the other stuff

- On Monday, we'll start exploring the "matrix stack" and getting a little bit into OpenGL - until then, have a great weekend!