/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkNormalBevelSource.h"

#include "SkNormalSource.h"
#include "SkNormalSourcePriv.h"
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

#if SK_SUPPORT_GPU
#include "GrInvariantOutput.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "SkGr.h"

/** \class NormalBevelFP
 *
 *  Fragment processor for the SkNormalBevelSource.
 *
 *  @param bevelType    type of the bevel
 *  @param bevelWidth   width of the bevel in device space
 *  @param bevelHeight  height of the bevel in device space
 */
class NormalBevelFP : public GrFragmentProcessor {
public:
    NormalBevelFP(SkNormalSource::BevelType bevelType, SkScalar bevelWidth, SkScalar bevelHeight)
        : fBevelType(bevelType)
        , fBevelWidth(bevelWidth)
        , fBevelHeight(bevelHeight) {
        this->initClassID<NormalBevelFP>();

        fUsesDistanceVectorField = true;
    }

    class GLSLNormalBevelFP : public GLSLNormalFP {
    public:
        GLSLNormalBevelFP() {
            fPrevWidth = SkFloatToScalar(0.0f);
            fPrevHeight = SkFloatToScalar(0.0f);
        }

        void onEmitCode(EmitArgs& args) override {
            GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
            const NormalBevelFP& fp = args.fFp.cast<NormalBevelFP>();
            GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;

            // Determining necessary uniforms and initializing them
            bool needWidth = true;
            bool needHeight = (fp.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
                               fp.fBevelType == SkNormalSource::BevelType::kRoundedIn);
            bool needNormalized = (fp.fBevelType == SkNormalSource::BevelType::kLinear);

            const char *widthUniName = nullptr;
            if (needWidth) {
                fWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
                                                       kDefault_GrSLPrecision, "Width",
                                                       &widthUniName);
            }

            const char* heightUniName = nullptr;
            if (needHeight) {
                fHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
                                                        kDefault_GrSLPrecision, "Height",
                                                        &heightUniName);
            }

