Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Compositor sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include "nodes_stacks.h"
27 : #include "texturing.h"
28 :
29 : #ifndef GPAC_DISABLE_VRML
30 :
31 :
32 : #define GRAD_TEXTURE_SIZE 128
33 : #define GRAD_TEXTURE_HSIZE 64
34 :
35 : enum
36 : {
37 : GF_SR_TEXTURE_GRAD_REGISTERED = 1<<6,
38 : GF_SR_TEXTURE_GRAD_NO_RGB = 1<<7,
39 : };
40 :
41 : /*linear/radial gradient*/
42 : typedef struct
43 : {
44 : GF_TextureHandler txh;
45 : char *tx_data;
46 : // Bool no_rgb_support;
47 : } GradientStack;
48 :
49 11798 : void GradientGetMatrix(GF_Node *transform, GF_Matrix2D *mat)
50 : {
51 23596 : gf_mx2d_init(*mat);
52 11798 : if (transform) {
53 0 : switch (gf_node_get_tag(transform) ) {
54 0 : case TAG_MPEG4_Transform2D:
55 : {
56 : M_Transform2D *tr = (M_Transform2D *)transform;
57 0 : gf_mx2d_add_scale_at(mat, 0, 0, tr->scale.x, tr->scale.y, tr->scaleOrientation);
58 0 : gf_mx2d_add_rotation(mat, tr->center.x, tr->center.y, tr->rotationAngle);
59 0 : gf_mx2d_add_translation(mat, tr->translation.x, tr->translation.y);
60 : }
61 0 : break;
62 0 : case TAG_MPEG4_TransformMatrix2D:
63 : {
64 : M_TransformMatrix2D *tm = (M_TransformMatrix2D*)transform;
65 0 : gf_mx2d_init(*mat);
66 0 : mat->m[0] = tm->mxx;
67 0 : mat->m[1] = tm->mxy;
68 0 : mat->m[2] = tm->tx;
69 0 : mat->m[3] = tm->myx;
70 0 : mat->m[4] = tm->myy;
71 0 : mat->m[5] = tm->ty;
72 : }
73 0 : break;
74 : default:
75 : break;
76 : }
77 11798 : }
78 11798 : }
79 :
80 508 : static void DestroyGradient(GF_Node *node, void *rs, Bool is_destroy)
81 : {
82 508 : if (is_destroy) {
83 508 : GradientStack *st = (GradientStack *) gf_node_get_private(node);
84 508 : gf_sc_texture_destroy(&st->txh);
85 508 : if (st->tx_data) gf_free(st->tx_data);
86 508 : gf_free(st);
87 : }
88 508 : }
89 :
90 3226 : static void UpdateLinearGradient(GF_TextureHandler *txh)
91 : {
92 : u32 i, *cols;
93 : Fixed a;
94 : Bool const_a;
95 : GF_EVGStencil *stencil;
96 3226 : M_LinearGradient *lg = (M_LinearGradient *) txh->owner;
97 3226 : GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
98 :
99 3226 : if (!gf_node_dirty_get(txh->owner)) {
100 2075 : txh->needs_refresh = 0;
101 2075 : return;
102 : }
103 1151 : if (lg->key.count > lg->keyValue.count) return;
104 :
105 1151 : if (!txh->tx_io) {
106 57 : gf_node_dirty_set(gf_node_get_parent(txh->owner, 0), 0, 1);
107 57 : gf_node_dirty_set(txh->owner, 0, 1);
108 57 : gf_sc_texture_allocate(txh);
109 : }
110 :
111 1151 : stencil = gf_sc_texture_get_stencil(txh);
112 1151 : if (!stencil) stencil = gf_evg_stencil_new(GF_STENCIL_LINEAR_GRADIENT);
113 : /*set stencil even if assigned, this invalidates the associated bitmap state in 3D*/
114 1151 : gf_sc_texture_set_stencil(txh, stencil);
115 :
116 1151 : gf_node_dirty_clear(txh->owner, 0);
117 1151 : txh->needs_refresh = 1;
118 :
119 1151 : st->txh.transparent = 0;
120 1151 : const_a = (lg->opacity.count == 1) ? 1 : 0;
121 1151 : cols = (u32*)gf_malloc(sizeof(u32) * lg->key.count);
122 4714 : for (i=0; i<lg->key.count; i++) {
123 3563 : a = (const_a ? lg->opacity.vals[0] : lg->opacity.vals[i]);
124 3563 : cols[i] = GF_COL_ARGB_FIXED(a, lg->keyValue.vals[i].red, lg->keyValue.vals[i].green, lg->keyValue.vals[i].blue);
125 3563 : if (a != FIX_ONE) txh->transparent = 1;
126 : }
127 1151 : gf_evg_stencil_set_gradient_interpolation(stencil, lg->key.vals, cols, lg->key.count);
128 1151 : gf_free(cols);
129 1151 : gf_evg_stencil_set_gradient_mode(stencil, (GF_GradientMode) lg->spreadMethod);
130 : }
131 :
132 :
133 1459 : static void LG_ComputeMatrix(GF_TextureHandler *txh, GF_Rect *bounds, GF_Matrix2D *mat, Bool for_3d)
134 : {
135 : GF_EVGStencil *stencil;
136 1459 : M_LinearGradient *lg = (M_LinearGradient *) txh->owner;
137 :
138 1459 : stencil = gf_sc_texture_get_stencil(txh);
139 1459 : if (!stencil) return;
140 :
141 1459 : if (lg->key.count<2) return;
142 1459 : if (lg->key.count != lg->keyValue.count) return;
143 :
144 : /*create gradient brush if needed*/
145 1459 : if (!txh->tx_io) return;
146 :
147 1459 : GradientGetMatrix((GF_Node *) lg->transform, mat);
148 :
149 : /*translate to the center of the bounds*/
150 1459 : gf_mx2d_add_translation(mat, gf_divfix(bounds->x, bounds->width), gf_divfix(bounds->y - bounds->height, bounds->height));
151 : /*scale back to object coordinates - the gradient is still specified in texture coordinates
152 : i order to avoid overflows in fixed point*/
153 1459 : gf_mx2d_add_scale(mat, bounds->width, bounds->height);
154 :
155 1459 : gf_evg_stencil_set_linear_gradient(stencil, lg->startPoint.x, lg->startPoint.y, lg->endPoint.x, lg->endPoint.y);
156 : }
157 :
158 : //TODO - replace this with shader-based code ...
159 :
160 314 : static void BuildLinearGradientTexture(GF_TextureHandler *txh)
161 : {
162 : u32 i;
163 : SFVec2f start, end;
164 : u32 *cols;
165 : Fixed a;
166 : Bool const_a;
167 : GF_Matrix2D mat;
168 : GF_EVGStencil * stenc;
169 : GF_EVGSurface *surface;
170 : GF_EVGStencil * texture2D;
171 : GF_Path *path;
172 : GF_Err e;
173 : Bool transparent;
174 : u32 pix_fmt = 0;
175 314 : M_LinearGradient *lg = (M_LinearGradient *) txh->owner;
176 314 : GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
177 :
178 314 : if (!txh->tx_io) return;
179 :
180 314 : if (!(txh->flags & GF_SR_TEXTURE_GRAD_REGISTERED)) {
181 8 : txh->flags |= GF_SR_TEXTURE_GRAD_REGISTERED;
182 8 : if (gf_list_find(txh->compositor->textures, txh)<0)
183 8 : gf_list_insert(txh->compositor->textures, txh, 0);
184 : }
185 :
186 314 : if (lg->key.count<2) return;
187 314 : if (lg->key.count != lg->keyValue.count) return;
188 :
189 314 : start = lg->startPoint;
190 314 : end = lg->endPoint;
191 :
192 314 : transparent = (lg->opacity.count==1) ? (lg->opacity.vals[0]!=FIX_ONE) : 1;
193 :
194 : /*init our 2D graphics stuff*/
195 314 : texture2D = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
196 314 : if (!texture2D) return;
197 314 : surface = gf_evg_surface_new(1);
198 314 : if (!surface) {
199 0 : gf_evg_stencil_delete(texture2D);
200 0 : return;
201 : }
202 :
203 314 : if (st->txh.flags & GF_SR_TEXTURE_GRAD_NO_RGB) transparent = 1;
204 :
205 314 : if (st->tx_data && (st->txh.transparent != transparent)) {
206 0 : gf_free(st->tx_data);
207 0 : st->tx_data = NULL;
208 : }
209 :
210 314 : if (transparent) {
211 0 : if (!st->tx_data) {
212 0 : st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
213 : }
214 0 : memset(st->tx_data, 0, sizeof(char)*txh->stride*txh->height);
215 :
216 : pix_fmt = GF_PIXEL_RGBA;
217 0 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
218 0 : if (e) {
219 : pix_fmt = GF_PIXEL_ARGB;
220 0 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
221 : }
222 : } else {
223 314 : if (!st->tx_data) {
224 8 : st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*3);
225 : }
226 314 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 3*GRAD_TEXTURE_SIZE, GF_PIXEL_RGB);
227 : /*try with ARGB (it actually is needed for GDIplus module since GDIplus cannot handle native RGB texture (it works in BGR)*/
228 314 : if (e) {
229 : /*remember for later use*/
230 0 : st->txh.flags |= GF_SR_TEXTURE_GRAD_NO_RGB;
231 : transparent = 1;
232 0 : gf_free(st->tx_data);
233 0 : st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
234 0 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, GF_PIXEL_ARGB);
235 : }
236 : }
237 314 : st->txh.transparent = transparent;
238 :
239 314 : if (e) {
240 0 : gf_free(st->tx_data);
241 0 : gf_evg_stencil_delete(texture2D);
242 0 : gf_evg_surface_delete(surface);
243 0 : return;
244 : }
245 314 : e = gf_evg_surface_attach_to_texture(surface, texture2D);
246 314 : if (e) {
247 0 : gf_evg_stencil_delete(texture2D);
248 0 : gf_evg_surface_delete(surface);
249 0 : return;
250 : }
251 :
252 : /*create & setup gradient*/
253 314 : stenc = gf_evg_stencil_new(GF_STENCIL_LINEAR_GRADIENT);
254 314 : if (!stenc) {
255 0 : gf_evg_stencil_delete(texture2D);
256 0 : gf_evg_surface_delete(surface);
257 0 : return;
258 : }
259 : /*move line to object space*/
260 314 : start.x *= GRAD_TEXTURE_SIZE;
261 314 : end.x *= GRAD_TEXTURE_SIZE;
262 314 : start.y *= GRAD_TEXTURE_SIZE;
263 314 : end.y *= GRAD_TEXTURE_SIZE;
264 314 : gf_evg_stencil_set_linear_gradient(stenc, start.x, start.y, end.x, end.y);
265 314 : const_a = (lg->opacity.count == 1) ? 1 : 0;
266 314 : cols = (u32*)gf_malloc(sizeof(u32) * lg->key.count);
267 1280 : for (i=0; i<lg->key.count; i++) {
268 966 : a = (const_a ? lg->opacity.vals[0] : lg->opacity.vals[i]);
269 966 : cols[i] = GF_COL_ARGB_FIXED(a, lg->keyValue.vals[i].red, lg->keyValue.vals[i].green, lg->keyValue.vals[i].blue);
270 : }
271 314 : gf_evg_stencil_set_gradient_interpolation(stenc, lg->key.vals, cols, lg->key.count);
272 314 : gf_free(cols);
273 314 : gf_evg_stencil_set_gradient_mode(stenc, (GF_GradientMode)lg->spreadMethod);
274 :
275 : /*fill surface*/
276 314 : path = gf_path_new();
277 314 : gf_path_add_move_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
278 314 : gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
279 314 : gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
280 314 : gf_path_add_line_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
281 314 : gf_path_close(path);
282 :
283 : /*add gradient transform*/
284 314 : GradientGetMatrix(lg->transform, &mat);
285 :
286 : /*move transform to object space*/
287 314 : mat.m[2] *= GRAD_TEXTURE_SIZE;
288 314 : mat.m[5] *= GRAD_TEXTURE_SIZE;
289 : /*translate to the center of the bounds*/
290 314 : gf_mx2d_add_translation(&mat, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
291 : /*back to GL bottom->up order*/
292 314 : gf_mx2d_add_scale(&mat, FIX_ONE, -FIX_ONE);
293 314 : gf_evg_stencil_set_matrix(stenc, &mat);
294 :
295 314 : gf_evg_surface_set_raster_level(surface, GF_RASTER_HIGH_QUALITY);
296 314 : gf_evg_surface_set_path(surface, path);
297 314 : gf_evg_surface_fill(surface, stenc);
298 314 : gf_evg_stencil_delete(stenc);
299 314 : gf_evg_surface_delete(surface);
300 314 : gf_evg_stencil_delete(texture2D);
301 314 : gf_path_del(path);
302 :
303 314 : txh->data = st->tx_data;
304 314 : txh->width = GRAD_TEXTURE_SIZE;
305 314 : txh->height = GRAD_TEXTURE_SIZE;
306 314 : txh->transparent = transparent;
307 314 : if (transparent) {
308 : u32 j;
309 0 : txh->stride = GRAD_TEXTURE_SIZE*4;
310 0 : txh->pixelformat = GF_PIXEL_RGBA;
311 :
312 : /*back to RGBA texturing*/
313 0 : if (pix_fmt != GF_PIXEL_RGBA) {
314 0 : for (i=0; i<txh->height; i++) {
315 0 : char *data = txh->data + i*txh->stride;
316 0 : for (j=0; j<txh->width; j++) {
317 0 : u32 val = *(u32 *) &data[4*j];
318 0 : data[4*j] = (val>>16) & 0xFF;
319 0 : data[4*j+1] = (val>>8) & 0xFF;
320 0 : data[4*j+2] = (val) & 0xFF;
321 0 : data[4*j+3] = (val>>24) & 0xFF;
322 : }
323 : }
324 : }
325 : } else {
326 314 : txh->stride = GRAD_TEXTURE_SIZE*3;
327 314 : txh->pixelformat = GF_PIXEL_RGB;
328 : }
329 314 : txh->flags |= GF_SR_TEXTURE_NO_GL_FLIP;
330 314 : gf_sc_texture_set_data(txh);
331 : }
332 :
333 74 : void compositor_init_linear_gradient(GF_Compositor *compositor, GF_Node *node)
334 : {
335 : GradientStack *st;
336 74 : GF_SAFEALLOC(st, GradientStack);
337 74 : if (!st) {
338 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate gradient stack\n"));
339 : return;
340 : }
341 :
342 : /*!!! Gradients are textures but are not registered as textures with the compositor in order to avoid updating
343 : too many textures each frame - gradients are only registered with the compositor when they are used in OpenGL, in order
344 : to release associated HW resource when no longer used*/
345 74 : st->txh.owner = node;
346 74 : st->txh.compositor = compositor;
347 74 : st->txh.update_texture_fcnt = UpdateLinearGradient;
348 74 : st->txh.compute_gradient_matrix = LG_ComputeMatrix;
349 :
350 74 : gf_node_set_private(node, st);
351 74 : gf_node_set_callback_function(node, DestroyGradient);
352 : }
353 :
354 :
355 2 : static void BuildRadialGradientTexture(GF_TextureHandler *txh)
356 : {
357 : u32 i;
358 : SFVec2f center, focal;
359 : u32 *cols;
360 : Fixed a, radius;
361 : Bool const_a;
362 : GF_Matrix2D mat;
363 : GF_EVGStencil * stenc;
364 : GF_EVGSurface *surface;
365 : GF_EVGStencil * texture2D;
366 : GF_Path *path;
367 : GF_Err e;
368 : u32 pix_fmt = 0;
369 : Bool transparent;
370 2 : M_RadialGradient *rg = (M_RadialGradient*) txh->owner;
371 2 : GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
372 :
373 2 : if (!txh->tx_io) return;
374 :
375 2 : if (!(txh->flags & GF_SR_TEXTURE_GRAD_REGISTERED)) {
376 1 : txh->flags |= GF_SR_TEXTURE_GRAD_REGISTERED;
377 1 : if (gf_list_find(txh->compositor->textures, txh)<0)
378 1 : gf_list_insert(txh->compositor->textures, txh, 0);
379 : }
380 :
381 2 : if (rg->key.count<2) return;
382 2 : if (rg->key.count != rg->keyValue.count) return;
383 :
384 2 : transparent = (rg->opacity.count==1) ? ((rg->opacity.vals[0]!=FIX_ONE) ? 1 : 0) : 1;
385 :
386 : /*init our 2D graphics stuff*/
387 2 : texture2D = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
388 2 : if (!texture2D) return;
389 2 : surface = gf_evg_surface_new(1);
390 2 : if (!surface) {
391 0 : gf_evg_stencil_delete(texture2D);
392 0 : return;
393 : }
394 :
395 2 : if (st->txh.flags & GF_SR_TEXTURE_GRAD_NO_RGB) transparent = 1;
396 :
397 2 : if (st->tx_data && (st->txh.transparent != transparent)) {
398 0 : gf_free(st->tx_data);
399 0 : st->tx_data = NULL;
400 : }
401 :
402 2 : if (transparent) {
403 2 : if (!st->tx_data) {
404 1 : st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
405 : }
406 2 : memset(st->tx_data, 0, sizeof(char)*txh->stride*txh->height);
407 :
408 : pix_fmt = GF_PIXEL_RGBA;
409 :
410 2 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
411 :
412 2 : if (e) {
413 : pix_fmt = GF_PIXEL_ARGB;
414 0 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
415 : }
416 : } else {
417 0 : if (!st->tx_data) {
418 0 : st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*3);
419 : }
420 0 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 3*GRAD_TEXTURE_SIZE, GF_PIXEL_RGB);
421 : /*try with ARGB (it actually is needed for GDIplus module since GDIplus cannot handle native RGB texture (it works in BGR)*/
422 0 : if (e) {
423 : /*remember for later use*/
424 0 : st->txh.flags |= GF_SR_TEXTURE_GRAD_NO_RGB;
425 : transparent = 1;
426 0 : gf_free(st->tx_data);
427 0 : st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
428 0 : e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, GF_PIXEL_ARGB);
429 : }
430 : }
431 2 : st->txh.transparent = transparent;
432 :
433 2 : if (e) {
434 0 : gf_free(st->tx_data);
435 0 : gf_evg_stencil_delete(texture2D);
436 0 : gf_evg_surface_delete(surface);
437 0 : return;
438 : }
439 2 : e = gf_evg_surface_attach_to_texture(surface, texture2D);
440 2 : if (e) {
441 0 : gf_evg_stencil_delete(texture2D);
442 0 : gf_evg_surface_delete(surface);
443 0 : return;
444 : }
445 :
446 : /*create & setup gradient*/
447 2 : stenc = gf_evg_stencil_new(GF_STENCIL_RADIAL_GRADIENT);
448 2 : if (!stenc) {
449 0 : gf_evg_stencil_delete(texture2D);
450 0 : gf_evg_surface_delete(surface);
451 : }
452 :
453 2 : center = rg->center;
454 2 : focal = rg->focalPoint;
455 2 : radius = rg->radius;
456 :
457 : /*move circle to object space*/
458 2 : center.x *= GRAD_TEXTURE_SIZE;
459 2 : center.y *= GRAD_TEXTURE_SIZE;
460 2 : focal.x *= GRAD_TEXTURE_SIZE;
461 2 : focal.y *= GRAD_TEXTURE_SIZE;
462 2 : radius *= GRAD_TEXTURE_SIZE;
463 :
464 2 : gf_evg_stencil_set_radial_gradient(stenc, center.x, center.y, focal.x, focal.y, radius, radius);
465 :
466 2 : const_a = (rg->opacity.count == 1) ? 1 : 0;
467 2 : cols = (u32*) gf_malloc(sizeof(u32) * rg->key.count);
468 8 : for (i=0; i<rg->key.count; i++) {
469 6 : a = (const_a ? rg->opacity.vals[0] : rg->opacity.vals[i]);
470 6 : cols[i] = GF_COL_ARGB_FIXED(a, rg->keyValue.vals[i].red, rg->keyValue.vals[i].green, rg->keyValue.vals[i].blue);
471 : }
472 2 : gf_evg_stencil_set_gradient_interpolation(stenc, rg->key.vals, cols, rg->key.count);
473 2 : gf_free(cols);
474 2 : gf_evg_stencil_set_gradient_mode(stenc, (GF_GradientMode)rg->spreadMethod);
475 :
476 : /*fill surface*/
477 2 : path = gf_path_new();
478 2 : gf_path_add_move_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
479 2 : gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
480 2 : gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
481 2 : gf_path_add_line_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
482 2 : gf_path_close(path);
483 :
484 : /*add gradient transform*/
485 2 : GradientGetMatrix(rg->transform, &mat);
486 : /*move transform to object space*/
487 2 : mat.m[2] *= GRAD_TEXTURE_SIZE;
488 2 : mat.m[5] *= GRAD_TEXTURE_SIZE;
489 : /*translate to the center of the bounds*/
490 2 : gf_mx2d_add_translation(&mat, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
491 : /*back to GL bottom->up order*/
492 2 : gf_mx2d_add_scale(&mat, FIX_ONE, -FIX_ONE);
493 2 : gf_evg_stencil_set_matrix(stenc, &mat);
494 :
495 2 : gf_evg_surface_set_raster_level(surface, GF_RASTER_HIGH_QUALITY);
496 2 : gf_evg_surface_set_path(surface, path);
497 2 : gf_evg_surface_fill(surface, stenc);
498 2 : gf_evg_stencil_delete(stenc);
499 2 : gf_evg_surface_delete(surface);
500 2 : gf_evg_stencil_delete(texture2D);
501 2 : gf_path_del(path);
502 :
503 2 : txh->data = st->tx_data;
504 2 : txh->width = GRAD_TEXTURE_SIZE;
505 2 : txh->height = GRAD_TEXTURE_SIZE;
506 2 : txh->transparent = transparent;
507 2 : if (transparent) {
508 : u32 j;
509 2 : txh->stride = GRAD_TEXTURE_SIZE*4;
510 2 : txh->pixelformat = GF_PIXEL_RGBA;
511 :
512 : /*back to RGBA texturing*/
513 2 : if (pix_fmt == GF_PIXEL_ARGB) {
514 0 : for (i=0; i<txh->height; i++) {
515 0 : char *data = txh->data + i*txh->stride;
516 0 : for (j=0; j<txh->width; j++) {
517 : u8 pa, pr, pg, pb;
518 0 : pa = data[4*j];
519 0 : pr = data[4*j+1];
520 0 : pg = data[4*j+2];
521 0 : pb = data[4*j+3];
522 0 : data[4*j] = pr;
523 0 : data[4*j+1] = pg;
524 0 : data[4*j+2] = pb;
525 0 : data[4*j+3] = pa;
526 : }
527 : }
528 : }
529 : } else {
530 0 : txh->stride = GRAD_TEXTURE_SIZE*3;
531 0 : txh->pixelformat = GF_PIXEL_RGB;
532 : }
533 : // tx_set_blend_enable(txh, 1);
534 2 : txh->flags |= GF_SR_TEXTURE_NO_GL_FLIP;
535 2 : gf_sc_texture_set_data(txh);
536 2 : return;
537 : }
538 :
539 25093 : static void UpdateRadialGradient(GF_TextureHandler *txh)
540 : {
541 : Bool const_a;
542 : GF_EVGStencil * stencil;
543 : u32 i, *cols;
544 : Fixed a;
545 25093 : M_RadialGradient *rg = (M_RadialGradient*) txh->owner;
546 25093 : GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
547 :
548 25093 : if (!gf_node_dirty_get(txh->owner)) {
549 24335 : txh->needs_refresh = 0;
550 24335 : return;
551 : }
552 758 : if (rg->key.count > rg->keyValue.count) return;
553 :
554 758 : if (!txh->tx_io) gf_sc_texture_allocate(txh);
555 :
556 758 : stencil = gf_sc_texture_get_stencil(txh);
557 758 : if (!stencil) stencil = gf_evg_stencil_new(GF_STENCIL_RADIAL_GRADIENT);
558 : /*set stencil even if assigned, this invalidates the associated bitmap state in 3D*/
559 758 : gf_sc_texture_set_stencil(txh, stencil);
560 :
561 758 : gf_node_dirty_clear(txh->owner, 0);
562 758 : txh->needs_refresh = 1;
563 :
564 758 : st->txh.transparent = 0;
565 1548 : for (i=0; i<rg->opacity.count; i++) {
566 824 : if (rg->opacity.vals[i] != FIX_ONE) {
567 34 : st->txh.transparent = 1;
568 34 : break;
569 : }
570 : }
571 :
572 758 : const_a = (rg->opacity.count == 1) ? 1 : 0;
573 758 : cols = (u32*)gf_malloc(sizeof(u32) * rg->key.count);
574 2641 : for (i=0; i<rg->key.count; i++) {
575 1883 : a = (const_a ? rg->opacity.vals[0] : rg->opacity.vals[i]);
576 1883 : cols[i] = GF_COL_ARGB_FIXED(a, rg->keyValue.vals[i].red, rg->keyValue.vals[i].green, rg->keyValue.vals[i].blue);
577 : }
578 758 : gf_evg_stencil_set_gradient_interpolation(stencil, rg->key.vals, cols, rg->key.count);
579 758 : gf_free(cols);
580 :
581 758 : gf_evg_stencil_set_gradient_mode(stencil, (GF_GradientMode) rg->spreadMethod);
582 :
583 : }
584 :
585 10023 : static void RG_ComputeMatrix(GF_TextureHandler *txh, GF_Rect *bounds, GF_Matrix2D *mat, Bool for_3d)
586 : {
587 : GF_EVGStencil * stencil;
588 10023 : M_RadialGradient *rg = (M_RadialGradient *) txh->owner;
589 :
590 10023 : if (rg->key.count<2) return;
591 10023 : if (rg->key.count != rg->keyValue.count) return;
592 :
593 10023 : if (!txh->tx_io) return;
594 :
595 10023 : stencil = gf_sc_texture_get_stencil(txh);
596 10023 : if (!stencil) return;
597 :
598 10023 : GradientGetMatrix((GF_Node *) rg->transform, mat);
599 :
600 10023 : gf_evg_stencil_set_radial_gradient(stencil, rg->center.x, rg->center.y, rg->focalPoint.x, rg->focalPoint.y, rg->radius, rg->radius);
601 : /*move to center of bounds*/
602 10023 : gf_mx2d_add_translation(mat, gf_divfix(bounds->x, bounds->width), gf_divfix(bounds->y - bounds->height, bounds->height));
603 : /*scale back to object coordinates - the gradient is still specified in texture coordinates
604 : i order to avoid overflows in fixed point*/
605 10023 : gf_mx2d_add_scale(mat, bounds->width, bounds->height);
606 : }
607 :
608 :
609 434 : void compositor_init_radial_gradient(GF_Compositor *compositor, GF_Node *node)
610 : {
611 : GradientStack *st;
612 434 : GF_SAFEALLOC(st, GradientStack);
613 434 : if (!st) {
614 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate gradient stack\n"));
615 : return;
616 : }
617 :
618 : /*!!! Gradients are textures but are not registered as textures with the compositor in order to avoid updating
619 : too many textures each frame - gradients are only registered with the compositor when they are used in OpenGL, in order
620 : to release associated HW resource when no longer used*/
621 434 : st->txh.owner = node;
622 434 : st->txh.compositor = compositor;
623 434 : st->txh.update_texture_fcnt = UpdateRadialGradient;
624 434 : st->txh.compute_gradient_matrix = RG_ComputeMatrix;
625 :
626 434 : gf_node_set_private(node, st);
627 434 : gf_node_set_callback_function(node, DestroyGradient);
628 : }
629 :
630 27340 : GF_TextureHandler *compositor_mpeg4_get_gradient_texture(GF_Node *node)
631 : {
632 27340 : GradientStack *st = (GradientStack*) gf_node_get_private(node);
633 27340 : st->txh.update_texture_fcnt(&st->txh);
634 27340 : return &st->txh;
635 : }
636 :
637 : #endif /*GPAC_DISABLE_VRML*/
638 :
639 316 : void compositor_gradient_update(GF_TextureHandler *txh)
640 : {
641 316 : switch (gf_node_get_tag(txh->owner) ) {
642 : #ifndef GPAC_DISABLE_VRML
643 2 : case TAG_MPEG4_RadialGradient:
644 2 : BuildRadialGradientTexture(txh);
645 2 : break;
646 314 : case TAG_MPEG4_LinearGradient:
647 314 : BuildLinearGradientTexture(txh);
648 314 : break;
649 : #endif
650 :
651 : #ifndef GPAC_DISABLE_SVG
652 0 : case TAG_SVG_linearGradient:
653 : case TAG_SVG_radialGradient:
654 0 : compositor_svg_build_gradient_texture(txh);
655 0 : break;
656 : #endif
657 : }
658 316 : }
659 :
|