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 "visual_manager.h"
27 : #include "drawable.h"
28 : #include "nodes_stacks.h"
29 : #include "texturing.h"
30 : #include <gpac/options.h>
31 :
32 : //#define SKIP_DRAW
33 :
34 22826 : GF_Err visual_2d_init_raster(GF_VisualManager *visual)
35 : {
36 22826 : if (!visual->raster_surface) {
37 582 : visual->raster_surface = gf_evg_surface_new(visual->center_coords);
38 582 : if (!visual->raster_surface) return GF_IO_ERR;
39 : }
40 22826 : return visual->GetSurfaceAccess(visual);
41 : }
42 :
43 22826 : void visual_2d_release_raster(GF_VisualManager *visual)
44 : {
45 22826 : if (visual->raster_surface) {
46 22826 : visual->ReleaseSurfaceAccess(visual);
47 : }
48 22826 : }
49 :
50 :
51 3125 : void visual_2d_clear_surface(GF_VisualManager *visual, GF_IRect *rc, u32 BackColor, u32 is_offscreen)
52 : {
53 : #ifdef SKIP_DRAW
54 : return;
55 : #endif
56 3125 : if (! visual->CheckAttached(visual) ) return;
57 :
58 3125 : if (!BackColor && !visual->offscreen && !visual->compositor->dyn_filter_mode) {
59 1796 : if ( !(visual->compositor->init_flags & GF_TERM_WINDOW_TRANSPARENT)) {
60 1796 : BackColor = visual->compositor->back_color;
61 : }
62 : }
63 :
64 3125 : gf_evg_surface_clear(visual->raster_surface, rc, BackColor);
65 : }
66 :
67 166 : static void draw_clipper(GF_VisualManager *visual, struct _drawable_context *ctx)
68 : {
69 : GF_PenSettings clipset;
70 : GF_Path *clippath, *cliper;
71 :
72 166 : if (ctx->flags & CTX_IS_BACKGROUND) return;
73 :
74 : memset(&clipset, 0, sizeof(GF_PenSettings));
75 166 : clipset.width = 2*FIX_ONE;
76 :
77 166 : clippath = gf_path_new();
78 166 : gf_path_add_rect_center(clippath, ctx->bi->unclip.x + ctx->bi->unclip.width/2, ctx->bi->unclip.y - ctx->bi->unclip.height/2, ctx->bi->unclip.width, ctx->bi->unclip.height);
79 166 : cliper = gf_path_get_outline(clippath, clipset);
80 166 : gf_path_del(clippath);
81 166 : gf_evg_surface_set_matrix(visual->raster_surface, NULL);
82 166 : gf_evg_surface_set_clipper(visual->raster_surface, NULL);
83 166 : gf_evg_surface_set_path(visual->raster_surface, cliper);
84 166 : gf_evg_stencil_set_brush_color(visual->raster_brush, 0xFF000000);
85 166 : gf_evg_surface_fill(visual->raster_surface, visual->raster_brush);
86 166 : gf_path_del(cliper);
87 : }
88 :
89 685725 : static void visual_2d_fill_path(GF_VisualManager *visual, DrawableContext *ctx, GF_EVGStencil * stencil, GF_TraverseState *tr_state, Bool is_erase)
90 : {
91 : Bool has_modif = GF_FALSE;
92 : GF_IRect clip;
93 :
94 : /*direct drawing : use ctx clip*/
95 685725 : if (tr_state->immediate_draw) {
96 23616 : if (ctx->bi->clip.width && ctx->bi->clip.height) {
97 23616 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Redrawing node %s [%s] (direct draw)\n", gf_node_get_log_name(ctx->drawable->node), gf_node_get_class_name(ctx->drawable->node) ));
98 :
99 23616 : if (stencil) {
100 23616 : gf_evg_surface_set_clipper(visual->raster_surface, &ctx->bi->clip);
101 23616 : gf_evg_surface_fill(visual->raster_surface, stencil);
102 : } else {
103 0 : gf_evg_surface_clear(visual->raster_surface, &ctx->bi->clip, 0);
104 : }
105 :
106 : has_modif = GF_TRUE;
107 : }
108 : }
109 : /*indirect drawing, draw path in all dirty areas*/
110 : else {
111 : u32 i;
112 1184111 : for (i=0; i<visual->to_redraw.count; i++) {
113 : /*there's an opaque region above, don't draw*/
114 : #ifdef TRACK_OPAQUE_REGIONS
115 : if (!is_erase && (visual->draw_node_index<visual->to_redraw.list[i].opaque_node_index)) continue;
116 : #endif
117 1184111 : clip = ctx->bi->clip;
118 1184111 : gf_irect_intersect(&clip, &visual->to_redraw.list[i].rect);
119 1184111 : if (clip.width && clip.height) {
120 230629 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Redrawing node %s [%s] (indirect draw @ dirty rect idx %d)\n", gf_node_get_log_name(ctx->drawable->node), gf_node_get_class_name(ctx->drawable->node), i));
121 230629 : if (stencil) {
122 230629 : gf_evg_surface_set_clipper(visual->raster_surface, &clip);
123 230629 : gf_evg_surface_fill(visual->raster_surface, stencil);
124 : } else {
125 0 : gf_evg_surface_clear(visual->raster_surface, &clip, 0);
126 : }
127 : has_modif = 1;
128 : }
129 : }
130 : }
131 : #ifndef GPAC_DISABLE_3D
132 685725 : if (!is_erase)
133 685425 : visual->nb_objects_on_canvas_since_last_ogl_flush++;
134 : #endif
135 685725 : if (has_modif) {
136 253097 : visual->has_modif = 1;
137 : #ifndef GPAC_DISABLE_3D
138 253097 : if (!visual->offscreen && visual->compositor->hybrid_opengl && !is_erase)
139 21817 : ra_union_rect(&visual->hybgl_drawn, &ctx->bi->clip);
140 : #endif
141 : }
142 685725 : }
143 :
144 674164 : static void visual_2d_set_options(GF_Compositor *compositor, GF_EVGSurface *rend, Bool forText, Bool no_antialias)
145 : {
146 674164 : if (no_antialias) {
147 14126 : gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_SPEED);
148 : } else {
149 660078 : switch (compositor->aa) {
150 0 : case GF_ANTIALIAS_NONE:
151 0 : gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_SPEED);
152 : break;
153 0 : case GF_ANTIALIAS_TEXT:
154 0 : if (forText) {
155 0 : gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_QUALITY);
156 : } else {
157 0 : gf_evg_surface_set_raster_level(rend, compositor->fast ? GF_RASTER_HIGH_QUALITY : GF_RASTER_MID);
158 : }
159 : break;
160 660078 : case GF_ANTIALIAS_FULL:
161 : default:
162 660078 : gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_QUALITY);
163 : break;
164 : }
165 : }
166 674164 : }
167 :
168 :
169 : #ifndef GPAC_DISABLE_VRML
170 16211 : static void visual_2d_get_texture_transform(GF_Node *__appear, GF_TextureHandler *txh, GF_Matrix2D *mat, Bool line_texture, Fixed final_width, Fixed final_height)
171 : {
172 : u32 node_tag;
173 : M_Appearance *appear;
174 : GF_Node *txtrans = NULL;
175 32422 : gf_mx2d_init(*mat);
176 :
177 16211 : if (!__appear || !txh) return;
178 : appear = (M_Appearance *)__appear;
179 :
180 16211 : if (!line_texture) {
181 14590 : if (!appear->textureTransform) return;
182 : txtrans = appear->textureTransform;
183 : } else {
184 1621 : if (gf_node_get_tag(appear->material) != TAG_MPEG4_Material2D) return;
185 1621 : if (gf_node_get_tag(((M_Material2D *)appear->material)->lineProps) != TAG_MPEG4_XLineProperties) return;
186 1621 : txtrans = ((M_XLineProperties *) ((M_Material2D *)appear->material)->lineProps)->textureTransform;
187 : }
188 3260 : if (!txtrans) return;
189 :
190 : /*gradient doesn't need bounds info in texture transform*/
191 1933 : if (txh->compute_gradient_matrix) {
192 : final_width = final_height = FIX_ONE;
193 : }
194 1933 : node_tag = gf_node_get_tag(txtrans);
195 1933 : if (node_tag==TAG_MPEG4_TextureTransform) {
196 : /*VRML: Tc' = -C � S � R � C � T � Tc*/
197 : M_TextureTransform *txt = (M_TextureTransform *) txtrans;
198 1051 : SFVec2f scale = txt->scale;
199 1051 : if (!scale.x) scale.x = FIX_ONE/100;
200 1051 : if (!scale.y) scale.y = FIX_ONE/100;
201 :
202 1051 : gf_mx2d_add_translation(mat, -gf_mulfix(txt->center.x, final_width), -gf_mulfix(txt->center.y, final_height) );
203 1051 : gf_mx2d_add_scale(mat, scale.x, scale.y);
204 1051 : gf_mx2d_add_rotation(mat, 0, 0, txt->rotation);
205 1051 : gf_mx2d_add_translation(mat, gf_mulfix(txt->center.x, final_width), gf_mulfix(txt->center.y, final_height) );
206 1051 : gf_mx2d_add_translation(mat, gf_mulfix(txt->translation.x, final_width), gf_mulfix(txt->translation.y, final_height) );
207 : /*and inverse the matrix (this is texture transform, cf VRML)*/
208 1051 : gf_mx2d_inverse(mat);
209 : return;
210 : }
211 882 : if (node_tag==TAG_MPEG4_TransformMatrix2D) {
212 882 : tr_mx2d_get_matrix((GF_Node *) txtrans, mat);
213 882 : mat->m[2] = gf_mulfix(mat->m[2], final_width);
214 882 : mat->m[5] = gf_mulfix(mat->m[5], final_height);
215 882 : gf_mx2d_inverse(mat);
216 882 : return;
217 : }
218 : }
219 : #endif /*GPAC_DISABLE_VRML*/
220 :
221 11692 : static void visual_2d_draw_gradient(GF_VisualManager *visual, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_TraverseState *tr_state, GF_Matrix2D *ext_mx, GF_Rect *orig_bounds)
222 : {
223 : GF_Rect rc;
224 : GF_EVGStencil * stencil;
225 : GF_Matrix2D g_mat;
226 :
227 11692 : if (!txh) txh = ctx->aspect.fill_texture;
228 :
229 11692 : gf_path_get_bounds(path, &rc);
230 11692 : if (!rc.width || !rc.height || !txh->tx_io) return;
231 :
232 11692 : if (orig_bounds) {
233 5134 : txh->compute_gradient_matrix(txh, orig_bounds, &g_mat, 0);
234 : } else {
235 6558 : txh->compute_gradient_matrix(txh, &rc, &g_mat, 0);
236 : }
237 11692 : stencil = gf_sc_texture_get_stencil(txh);
238 11692 : if (!stencil) return;
239 :
240 : #ifndef GPAC_DISABLE_VRML
241 11692 : if (ctx->flags & CTX_HAS_APPEARANCE) {
242 : GF_Matrix2D txt_mat;
243 11482 : visual_2d_get_texture_transform(ctx->appear, txh, &txt_mat, (txh == ctx->aspect.fill_texture) ? 0 : 1, INT2FIX(txh->width), INT2FIX(txh->height));
244 11482 : gf_mx2d_add_matrix(&g_mat, &txt_mat);
245 : }
246 : #endif
247 :
248 : /*move to bottom-left corner of bounds */
249 11692 : if (ext_mx) gf_mx2d_add_matrix(&g_mat, ext_mx);
250 11692 : if (orig_bounds) gf_mx2d_add_translation(&g_mat, (orig_bounds->x), (orig_bounds->y - orig_bounds->height));
251 :
252 11692 : gf_mx2d_add_matrix(&g_mat, &ctx->transform);
253 :
254 11692 : gf_evg_stencil_set_matrix(stencil, &g_mat);
255 11692 : gf_evg_stencil_set_color_matrix(stencil, ctx->col_mat);
256 :
257 : /*MPEG-4/VRML context or no fill info*/
258 11692 : if (ctx->flags & CTX_HAS_APPEARANCE || !ctx->aspect.fill_color)
259 11482 : gf_evg_stencil_set_alpha(stencil, 0xFF);
260 : else
261 210 : gf_evg_stencil_set_alpha(stencil, GF_COL_A(ctx->aspect.fill_color) );
262 :
263 11692 : gf_evg_surface_set_matrix(visual->raster_surface, &ctx->transform);
264 11692 : txh->flags |= GF_SR_TEXTURE_USED;
265 :
266 11692 : gf_evg_surface_set_path(visual->raster_surface, path);
267 11692 : visual_2d_fill_path(visual, ctx, stencil, tr_state, 0);
268 11692 : gf_evg_surface_set_path(visual->raster_surface, NULL);
269 :
270 11692 : ctx->flags |= CTX_PATH_FILLED;
271 : }
272 :
273 :
274 :
275 40 : void visual_2d_texture_path_text(GF_VisualManager *visual, DrawableContext *txt_ctx, GF_Path *path, GF_Rect *object_bounds, GF_TextureHandler *txh, GF_TraverseState *tr_state)
276 : {
277 : GF_EVGStencil * stencil;
278 : Fixed sS, sT;
279 : GF_Matrix2D gf_mx2d_txt;
280 : GF_Rect orig_rc;
281 : u8 alpha, r, g, b;
282 : GF_ColorMatrix cmat;
283 :
284 40 : if (! visual->CheckAttached(visual) ) return;
285 :
286 :
287 40 : stencil = gf_sc_texture_get_stencil(txh);
288 40 : if (!stencil) return;
289 :
290 40 : visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1);
291 :
292 : /*get original bounds*/
293 40 : orig_rc = *object_bounds;
294 :
295 : /*get scaling ratio so that active texture view is stretched to original bounds (std 2D shape texture mapping in MPEG4)*/
296 40 : sS = gf_divfix(orig_rc.width, INT2FIX(txh->width));
297 40 : sT = gf_divfix(orig_rc.height, INT2FIX(txh->height));
298 :
299 40 : gf_mx2d_init(gf_mx2d_txt);
300 40 : gf_mx2d_add_scale(&gf_mx2d_txt, sS, sT);
301 :
302 : /*move to bottom-left corner of bounds */
303 40 : gf_mx2d_add_translation(&gf_mx2d_txt, (orig_rc.x), (orig_rc.y - orig_rc.height));
304 :
305 : /*move to final coordinate system*/
306 40 : gf_mx2d_add_matrix(&gf_mx2d_txt, &txt_ctx->transform);
307 :
308 : /*set path transform, except for background2D node which is directly build in the final coord system*/
309 40 : gf_evg_stencil_set_matrix(stencil, &gf_mx2d_txt);
310 :
311 40 : alpha = GF_COL_A(txt_ctx->aspect.fill_color);
312 40 : r = GF_COL_R(txt_ctx->aspect.fill_color);
313 40 : g = GF_COL_G(txt_ctx->aspect.fill_color);
314 40 : b = GF_COL_B(txt_ctx->aspect.fill_color);
315 :
316 : /*if col do a cxmatrix*/
317 40 : if (!r && !g && !b) {
318 40 : gf_evg_stencil_set_alpha(stencil, alpha);
319 : } else {
320 0 : gf_evg_stencil_set_alpha(stencil, 0xFF);
321 : memset(cmat.m, 0, sizeof(Fixed) * 20);
322 0 : cmat.m[4] = INT2FIX(r)/255;
323 0 : cmat.m[9] = INT2FIX(g)/255;
324 0 : cmat.m[14] = INT2FIX(b)/255;
325 0 : cmat.m[18] = INT2FIX(alpha)/255;
326 0 : cmat.identity = 0;
327 0 : gf_evg_stencil_set_color_matrix(stencil, &cmat);
328 : }
329 :
330 40 : gf_evg_surface_set_matrix(visual->raster_surface, &txt_ctx->transform);
331 40 : txh->flags |= GF_SR_TEXTURE_USED;
332 :
333 : /*push path*/
334 40 : gf_evg_surface_set_path(visual->raster_surface, path);
335 :
336 40 : visual_2d_fill_path(visual, txt_ctx, stencil, tr_state, 0);
337 40 : gf_evg_surface_set_path(visual->raster_surface, NULL);
338 40 : txt_ctx->flags |= CTX_PATH_FILLED;
339 : }
340 :
341 :
342 : #ifndef GPAC_DISABLE_3D
343 :
344 1553 : void visual_2d_flush_hybgl_canvas(GF_VisualManager *visual, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_TraverseState *tr_state)
345 : {
346 : Bool line_texture = GF_FALSE;
347 : u32 i;
348 : u32 prev_color;
349 : Bool transparent, had_flush = 0;
350 1553 : u32 nb_obj_left_on_canvas = visual->nb_objects_on_canvas_since_last_ogl_flush;
351 : u8 alpha;
352 :
353 1553 : if (! visual->hybgl_drawn.count)
354 : return;
355 :
356 : //we have drawn things on the canvas before this object, flush canvas to GPU
357 :
358 1078 : if (txh && (txh==ctx->aspect.line_texture)) {
359 : line_texture = GF_TRUE;
360 0 : alpha = GF_COL_A(ctx->aspect.line_color);
361 : prev_color = ctx->aspect.line_color;
362 0 : ctx->aspect.line_texture = NULL;
363 0 : ctx->aspect.line_color = 0;
364 : } else {
365 1078 : alpha = GF_COL_A(ctx->aspect.fill_color);
366 1078 : if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
367 : prev_color = ctx->aspect.fill_color;
368 1078 : ctx->aspect.fill_texture = NULL;
369 1078 : ctx->aspect.fill_color = 0;
370 :
371 : }
372 1078 : transparent = txh ? (txh->transparent || (alpha!=0xFF)) : GF_TRUE;
373 : //clear wherever we have overlap
374 2165 : for (i=0; i<visual->hybgl_drawn.count; i++) {
375 1087 : GF_IRect rc = ctx->bi->clip;
376 1087 : gf_irect_intersect(&ctx->bi->clip, &visual->hybgl_drawn.list[i].rect);
377 1087 : if (ctx->bi->clip.width && ctx->bi->clip.height) {
378 : //if something behind this, flush canvas to gpu
379 1051 : if (transparent) {
380 901 : if (!had_flush) {
381 : //flush the complete area below this object, regardless of intersections
382 901 : compositor_2d_hybgl_flush_video(visual->compositor, tr_state->immediate_draw ? NULL : &rc);
383 : had_flush = 1;
384 : }
385 : //if object was not completely in the flush region we will need to flush the canvas
386 901 : if ( gf_irect_inside(&rc, &visual->hybgl_drawn.list[i].rect)) {
387 : //it may happen that we had no object on the canvas but syil have their bounds (we only drew textures)
388 337 : if (nb_obj_left_on_canvas)
389 186 : nb_obj_left_on_canvas--;
390 : }
391 : }
392 : //immediate mode flush, erase all canvas (we just completely flusged it)
393 1051 : if (tr_state->immediate_draw && had_flush && !tr_state->immediate_for_defer) {
394 1 : gf_evg_surface_clear(visual->raster_surface, NULL, 0);
395 : }
396 : //defer mode, erase all part of the canvas below us
397 1050 : else if (txh) {
398 300 : visual_2d_draw_path_extended(visual, ctx->drawable->path, ctx, NULL, NULL, tr_state, NULL, NULL, GF_TRUE);
399 : } else {
400 750 : gf_evg_surface_clear(visual->raster_surface, &ctx->bi->clip, 0);
401 : }
402 : }
403 1087 : ctx->bi->clip = rc;
404 : }
405 1078 : if (line_texture) {
406 0 : ctx->aspect.line_color = prev_color;
407 0 : ctx->aspect.line_texture = txh;
408 : } else {
409 1078 : ctx->aspect.fill_color = prev_color;
410 1078 : ctx->aspect.fill_texture = txh;
411 : }
412 :
413 1078 : if (had_flush) {
414 901 : visual->nb_objects_on_canvas_since_last_ogl_flush = nb_obj_left_on_canvas;
415 : }
416 : }
417 :
418 778 : void visual_2d_texture_path_opengl_auto(GF_VisualManager *visual, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_Rect *orig_bounds, GF_Matrix2D *ext_mx, GF_TraverseState *tr_state)
419 : {
420 : GF_Rect clipper;
421 : GF_Matrix mx, bck_mx;
422 778 : u32 prev_mode = tr_state->traversing_mode;
423 778 : u32 prev_type_3d = tr_state->visual->type_3d;
424 :
425 778 : visual_2d_flush_hybgl_canvas(visual, txh, ctx, tr_state);
426 :
427 778 : tr_state->visual->type_3d = 4;
428 778 : tr_state->appear = ctx->appear;
429 778 : if (ctx->col_mat) gf_cmx_copy(&tr_state->color_mat, ctx->col_mat);//
430 778 : gf_mx_copy(bck_mx, tr_state->model_matrix);
431 :
432 778 : tr_state->traversing_mode=TRAVERSE_DRAW_3D;
433 : //in hybridGL the 2D camera is always setup as centered-coords, we have to insert flip+translation in case of top-left origin
434 778 : if (tr_state->visual->center_coords) {
435 772 : gf_mx_from_mx2d(&tr_state->model_matrix, &ctx->transform);
436 : } else {
437 12 : gf_mx_init(tr_state->model_matrix);
438 6 : gf_mx_add_scale(&tr_state->model_matrix, FIX_ONE, -FIX_ONE, FIX_ONE);
439 6 : gf_mx_add_translation(&tr_state->model_matrix, -tr_state->camera->width/2, -tr_state->camera->height/2, 0);
440 :
441 6 : gf_mx_from_mx2d(&mx, &ctx->transform);
442 6 : gf_mx_add_matrix(&tr_state->model_matrix, &mx);
443 : }
444 :
445 778 : clipper.x = INT2FIX(ctx->bi->clip.x);
446 778 : clipper.y = INT2FIX(ctx->bi->clip.y);
447 778 : clipper.width = INT2FIX(ctx->bi->clip.width);
448 778 : clipper.height = INT2FIX(ctx->bi->clip.height);
449 778 : visual_3d_set_clipper_2d(tr_state->visual, clipper, NULL);
450 :
451 778 : gf_node_allow_cyclic_traverse(ctx->drawable->node);
452 778 : gf_node_traverse(ctx->drawable->node, tr_state);
453 :
454 778 : tr_state->visual->type_3d=prev_type_3d;
455 778 : tr_state->traversing_mode=prev_mode;
456 778 : if (ctx->col_mat) gf_cmx_init(&tr_state->color_mat);
457 :
458 778 : ctx->flags |= CTX_PATH_FILLED;
459 :
460 778 : visual_3d_reset_clipper_2d(tr_state->visual);
461 : gf_mx_copy(tr_state->model_matrix, bck_mx);
462 778 : }
463 : #endif
464 :
465 :
466 17692 : void visual_2d_texture_path_extended(GF_VisualManager *visual, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_Rect *orig_bounds, GF_Matrix2D *ext_mx, GF_TraverseState *tr_state)
467 : {
468 : Fixed sS, sT;
469 : u32 tx_tile;
470 : GF_EVGStencil * tx_raster;
471 : GF_Matrix2D mx_texture;
472 : GF_Rect orig_rc;
473 :
474 30448 : if (! visual->CheckAttached(visual) ) return;
475 :
476 17692 : if (!txh) txh = ctx->aspect.fill_texture;
477 17692 : if (!txh) return;
478 17692 : if (!txh->tx_io && !txh->data) {
479 286 : gf_node_dirty_set(txh->owner, 0, 1);
480 :
481 286 : txh->needs_refresh=1;
482 286 : return;
483 : }
484 :
485 :
486 : /*this is gradient draw*/
487 17406 : if (txh->compute_gradient_matrix) {
488 11692 : visual_2d_draw_gradient(visual, path, txh, ctx, tr_state, ext_mx, orig_bounds);
489 11692 : return;
490 : }
491 :
492 :
493 : #ifndef GPAC_DISABLE_3D
494 5714 : if (visual->compositor->hybrid_opengl) {
495 778 : visual_2d_texture_path_opengl_auto(visual, path, txh, ctx, orig_bounds, ext_mx, tr_state);
496 778 : return;
497 : }
498 : #endif
499 :
500 4936 : if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
501 : GF_Window src, dst;
502 0 : visual_2d_fill_path(visual, ctx, NULL, tr_state, 0);
503 :
504 : /*if texture not ready, update the size before computing output rectangles */
505 0 : if (!txh->width || !txh->height) {
506 0 : gf_mo_get_visual_info(txh->stream, &txh->width, &txh->height, &txh->stride, &txh->pixel_ar, &txh->pixelformat, &txh->is_flipped);
507 : /*in case the node is an MPEG-4 bitmap, force stack rebuild at next frame */
508 0 : gf_node_dirty_set(ctx->drawable->node, GF_SG_NODE_DIRTY, 1);
509 : }
510 :
511 0 : compositor_texture_rectangles(visual, txh, &ctx->bi->clip, &ctx->bi->unclip, &src, &dst, NULL, NULL);
512 : return;
513 : }
514 :
515 4936 : if (!gf_sc_texture_push_image(txh, 0, 1)) return;
516 4936 : tx_raster = gf_sc_texture_get_stencil(txh);
517 :
518 : /*setup quality even for background (since quality concerns images)*/
519 4936 : visual_2d_set_options(visual->compositor, visual->raster_surface, ctx->flags & CTX_IS_TEXT, ctx->flags & CTX_NO_ANTIALIAS);
520 :
521 : /*get original bounds*/
522 4936 : if (orig_bounds) {
523 0 : orig_rc = *orig_bounds;
524 : } else {
525 4936 : gf_path_get_bounds(path, &orig_rc);
526 : }
527 :
528 : /*get scaling ratio so that active texture view is stretched to original bounds (std 2D shape texture mapping in MPEG4)*/
529 4936 : sS = orig_rc.width / txh->width;
530 4936 : sT = orig_rc.height / txh->height;
531 :
532 4936 : gf_mx2d_init(mx_texture);
533 4936 : gf_mx2d_add_scale(&mx_texture, sS, sT);
534 :
535 : #ifndef GPAC_DISABLE_VRML
536 : /*apply texture transform*/
537 4936 : if (ctx->flags & CTX_HAS_APPEARANCE) {
538 : GF_Matrix2D tex_trans;
539 4729 : visual_2d_get_texture_transform(ctx->appear, txh, &tex_trans, (txh == ctx->aspect.fill_texture) ? 0 : 1, txh->width * sS, txh->height * sT);
540 4729 : gf_mx2d_add_matrix(&mx_texture, &tex_trans);
541 : }
542 : #endif
543 :
544 : /*move to bottom-left corner of bounds */
545 4936 : gf_mx2d_add_translation(&mx_texture, (orig_rc.x), (orig_rc.y - orig_rc.height));
546 :
547 4936 : if (ext_mx) gf_mx2d_add_matrix(&mx_texture, ext_mx);
548 :
549 : /*move to final coordinate system (except background which is built directly in final coord system)*/
550 4936 : if (!(ctx->flags & CTX_IS_BACKGROUND) ) gf_mx2d_add_matrix(&mx_texture, &ctx->transform);
551 :
552 : /*set path transform*/
553 4936 : gf_evg_stencil_set_matrix(tx_raster, &mx_texture);
554 :
555 :
556 : tx_tile = 0;
557 4936 : if (txh->flags & GF_SR_TEXTURE_REPEAT_S) tx_tile |= GF_TEXTURE_REPEAT_S;
558 4936 : if (txh->flags & GF_SR_TEXTURE_REPEAT_T) tx_tile |= GF_TEXTURE_REPEAT_T;
559 4936 : if (ctx->flags & CTX_FLIPED_COORDS)
560 0 : tx_tile |= GF_TEXTURE_FLIP_Y;
561 4936 : gf_evg_stencil_set_mapping(tx_raster, (GF_TextureMapFlags) tx_tile);
562 :
563 4936 : if (!(ctx->flags & CTX_IS_BACKGROUND) ) {
564 4729 : u8 a = GF_COL_A(ctx->aspect.fill_color);
565 4729 : if (!a) a = GF_COL_A(ctx->aspect.line_color);
566 : /*texture alpha scale is the original material transparency, NOT the one after color transform*/
567 4729 : gf_evg_stencil_set_alpha(tx_raster, a );
568 4729 : gf_evg_stencil_set_color_matrix(tx_raster, ctx->col_mat);
569 :
570 4729 : gf_evg_surface_set_matrix(visual->raster_surface, &ctx->transform);
571 : } else {
572 207 : gf_evg_surface_set_matrix(visual->raster_surface, NULL);
573 : }
574 4936 : txh->flags |= GF_SR_TEXTURE_USED;
575 :
576 : /*push path & draw*/
577 4936 : gf_evg_surface_set_path(visual->raster_surface, path);
578 4936 : visual_2d_fill_path(visual, ctx, tx_raster, tr_state, 0);
579 4936 : gf_evg_surface_set_path(visual->raster_surface, NULL);
580 :
581 :
582 :
583 4936 : ctx->flags |= CTX_PATH_FILLED;
584 : }
585 :
586 73611 : void visual_2d_texture_path(GF_VisualManager *visual, GF_Path *path, struct _drawable_context *ctx, GF_TraverseState *tr_state)
587 : {
588 : #ifdef SKIP_DRAW
589 : return;
590 : #endif
591 73611 : if (! visual->CheckAttached(visual) ) return;
592 :
593 73611 : if ((ctx->flags & CTX_PATH_FILLED) || !ctx->aspect.fill_texture || visual->compositor->is_hidden) return;
594 :
595 : /*this is ambiguous in the spec, what if the material is filled and the texture is transparent ?
596 : let's draw, it's nicer */
597 : #if 0
598 : if (GF_COL_A(ctx->aspect.fill_color) && ctx->aspect.fill_texture->transparent) {
599 : visual_2d_draw_path(visual, path, ctx, NULL, NULL);
600 : ctx->flags &= ~CTX_PATH_FILLED;
601 : }
602 : #endif
603 :
604 10769 : visual_2d_texture_path_extended(visual, path, NULL, ctx, NULL, NULL, tr_state);
605 : }
606 :
607 : #define ADAPTATION_SIZE 0
608 :
609 :
610 669228 : void visual_2d_draw_path_extended(GF_VisualManager *visual, GF_Path *path, DrawableContext *ctx, GF_EVGStencil * brush, GF_EVGStencil * pen, GF_TraverseState *tr_state, GF_Rect *orig_bounds, GF_Matrix2D *ext_mx, Bool is_erase)
611 : {
612 : Bool dofill, dostrike;
613 : #ifdef SKIP_DRAW
614 : return;
615 : #endif
616 669228 : if (! visual->CheckAttached(visual) ) return;
617 :
618 669228 : if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) {
619 0 : if (visual->compositor->bvol) draw_clipper(visual, ctx);
620 : return;
621 : }
622 :
623 669228 : if (! (ctx->flags & CTX_IS_BACKGROUND) )
624 669228 : visual_2d_set_options(visual->compositor, visual->raster_surface, ctx->flags & CTX_IS_TEXT, ctx->flags & CTX_NO_ANTIALIAS);
625 :
626 : dofill = dostrike = 0;
627 669228 : if (!(ctx->flags & CTX_PATH_FILLED) && (is_erase || GF_COL_A(ctx->aspect.fill_color)) ) {
628 : dofill = 1;
629 634171 : if (!brush) {
630 634171 : brush = visual->raster_brush;
631 634171 : gf_evg_stencil_set_brush_color(brush, ctx->aspect.fill_color);
632 : }
633 : }
634 :
635 :
636 : /*compute width based on transform and top_level transform*/
637 669228 : if (!(ctx->flags & CTX_PATH_STROKE) && ctx->aspect.pen_props.width) {
638 : dostrike = 1;
639 632246 : } else if (!dofill) {
640 : return;
641 : }
642 :
643 : /*set path transform, except for background2D node which is directly build in the final coord system*/
644 663702 : gf_evg_surface_set_matrix(visual->raster_surface, (ctx->flags & CTX_IS_BACKGROUND) ? NULL : &ctx->transform);
645 :
646 : /*fill path*/
647 663702 : if (dofill) {
648 : #if ADAPTATION_SIZE
649 : if ((ctx->bi->clip.width<ADAPTATION_SIZE) && (ctx->bi->clip.height<ADAPTATION_SIZE)) {
650 : gf_evg_surface_clear(visual->raster_surface, &ctx->bi->clip, ctx->aspect.fill_color);
651 : } else
652 : #endif
653 : {
654 : /*push path*/
655 634171 : gf_evg_surface_set_path(visual->raster_surface, path);
656 634171 : visual_2d_fill_path(visual, ctx, brush, tr_state, is_erase);
657 634171 : gf_evg_surface_set_path(visual->raster_surface, NULL);
658 : }
659 : }
660 :
661 663702 : if (dostrike) {
662 : #if ADAPTATION_SIZE
663 : if ((ctx->bi->clip.width<ADAPTATION_SIZE) && (ctx->bi->clip.height<ADAPTATION_SIZE)) {
664 : } else
665 : #endif
666 : {
667 : StrikeInfo2D *si;
668 :
669 36982 : if (!pen) {
670 36982 : pen = visual->raster_brush;
671 36982 : gf_evg_stencil_set_brush_color(pen, ctx->aspect.line_color);
672 : }
673 :
674 36982 : si = drawable_get_strikeinfo(visual->compositor, ctx->drawable, &ctx->aspect, ctx->appear, path, ctx->flags, NULL);
675 36982 : if (si && si->outline) {
676 36675 : if (ctx->aspect.line_texture) {
677 1789 : visual_2d_texture_path_extended(visual, si->outline, ctx->aspect.line_texture, ctx, orig_bounds, ext_mx, tr_state);
678 : } else {
679 34886 : gf_evg_surface_set_path(visual->raster_surface, si->outline);
680 34886 : visual_2d_fill_path(visual, ctx, pen, tr_state, 0);
681 : }
682 : /*that's ugly, but we cannot cache path outline for IFS2D/ILS2D*/
683 36675 : if (path && !(ctx->flags & CTX_IS_TEXT) && (path!=ctx->drawable->path) ) {
684 8 : gf_path_del(si->outline);
685 8 : si->outline = NULL;
686 : }
687 : }
688 : // drawable_reset_path_outline(ctx->drawable);
689 : }
690 : }
691 :
692 663702 : if (visual->compositor->bvol) draw_clipper(visual, ctx);
693 : }
694 :
695 663794 : void visual_2d_draw_path(GF_VisualManager *visual, GF_Path *path, DrawableContext *ctx, GF_EVGStencil * brush, GF_EVGStencil * pen, GF_TraverseState *tr_state)
696 : {
697 663794 : visual_2d_draw_path_extended(visual, path, ctx, brush, pen, tr_state, NULL, NULL, GF_FALSE);
698 663794 : }
699 :
700 1332 : void visual_2d_fill_rect(GF_VisualManager *visual, DrawableContext *ctx, GF_Rect *_rc, u32 color, u32 strike_color, GF_TraverseState *tr_state)
701 : {
702 : GF_Path *path;
703 : GF_Rect *rc;
704 : #ifdef SKIP_DRAW
705 : return;
706 : #endif
707 :
708 1332 : if (! visual->CheckAttached(visual) ) return;
709 :
710 1332 : if (!color && !strike_color) return;
711 :
712 0 : if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) {
713 0 : if (visual->compositor->bvol) draw_clipper(visual, ctx);
714 : return;
715 : }
716 :
717 : /*no aa*/
718 0 : visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1);
719 0 : if (_rc) {
720 : rc = _rc;
721 0 : gf_evg_surface_set_matrix(visual->raster_surface, &ctx->transform);
722 : }
723 : else {
724 0 : rc = &ctx->bi->unclip;
725 0 : gf_evg_surface_set_matrix(visual->raster_surface, NULL);
726 : }
727 :
728 0 : path = gf_path_new();
729 0 : gf_path_add_move_to(path, rc->x, rc->y-rc->height);
730 0 : gf_path_add_line_to(path, rc->x+rc->width, rc->y-rc->height);
731 0 : gf_path_add_line_to(path, rc->x+rc->width, rc->y);
732 0 : gf_path_add_line_to(path, rc->x, rc->y);
733 0 : gf_path_close(path);
734 :
735 :
736 0 : if (color) {
737 : /*push path*/
738 0 : gf_evg_surface_set_path(visual->raster_surface, path);
739 0 : gf_evg_stencil_set_brush_color(visual->raster_brush, color);
740 0 : visual_2d_fill_path(visual, ctx, visual->raster_brush, tr_state, 0);
741 0 : gf_evg_surface_set_path(visual->raster_surface, NULL);
742 : }
743 0 : if (strike_color) {
744 : GF_Path *outline;
745 : GF_PenSettings pen;
746 : memset(&pen, 0, sizeof(GF_PenSettings));
747 0 : pen.width = 1;
748 0 : pen.join = GF_LINE_JOIN_BEVEL;
749 0 : pen.dash = GF_DASH_STYLE_DOT;
750 0 : gf_evg_stencil_set_brush_color(visual->raster_brush, strike_color);
751 0 : outline = gf_path_get_outline(path, pen);
752 0 : outline->flags &= ~GF_PATH_FILL_ZERO_NONZERO;
753 0 : gf_evg_surface_set_path(visual->raster_surface, outline);
754 0 : visual_2d_fill_path(visual, ctx, visual->raster_brush, tr_state, 0);
755 0 : gf_evg_surface_set_path(visual->raster_surface, NULL);
756 0 : gf_path_del(outline);
757 : }
758 :
759 0 : gf_path_del(path);
760 : }
761 :
762 : #if 0 //unused
763 : void visual_2d_fill_irect(GF_VisualManager *visual, GF_IRect *rc, u32 fill, u32 strike)
764 : {
765 : GF_Path *path;
766 : GF_Path *outline;
767 : GF_PenSettings pen;
768 : #ifdef SKIP_DRAW
769 : return;
770 : #endif
771 :
772 : if (!rc) return;
773 :
774 : if (! visual->CheckAttached(visual) ) return;
775 :
776 : if (!fill && !strike ) return;
777 :
778 : /*no aa*/
779 : visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1);
780 : gf_evg_surface_set_matrix(visual->raster_surface, NULL);
781 :
782 : gf_evg_surface_set_raster_level(visual->raster_surface, GF_RASTER_HIGH_SPEED);
783 : gf_evg_surface_set_matrix(visual->raster_surface, NULL);
784 :
785 : path = gf_path_new();
786 : gf_path_add_move_to(path, INT2FIX(rc->x-1), INT2FIX(rc->y+2-rc->height));
787 : gf_path_add_line_to(path, INT2FIX(rc->x+rc->width-2), INT2FIX(rc->y+2-rc->height));
788 : gf_path_add_line_to(path, INT2FIX(rc->x+rc->width), INT2FIX(rc->y));
789 : gf_path_add_line_to(path, INT2FIX(rc->x), INT2FIX(rc->y));
790 : gf_path_close(path);
791 :
792 : if (fill) {
793 : gf_evg_surface_set_path(visual->raster_surface, path);
794 : gf_evg_stencil_set_brush_color(visual->raster_brush, fill);
795 :
796 : gf_evg_surface_set_clipper(visual->raster_surface, rc);
797 : gf_evg_surface_fill(visual->raster_surface, visual->raster_brush);
798 :
799 : gf_evg_surface_set_path(visual->raster_surface, NULL);
800 : }
801 :
802 : if (strike) {
803 : memset(&pen, 0, sizeof(GF_PenSettings));
804 : pen.width = 2;
805 : pen.align = GF_PATH_LINE_INSIDE;
806 : pen.join = GF_LINE_JOIN_BEVEL;
807 : outline = gf_path_get_outline(path, pen);
808 : outline->flags &= ~GF_PATH_FILL_ZERO_NONZERO;
809 :
810 : gf_evg_surface_set_path(visual->raster_surface, outline);
811 : gf_evg_stencil_set_brush_color(visual->raster_brush, strike);
812 :
813 : gf_evg_surface_set_clipper(visual->raster_surface, rc);
814 : gf_evg_surface_fill(visual->raster_surface, visual->raster_brush);
815 :
816 : gf_evg_surface_set_path(visual->raster_surface, NULL);
817 : gf_path_del(outline);
818 : }
819 : gf_path_del(path);
820 : #ifndef GPAC_DISABLE_3D
821 : if (!visual->offscreen && visual->compositor->hybrid_opengl)
822 : ra_union_rect(&visual->hybgl_drawn, rc);
823 : #endif
824 : }
825 : #endif
826 :
|