            const char* normalizedWidthUniName = nullptr;
            const char* normalizedHeightUniName = nullptr;
            if (needNormalized) {
                fNormalizedWidthUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                                 kFloat_GrSLType,
                                                                 kDefault_GrSLPrecision,
                                                                 "NormalizedWidth",
                                                                 &normalizedWidthUniName);
                fNormalizedHeightUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                                  kFloat_GrSLType,
                                                                  kDefault_GrSLPrecision,
                                                                  "NormalizedHeight",
                                                                  &normalizedHeightUniName);
            }

            // Here we are splitting the distance vector into length and normalized direction
            fragBuilder->codeAppendf("float dv_length = %s.z;",
                                     fragBuilder->distanceVectorName());
            fragBuilder->codeAppendf("vec2 dv_norm = %s.xy;",
                                     fragBuilder->distanceVectorName());

            // Asserting presence of necessary uniforms
            SkASSERT(widthUniName);

            fragBuilder->codeAppend( "vec3 normal;");
            fragBuilder->codeAppendf("if (dv_length >= %s) {", widthUniName);
            fragBuilder->codeAppend( "    normal = vec3(0.0, 0.0, 1.0);");
            fragBuilder->codeAppend( "} else {");
            this->emitMath(fragBuilder, fp.fBevelType, widthUniName, heightUniName,
                           normalizedWidthUniName, normalizedHeightUniName);
            fragBuilder->codeAppend( "}");
            fragBuilder->codeAppendf("%s = vec4(normal, 0.0);", args.fOutputColor);
        }

        static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
            const NormalBevelFP& fp = proc.cast<NormalBevelFP>();
            b->add32(static_cast<int>(fp.fBevelType));
        }

    protected:
        void setNormalData(const GrGLSLProgramDataManager& pdman,
                           const GrProcessor& proc) override {
            const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();

            // Updating uniform if bevel type requires it and data has changed

            bool needWidth = true;
            bool needHeight = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedOut ||
                               normalBevelFP.fBevelType == SkNormalSource::BevelType::kRoundedIn);
            bool needNormalized = (normalBevelFP.fBevelType == SkNormalSource::BevelType::kLinear);

            bool dirtyWidth = (fPrevWidth  != normalBevelFP.fBevelWidth);
            bool dirtyHeight = (fPrevHeight != normalBevelFP.fBevelHeight);
            bool dirtyNormalized = (dirtyHeight || dirtyWidth);


            if (needWidth && dirtyWidth) {
                pdman.set1f(fWidthUni, normalBevelFP.fBevelWidth);
                fPrevWidth = normalBevelFP.fBevelWidth;
            }
            if (needHeight && dirtyHeight) {
                pdman.set1f(fHeightUni, normalBevelFP.fBevelHeight);
                fPrevHeight = normalBevelFP.fBevelHeight;
            }
            if (needNormalized && dirtyNormalized) {
                SkScalar height = normalBevelFP.fBevelHeight;
                SkScalar width  = normalBevelFP.fBevelWidth;

                SkScalar length = SkScalarSqrt(SkScalarSquare(height) + SkScalarSquare(width));
                pdman.set1f(fNormalizedHeightUni, height/length);
                pdman.set1f(fNormalizedWidthUni, width/length);
            }
        }

        // This method emits the code that calculates the normal orthgonal to the simulated beveled
        // surface. In the comments inside the function, the math involved is described. For this
        // purpose, the d-axis is defined to be the axis co-linear to the distance vector, where the
        // origin is the end of the bevel inside the shape.
        void emitMath(GrGLSLFPFragmentBuilder* fb, SkNormalSource::BevelType type,
                      const char* width, const char* height, const char* normalizedWidth,
                      const char* normalizedHeight) {
            switch (type) {
                case SkNormalSource::BevelType::kLinear:
                    // Asserting presence of necessary uniforms
                    SkASSERT(normalizedHeight);
                    SkASSERT(normalizedWidth);

                    // Because the slope of the bevel is -height/width, the vector
                    // normalized(vec2(height, width)) is the d- and z-components of the normal
                    // vector that is orthogonal to the linear bevel. Multiplying the d-component
                    // to the normalized distance vector splits it into x- and y-components.
                    fb->codeAppendf("normal = vec3(%s * dv_norm, %s);",
                                    normalizedHeight, normalizedWidth);
                    break;
                case SkNormalSource::BevelType::kRoundedOut:
                    // Fall through
                case SkNormalSource::BevelType::kRoundedIn:
                    // Asserting presence of necessary uniforms
                    SkASSERT(height);
                    SkASSERT(width);

                    // Setting the current position in the d-axis to the distance from the end of
                    // the bevel as opposed to the beginning if the bevel is rounded in, essentially
                    // flipping the bevel calculations.
                    if ( type == SkNormalSource::BevelType::kRoundedIn ) {
                        fb->codeAppendf("float currentPos_d = %s - dv_length;", width);
                    } else if (type == SkNormalSource::BevelType::kRoundedOut) {
                        fb->codeAppendf("float currentPos_d = dv_length;");
                    }

                    fb->codeAppendf("float rootDOverW = sqrt(currentPos_d/%s);", width);

                    // Calculating the d- and z-components of the normal, where 'd' is the axis
                    // co-linear to the distance vector. Equation was derived from the formula for
                    // a bezier curve by solving the parametric equation for d(t) and z(t), then
                    // with those, calculate d'(t), z'(t) and t(d), and from these, d'(d) and z'(d).
                    // z'(d)/d'(d) results in the slope of the bevel at d, so we construct an
                    // orthogonal vector of slope -d'(d)/z'(d) and length 1.
                    fb->codeAppendf("vec2 unnormalizedNormal_dz = vec2(%s*(1.0-rootDOverW), "
                                                                       "%s*rootDOverW);",
                                    height, width);
                    fb->codeAppendf("vec2 normal_dz = normalize(unnormalizedNormal_dz);");

                    // Multiplying the d-component to the normalized distance vector splits it into
                    // x- and y-components.
                    fb->codeAppendf("normal = vec3(normal_dz.x*dv_norm, normal_dz.y);");

                    break;
                default:
                    SkDEBUGFAIL("Invalid bevel type passed to emitMath");
            }
        }

    private:
        SkScalar fPrevWidth;
        GrGLSLProgramDataManager::UniformHandle fWidthUni;

        SkScalar fPrevHeight;
        GrGLSLProgramDataManager::UniformHandle fHeightUni;

        // width / length(<width,height>)
        GrGLSLProgramDataManager::UniformHandle fNormalizedWidthUni;
        // height / length(<width,height>)
        GrGLSLProgramDataManager::UniformHandle fNormalizedHeightUni;
    };

    void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
        GLSLNormalBevelFP::GenKey(*this, caps, b);
    }

    const char* name() const override { return "NormalBevelFP"; }

    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
        inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput);
    }

