/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ip.rsh" #pragma rs_fp_relaxed static float shadowFilterMap[] = { -0.00591f, 0.0001f, 1.16488f, 0.01668f, -0.18027f, -0.06791f, -0.12625f, 0.09001f, 0.15065f, -0.03897f }; static float poly[] = { 0.f, 0.f, 0.f, 0.f, 0.f }; static const int ABITS = 4; static const int HSCALE = 256; static const int k1=255 << ABITS; static const int k2=HSCALE << ABITS; static float fastevalPoly(float *poly,int n, float x){ float f =x; float sum = poly[0]+poly[1]*f; int i; for (i = 2; i < n; i++) { f*=x; sum += poly[i]*f; } return sum; } static ushort3 rgb2hsv( uchar4 rgb) { int iMin,iMax,chroma; int ri = rgb.r; int gi = rgb.g; int bi = rgb.b; short rv,rs,rh; if (ri > gi) { iMax = max (ri, bi); iMin = min (gi, bi); } else { iMax = max (gi, bi); iMin = min (ri, bi); } chroma = iMax - iMin; // set value rv = (short)( iMax << ABITS); // set saturation if (rv == 0) rs = 0; else rs = (short)((k1*chroma)/iMax); // set hue if (rs == 0) rh = 0; else { if ( ri == iMax ) { rh = (short)( (k2*(6*chroma+gi - bi))/(6*chroma)); if (rh >= k2) rh -= k2; } else if (gi == iMax) rh = (short)( (k2*(2*chroma+bi - ri ))/(6*chroma)); else // (bi == iMax ) rh = (short)( (k2*(4*chroma+ri - gi ))/(6*chroma)); } ushort3 out; out.x = rv; out.y = rs; out.z = rh; return out; } static uchar4 hsv2rgb(ushort3 hsv) { int ABITS = 4; int HSCALE = 256; int m; int H,X,ih,is,iv; int k1=255< cs == 0 --> m=cv if (cs == 0) { rb = ( rg = ( rr =( cv >> ABITS) )); } else { ih=(int)ch; is=(int)cs; iv=(int)cv; H = (6*ih)/k2; X = ((iv*is)/k2)*(k2- abs(6*ih- 2*(H>>1)*k2 - k2)) ; // removing additional bits --> unit8 X=( (X+iv*(k1 - is ))/k1 + k3 ) >> ABITS; m=m >> ABITS; // ( chroma + m ) --> cv ; cv=(short) (cv >> ABITS); switch (H) { case 0: rr = cv; rg = X; rb = m; break; case 1: rr = X; rg = cv; rb = m; break; case 2: rr = m; rg = cv; rb = X; break; case 3: rr = m; rg = X; rb = cv; break; case 4: rr = X; rg = m; rb = cv; break; case 5: rr = cv; rg = m ; rb = X; break; } } uchar4 rgb; rgb.r = rr; rgb.g = rg; rgb.b = rb; return rgb; } void prepareShadows(float scale) { float s = (scale>=0) ? scale : scale / 5.f; for (int i = 0; i < 5; i++) { poly[i] = fastevalPoly(shadowFilterMap+i*2,2 , s); } } uchar4 RS_KERNEL shadowsKernel(uchar4 in) { ushort3 hsv = rgb2hsv(in); float v = (fastevalPoly(poly, 5, hsv.x * (1.f / 4080.f)) * 4080.f); hsv.x = (unsigned short) clamp(v, 0.f, 4080.f); return hsv2rgb(hsv); }