1/*
2 * Copyright 2013 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 GrCoordTransform_DEFINED
9#define GrCoordTransform_DEFINED
10
11#include "GrEffect.h"
12#include "SkMatrix.h"
13#include "GrTexture.h"
14#include "GrTypes.h"
15
16/**
17 * Coordinates available to GrEffect subclasses for requesting transformations. Transformed
18 * coordinates are made available in the the portion of fragment shader emitted by the effect.
19 */
20enum GrCoordSet {
21    /**
22     * The user-space coordinates that map to the fragment being rendered. These coords account for
23     * any change of coordinate system done on the CPU by GrContext before rendering, and also are
24     * correct for draws that take explicit local coords rather than inferring them from the
25     * primitive's positions (e.g. drawVertices). These are usually the coords a GrEffect wants.
26     */
27    kLocal_GrCoordSet,
28
29    /**
30     * The actual vertex position. Note that GrContext may not draw using the original view matrix
31     * specified by the caller, as it may have transformed vertices into another space. These are
32     * usually not the coordinates a GrEffect wants.
33     */
34    kPosition_GrCoordSet
35};
36
37/**
38 * A class representing a linear transformation from one of the built-in coordinate sets (local or
39 * position). GrEffects just define these transformations, and the framework does the rest of the
40 * work to make the transformed coordinates available in their fragment shader.
41 */
42class GrCoordTransform : SkNoncopyable {
43public:
44    GrCoordTransform() { SkDEBUGCODE(fInEffect = false); }
45
46    /**
47     * Create a transformation that maps [0, 1] to a texture's boundaries.
48     */
49    GrCoordTransform(GrCoordSet sourceCoords, const GrTexture* texture) {
50        SkDEBUGCODE(fInEffect = false);
51        this->reset(sourceCoords, texture);
52    }
53
54    /**
55     * Create a transformation from a matrix. The optional texture parameter is used to infer if the
56     * framework should internally do a y reversal to account for it being upside down by Skia's
57     * coord convention.
58     */
59    GrCoordTransform(GrCoordSet sourceCoords, const SkMatrix& m, const GrTexture* texture = NULL) {
60        SkDEBUGCODE(fInEffect = false);
61        this->reset(sourceCoords, m, texture);
62    }
63
64    void reset(GrCoordSet sourceCoords, const GrTexture* texture) {
65        SkASSERT(!fInEffect);
66        SkASSERT(NULL != texture);
67        this->reset(sourceCoords, GrEffect::MakeDivByTextureWHMatrix(texture), texture);
68    }
69
70    void reset(GrCoordSet sourceCoords, const SkMatrix& m, const GrTexture* texture = NULL) {
71        SkASSERT(!fInEffect);
72        fSourceCoords = sourceCoords;
73        fMatrix = m;
74        fReverseY = NULL != texture && kBottomLeft_GrSurfaceOrigin == texture->origin();
75    }
76
77    GrCoordTransform& operator= (const GrCoordTransform& other) {
78        SkASSERT(!fInEffect);
79        fSourceCoords = other.fSourceCoords;
80        fMatrix = other.fMatrix;
81        fReverseY = other.fReverseY;
82        return *this;
83    }
84
85    /**
86     * Access the matrix for editing. Note, this must be done before adding the transform to an
87     * effect, since effects are immutable.
88     */
89    SkMatrix* accessMatrix() {
90        SkASSERT(!fInEffect);
91        return &fMatrix;
92    }
93
94    bool operator== (const GrCoordTransform& other) const {
95        return fSourceCoords == other.fSourceCoords &&
96               fMatrix.cheapEqualTo(other.fMatrix) &&
97               fReverseY == other.fReverseY;
98    }
99
100    GrCoordSet sourceCoords() const { return fSourceCoords; }
101    const SkMatrix& getMatrix() const { return fMatrix; }
102    bool reverseY() const { return fReverseY; }
103
104private:
105    GrCoordSet fSourceCoords;
106    SkMatrix   fMatrix;
107    bool       fReverseY;
108
109    typedef SkNoncopyable INHERITED;
110
111#ifdef SK_DEBUG
112public:
113    void setInEffect() const { fInEffect = true; }
114private:
115    mutable bool fInEffect;
116#endif
117};
118
119#endif
120