//****************************************************************************//
//************* Introduction to GLSL/Shaders - March 8th, 2019 **************//
//**************************************************************************//

- "If you're coming into the room right now, yes, it's unbearably hot - the AC's broken"
    - They're trying desperately to prop open the the doors to get some air flowing in...
- "If you're curious about if you have raytracing in your GPU, just ask yourself the following question: 'Did I pay more than $1000 for this piece of hardware?'"
----------------------------------------------------------

- Alright, we talked a bit about the architecture of current graphics cards yesterday - now, we're going to switch gears a little bit and talk about the software we can write for these cards
    - In particular, there're "shading languages" we can use to write programs for these cards, like the GLSL language (for OpenGL), HLSL (for DirectX), etc.
        - In this class, we'll mostly be focusing on the GLSL language
    - Here's a basic overview of how information "flows through" the programs we'd write in GLSL:
        - We start out by getting some OpenGL input variables from our graphics program, like the screen-space vertex positions, color, normals, and texture coordinates
        - A VERTEX PROGRAM we write in GLSL then takes that information for each vertex and spits out the 2D vertex position and the colors for the front/back faces of the polygons, and passes along the texture coordinates (usually unaltered)
            - Realistically, separate front/back colors for a polygon aren't used very often
        - From there, the output is passed along to the rasterizer, which interpolates those color/texture values across the polygon and turns them into fragments, containing the color and texture information for each pixel (amongst other things)
        - Finally, those fragments go into a FRAGMENT PROGRAM, which operates on them and changes a given fragment however we'd like before it goes to the screen
    - At a lower level, of course, each of these stages might have multiple sub-stages, physical components, different nuances, etc., but this is the general "pipeline" we can think about

- That's the "process" for how a GLSL program is used, but what IS GLSL anyway?
    - Well, it's a C-like programming language that's used to define these graphic operations we care about
        - It has some standard datatypes like int, float, bool, etc., but also some graphic specific ones:
            - Vec2 (e.g. texture coordinates)
            - Vec3 (3D positions, normal vectors, RGB colors, etc.)
            - Vec4 (homogenous coordinates, RGBA colors w/ transparency, etc.)
            - mat3/4 (3x3 matrix and 4x4 matrix datatype, respectively, used for transformations)
            - uniform sampler2D (e.g. texture maps)
                - "This is a LOUSY name for a datatype, if you ask me; it should've just been called a texture map, since that's what it's almost always used for"
                    - The 'uniform' keyword means we're going to use the same value for every fragment/pixel, which makes sense for things like textures; 'varying' means the information will get passed through the rasterizer and be interpolated for EACH pixel separately (e.g. normals will be interpolated on a per-pixel basis, etc.)
                - Also, yes, this is two separate words
        - Similarly, it's got your standard operators like +, -, *, %, =, etc., BUT some of the operators are overloaded (for instance, * will multiply two matrices by default, scale vector by a scalar, etc.)
            - There are some standard functions you can use without importing anything, like sin/cos, abs, floor/ceil, min/max, pow, sqrt, etc.
            - There are also plenty of vector operators, like length, dot, cross, and normalize
            - There are also some WEIRD ones, like "inversesqrt" (which is typically used to get )
                - Another weird one is "texture2D," which takes in a sampler and a texture map

- Let's look at an example GLSL program for implementing a diffuse shader - "most hardware nowadays supports this natively anyway, but it's a good teaching example"
    - Typically, when you write a vertex shader, you'll also write a fragment shader - you don't typically get one without the other
    - Here's what the vertex program would look like:

            varying vec3 normal; // varying means this'll be different for each pixel
            varying vec3 vertex_to_light;

            // Note that variables like "gl_Normal" are predefined and implicitly passed to the shader without us needing to explicitly specify them as inputs/outputs

            void main() {
                gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //transforms our polygon's vertices into 2D; this matrix is pre-defined in the language
                normal = gl_NormalMatrix * gl_Normal; //converts the normals to 2D
                vec4 vertex_modelview = gl_ModelViewMatrix * gl_Vertex; //converts it to a 3D position, but does NOT project it to 2D yet - we'll use this to get a vector to our light source
                vertex_to_light = vec3(gl_LightSources[0].position - vertex_modelview)
                // we won't bother normalizing these variables, since the rasterizer output isn't unit-length anyway
            }

    - Here's the corresponding fragment program:

            # PROCESSING_COLOR_SHADER //required in Processing-flavored GLSL; says we're making a shader instead of a texture mapper

            //import our vertex shader's outputs explicitly
            varying vec3 normal;
            varying vec3 vertex_to_light;

            void main() {
                const vec4 diffuse_color = vec4(1.0, 0.0, 0.0, 1.0); //red, opaque
                vec3 n_normal = normalize(normal);
                vec3 n_vertex_to_light = normalize(vertex_to_light);

                // Calculate red * (N*L) lighting equation
                float diffuse = clamp(dot(n_normalize, n_vertex_to_light), 0.0, 1.0); //'clamp' restricts result to [0, 1] range
                gl_FragColor = diffuse * diffuseColor;
            }

        - Notice that the output here is just assigning to the predefined variable "gl_FragColor"

- Okay, keep working on your raytracers, and we'll chug along on Monday!