#version 120

/*
 Copyright (C) 2010-2017 Kristian Duske
 
 This file is part of TrenchBroom.
 
 TrenchBroom is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 TrenchBroom is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
 */

float getSoftStripes(float value, float gridSize, float stripeSize) {
    float mainVal = value * gridSize;
    float filterWidth = fwidth(value);
    float edge = filterWidth * gridSize * 2.0;
    
    // major line shading, currently set to place a major line every 64 units
    float mValue = 1.0 / (64.0 * gridSize);
    float triMajor = abs(2.0 * fract(mainVal * mValue) - 1.0);
    float isMajor = step(1.0 - mValue, triMajor);
    
    float outIntensity = isMajor * 0.7 + 0.85; // tweak intensities here
    float sSize = stripeSize;
    
    float triangle = abs(2.0 * fract(mainVal) - 1.0);
    return smoothstep(sSize - edge, sSize + edge, triangle) * outIntensity;
}

/**
 * Draws two overlaid grids
 * 
 * @param inCoords fragment coordinates (TODO: document units)
 * @param gridRatio the reciprocal of the first grid size, e.g. (1/16) for a 16 unit grid
 * @param gridRatio2 the reciprocal of the second grid size, e.g. (1/16) for a 16 unit grid
 * @param lineWidth the line width (TODO: document units)
 * @param gridBlend the fraction of the two grids to draw, between 0 and 1, 
 *                  where 0.0 means 100% of grid one, and 1.0 means 100% of grid two.
 */
float gridLinesSoft(vec2 inCoords, float gridRatio, float gridRatio2, float lineWidth, float gridBlend) {
    float stripeRatio = lineWidth * gridRatio;
    float stripeRatio2 = lineWidth * gridRatio2;
    float stripeSize = 1.0 - stripeRatio;
    float stripeSize2 = 1.0 - stripeRatio2;
    
    float theGrid, nextGrid;
    
    theGrid = getSoftStripes(inCoords.x, gridRatio, stripeSize);
    theGrid = max(theGrid, getSoftStripes(inCoords.y, gridRatio, stripeSize));
    nextGrid = getSoftStripes(inCoords.x, gridRatio2, stripeSize2);
    nextGrid = max(nextGrid, getSoftStripes(inCoords.y, gridRatio2, stripeSize2));
    
    theGrid = mix(theGrid, nextGrid, gridBlend);
    
    return theGrid * 0.5;
}

/**
 * Given a valid grid size, returns the next larger one.
 */
float gridNextLarger(float size) {
    return 2.0 * size;
}

/**
 * Given any size, finds the next smaller size that is a proper grid size.
 * Returns the input unmodified if it's already a grid size.
 */
float gridFloor(float size) {
    return exp2(floor(log2(size)));
}

/*
 * Computes the grid for the current fragment with the given parameters.
 *
 * @param coords the coordinates of the fragment in world space (same units as gridSize)
 * @param normal the normal vector of the fragment
 * @param gridSize the actual size of the grid (e.g. 16, 32, 64, etc.)
 * @param minGridSize the minimal grid size to render (to fade out smaller grids to prevent moire etc.)
 * @param lineWidthFactor a factor for the line width of the grid
 *
 * @return opacity of the grid line to draw on this fragment, in [0..1]
 */
float grid(vec3 coords, vec3 normal, float gridSize, float minGridSize, float lineWidthFactor) {
    float lineWidth = (gridSize < 1.0 ? (1.0 / 32.0)
                       : (gridSize < 4.0 ? 0.25 : 0.5)) * lineWidthFactor;

    // magic number to make the grid fade sooner, preventing aliasing
    float minGridSizeToRender = minGridSize * 2.0;

    float baseGridSize = gridFloor(minGridSizeToRender);
    if (gridSize > baseGridSize) {
        baseGridSize = gridSize;
    }
    float nextGridSize = gridNextLarger(baseGridSize);
    
    // This is 0 if we want to render just baseGridSize, and 1 if we want to fully render at nextGridSize
    float gridBlend = smoothstep(baseGridSize, nextGridSize, minGridSizeToRender);

    float gridRatio = 1.0 / baseGridSize;
    float gridRatio2 = 1.0 / nextGridSize;
    
    vec2 baseCoords; // coordinates used for overlay creation
    
    if (abs(normal.x) > abs(normal.y)) {
        if (abs(normal.x) > abs(normal.z))
            baseCoords = coords.yz;
        else
            baseCoords = coords.xy;
    } else if (abs(normal.y) > abs(normal.z)) {
        baseCoords = coords.xz;
    } else {
        baseCoords = coords.xy;
    }

    return gridLinesSoft(baseCoords, gridRatio, gridRatio2, lineWidth, gridBlend);
}
