#version 150


float rsin(float i, float Wave) {
    return (sin(i) + sin(2 * i) + sin(3 * i) + 2 * sin(3 * i - 3) - 0.15) / 2.22 * sin(i / 2.71) * Wave;
}

float rtan(float i, float Wave) {
    return (sin(i) + sin(2 * i) + sin(3 * i) + 2 * sin(3 * i - 3) + 0.25) / 1.45 * sin(i / 2.71) * Wave;
}

float rcos(float i, float Wave) {
    return (cos(i) + cos(2 * i) + cos(3 * i) + 2 * cos(3 * i - 3) + 0.2) / 1.91 * cos(i / 2.71) * Wave;
}

vec3 wave_render(vec3 position, float waveStrength, float waveSpeed, float waveHeight) {
    float xs = 0.0;
    float ys = 0.0;
    float zs = 0.0;
    xs = rsin((position.x + position.y + waveSpeed) / 2, waveStrength) * -1;
    ys = rtan((position.x + position.y - position.z + waveSpeed) / 2, waveStrength) * waveHeight;
    zs = rcos((position.z + position.y + waveSpeed) / 2, waveStrength) * -1;
    vec4 wavedPos = vec4(position, 1) + vec4(xs / 32, (ys - (waveStrength * (waveHeight * 1.2))) / 32, zs / 32, 0);
    position = wavedPos.xyz;
    return position;
}

vec3 orbital_render(vec3 position, vec3 Position, float GameTime) {
    vec3 blockPos = mod(Position, 1.0) - 0.5;
    position -= blockPos;
    blockPos *= 1.0 + max(0.0, sin(GameTime * 20000.0) - 0.8) * 0.25;
    float thetaX = sin(GameTime * 1000.0) * 4.0;
    float thetaY = GameTime * 1000.0;
    float thetaZ = cos(GameTime * 1000.0) * 4.0;
    mat3 rotX = mat3(vec3(1, 0, 0), vec3(0, cos(thetaX), -sin(thetaX)), vec3(0, sin(thetaX), cos(thetaX)));
    mat3 rotY = mat3(vec3(cos(thetaY), 0, sin(thetaY)), vec3(0, 1, 0), vec3(-sin(thetaY), 0, cos(thetaY)));
    mat3 rotZ = mat3(vec3(cos(thetaZ), -sin(thetaZ), 0), vec3(sin(thetaZ), cos(thetaZ), 0), vec3(0, 0, 1));
    mat3 rot = rotX * rotY * rotZ;
    blockPos = rot * blockPos;
    position += blockPos;
    position.y += 0.07;
    return position;
}

vec3 sway_render(vec3 position, vec3 Position, float GameTime, vec3 ChunkOffset) {
    float lanternTime = (1 + fract(dot(floor(Position), vec3(1))) / 2.0) * GameTime * 1200 + dot(floor(Position), vec3(1)) * 1234.0;
    vec3 newForward = normalize(vec3(sin(lanternTime) * (0.1 * Waving_Objects), sin(lanternTime * 1.61803398875) * (0.1 * Waving_Objects), -1 + sin(lanternTime * 3.14) * (0.1 * Waving_Objects)));
    vec3 relativePos = fract(Position);
    if (relativePos.y > 0.001) {
        relativePos -= vec3(0.5, 1, 0.5);
        vec3 tangent = normalize(cross(vec3(0, 1, 0), newForward));
        vec3 bitangent = cross(newForward, tangent);
        mat3 tbnMatrix = mat3(tangent, bitangent, newForward);
        relativePos = tbnMatrix * relativePos;
        position = floor(Position) + relativePos + vec3(0.5, 1, 0.5) + ChunkOffset;
    }
    return position;
}

vec3 liquid_render(vec3 position, vec3 Position, float GameTime) {
    vec3 offset = vec3(
        sin(position.x + 4000 * GameTime) * cos(GameTime * 300),
        cos(distance(Position.xz, vec2(8, 8)) * 10 + 4000 * GameTime) * 0.8,
        cos(position.z + 4000 * GameTime) * sin(GameTime * 300)
    );
    position += offset / vec3(32.0, 16.0, 32.0);
    return position;
}

float chunkTranslate(vec3 chunkOffset, float fogEnd, mat4 modelViewMat) {
    return pow(max(length((modelViewMat * vec4(chunkOffset.x + 8.0, 0.0, chunkOffset.z + 8.0, 1.0)).xyz) / fogEnd - 1.0, 0.0) * 5.0, 2.0);
}

mat3 rotationMatrix(vec3 axis, float angle) {
    axis = normalize(axis);
    float s = sin(angle);
    float c = cos(angle);
    float oc = 1.0 - c;
    
    return mat3(oc * axis.x * axis.x + c,           oc * axis.x * axis.y - axis.z * s,  oc * axis.z * axis.x + axis.y * s,
                oc * axis.x * axis.y + axis.z * s,  oc * axis.y * axis.y + c,           oc * axis.y * axis.z - axis.x * s,
                oc * axis.z * axis.x - axis.y * s,  oc * axis.y * axis.z + axis.x * s,  oc * axis.z * axis.z + c);
}
