blob: f852aae879b1f20f322386a8885e610a01baa6a9 [file] [log] [blame]
/*
* 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<<ABITS;
int k2=HSCALE<<ABITS;
int k3=1<<(ABITS-1);
int rr=0;
int rg=0;
int rb=0;
short cv = hsv.x;
short cs = hsv.y;
short ch = hsv.z;
// set chroma and min component value m
//chroma = ( cv * cs )/k1;
//m = cv - chroma;
m = ((int)cv*(k1 - (int)cs ))/k1;
// chroma == 0 <-> 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);
}