IsodiModel.vertexShader
struct IsodiModel
static immutable 
auto vertexShader = 
format!"
            #version 330
            #define PI %s
        "(raylib.PI) ~ q{
            in vec3 vertexPosition;
            in vec2 vertexTexCoord;
            in vec4 vertexVariantUV;
            in float vertexBone;
            uniform mat4 transform;
            uniform mat4 modelview;
            uniform mat4 projection;
            uniform int flatten;
            uniform sampler2D matrixTexture;
            out vec2 fragTexCoord;
            out vec4 fragVariantUV;
            out vec2 fragAnchor;
            flat out int angle;
            /// Rotate a vector by a quaternion.
            /// See: https://stackoverflow.com/questions/9037174/glsl-rotation-with-a-rotation-vector/9037454#9037454
            vec4 rotate(vec4 vector, vec4 quat) {
                vec3 temp = cross(quat.xyz, vector.xyz) + quat.w * vector.xyz;
                return vector + vec4(2.0 * cross(quat.xyz, temp), 0.0);
            }
            void main() {
                // Send vertex attributes to fragment shader
                fragTexCoord = vertexTexCoord;
                fragVariantUV = vertexVariantUV;
                // Flatview: Camera transform (modelview) excluding vertex height
                mat4 flatview = modelview;
                flatview[0].y = 0;
                flatview[1].y = 1;
                flatview[2].y = 0;
                // Keep [3] to let translations (such as sharpview) through
                // Also correct Z result, required for proper angle checking
                flatview[1].z = 0;
                flatview[2].z /= modelview[1].y;
                // Note: I achieved this correction by experimenting. It might not be mathematically accurate, but
                // it looks good enough.
                // Set transform matrix, angle quaternion and angle index for this bone
                mat4 boneMatrix = mat4(1.0);
                vec4 boneQuat = vec4(0, 0, 0, 1);
                angle = 0;
                // If we do have bone data
                if (!isnan(vertexBone)) {
                    // Load the matrix
                    boneMatrix = mat4(
                        texture2D(matrixTexture, vec2(0.0/4, vertexBone)),
                        texture2D(matrixTexture, vec2(1.0/4, vertexBone)),
                        texture2D(matrixTexture, vec2(2.0/4, vertexBone)),
                        texture2D(matrixTexture, vec2(3.0/4, vertexBone))
                    );
                    // Get the normal in camera view, only as seen from top in 2D
                    vec2 normal = normalize(
                        (flatview * boneMatrix * vec4(0, 0, 1, 0)).xz
                    );
                    // Get the bone's orientation in the 2D plane (around Z axis)
                    float orientation = atan(normal.y, normal.x) + PI / 2;
                    // Snap the angle to texture angles
                    // TODO Use the bone's angle property
                    float snapped = round(orientation * 2 / PI);
                    // Revert the rotation for textures
                    angle = (4-int(snapped)) % 4;
                    // Convert angle index to radians
                    orientation = snapped * PI / 2 / 2;
                    // Create a quaternion to counter the orientation
                    boneQuat = vec4(0, sin(orientation), 0, cos(orientation));
                }
                // Transform the vertex according to bone properties
                vec4 position = boneMatrix * rotate(vec4(vertexPosition, 1), boneQuat);
                // Set the anchor
                fragAnchor = position.xz;
                // Regular shape
                if (flatten == 0) {
                    // Calculate final vertex position
                    gl_Position = projection * modelview * transform * position;
                }
                // Flattened shape
                else {
                    // Sharp: Camera transform only affecting height
                    mat4 sharpview = mat4(
                        1, modelview[0].y, 0, 0,
                        0, modelview[1].y, 0, 0,
                        0, modelview[2].y, 1, 0,
                        0, modelview[3].y, 0, 1
                    );
                    // Calculate the final position in flat mode
                    gl_Position = projection * flatview * (
                        // Get the regular position
                        position
                        // Apply transform
                        + sharpview * (transform * vec4(1, 1, 1, 1) - vec4(1, 1, 1, 1))
                    );
                    // TODO Fix transform to work properly with rotations.
                }
            }
        } ~ '\0';
 
		isodi isodi_model IsodiModel 
		functionsstatic functionsstatic variablesvariables 
	 
	
Default fragment shader used to render the model.
The data is null-terminated for C compatibility.