summaryrefslogtreecommitdiff
path: root/src/modules/evas/engines/software_generic/filters
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2017-01-17 21:00:36 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2017-04-14 11:26:42 +0900
commit1b95d22c2c48f5ba23268dd917fa75524102ef7a (patch)
treed63dd592e79c3f18a63fb46b7d10c989b21da8dc /src/modules/evas/engines/software_generic/filters
parentb56a788e96fc26c72b38b3137d586bdd78521740 (diff)
evas filters: Move bump to software generic (6/8)
Diffstat (limited to 'src/modules/evas/engines/software_generic/filters')
-rw-r--r--src/modules/evas/engines/software_generic/filters/evas_engine_filter.h1
-rw-r--r--src/modules/evas/engines/software_generic/filters/evas_filter_bump.c409
2 files changed, 410 insertions, 0 deletions
diff --git a/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h b/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h
index ee26a0fa30..31a326cc50 100644
--- a/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h
+++ b/src/modules/evas/engines/software_generic/filters/evas_engine_filter.h
@@ -5,6 +5,7 @@
5#include "draw.h" 5#include "draw.h"
6 6
7Evas_Filter_Apply_Func eng_filter_blend_func_get(Evas_Filter_Command *cmd); 7Evas_Filter_Apply_Func eng_filter_blend_func_get(Evas_Filter_Command *cmd);
8Evas_Filter_Apply_Func eng_filter_bump_func_get(Evas_Filter_Command *cmd);
8Evas_Filter_Apply_Func eng_filter_curve_func_get(Evas_Filter_Command *cmd); 9Evas_Filter_Apply_Func eng_filter_curve_func_get(Evas_Filter_Command *cmd);
9Evas_Filter_Apply_Func eng_filter_displace_func_get(Evas_Filter_Command *cmd); 10Evas_Filter_Apply_Func eng_filter_displace_func_get(Evas_Filter_Command *cmd);
10Evas_Filter_Apply_Func eng_filter_fill_func_get(Evas_Filter_Command *cmd); 11Evas_Filter_Apply_Func eng_filter_fill_func_get(Evas_Filter_Command *cmd);
diff --git a/src/modules/evas/engines/software_generic/filters/evas_filter_bump.c b/src/modules/evas/engines/software_generic/filters/evas_filter_bump.c
new file mode 100644
index 0000000000..3b33c209b4
--- /dev/null
+++ b/src/modules/evas/engines/software_generic/filters/evas_filter_bump.c
@@ -0,0 +1,409 @@
1/* Simple bump map algorithms for the software engine */
2
3#include "evas_engine_filter.h"
4#include <math.h>
5
6#ifdef CLAMP
7# undef CLAMP
8#endif
9#define CLAMP(a,b,c) MIN(MAX((b),(a)),(c))
10
11#define DEFAULT_ZANGLE 45.f
12
13static Eina_Bool _bump_map_cpu_alpha_alpha(Evas_Filter_Command *cmd);
14static Eina_Bool _bump_map_cpu_alpha_rgba(Evas_Filter_Command *cmd);
15
16Evas_Filter_Apply_Func
17eng_filter_bump_func_get(Evas_Filter_Command *cmd)
18{
19 int w, h;
20
21 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd, NULL);
22 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->input, NULL);
23 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->mask, NULL);
24 EINA_SAFETY_ON_NULL_RETURN_VAL(cmd->output, NULL);
25 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->input != cmd->output, NULL);
26
27 w = cmd->input->w;
28 h = cmd->input->h;
29 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->output->w == w, NULL);
30 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->output->h == h, NULL);
31 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->mask->w == w, NULL);
32 EINA_SAFETY_ON_FALSE_RETURN_VAL(cmd->mask->h == h, NULL);
33
34 // FIXME: Bump map support is not implemented for RGBA input!
35
36 if (cmd->output->alpha_only)
37 return _bump_map_cpu_alpha_alpha;
38 else
39 return _bump_map_cpu_alpha_rgba;
40}
41
42static void
43_phong_alpha_generate(uint8_t *phong, uint8_t dark, uint8_t color, uint8_t white,
44 float sf)
45{
46 int x, y;
47
48 // FIXME: Flat surfaces should be of color COLOR when compensate is set
49 // FIXME: Include white in the computation for specular light
50 (void) white;
51 (void) sf;
52
53 /*
54 float3 lightDir = light.position - pos3D; //3D position in space of the surface
55 float distance = length( lightDir );
56 lightDir = lightDir / distance; // = normalize( lightDir );
57 distance = distance * distance; //This line may be optimised using Inverse square root
58
59 //Intensity of the diffuse light. Saturate to keep within the 0-1 range.
60 float NdotL = dot( normal, lightDir );
61 float intensity = saturate( NdotL );
62
63 // Calculate the diffuse light factoring in light color, power and the attenuation
64 OUT.Diffuse = intensity * light.diffuseColor * light.diffusePower / distance;
65
66 //Calculate the half vector between the light vector and the view vector.
67 //This is faster than calculating the actual reflective vector.
68 float3 H = normalize( lightDir + viewDir );
69
70 //Intensity of the specular light
71 float NdotH = dot( normal, H );
72 intensity = pow( saturate( NdotH ), specularHardness );
73
74 //Sum up the specular light factoring
75 OUT.Specular = intensity * light.specularColor * light.specularPower / distance;
76 */
77
78 for (y = 0; y < 256; y++)
79 for (x = 0; x < 256; x++)
80 {
81 float dx = (127.5 - x);
82 float dy = (127.5 - y);
83 float dist = sqrt(dx*dx + dy*dy) * 2.;
84 int diff = dark + MAX(255 - dist, 0) * (color - dark) / 255;
85 int spec = 0; // TODO
86 phong[x + (y << 8)] = MIN(MAX(diff + spec, 0), 255);
87 }
88}
89
90static Eina_Bool
91_bump_map_cpu_alpha_alpha(Evas_Filter_Command *cmd)
92{
93 uint8_t *src_map, *map_map, *dst_map;
94 uint8_t *src, *map, *dst, *map_y1, *map_y2;
95 uint8_t dark, color, white;
96 uint8_t *phong = NULL;
97 Eina_Bool ret = EINA_FALSE;
98 int x, y, w, h, lx, ly;
99 unsigned int ss, ms, ds, slen, dlen, mlen;
100 float xyangle, zangle, sf, lxy;
101
102 w = cmd->input->w;
103 h = cmd->input->h;
104 EINA_SAFETY_ON_FALSE_RETURN_VAL(w > 2 && h > 2, EINA_FALSE);
105
106 src_map = src = _buffer_map_all(cmd->input->buffer, &slen, E_READ, E_ALPHA, &ss);
107 map_map = map = _buffer_map_all(cmd->mask->buffer, &mlen, E_READ, E_ALPHA, &ms);
108 dst_map = dst = _buffer_map_all(cmd->output->buffer, &dlen, E_WRITE, E_ALPHA, &ds);
109 EINA_SAFETY_ON_FALSE_GOTO(src && dst && map, end);
110
111 xyangle = cmd->bump.xyangle;
112 zangle = cmd->bump.zangle;
113 sf = cmd->bump.specular_factor;
114
115 dark = cmd->bump.dark >> 24;
116 white = cmd->bump.white >> 24;
117 color = cmd->bump.color >> 24;
118
119 // Convenience for alpha output only
120 if ((!dark && !white && !color) ||
121 (dark == 0xff && white == 0xff && color == 0xff))
122 {
123 INF("Bump colors are all 0 or 255. Using low byte instead of alpha.");
124 dark = cmd->bump.dark & 0xff;
125 white = cmd->bump.white & 0xff;
126 color = cmd->bump.color & 0xff;
127 }
128
129 // Compute appropriate lx, ly
130 if (fabsf(zangle) >= 90.f)
131 {
132 WRN("Z angle was defined as %.0f, out of range. Defaults to %.0f.",
133 zangle, DEFAULT_ZANGLE);
134 zangle = DEFAULT_ZANGLE;
135 }
136
137 lxy = sin(fabs(zangle * M_PI / 180.));
138 lx = (int) (40.f * (lxy + 1.0) * cos(xyangle * M_PI / 180.));
139 ly = (int) (40.f * (lxy + 1.0) * sin(xyangle * M_PI / 180.));
140 INF("Using light vector (%d,%d)", lx, ly);
141
142 // Generate light table
143 phong = malloc(256 * 256 * sizeof(*phong));
144 EINA_SAFETY_ON_NULL_GOTO(phong, end);
145 _phong_alpha_generate(phong, dark, color, white, sf);
146
147 for (y = 0; y < h; y++)
148 {
149 int gx, gy, vx, vy;
150
151 if (!y)
152 {
153 map_y1 = map;
154 map_y2 = map + w;
155 }
156 else if (y == (h - 1))
157 {
158 map_y1 = map - w;
159 map_y2 = map;
160 }
161 else
162 {
163 map_y1 = map - w;
164 map_y2 = map + w;
165 }
166
167 // x = 0
168 gx = (map[1] - map[0]) / 2;
169 gy = (*map_y2 - *map_y1) / 2;
170 vx = gx + lx + 127;
171 vy = (-gy) + ly + 127;
172
173 //printf("dx,dy: %d,%d, lx,ly: %d,%d, vx,vy: %d,%d\n", gx, gy, lx, ly, vx, vy);
174
175 if ((vx & 0xFF00) || (vy & 0xFF00))
176 *dst = *src * dark;
177 else
178 *dst = (*src * phong[(vy << 8) + vx]) >> 8;
179
180 dst++, src++, map_y1++, map_y2++;
181 for (x = 1; x < (w - 1); x++, map++, map_y1++, map_y2++, src++, dst++)
182 {
183 // note: map is one pixel left of (x,y)
184
185 if (!*src)
186 {
187 *dst = 0;
188 continue;
189 }
190
191 // compute gradient (gx, gy). this gives us the normal vector
192 gx = (map[2] - map[0]) / 2;
193 gy = (*map_y2 - *map_y1) / 2;
194
195 // compute halfway vector between light and gradient vectors
196 vx = gx + lx + 127;
197 vy = (-gy) + ly + 127;
198
199 // take light from the phong table
200 if ((vx & 0xFF00) || (vy & 0xFF00))
201 *dst = *src * dark;
202 else
203 *dst = (*src * phong[(vy << 8) + vx]) >> 8;
204 }
205
206 // x = (w - 1)
207 gx = (map[1] - map[0]) / 2;
208 gy = (*map_y2 - *map_y1) / 2;
209 vx = gx + lx + 127;
210 vy = (-gy) + ly + 127;
211
212 if ((vx & 0xFF00) || (vy & 0xFF00))
213 *dst = *src * dark;
214 else
215 *dst = (*src * phong[(vy << 8) + vx]) >> 8;
216
217 map += 2;
218 dst++;
219 src++;
220 }
221
222 ret = EINA_TRUE;
223
224end:
225 ector_buffer_unmap(cmd->input->buffer, src_map, slen);
226 ector_buffer_unmap(cmd->mask->buffer, map_map, mlen);
227 ector_buffer_unmap(cmd->output->buffer, dst_map, dlen);
228 free(phong);
229 return ret;
230}
231
232static Eina_Bool
233_bump_map_cpu_alpha_rgba(Evas_Filter_Command *cmd)
234{
235 uint8_t *src_map, *map_map;
236 uint8_t *src, *map, *map_y1, *map_y2;
237 uint32_t *dst, *dst_map;
238 uint32_t dark, color, white, col;
239 Eina_Bool compensate, ret = EINA_FALSE;
240 int x, y, w, h, lx, ly, lz, gz, NL, diffusion, gzlz, gz2;
241 unsigned int ss, ms, ds, slen, dlen, mlen;
242 double xyangle, zangle, sf, lxy, elevation;
243
244 w = cmd->input->w;
245 h = cmd->input->h;
246 EINA_SAFETY_ON_FALSE_RETURN_VAL(w > 2 && h > 2, EINA_FALSE);
247
248 src_map = src = _buffer_map_all(cmd->input->buffer, &slen, E_READ, E_ALPHA, &ss);
249 map_map = map = _buffer_map_all(cmd->mask->buffer, &mlen, E_READ, E_ALPHA, &ms);
250 dst_map = dst = (uint32_t *) _buffer_map_all(cmd->output->buffer, &dlen, E_WRITE, E_ARGB, &ds);
251 EINA_SAFETY_ON_FALSE_GOTO(src && dst && map, end);
252
253 xyangle = cmd->bump.xyangle;
254 zangle = cmd->bump.zangle;
255 sf = cmd->bump.specular_factor;
256 compensate = cmd->bump.compensate;
257 elevation = cmd->bump.elevation;
258
259 dark = cmd->bump.dark;
260 white = cmd->bump.white;
261 color = cmd->bump.color;
262
263 // Compute appropriate lx, ly
264 if (fabs(zangle) >= 90.)
265 {
266 WRN("Z angle was defined as %.0f, out of range. Defaults to %.0f.",
267 zangle, DEFAULT_ZANGLE);
268 zangle = DEFAULT_ZANGLE;
269 }
270
271 lxy = 255. * cos(zangle * M_PI / 180.);
272 lx = (int) (lxy * cos(xyangle * M_PI / 180.));
273 ly = (int) (lxy * sin(xyangle * M_PI / 180.));
274 lz = (int) (255. * sin(zangle));
275 INF("Using light vector (%d,%d,%d)", lx, ly, lz);
276
277 if (elevation <= 0)
278 {
279 WRN("Invalid elevation value of %.0f, using 10 instead.", elevation);
280 elevation = 10.0;
281 }
282
283 gz = (6*255) / elevation;
284 gzlz = gz * lz;
285 gz2 = gz * gz;
286
287 // Generate light table
288 // FIXME: phong LUT not used (we need two)
289 //phong = malloc(256 * 256 * sizeof(*phong));
290 //EINA_SAFETY_ON_NULL_RETURN_VAL(phong, EINA_FALSE);
291 //_phong_rgba_generate(phong, 1.5, sf, 20, dark, color, white);
292
293 // FIXME: x=0 and x=w-1 are NOT implemented.
294
295 for (y = 0; y < h; y++)
296 {
297 int gx, gy;
298
299 if (!y)
300 {
301 map_y1 = map;
302 map_y2 = map + w;
303 }
304 else if (y == (h - 1))
305 {
306 map_y1 = map - w;
307 map_y2 = map;
308 }
309 else
310 {
311 map_y1 = map - w;
312 map_y2 = map + w;
313 }
314
315 for (x = 0; x < w; x++, dst++, src++, map++, map_y1++, map_y2++)
316 {
317 if (!*src) continue;
318
319 /* Color intensity is defined as:
320 * I = Kd*N.L*Cd + Ks*N.H*Cs
321 * Where Ks and Kd are 1 in this implementation
322 * And Cs is white, Cd is color
323 */
324
325 /* Compute N.L
326 * N = (gx,gy,gz)
327 * L = (lx,ly,lz) |L| = 255
328 */
329
330 if (EINA_LIKELY(x && (x < (w - 1))))
331 {
332 gx = map[-1] + map_y1[-1] + map_y2[-1] - map[1] - map_y1[1] - map_y2[1];
333 gy = map_y2[-1] + map_y2[0] + map_y2[1] - map_y1[-1] - map_y1[0] - map_y1[1];
334 }
335 else if (!x)
336 {
337 gx = map[0] + map_y1[0] + map_y2[0] - map[1] - map_y1[1] - map_y2[1];
338 gy = map_y2[0] + map_y2[1] + map_y2[1] - map_y1[0] - map_y1[1] - map_y1[1];
339 }
340 else
341 {
342 gx = map[-1] + map_y1[-1] + map_y2[-1] - map[0] - map_y1[0] - map_y2[0];
343 gy = map_y2[-1] + map_y2[0] + map_y2[0] - map_y1[-1] - map_y1[0] - map_y1[0];
344 }
345
346 NL = gx*lx + gy*ly + gzlz;
347
348 if (0 && NL < 0)
349 {
350 // TODO: Check this
351 diffusion = lz;
352 }
353 else
354 {
355 int g2 = gx*gx + gy*gy + gz2;
356 diffusion = NL / sqrt(MAX(g2, 1));
357 //diffusion += MAX(0, lz - diffusion);
358 }
359
360 if (compensate)
361 diffusion = diffusion * 255 / lz;
362
363 diffusion = CLAMP(1, diffusion + 1, 256);
364 col = INTERP_256(diffusion, color, dark);
365
366 if (sf > 0)
367 {
368 /* Compute N.H
369 * H = (L+V) / |L+V|
370 * V = (0,0,255)
371 * L = (lx,ly,lz) |L| = 255
372 */
373
374 // FIXME: All these doubles :)
375
376 int shine;
377 const double hnorm = sqrt(lx*lx + ly*ly + (lz+255)*(lz+255));
378 const double hx = (double) lx / hnorm;
379 const double hy = (double) ly / hnorm;
380 const double hz = (double) (lz+255) / hnorm;
381 double NHx = hx*gx / 255.0;
382 double NHy = hy*gy / 255.0;
383 double nz = sqrt(255.0*255.0 - gx*gx - gy*gy);
384 double NHz = (hz*nz) / 255.0;
385 double NH = NHx + NHy + NHz;
386 double specular = NH > 0 ? pow(NH, sf) : 0;
387
388 if (compensate)
389 {
390 const double basespecular = pow(hz, sf);
391 shine = (specular - basespecular) * 255.0 / (1.0 - basespecular);
392 }
393 else shine = specular * 255.0;
394
395 col = INTERP_256(CLAMP(1, shine + 1, 256), white, col);
396 }
397
398 *dst = INTERP_256(*src + 1, col, *dst);
399 }
400 }
401
402 ret = EINA_TRUE;
403
404end:
405 ector_buffer_unmap(cmd->input->buffer, src_map, slen);
406 ector_buffer_unmap(cmd->mask->buffer, map_map, mlen);
407 ector_buffer_unmap(cmd->output->buffer, dst_map, dlen);
408 return ret;
409}