1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ip.rsh"
18#pragma rs_fp_relaxed
19
20static float shadowFilterMap[] = {
21    -0.00591f,  0.0001f,
22     1.16488f,  0.01668f,
23    -0.18027f, -0.06791f,
24    -0.12625f,  0.09001f,
25     0.15065f, -0.03897f
26};
27
28static float poly[] = {
29    0.f, 0.f,
30    0.f, 0.f,
31    0.f
32};
33
34static const int ABITS = 4;
35static const int HSCALE = 256;
36static const int k1=255 << ABITS;
37static const int k2=HSCALE << ABITS;
38
39static float fastevalPoly(float *poly,int n, float x){
40
41    float f =x;
42    float sum = poly[0]+poly[1]*f;
43    int i;
44    for (i = 2; i < n; i++) {
45        f*=x;
46        sum += poly[i]*f;
47    }
48    return sum;
49}
50
51static ushort3 rgb2hsv( uchar4 rgb)
52{
53    int iMin,iMax,chroma;
54
55    int ri = rgb.r;
56    int gi = rgb.g;
57    int bi = rgb.b;
58    short rv,rs,rh;
59
60    if (ri > gi) {
61        iMax = max (ri, bi);
62        iMin = min (gi, bi);
63    } else {
64        iMax = max (gi, bi);
65        iMin = min (ri, bi);
66    }
67
68    chroma = iMax - iMin;
69    // set value
70    rv = (short)( iMax << ABITS);
71
72    // set saturation
73    if (rv == 0)
74        rs = 0;
75    else
76        rs = (short)((k1*chroma)/iMax);
77
78    // set hue
79    if (rs == 0)
80        rh = 0;
81    else {
82        if ( ri == iMax ) {
83            rh  = (short)( (k2*(6*chroma+gi - bi))/(6*chroma));
84            if (rh >= k2) rh -= k2;
85        } else if (gi  == iMax)
86            rh  = (short)( (k2*(2*chroma+bi - ri ))/(6*chroma));
87        else // (bi == iMax )
88                    rh  = (short)( (k2*(4*chroma+ri - gi ))/(6*chroma));
89    }
90
91    ushort3 out;
92    out.x = rv;
93    out.y = rs;
94    out.z = rh;
95    return out;
96}
97
98static uchar4 hsv2rgb(ushort3 hsv)
99{
100    int ABITS = 4;
101    int HSCALE = 256;
102    int m;
103    int H,X,ih,is,iv;
104    int k1=255<<ABITS;
105    int k2=HSCALE<<ABITS;
106    int k3=1<<(ABITS-1);
107    int rr=0;
108    int rg=0;
109    int rb=0;
110    short cv = hsv.x;
111    short cs = hsv.y;
112    short ch = hsv.z;
113
114    // set chroma and min component value m
115    //chroma = ( cv * cs )/k1;
116    //m = cv - chroma;
117    m = ((int)cv*(k1 - (int)cs ))/k1;
118
119    // chroma  == 0 <-> cs == 0 --> m=cv
120    if (cs == 0) {
121        rb = ( rg = ( rr =( cv >> ABITS) ));
122    } else {
123        ih=(int)ch;
124        is=(int)cs;
125        iv=(int)cv;
126
127        H = (6*ih)/k2;
128        X = ((iv*is)/k2)*(k2- abs(6*ih- 2*(H>>1)*k2 - k2)) ;
129
130        // removing additional bits --> unit8
131        X=( (X+iv*(k1 - is ))/k1 + k3 ) >> ABITS;
132        m=m >> ABITS;
133
134        // ( chroma + m ) --> cv ;
135        cv=(short) (cv >> ABITS);
136        switch (H) {
137        case 0:
138            rr = cv;
139            rg = X;
140            rb = m;
141            break;
142        case 1:
143            rr = X;
144            rg = cv;
145            rb = m;
146            break;
147        case 2:
148            rr = m;
149            rg = cv;
150            rb = X;
151            break;
152        case 3:
153            rr = m;
154            rg = X;
155            rb = cv;
156            break;
157        case 4:
158            rr = X;
159            rg = m;
160            rb = cv;
161            break;
162        case 5:
163            rr = cv;
164            rg = m ;
165            rb = X;
166            break;
167        }
168    }
169
170    uchar4 rgb;
171
172    rgb.r =  rr;
173    rgb.g =  rg;
174    rgb.b =  rb;
175
176    return rgb;
177}
178
179void prepareShadows(float scale) {
180    float s = (scale>=0) ? scale : scale / 5.f;
181    for (int i = 0; i < 5; i++) {
182        poly[i] = fastevalPoly(shadowFilterMap+i*2,2 , s);
183    }
184}
185
186uchar4 RS_KERNEL shadowsKernel(uchar4 in) {
187    ushort3 hsv = rgb2hsv(in);
188    float v = (fastevalPoly(poly, 5, hsv.x * (1.f / 4080.f)) * 4080.f);
189    hsv.x = (unsigned short) clamp(v, 0.f, 4080.f);
190    return hsv2rgb(hsv);
191}
192