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 :
27 :
28 : #include "nodes_stacks.h"
29 : #include "visual_manager.h"
30 : #include "texturing.h"
31 :
32 : #ifndef GPAC_DISABLE_VRML
33 :
34 : typedef struct _bitmap_stack
35 : {
36 : Drawable s_graph;
37 : /*cached size for 3D mode*/
38 : SFVec2f size, scale;
39 : u32 prev_tx_w, prev_tx_h;
40 : GF_Rect rc, unclip_rc;
41 : } BitmapStack;
42 :
43 :
44 :
45 8076 : static void Bitmap_BuildGraph(GF_Node *node, BitmapStack *st, GF_TraverseState *tr_state, GF_Rect *out_rc, Bool notify_changes)
46 : {
47 : GF_TextureHandler *txh;
48 : Fixed sx, sy;
49 : SFVec2f size;
50 :
51 : M_Bitmap *bmp = (M_Bitmap *)node;
52 :
53 15667 : if (!tr_state->appear) return;
54 7982 : if (! ((M_Appearance *)tr_state->appear)->texture) return;
55 7934 : txh = gf_sc_texture_get_handler( ((M_Appearance *)tr_state->appear)->texture );
56 : /*bitmap not ready*/
57 7934 : if (!txh || !txh->width || !txh->height
58 : #ifndef GPAC_DISABLE_3D
59 6929 : || (tr_state->visual->type_3d && !txh->tx_io)
60 : #endif
61 : ) {
62 1005 : if (notify_changes) gf_node_dirty_set(node, 0, 1);
63 : return;
64 : }
65 : /*no change in scale and same texture size*/
66 6929 : if ((st->scale.x==bmp->scale.x) && (st->scale.y==bmp->scale.y) && (st->prev_tx_w == txh->width) && (st->prev_tx_h == txh->height)) {
67 6444 : *out_rc = st->rc;
68 6444 : gf_node_dirty_clear(node, 0);
69 6444 : return;
70 : }
71 :
72 485 : st->prev_tx_w = txh->width;
73 485 : st->prev_tx_h = txh->height;
74 :
75 485 : sx = bmp->scale.x;
76 485 : if (sx<0) sx = FIX_ONE;
77 485 : sy = bmp->scale.y;
78 485 : if (sy<0) sy = FIX_ONE;
79 485 : st->scale = bmp->scale;
80 :
81 485 : compositor_adjust_scale(txh->owner, &sx, &sy);
82 :
83 : /*check size change*/
84 485 : size.x = gf_mulfix(INT2FIX(txh->width),sx);
85 485 : size.y = gf_mulfix(INT2FIX(txh->height),sy);
86 : /*if we have a PAR update it!!*/
87 485 : if (txh->pixel_ar) {
88 13 : u32 n = (txh->pixel_ar>>16) & 0xFFFF;
89 13 : u32 d = (txh->pixel_ar) & 0xFFFF;
90 13 : size.x = gf_mulfix(INT2FIX( (txh->width * n) / d),sx);
91 : }
92 :
93 :
94 : /*we're in meter metrics*/
95 485 : if (!tr_state->pixel_metrics) {
96 3 : size.x = gf_divfix(size.x, tr_state->min_hsize);
97 3 : size.y = gf_divfix(size.y, tr_state->min_hsize);
98 : }
99 485 : *out_rc = st->rc = gf_rect_center(size.x, size.y);
100 :
101 485 : gf_node_dirty_clear(node, 0);
102 :
103 485 : if ((st->size.x==size.x) && (st->size.y==size.y)) return;
104 485 : st->size = size;
105 :
106 : /*change in size*/
107 485 : if (notify_changes) gf_node_dirty_set(node, 0, 1);
108 :
109 : /*get size with scale*/
110 485 : drawable_reset_path(&st->s_graph);
111 485 : gf_path_add_rect_center(st->s_graph.path, 0, 0, st->size.x, st->size.y);
112 : }
113 :
114 : #ifndef GPAC_DISABLE_3D
115 771 : static void draw_bitmap_3d(GF_Node *node, GF_TraverseState *tr_state)
116 : {
117 : GF_Node *appear;
118 : DrawAspect2D asp;
119 : GF_ColorKey keyColor;
120 771 : BitmapStack *st = (BitmapStack *)gf_node_get_private(node);
121 : M_Bitmap *bmp = (M_Bitmap *)node;
122 :
123 : /*no choice but to update the graph since a bitmap may be used with several textures ...*/
124 771 : Bitmap_BuildGraph(node, st, tr_state, &tr_state->bounds, 0);
125 :
126 : memset(&asp, 0, sizeof(DrawAspect2D));
127 771 : drawable_get_aspect_2d_mpeg4(node, &asp, tr_state);
128 :
129 771 : appear = tr_state->override_appearance ? tr_state->override_appearance : tr_state->appear;
130 : /*check for material key materialKey*/
131 771 : if (appear) {
132 : M_Appearance *app = (M_Appearance *)appear;
133 681 : if ( app->material && (gf_node_get_tag((GF_Node *)app->material)==TAG_MPEG4_MaterialKey) ) {
134 46 : M_MaterialKey*mk = (M_MaterialKey*)app->material;
135 46 : if (mk->isKeyed) {
136 46 : keyColor.r = FIX2INT(mk->keyColor.red * 255);
137 46 : keyColor.g = FIX2INT(mk->keyColor.green * 255);
138 46 : keyColor.b = FIX2INT(mk->keyColor.blue * 255);
139 46 : keyColor.alpha = FIX2INT( (FIX_ONE - mk->transparency) * 255);
140 46 : keyColor.low = FIX2INT(mk->lowThreshold * 255);
141 46 : keyColor.high = FIX2INT(mk->highThreshold * 255);
142 46 : tr_state->col_key = &keyColor;
143 : }
144 : }
145 : }
146 :
147 771 : compositor_3d_draw_bitmap(&st->s_graph, &asp, tr_state, st->size.x, st->size.y, bmp->scale.x, bmp->scale.y);
148 :
149 771 : tr_state->col_key = NULL;
150 771 : }
151 : #endif
152 :
153 5897 : static void draw_bitmap_2d(GF_Node *node, GF_TraverseState *tr_state)
154 : {
155 : GF_ColorKey keyColor;
156 5897 : DrawableContext *ctx = tr_state->ctx;
157 5897 : BitmapStack *st = (BitmapStack *) gf_node_get_private(node);
158 :
159 :
160 : /*bitmaps are NEVER rotated (forbidden in spec). In case a rotation was done we still display (reset the skew components)*/
161 5897 : ctx->transform.m[1] = ctx->transform.m[3] = 0;
162 :
163 : /*check for material key materialKey*/
164 5897 : if (ctx->appear) {
165 : M_Appearance *app = (M_Appearance *)ctx->appear;
166 5897 : if ( app->material && (gf_node_get_tag((GF_Node *)app->material)==TAG_MPEG4_MaterialKey) ) {
167 121 : M_MaterialKey*mk = (M_MaterialKey*)app->material;
168 121 : if (mk->isKeyed) {
169 121 : keyColor.r = FIX2INT(mk->keyColor.red * 255);
170 121 : keyColor.g = FIX2INT(mk->keyColor.green * 255);
171 121 : keyColor.b = FIX2INT(mk->keyColor.blue * 255);
172 121 : keyColor.alpha = FIX2INT( (FIX_ONE - mk->transparency) * 255);
173 121 : keyColor.low = FIX2INT(mk->lowThreshold * 255);
174 121 : keyColor.high = FIX2INT(mk->highThreshold * 255);
175 121 : tr_state->col_key = &keyColor;
176 :
177 : }
178 : }
179 : }
180 :
181 : /*no HW, fall back to the graphics driver*/
182 5897 : if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx)) {
183 : GF_Matrix2D _mat;
184 331 : GF_Rect rc = gf_rect_center(ctx->bi->unclip.width, ctx->bi->unclip.height);
185 331 : gf_mx2d_copy(_mat, ctx->transform);
186 331 : gf_mx2d_inverse(&_mat);
187 331 : gf_mx2d_apply_rect(&_mat, &rc);
188 331 : if ((st->unclip_rc.width != rc.width) || (st->unclip_rc.height != rc.height)) {
189 116 : drawable_reset_path(&st->s_graph);
190 116 : gf_path_add_rect_center(st->s_graph.path, 0, 0, rc.width, rc.height);
191 116 : st->unclip_rc = rc;
192 : }
193 331 : ctx->flags |= CTX_NO_ANTIALIAS;
194 331 : visual_2d_texture_path(tr_state->visual, st->s_graph.path, ctx, tr_state);
195 : }
196 5897 : tr_state->col_key = NULL;
197 5897 : }
198 :
199 14924 : static void TraverseBitmap(GF_Node *node, void *rs, Bool is_destroy)
200 : {
201 : GF_Rect rc;
202 : Bool rectangle_check_adaptation(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state);
203 : DrawableContext *ctx;
204 14924 : BitmapStack *st = (BitmapStack *)gf_node_get_private(node);
205 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
206 :
207 14924 : if (is_destroy) {
208 272 : drawable_del_ex(&st->s_graph, gf_sc_get_compositor(node), GF_TRUE);
209 272 : gf_free(st);
210 272 : return;
211 : }
212 14652 : if (! rectangle_check_adaptation(node, &st->s_graph, tr_state))
213 : return;
214 :
215 14652 : switch (tr_state->traversing_mode) {
216 5897 : case TRAVERSE_DRAW_2D:
217 5897 : draw_bitmap_2d(node, tr_state);
218 5897 : return;
219 : #ifndef GPAC_DISABLE_3D
220 771 : case TRAVERSE_DRAW_3D:
221 771 : draw_bitmap_3d(node, tr_state);
222 771 : return;
223 : #endif
224 679 : case TRAVERSE_PICK:
225 : //drawable_pick(st->graph, tr_state);
226 679 : vrml_drawable_pick(&st->s_graph, tr_state);
227 679 : return;
228 172 : case TRAVERSE_GET_BOUNDS:
229 172 : Bitmap_BuildGraph(node, st, tr_state, &tr_state->bounds,
230 : #ifndef GPAC_DISABLE_3D
231 172 : tr_state->visual->type_3d ? 1 : 0
232 : #else
233 : 0
234 : #endif
235 : );
236 :
237 172 : return;
238 7133 : case TRAVERSE_SORT:
239 : #ifndef GPAC_DISABLE_3D
240 7133 : if (tr_state->visual->type_3d) return;
241 : #endif
242 : break;
243 : default:
244 : return;
245 : }
246 :
247 : memset(&rc, 0, sizeof(rc));
248 7133 : Bitmap_BuildGraph(node, st, tr_state, &rc, 1);
249 7133 : if (!rc.width || !rc.height) return;
250 :
251 6153 : ctx = drawable_init_context_mpeg4(&st->s_graph, tr_state);
252 6153 : if (!ctx || !ctx->aspect.fill_texture ) {
253 0 : visual_2d_remove_last_context(tr_state->visual);
254 0 : return;
255 : }
256 :
257 :
258 : /*even if set this is not true*/
259 6153 : ctx->aspect.pen_props.width = 0;
260 6153 : ctx->flags |= CTX_NO_ANTIALIAS;
261 :
262 6153 : ctx->flags &= ~CTX_IS_TRANSPARENT;
263 : /*if clipper then transparent*/
264 :
265 6153 : if (ctx->aspect.fill_texture->transparent) {
266 315 : ctx->flags |= CTX_IS_TRANSPARENT;
267 : } else {
268 5838 : M_Appearance *app = (M_Appearance *)ctx->appear;
269 5838 : if ( app->material && (gf_node_get_tag((GF_Node *)app->material)==TAG_MPEG4_MaterialKey) ) {
270 121 : if (((M_MaterialKey*)app->material)->isKeyed) {
271 121 : if (((M_MaterialKey*)app->material)->transparency==FIX_ONE) {
272 0 : visual_2d_remove_last_context(tr_state->visual);
273 0 : return;
274 : }
275 121 : ctx->flags |= CTX_IS_TRANSPARENT;
276 : }
277 : }
278 5717 : else if (!tr_state->color_mat.identity) {
279 0 : ctx->flags |= CTX_IS_TRANSPARENT;
280 : } else {
281 5717 : u8 alpha = GF_COL_A(ctx->aspect.fill_color);
282 : /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/
283 5717 : if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
284 5717 : if (alpha < 0xFF) ctx->flags |= CTX_IS_TRANSPARENT;
285 : }
286 : }
287 :
288 : /*bounds are stored when building graph*/
289 6153 : drawable_finalize_sort(ctx, tr_state, &rc);
290 : }
291 :
292 :
293 272 : void compositor_init_bitmap(GF_Compositor *compositor, GF_Node *node)
294 : {
295 : BitmapStack *st;
296 272 : GF_SAFEALLOC(st, BitmapStack);
297 272 : if (!st) {
298 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate bitmap stack\n"));
299 : return;
300 : }
301 272 : drawable_init_ex(&st->s_graph);
302 272 : st->s_graph.node = node;
303 272 : st->s_graph.flags = DRAWABLE_USE_TRAVERSE_DRAW;
304 272 : gf_node_set_private(node, st);
305 272 : gf_node_set_callback_function(node, TraverseBitmap);
306 : }
307 :
308 : #endif
309 :
|