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 
visual_2d_init_raster(GF_VisualManager * visual)34 GF_Err visual_2d_init_raster(GF_VisualManager *visual)
35 {
36 	if (!visual->raster_surface) {
37 		visual->raster_surface = gf_evg_surface_new(visual->center_coords);
38 		if (!visual->raster_surface) return GF_IO_ERR;
39 	}
40 	return visual->GetSurfaceAccess(visual);
41 }
42 
visual_2d_release_raster(GF_VisualManager * visual)43 void visual_2d_release_raster(GF_VisualManager *visual)
44 {
45 	if (visual->raster_surface) {
46 		visual->ReleaseSurfaceAccess(visual);
47 	}
48 }
49 
50 
visual_2d_clear_surface(GF_VisualManager * visual,GF_IRect * rc,u32 BackColor,u32 is_offscreen)51 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 	if (! visual->CheckAttached(visual) ) return;
57 
58 	if (!BackColor && !visual->offscreen && !visual->compositor->dyn_filter_mode) {
59 		if ( !(visual->compositor->init_flags & GF_TERM_WINDOW_TRANSPARENT)) {
60 			BackColor = visual->compositor->back_color;
61 		}
62 	}
63 
64 	gf_evg_surface_clear(visual->raster_surface, rc, BackColor);
65 }
66 
draw_clipper(GF_VisualManager * visual,struct _drawable_context * ctx)67 static void draw_clipper(GF_VisualManager *visual, struct _drawable_context *ctx)
68 {
69 	GF_PenSettings clipset;
70 	GF_Path *clippath, *cliper;
71 
72 	if (ctx->flags & CTX_IS_BACKGROUND) return;
73 
74 	memset(&clipset, 0, sizeof(GF_PenSettings));
75 	clipset.width = 2*FIX_ONE;
76 
77 	clippath = gf_path_new();
78 	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 	cliper = gf_path_get_outline(clippath, clipset);
80 	gf_path_del(clippath);
81 	gf_evg_surface_set_matrix(visual->raster_surface, NULL);
82 	gf_evg_surface_set_clipper(visual->raster_surface, NULL);
83 	gf_evg_surface_set_path(visual->raster_surface, cliper);
84 	gf_evg_stencil_set_brush_color(visual->raster_brush, 0xFF000000);
85 	gf_evg_surface_fill(visual->raster_surface, visual->raster_brush);
86 	gf_path_del(cliper);
87 }
88 
visual_2d_fill_path(GF_VisualManager * visual,DrawableContext * ctx,GF_EVGStencil * stencil,GF_TraverseState * tr_state,Bool is_erase)89 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 	if (tr_state->immediate_draw) {
96 		if (ctx->bi->clip.width && ctx->bi->clip.height) {
97 			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 			if (stencil) {
100 				gf_evg_surface_set_clipper(visual->raster_surface, &ctx->bi->clip);
101 				gf_evg_surface_fill(visual->raster_surface, stencil);
102 			} else {
103 				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 		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 			clip = ctx->bi->clip;
118 			gf_irect_intersect(&clip, &visual->to_redraw.list[i].rect);
119 			if (clip.width && clip.height) {
120 				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 				if (stencil) {
122 					gf_evg_surface_set_clipper(visual->raster_surface, &clip);
123 					gf_evg_surface_fill(visual->raster_surface, stencil);
124 				} else {
125 					gf_evg_surface_clear(visual->raster_surface, &clip, 0);
126 				}
127 				has_modif = 1;
128 			}
129 		}
130 	}
131 #ifndef GPAC_DISABLE_3D
132 	if (!is_erase)
133 		visual->nb_objects_on_canvas_since_last_ogl_flush++;
134 #endif
135 	if (has_modif) {
136 		visual->has_modif = 1;
137 #ifndef GPAC_DISABLE_3D
138 		if (!visual->offscreen && visual->compositor->hybrid_opengl && !is_erase)
139 			ra_union_rect(&visual->hybgl_drawn, &ctx->bi->clip);
140 #endif
141 	}
142 }
143 
visual_2d_set_options(GF_Compositor * compositor,GF_EVGSurface * rend,Bool forText,Bool no_antialias)144 static void visual_2d_set_options(GF_Compositor *compositor, GF_EVGSurface *rend, Bool forText, Bool no_antialias)
145 {
146 	if (no_antialias) {
147 		gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_SPEED);
148 	} else {
149 		switch (compositor->aa) {
150 		case GF_ANTIALIAS_NONE:
151 			gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_SPEED);
152 			break;
153 		case GF_ANTIALIAS_TEXT:
154 			if (forText) {
155 				gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_QUALITY);
156 			} else {
157 				gf_evg_surface_set_raster_level(rend, compositor->fast ? GF_RASTER_HIGH_QUALITY : GF_RASTER_MID);
158 			}
159 			break;
160 		case GF_ANTIALIAS_FULL:
161 		default:
162 			gf_evg_surface_set_raster_level(rend, GF_RASTER_HIGH_QUALITY);
163 			break;
164 		}
165 	}
166 }
167 
168 
169 #ifndef GPAC_DISABLE_VRML
visual_2d_get_texture_transform(GF_Node * __appear,GF_TextureHandler * txh,GF_Matrix2D * mat,Bool line_texture,Fixed final_width,Fixed final_height)170 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 	gf_mx2d_init(*mat);
176 
177 	if (!__appear || !txh) return;
178 	appear = (M_Appearance *)__appear;
179 
180 	if (!line_texture) {
181 		if (!appear->textureTransform) return;
182 		txtrans = appear->textureTransform;
183 	} else {
184 		if (gf_node_get_tag(appear->material) != TAG_MPEG4_Material2D) return;
185 		if (gf_node_get_tag(((M_Material2D *)appear->material)->lineProps) != TAG_MPEG4_XLineProperties) return;
186 		txtrans = ((M_XLineProperties *) ((M_Material2D *)appear->material)->lineProps)->textureTransform;
187 	}
188 	if (!txtrans) return;
189 
190 	/*gradient doesn't need bounds info in texture transform*/
191 	if (txh->compute_gradient_matrix) {
192 		final_width = final_height = FIX_ONE;
193 	}
194 	node_tag = gf_node_get_tag(txtrans);
195 	if (node_tag==TAG_MPEG4_TextureTransform) {
196 		/*VRML: Tc' = -C � S � R � C � T � Tc*/
197 		M_TextureTransform *txt = (M_TextureTransform *) txtrans;
198 		SFVec2f scale = txt->scale;
199 		if (!scale.x) scale.x = FIX_ONE/100;
200 		if (!scale.y) scale.y = FIX_ONE/100;
201 
202 		gf_mx2d_add_translation(mat, -gf_mulfix(txt->center.x, final_width), -gf_mulfix(txt->center.y, final_height) );
203 		gf_mx2d_add_scale(mat, scale.x, scale.y);
204 		gf_mx2d_add_rotation(mat, 0, 0, txt->rotation);
205 		gf_mx2d_add_translation(mat, gf_mulfix(txt->center.x, final_width), gf_mulfix(txt->center.y, final_height) );
206 		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 		gf_mx2d_inverse(mat);
209 		return;
210 	}
211 	if (node_tag==TAG_MPEG4_TransformMatrix2D) {
212 		tr_mx2d_get_matrix((GF_Node *) txtrans, mat);
213 		mat->m[2] = gf_mulfix(mat->m[2], final_width);
214 		mat->m[5] = gf_mulfix(mat->m[5], final_height);
215 		gf_mx2d_inverse(mat);
216 		return;
217 	}
218 }
219 #endif /*GPAC_DISABLE_VRML*/
220 
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)221 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 	if (!txh) txh = ctx->aspect.fill_texture;
228 
229 	gf_path_get_bounds(path, &rc);
230 	if (!rc.width || !rc.height || !txh->tx_io) return;
231 
232 	if (orig_bounds) {
233 		txh->compute_gradient_matrix(txh, orig_bounds, &g_mat, 0);
234 	} else {
235 		txh->compute_gradient_matrix(txh, &rc, &g_mat, 0);
236 	}
237 	stencil = gf_sc_texture_get_stencil(txh);
238 	if (!stencil) return;
239 
240 #ifndef GPAC_DISABLE_VRML
241 	if (ctx->flags & CTX_HAS_APPEARANCE) {
242 		GF_Matrix2D txt_mat;
243 		visual_2d_get_texture_transform(ctx->appear, txh, &txt_mat, (txh == ctx->aspect.fill_texture) ? 0 : 1, INT2FIX(txh->width), INT2FIX(txh->height));
244 		gf_mx2d_add_matrix(&g_mat, &txt_mat);
245 	}
246 #endif
247 
248 	/*move to bottom-left corner of bounds */
249 	if (ext_mx) gf_mx2d_add_matrix(&g_mat, ext_mx);
250 	if (orig_bounds) gf_mx2d_add_translation(&g_mat, (orig_bounds->x), (orig_bounds->y - orig_bounds->height));
251 
252 	gf_mx2d_add_matrix(&g_mat, &ctx->transform);
253 
254 	gf_evg_stencil_set_matrix(stencil, &g_mat);
255 	gf_evg_stencil_set_color_matrix(stencil, ctx->col_mat);
256 
257 	/*MPEG-4/VRML context or no fill info*/
258 	if (ctx->flags & CTX_HAS_APPEARANCE || !ctx->aspect.fill_color)
259 		gf_evg_stencil_set_alpha(stencil, 0xFF);
260 	else
261 		gf_evg_stencil_set_alpha(stencil, GF_COL_A(ctx->aspect.fill_color) );
262 
263 	gf_evg_surface_set_matrix(visual->raster_surface, &ctx->transform);
264 	txh->flags |= GF_SR_TEXTURE_USED;
265 
266 	gf_evg_surface_set_path(visual->raster_surface, path);
267 	visual_2d_fill_path(visual, ctx, stencil, tr_state, 0);
268 	gf_evg_surface_set_path(visual->raster_surface, NULL);
269 
270 	ctx->flags |= CTX_PATH_FILLED;
271 }
272 
273 
274 
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)275 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 	if (! visual->CheckAttached(visual) ) return;
285 
286 
287 	stencil = gf_sc_texture_get_stencil(txh);
288 	if (!stencil) return;
289 
290 	visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1);
291 
292 	/*get original bounds*/
293 	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 	sS = gf_divfix(orig_rc.width, INT2FIX(txh->width));
297 	sT = gf_divfix(orig_rc.height, INT2FIX(txh->height));
298 
299 	gf_mx2d_init(gf_mx2d_txt);
300 	gf_mx2d_add_scale(&gf_mx2d_txt, sS, sT);
301 
302 	/*move to bottom-left corner of bounds */
303 	gf_mx2d_add_translation(&gf_mx2d_txt, (orig_rc.x), (orig_rc.y - orig_rc.height));
304 
305 	/*move to final coordinate system*/
306 	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 	gf_evg_stencil_set_matrix(stencil, &gf_mx2d_txt);
310 
311 	alpha = GF_COL_A(txt_ctx->aspect.fill_color);
312 	r = GF_COL_R(txt_ctx->aspect.fill_color);
313 	g = GF_COL_G(txt_ctx->aspect.fill_color);
314 	b = GF_COL_B(txt_ctx->aspect.fill_color);
315 
316 	/*if col do a cxmatrix*/
317 	if (!r && !g && !b) {
318 		gf_evg_stencil_set_alpha(stencil, alpha);
319 	} else {
320 		gf_evg_stencil_set_alpha(stencil, 0xFF);
321 		memset(cmat.m, 0, sizeof(Fixed) * 20);
322 		cmat.m[4] = INT2FIX(r)/255;
323 		cmat.m[9] = INT2FIX(g)/255;
324 		cmat.m[14] = INT2FIX(b)/255;
325 		cmat.m[18] = INT2FIX(alpha)/255;
326 		cmat.identity = 0;
327 		gf_evg_stencil_set_color_matrix(stencil, &cmat);
328 	}
329 
330 	gf_evg_surface_set_matrix(visual->raster_surface, &txt_ctx->transform);
331 	txh->flags |= GF_SR_TEXTURE_USED;
332 
333 	/*push path*/
334 	gf_evg_surface_set_path(visual->raster_surface, path);
335 
336 	visual_2d_fill_path(visual, txt_ctx, stencil, tr_state, 0);
337 	gf_evg_surface_set_path(visual->raster_surface, NULL);
338 	txt_ctx->flags |= CTX_PATH_FILLED;
339 }
340 
341 
342 #ifndef GPAC_DISABLE_3D
343 
visual_2d_flush_hybgl_canvas(GF_VisualManager * visual,GF_TextureHandler * txh,struct _drawable_context * ctx,GF_TraverseState * tr_state)344 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 	u32 nb_obj_left_on_canvas = visual->nb_objects_on_canvas_since_last_ogl_flush;
351 	u8 alpha;
352 
353 	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 	if (txh && (txh==ctx->aspect.line_texture)) {
359 		line_texture = GF_TRUE;
360 		alpha = GF_COL_A(ctx->aspect.line_color);
361 		prev_color = ctx->aspect.line_color;
362 		ctx->aspect.line_texture = NULL;
363 		ctx->aspect.line_color = 0;
364 	} else {
365 		alpha = GF_COL_A(ctx->aspect.fill_color);
366 		if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
367 		prev_color = ctx->aspect.fill_color;
368 		ctx->aspect.fill_texture = NULL;
369 		ctx->aspect.fill_color = 0;
370 
371 	}
372 	transparent = txh ? (txh->transparent || (alpha!=0xFF)) : GF_TRUE;
373 	//clear wherever we have overlap
374 	for (i=0; i<visual->hybgl_drawn.count; i++) {
375 		GF_IRect rc = ctx->bi->clip;
376 		gf_irect_intersect(&ctx->bi->clip, &visual->hybgl_drawn.list[i].rect);
377 		if (ctx->bi->clip.width && ctx->bi->clip.height) {
378 			//if something behind this, flush canvas to gpu
379 			if (transparent) {
380 				if (!had_flush) {
381 					//flush the complete area below this object, regardless of intersections
382 					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 				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 					if (nb_obj_left_on_canvas)
389 						nb_obj_left_on_canvas--;
390 				}
391 			}
392 			//immediate mode flush, erase all canvas (we just completely flusged it)
393 			if (tr_state->immediate_draw && had_flush && !tr_state->immediate_for_defer) {
394 				gf_evg_surface_clear(visual->raster_surface, NULL, 0);
395 			}
396 			//defer mode, erase all part of the canvas below us
397 			else if (txh) {
398 				visual_2d_draw_path_extended(visual, ctx->drawable->path, ctx, NULL, NULL, tr_state, NULL, NULL, GF_TRUE);
399 			} else {
400 				gf_evg_surface_clear(visual->raster_surface, &ctx->bi->clip, 0);
401 			}
402 		}
403 		ctx->bi->clip = rc;
404 	}
405 	if (line_texture) {
406 		ctx->aspect.line_color = prev_color;
407 		ctx->aspect.line_texture = txh;
408 	} else {
409 		ctx->aspect.fill_color = prev_color;
410 		ctx->aspect.fill_texture = txh;
411 	}
412 
413 	if (had_flush) {
414 		visual->nb_objects_on_canvas_since_last_ogl_flush = nb_obj_left_on_canvas;
415 	}
416 }
417 
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)418 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 	u32 prev_mode = tr_state->traversing_mode;
423 	u32 prev_type_3d = tr_state->visual->type_3d;
424 
425 	visual_2d_flush_hybgl_canvas(visual, txh, ctx, tr_state);
426 
427 	tr_state->visual->type_3d = 4;
428 	tr_state->appear = ctx->appear;
429 	if (ctx->col_mat) gf_cmx_copy(&tr_state->color_mat, ctx->col_mat);//
430 	gf_mx_copy(bck_mx, tr_state->model_matrix);
431 
432 	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 	if (tr_state->visual->center_coords) {
435 		gf_mx_from_mx2d(&tr_state->model_matrix, &ctx->transform);
436 	} else {
437 		gf_mx_init(tr_state->model_matrix);
438 		gf_mx_add_scale(&tr_state->model_matrix, FIX_ONE, -FIX_ONE, FIX_ONE);
439 		gf_mx_add_translation(&tr_state->model_matrix, -tr_state->camera->width/2, -tr_state->camera->height/2, 0);
440 
441 		gf_mx_from_mx2d(&mx, &ctx->transform);
442 		gf_mx_add_matrix(&tr_state->model_matrix, &mx);
443 	}
444 
445 	clipper.x = INT2FIX(ctx->bi->clip.x);
446 	clipper.y = INT2FIX(ctx->bi->clip.y);
447 	clipper.width = INT2FIX(ctx->bi->clip.width);
448 	clipper.height = INT2FIX(ctx->bi->clip.height);
449 	visual_3d_set_clipper_2d(tr_state->visual, clipper, NULL);
450 
451 	gf_node_allow_cyclic_traverse(ctx->drawable->node);
452 	gf_node_traverse(ctx->drawable->node, tr_state);
453 
454 	tr_state->visual->type_3d=prev_type_3d;
455 	tr_state->traversing_mode=prev_mode;
456 	if (ctx->col_mat) gf_cmx_init(&tr_state->color_mat);
457 
458 	ctx->flags |= CTX_PATH_FILLED;
459 
460 	visual_3d_reset_clipper_2d(tr_state->visual);
461 	gf_mx_copy(tr_state->model_matrix, bck_mx);
462 }
463 #endif
464 
465 
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)466 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 	if (! visual->CheckAttached(visual) ) return;
475 
476 	if (!txh) txh = ctx->aspect.fill_texture;
477 	if (!txh) return;
478 	if (!txh->tx_io && !txh->data) {
479 		gf_node_dirty_set(txh->owner, 0, 1);
480 
481 		txh->needs_refresh=1;
482 		return;
483 	}
484 
485 
486 	/*this is gradient draw*/
487 	if (txh->compute_gradient_matrix) {
488 		visual_2d_draw_gradient(visual, path, txh, ctx, tr_state, ext_mx, orig_bounds);
489 		return;
490 	}
491 
492 
493 #ifndef GPAC_DISABLE_3D
494 	if (visual->compositor->hybrid_opengl) {
495 		visual_2d_texture_path_opengl_auto(visual, path, txh, ctx, orig_bounds, ext_mx, tr_state);
496 		return;
497 	}
498 #endif
499 
500 	if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) {
501 		GF_Window src, dst;
502 		visual_2d_fill_path(visual, ctx, NULL, tr_state, 0);
503 
504 		/*if texture not ready, update the size before computing output rectangles */
505 		if (!txh->width || !txh->height) {
506 			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 			gf_node_dirty_set(ctx->drawable->node, GF_SG_NODE_DIRTY, 1);
509 		}
510 
511 		compositor_texture_rectangles(visual, txh, &ctx->bi->clip, &ctx->bi->unclip, &src, &dst, NULL, NULL);
512 		return;
513 	}
514 
515 	if (!gf_sc_texture_push_image(txh, 0, 1)) return;
516 	tx_raster = gf_sc_texture_get_stencil(txh);
517 
518 	/*setup quality even for background (since quality concerns images)*/
519 	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 	if (orig_bounds) {
523 		orig_rc = *orig_bounds;
524 	} else {
525 		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 	sS = orig_rc.width / txh->width;
530 	sT = orig_rc.height / txh->height;
531 
532 	gf_mx2d_init(mx_texture);
533 	gf_mx2d_add_scale(&mx_texture, sS, sT);
534 
535 #ifndef GPAC_DISABLE_VRML
536 	/*apply texture transform*/
537 	if (ctx->flags & CTX_HAS_APPEARANCE) {
538 		GF_Matrix2D tex_trans;
539 		visual_2d_get_texture_transform(ctx->appear, txh, &tex_trans, (txh == ctx->aspect.fill_texture) ? 0 : 1, txh->width * sS, txh->height * sT);
540 		gf_mx2d_add_matrix(&mx_texture, &tex_trans);
541 	}
542 #endif
543 
544 	/*move to bottom-left corner of bounds */
545 	gf_mx2d_add_translation(&mx_texture, (orig_rc.x), (orig_rc.y - orig_rc.height));
546 
547 	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 	if (!(ctx->flags & CTX_IS_BACKGROUND) ) gf_mx2d_add_matrix(&mx_texture, &ctx->transform);
551 
552 	/*set path transform*/
553 	gf_evg_stencil_set_matrix(tx_raster, &mx_texture);
554 
555 
556 	tx_tile = 0;
557 	if (txh->flags & GF_SR_TEXTURE_REPEAT_S) tx_tile |= GF_TEXTURE_REPEAT_S;
558 	if (txh->flags & GF_SR_TEXTURE_REPEAT_T) tx_tile |= GF_TEXTURE_REPEAT_T;
559 	if (ctx->flags & CTX_FLIPED_COORDS)
560 		tx_tile |= GF_TEXTURE_FLIP_Y;
561 	gf_evg_stencil_set_mapping(tx_raster, (GF_TextureMapFlags) tx_tile);
562 
563 	if (!(ctx->flags & CTX_IS_BACKGROUND) ) {
564 		u8 a = GF_COL_A(ctx->aspect.fill_color);
565 		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 		gf_evg_stencil_set_alpha(tx_raster, a );
568 		gf_evg_stencil_set_color_matrix(tx_raster, ctx->col_mat);
569 
570 		gf_evg_surface_set_matrix(visual->raster_surface, &ctx->transform);
571 	} else {
572 		gf_evg_surface_set_matrix(visual->raster_surface, NULL);
573 	}
574 	txh->flags |= GF_SR_TEXTURE_USED;
575 
576 	/*push path & draw*/
577 	gf_evg_surface_set_path(visual->raster_surface, path);
578 	visual_2d_fill_path(visual, ctx, tx_raster, tr_state, 0);
579 	gf_evg_surface_set_path(visual->raster_surface, NULL);
580 
581 
582 
583 	ctx->flags |= CTX_PATH_FILLED;
584 }
585 
visual_2d_texture_path(GF_VisualManager * visual,GF_Path * path,struct _drawable_context * ctx,GF_TraverseState * tr_state)586 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 	if (! visual->CheckAttached(visual) ) return;
592 
593 	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 	visual_2d_texture_path_extended(visual, path, NULL, ctx, NULL, NULL, tr_state);
605 }
606 
607 #define ADAPTATION_SIZE		0
608 
609 
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)610 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 	if (! visual->CheckAttached(visual) ) return;
617 
618 	if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) {
619 		if (visual->compositor->bvol) draw_clipper(visual, ctx);
620 		return;
621 	}
622 
623 	if (! (ctx->flags & CTX_IS_BACKGROUND) )
624 		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 	if (!(ctx->flags & CTX_PATH_FILLED) && (is_erase || GF_COL_A(ctx->aspect.fill_color)) ) {
628 		dofill = 1;
629 		if (!brush) {
630 			brush = visual->raster_brush;
631 			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 	if (!(ctx->flags & CTX_PATH_STROKE) && ctx->aspect.pen_props.width) {
638 		dostrike = 1;
639 	} 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 	gf_evg_surface_set_matrix(visual->raster_surface, (ctx->flags & CTX_IS_BACKGROUND) ? NULL : &ctx->transform);
645 
646 	/*fill path*/
647 	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 			gf_evg_surface_set_path(visual->raster_surface, path);
656 			visual_2d_fill_path(visual, ctx, brush, tr_state, is_erase);
657 			gf_evg_surface_set_path(visual->raster_surface, NULL);
658 		}
659 	}
660 
661 	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 			if (!pen) {
670 				pen = visual->raster_brush;
671 				gf_evg_stencil_set_brush_color(pen, ctx->aspect.line_color);
672 			}
673 
674 			si = drawable_get_strikeinfo(visual->compositor, ctx->drawable, &ctx->aspect, ctx->appear, path, ctx->flags, NULL);
675 			if (si && si->outline) {
676 				if (ctx->aspect.line_texture) {
677 					visual_2d_texture_path_extended(visual, si->outline, ctx->aspect.line_texture, ctx, orig_bounds, ext_mx, tr_state);
678 				} else {
679 					gf_evg_surface_set_path(visual->raster_surface, si->outline);
680 					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 				if (path && !(ctx->flags & CTX_IS_TEXT) && (path!=ctx->drawable->path) ) {
684 					gf_path_del(si->outline);
685 					si->outline = NULL;
686 				}
687 			}
688 //			drawable_reset_path_outline(ctx->drawable);
689 		}
690 	}
691 
692 	if (visual->compositor->bvol) draw_clipper(visual, ctx);
693 }
694 
visual_2d_draw_path(GF_VisualManager * visual,GF_Path * path,DrawableContext * ctx,GF_EVGStencil * brush,GF_EVGStencil * pen,GF_TraverseState * tr_state)695 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 	visual_2d_draw_path_extended(visual, path, ctx, brush, pen, tr_state, NULL, NULL, GF_FALSE);
698 }
699 
visual_2d_fill_rect(GF_VisualManager * visual,DrawableContext * ctx,GF_Rect * _rc,u32 color,u32 strike_color,GF_TraverseState * tr_state)700 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 	if (! visual->CheckAttached(visual) ) return;
709 
710 	if (!color && !strike_color) return;
711 
712 	if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) {
713 		if (visual->compositor->bvol) draw_clipper(visual, ctx);
714 		return;
715 	}
716 
717 	/*no aa*/
718 	visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1);
719 	if (_rc) {
720 		rc = _rc;
721 		gf_evg_surface_set_matrix(visual->raster_surface, &ctx->transform);
722 	}
723 	else {
724 		rc = &ctx->bi->unclip;
725 		gf_evg_surface_set_matrix(visual->raster_surface, NULL);
726 	}
727 
728 	path = gf_path_new();
729 	gf_path_add_move_to(path, rc->x, rc->y-rc->height);
730 	gf_path_add_line_to(path, rc->x+rc->width, rc->y-rc->height);
731 	gf_path_add_line_to(path, rc->x+rc->width, rc->y);
732 	gf_path_add_line_to(path, rc->x, rc->y);
733 	gf_path_close(path);
734 
735 
736 	if (color) {
737 		/*push path*/
738 		gf_evg_surface_set_path(visual->raster_surface, path);
739 		gf_evg_stencil_set_brush_color(visual->raster_brush, color);
740 		visual_2d_fill_path(visual, ctx, visual->raster_brush, tr_state, 0);
741 		gf_evg_surface_set_path(visual->raster_surface, NULL);
742 	}
743 	if (strike_color) {
744 		GF_Path *outline;
745 		GF_PenSettings pen;
746 		memset(&pen, 0, sizeof(GF_PenSettings));
747 		pen.width = 1;
748 		pen.join = GF_LINE_JOIN_BEVEL;
749 		pen.dash = GF_DASH_STYLE_DOT;
750 		gf_evg_stencil_set_brush_color(visual->raster_brush, strike_color);
751 		outline = gf_path_get_outline(path,  pen);
752 		outline->flags &= ~GF_PATH_FILL_ZERO_NONZERO;
753 		gf_evg_surface_set_path(visual->raster_surface, outline);
754 		visual_2d_fill_path(visual, ctx, visual->raster_brush, tr_state, 0);
755 		gf_evg_surface_set_path(visual->raster_surface, NULL);
756 		gf_path_del(outline);
757 	}
758 
759 	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 
827