summaryrefslogtreecommitdiff
path: root/src/lib/ector/software/ector_software_gradient.c
diff options
context:
space:
mode:
authorSubhransu Sekhar Mohanty <sub.mohanty@samsung.com>2015-04-03 16:31:45 +0200
committerCedric BAIL <cedric@osg.samsung.com>2015-04-03 16:31:45 +0200
commit891ec145857c717105deb2481d224174b1c966ac (patch)
tree57b2caa588b66f531cbb28b90be14acae6c7ad67 /src/lib/ector/software/ector_software_gradient.c
parente99774946cf596b4527dcba92bbf17798eee9260 (diff)
ector: add software backend using FreeType rasterizer.
Diffstat (limited to 'src/lib/ector/software/ector_software_gradient.c')
-rw-r--r--src/lib/ector/software/ector_software_gradient.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/lib/ector/software/ector_software_gradient.c b/src/lib/ector/software/ector_software_gradient.c
new file mode 100644
index 0000000000..ed2b9fe985
--- /dev/null
+++ b/src/lib/ector/software/ector_software_gradient.c
@@ -0,0 +1,269 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5//Remove
6#include <assert.h>
7
8#include <math.h>
9#include <float.h>
10
11#include <Eina.h>
12#include <Ector.h>
13#include <software/Ector_Software.h>
14
15#include "ector_private.h"
16#include "ector_software_private.h"
17#include "ector_blend_private.h"
18
19
20#define GRADIENT_STOPTABLE_SIZE 1024
21#define FIXPT_BITS 8
22#define FIXPT_SIZE (1<<FIXPT_BITS)
23
24
25static inline int
26_gradient_clamp(const Ector_Renderer_Software_Gradient_Data *data, int ipos)
27{
28 if (data->gd->s == EFL_GFX_GRADIENT_SPREAD_REPEAT)
29 {
30 ipos = ipos % GRADIENT_STOPTABLE_SIZE;
31 ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
32 }
33 else if (data->gd->s == EFL_GFX_GRADIENT_SPREAD_REFLECT)
34 {
35 const int limit = GRADIENT_STOPTABLE_SIZE * 2;
36 ipos = ipos % limit;
37 ipos = ipos < 0 ? limit + ipos : ipos;
38 ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos;
39 }
40 else
41 {
42 if (ipos < 0)
43 ipos = 0;
44 else if (ipos >= GRADIENT_STOPTABLE_SIZE)
45 ipos = GRADIENT_STOPTABLE_SIZE-1;
46 }
47
48 return ipos;
49}
50
51
52static uint
53_gradient_pixel_fixed(const Ector_Renderer_Software_Gradient_Data *data, int fixed_pos)
54{
55 int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
56 return data->colorTable[_gradient_clamp(data, ipos)];
57}
58
59static inline uint
60_gradient_pixel(const Ector_Renderer_Software_Gradient_Data *data, float pos)
61{
62 int ipos = (int)(pos * (GRADIENT_STOPTABLE_SIZE - 1) + (float)(0.5));
63 return data->colorTable[_gradient_clamp(data, ipos)];
64}
65
66typedef double (*BLEND_FUNC)(double progress);
67
68static double
69_ease_linear(double t)
70{
71 return t;
72}
73
74static void
75_generate_gradient_color_table(Efl_Gfx_Gradient_Stop *gradient_stops, int stop_count, uint *colorTable, int size)
76{
77 int pos = 0;
78 Efl_Gfx_Gradient_Stop *curr, *next;
79 assert(stop_count > 0);
80
81 curr = gradient_stops;
82 uint current_color = ECTOR_ARGB_JOIN(curr->a, curr->r, curr->g, curr->b);
83 double incr = 1.0 / (double)size;
84 double fpos = 1.5 * incr;
85 current_color = _ector_premultiply(current_color);
86
87 colorTable[pos++] = current_color;
88
89 while (fpos <= curr->offset)
90 {
91 colorTable[pos] = colorTable[pos - 1];
92 pos++;
93 fpos += incr;
94 }
95
96 for (int i = 0; i < stop_count - 1; ++i)
97 {
98 curr = (gradient_stops + i);
99 next = (gradient_stops + i + 1);
100 double delta = 1/(next->offset - curr->offset);
101 uint next_color = ECTOR_ARGB_JOIN(next->a, next->r, next->g, next->b);
102 next_color = _ector_premultiply(next_color);
103 BLEND_FUNC func = &_ease_linear;
104 while (fpos < next->offset && pos < size)
105 {
106 double t = func((fpos - curr->offset) * delta);
107 int dist = (int)(256 * t);
108 int idist = 256 - dist;
109 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
110 ++pos;
111 fpos += incr;
112 }
113 current_color = next_color;
114 }
115
116 uint last_color = _ector_premultiply(current_color);
117 for (;pos < size; ++pos)
118 colorTable[pos] = last_color;
119
120 // Make sure the last color stop is represented at the end of the table
121 colorTable[size-1] = last_color;
122}
123
124
125void
126update_color_table(Ector_Renderer_Software_Gradient_Data *gdata)
127{
128 if(gdata->colorTable) return;
129
130 gdata->colorTable = malloc(GRADIENT_STOPTABLE_SIZE * 4);
131 _generate_gradient_color_table(gdata->gd->colors, gdata->gd->colors_count, gdata->colorTable, GRADIENT_STOPTABLE_SIZE);
132}
133
134void
135destroy_color_table(Ector_Renderer_Software_Gradient_Data *gdata)
136{
137 if (gdata->colorTable)
138 {
139 free(gdata->colorTable);
140 gdata->colorTable = NULL;
141 }
142}
143
144
145void
146fetch_linear_gradient(uint *buffer, Span_Data *data, int y, int x, int length)
147{
148 Ector_Renderer_Software_Gradient_Data *g_data = data->gradient;
149 float t, inc;
150 float rx=0, ry=0;
151
152 if (g_data->linear.l == 0)
153 {
154 t = inc = 0;
155 }
156 else
157 {
158 rx = data->inv.xy * (y + (float)0.5) + data->inv.xz + data->inv.xx * (x + (float)0.5);
159 ry = data->inv.yy * (y + (float)0.5) + data->inv.yz + data->inv.yx * (x + (float)0.5);
160 t = g_data->linear.dx*rx + g_data->linear.dy*ry + g_data->linear.off;
161 inc = g_data->linear.dx * data->inv.xx + g_data->linear.dx * data->inv.yx;
162
163 t *= (GRADIENT_STOPTABLE_SIZE - 1);
164 inc *= (GRADIENT_STOPTABLE_SIZE - 1);
165 }
166
167 uint *end = buffer + length;
168 if (inc > (float)(-1e-5) && inc < (float)(1e-5))
169 {
170 _ector_memfill(buffer, _gradient_pixel_fixed(g_data, (int)(t * FIXPT_SIZE)), length);
171 }
172 else
173 {
174 if (t + inc*length < (float)(INT_MAX >> (FIXPT_BITS + 1)) &&
175 t+inc*length > (float)(INT_MIN >> (FIXPT_BITS + 1)))
176 {
177 // we can use fixed point math
178 int t_fixed = (int)(t * FIXPT_SIZE);
179 int inc_fixed = (int)(inc * FIXPT_SIZE);
180 // #ifdef BUILD_SSE3
181 // if (evas_common_cpu_has_feature(CPU_FEATURE_SSE3)) {
182 // _fetch_linear_sse3(buffer, length, g_data, t_fixed, inc_fixed);
183 // } else
184 // #endif
185 {
186 while (buffer < end)
187 {
188 *buffer++ = _gradient_pixel_fixed(g_data, t_fixed);
189 t_fixed += inc_fixed;
190 }
191 }
192 }
193 else
194 {
195 // we have to fall back to float math
196 while (buffer < end) {
197 *buffer++ = _gradient_pixel(g_data, t/GRADIENT_STOPTABLE_SIZE);
198 t += inc;
199 }
200 }
201 }
202}
203
204static void
205_radial_helper_generic(uint *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data, float det,
206 float delta_det, float delta_delta_det, float b, float delta_b)
207{
208 for (int i = 0 ; i < length ; i++)
209 {
210 *buffer++ = _gradient_pixel(g_data, sqrt(det) - b);
211 det += delta_det;
212 delta_det += delta_delta_det;
213 b += delta_b;
214 }
215}
216
217void
218fetch_radial_gradient(uint *buffer, Span_Data *data, int y, int x, int length)
219{
220 Ector_Renderer_Software_Gradient_Data *g_data = data->gradient;
221
222 // avoid division by zero
223 if (abs(g_data->radial.a) <= 0.00001f)
224 {
225 _ector_memfill(buffer, 0, length);
226 return;
227 }
228
229 float rx = data->inv.xy * (y + (float)0.5) + data->inv.xz + data->inv.xx * (x + (float)0.5);
230 float ry = data->inv.yy * (y + (float)0.5) + data->inv.yz + data->inv.yx * (x + (float)0.5);
231
232 rx -= g_data->radial.fx;
233 ry -= g_data->radial.fy;
234
235 float inv_a = 1 / (float)(2 * g_data->radial.a);
236
237 const float delta_rx = data->inv.xx;
238 const float delta_ry = data->inv.yx;
239
240 float b = 2*(g_data->radial.dr*g_data->radial.fradius + rx * g_data->radial.dx + ry * g_data->radial.dy);
241 float delta_b = 2*(delta_rx * g_data->radial.dx + delta_ry * g_data->radial.dy);
242 const float b_delta_b = 2 * b * delta_b;
243 const float delta_b_delta_b = 2 * delta_b * delta_b;
244
245 const float bb = b * b;
246 const float delta_bb = delta_b * delta_b;
247 b *= inv_a;
248 delta_b *= inv_a;
249
250 const float rxrxryry = rx * rx + ry * ry;
251 const float delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
252 const float rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
253 const float delta_rx_plus_ry = 2 * delta_rxrxryry;
254
255 inv_a *= inv_a;
256
257 float det = (bb - 4 * g_data->radial.a * (g_data->radial.sqrfr - rxrxryry)) * inv_a;
258 float delta_det = (b_delta_b + delta_bb + 4 * g_data->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
259 const float delta_delta_det = (delta_b_delta_b + 4 * g_data->radial.a * delta_rx_plus_ry) * inv_a;
260
261 // #ifdef BUILD_SSE3
262 // if (evas_common_cpu_has_feature(CPU_FEATURE_SSE3)) {
263 // _radial_helper_sse3(buffer, length, g_data, det, delta_det, delta_delta_det, b, delta_b);
264 // } else
265 // #endif
266 { // generic fallback
267 _radial_helper_generic(buffer, length, g_data, det, delta_det, delta_delta_det, b, delta_b);
268 }
269}