1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrGLEffectMatrix_DEFINED
9#define GrGLEffectMatrix_DEFINED
10
11#include "GrGLEffect.h"
12#include "SkMatrix.h"
13
14class GrTexture;
15
16/**
17 * This is a helper to implement a matrix in a GrGLEffect that operates on incoming coords in the
18 * vertex shader and writes them to an attribute to be used in the fragment shader. When the input
19 * coords in the vertex shader are local coordinates this class accounts for the coord change matrix
20 * communicated via GrDrawEffect. The input coords may also be positions and in this case the coord
21 * change matrix is ignored. The GrGLEffectMatrix will emit different code based on the type of
22 * matrix and thus must contribute to the effect's key.
23 *
24 * This class cannot be used to apply a matrix to coordinates that come in the form of custom vertex
25 * attributes.
26 */
27class GrGLEffectMatrix {
28private:
29    // We specialize the generated code for each of these matrix types.
30    enum MatrixTypes {
31        kIdentity_MatrixType    = 0,
32        kTrans_MatrixType       = 1,
33        kNoPersp_MatrixType     = 2,
34        kGeneral_MatrixType     = 3,
35    };
36    // The key for is made up of a matrix type and a bit that indicates the source of the input
37    // coords.
38    enum {
39        kMatrixTypeKeyBits      = 2,
40        kMatrixTypeKeyMask      = (1 << kMatrixTypeKeyBits) - 1,
41        kPositionCoords_Flag    = (1 << kMatrixTypeKeyBits),
42        kKeyBitsPrivate         = kMatrixTypeKeyBits + 1,
43    };
44
45public:
46
47    typedef GrEffect::CoordsType CoordsType;
48
49    typedef GrGLEffect::EffectKey EffectKey;
50
51    /**
52     * The matrix uses kKeyBits of the effect's EffectKey. A GrGLEffect may place these bits at an
53     * arbitrary shift in its final key. However, when GrGLEffectMatrix::emitCode*() code is called
54     * the relevant bits must be in the lower kKeyBits of the key parameter.
55     */
56    enum {
57        kKeyBits = kKeyBitsPrivate,
58        kKeyMask = (1 << kKeyBits) - 1,
59    };
60
61    GrGLEffectMatrix(CoordsType coordsType)
62        : fUni(GrGLUniformManager::kInvalidUniformHandle)
63        , fCoordsType(coordsType) {
64        GrAssert(GrEffect::kLocal_CoordsType == coordsType ||
65                 GrEffect::kPosition_CoordsType == coordsType);
66        fPrevMatrix = SkMatrix::InvalidMatrix();
67    }
68
69    /**
70     * Generates the key for the portion of the code emitted by this class's emitCode() function.
71     * Pass a texture to make GrGLEffectMatrix automatically adjust for the texture's origin. Pass
72     * NULL when not using the EffectMatrix for a texture lookup, or if the GrGLEffect subclass
73     * wants to handle origin adjustments in some other manner. The coords type param must match the
74     * param that would be used to initialize GrGLEffectMatrix for the generating GrEffect.
75     */
76    static EffectKey GenKey(const SkMatrix& effectMatrix,
77                            const GrDrawEffect&,
78                            CoordsType,
79                            const GrTexture*);
80
81    /**
82     * Emits code to implement the matrix in the VS. A varying is added as an output of the VS and
83     * input to the FS. The varying may be either a vec2f or vec3f depending upon whether
84     * perspective interpolation is required or not. The names of the varying in the VS and FS are
85     * are returned as output parameters and the type of the varying is the return value. The suffix
86     * is an optional parameter that can be used to make all variables emitted by the object
87     * unique within a stage. It is only necessary if multiple GrGLEffectMatrix objects are used by
88     * a GrGLEffect.
89     */
90    GrSLType emitCode(GrGLShaderBuilder*,
91                      EffectKey,
92                      const char** fsCoordName, /* optional */
93                      const char** vsCoordName = NULL,
94                      const char* suffix = NULL);
95
96    /**
97     * This is similar to emitCode except that it performs perspective division in the FS if the
98     * texture coordinates have a w coordinate. The fsCoordName always refers to a vec2f.
99     */
100    void emitCodeMakeFSCoords2D(GrGLShaderBuilder*,
101                                EffectKey,
102                                const char** fsCoordName, /* optional */
103                                const char** vsVaryingName = NULL,
104                                GrSLType* vsVaryingType = NULL,
105                                const char* suffix = NULL);
106    /**
107     * Call from a GrGLEffect's subclass to update the texture matrix. The effectMatrix and texture
108     * params should match those used with GenKey.
109     */
110    void setData(const GrGLUniformManager& uniformManager,
111                 const SkMatrix& effectMatrix,
112                 const GrDrawEffect& drawEffect,
113                 const GrTexture*);
114
115    GrGLUniformManager::UniformHandle fUni;
116    GrSLType                          fUniType;
117    SkMatrix                          fPrevMatrix;
118    CoordsType                        fCoordsType;
119};
120
121#endif
122