1
2/*
3 * Copyright 2015 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkLightingShader_DEFINED
11#define SkLightingShader_DEFINED
12
13#include "SkFlattenable.h"
14#include "SkLight.h"
15#include "SkShader.h"
16#include "SkTDArray.h"
17
18class SkBitmap;
19class SkMatrix;
20
21class SK_API SkLightingShader {
22public:
23    class Lights  : public SkRefCnt {
24    public:
25        class Builder {
26        public:
27            Builder(const SkLight lights[], int numLights)
28                : fLights(new Lights(lights, numLights)) {}
29
30            Builder() : fLights(new Lights) {}
31
32            // TODO: limit the number of lights here or just ignore those
33            // above some maximum?
34            void add(const SkLight& light) {
35                if (fLights) {
36                    *fLights->fLights.push() = light;
37                }
38            }
39
40            const Lights* finish() {
41                return fLights.detach();
42            }
43
44        private:
45            SkAutoTUnref<Lights> fLights;
46        };
47
48        int numLights() const {
49            return fLights.count();
50        }
51
52        const SkLight& light(int index) const {
53            return fLights[index];
54        }
55
56    private:
57        Lights() {}
58        Lights(const SkLight lights[], int numLights) : fLights(lights, numLights) {}
59
60        SkTDArray<SkLight> fLights;
61
62        typedef SkRefCnt INHERITED;
63    };
64
65    /** Returns a shader that lights the diffuse and normal maps with a single light.
66
67        It returns a shader with a reference count of 1.
68        The caller should decrement the shader's reference count when done with the shader.
69        It is an error for count to be < 2.
70        @param  diffuse     the diffuse bitmap
71        @param  normal      the normal map
72        @param  light       the light applied to the normal map
73        @param  ambient     the linear (unpremul) ambient light color. Range is 0..1/channel.
74        @param  localMatrix the matrix mapping the textures to the dest rect
75
76        nullptr will be returned if:
77            either 'diffuse' or 'normal' are empty
78            either 'diffuse' or 'normal' are too big (> 65535 on a side)
79            'diffuse' and 'normal' aren't the same size
80
81        The lighting equation is currently:
82            result = LightColor * DiffuseColor * (Normal * LightDir) + AmbientColor
83
84        The normal map is currently assumed to be an 8888 image where the normal at a texel
85        is retrieved by:
86            N.x = R-127;
87            N.y = G-127;
88            N.z = B-127;
89            N.normalize();
90        The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is
91        (127, 127, 0).
92    */
93    static SkShader* Create(const SkBitmap& diffuse, const SkBitmap& normal,
94                            const Lights* lights, const SkVector& invNormRotation,
95                            const SkMatrix* diffLocalMatrix, const SkMatrix* normLocalMatrix);
96
97    SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
98};
99
100#endif
101