private:
    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalBevelFP; }

    bool onIsEqual(const GrFragmentProcessor& proc) const override {
        const NormalBevelFP& normalBevelFP = proc.cast<NormalBevelFP>();
        return fBevelType   == normalBevelFP.fBevelType &&
               fBevelWidth  == normalBevelFP.fBevelWidth &&
               fBevelHeight == normalBevelFP.fBevelHeight;
    }

    SkNormalSource::BevelType fBevelType;
    SkScalar fBevelWidth;
    SkScalar fBevelHeight;
};

sk_sp<GrFragmentProcessor> SkNormalBevelSourceImpl::asFragmentProcessor(
        const SkShader::AsFPArgs& args) const {

    // This assumes a uniform scale. Anisotropic scaling might not be handled gracefully.
    SkScalar maxScale = args.fViewMatrix->getMaxScale();

    // Providing device-space width and height
    return sk_make_sp<NormalBevelFP>(fType, maxScale * fWidth, maxScale * fHeight);
}

#endif // SK_SUPPORT_GPU

////////////////////////////////////////////////////////////////////////////

SkNormalBevelSourceImpl::Provider::Provider() {}

SkNormalBevelSourceImpl::Provider::~Provider() {}

SkNormalSource::Provider* SkNormalBevelSourceImpl::asProvider(const SkShader::ContextRec &rec,
                                                              void *storage) const {
    return new (storage) Provider();
}

size_t SkNormalBevelSourceImpl::providerSize(const SkShader::ContextRec&) const {
    return sizeof(Provider);
}

// TODO Implement feature for the CPU pipeline
void SkNormalBevelSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[],
                                                     int count) const {
    for (int i = 0; i < count; i++) {
        output[i] = {0.0f, 0.0f, 1.0f};
    }
}

////////////////////////////////////////////////////////////////////////////////

sk_sp<SkFlattenable> SkNormalBevelSourceImpl::CreateProc(SkReadBuffer& buf) {

    auto type = static_cast<SkNormalSource::BevelType>(buf.readInt());
    SkScalar width = buf.readScalar();
    SkScalar height = buf.readScalar();

    return sk_make_sp<SkNormalBevelSourceImpl>(type, width, height);
}

void SkNormalBevelSourceImpl::flatten(SkWriteBuffer& buf) const {
    this->INHERITED::flatten(buf);

    buf.writeInt(static_cast<int>(fType));
    buf.writeScalar(fWidth);
    buf.writeScalar(fHeight);
}

////////////////////////////////////////////////////////////////////////////

sk_sp<SkNormalSource> SkNormalSource::MakeBevel(BevelType type, SkScalar width, SkScalar height) {
    /* TODO make sure these checks are tolerant enough to account for loss of conversion when GPUs
       use 16-bit float types. We don't want to assume stuff is non-zero on the GPU and be wrong.*/
    SkASSERT(width > 0.0f && !SkScalarNearlyZero(width));
    if (SkScalarNearlyZero(height)) {
        return SkNormalSource::MakeFlat();
    }

    return sk_make_sp<SkNormalBevelSourceImpl>(type, width, height);
}
