void compositor_3d_draw_bitmap(Drawable *stack, DrawAspect2D *asp, GF_TraverseState *tr_state, Fixed width, Fixed height, Fixed bmp_scale_x, Fixed bmp_scale_y) { u8 alpha; GF_TextureHandler *txh; GF_Compositor *compositor = tr_state->visual->compositor; if (!asp->fill_texture) return; txh = asp->fill_texture; if (!txh || !txh->tx_io || !txh->width || !txh->height) return; if (((txh->pixelformat==GF_PIXEL_RGBD) || (txh->pixelformat==GF_PIXEL_YUVD))) { if (compositor->depth_gl_type) { if (txh->data && gf_sc_texture_convert(txh) ) visual_3d_point_sprite(tr_state->visual, stack, txh, tr_state); return; } } alpha = GF_COL_A(asp->fill_color); /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/ if (!alpha) alpha = GF_COL_A(asp->line_color); visual_3d_set_state(tr_state->visual, V3D_STATE_LIGHT, GF_FALSE); visual_3d_enable_antialias(tr_state->visual, GF_FALSE); if (alpha && (alpha != 0xFF)) { visual_3d_set_material_2d_argb(tr_state->visual, GF_COL_ARGB(alpha, 0xFF, 0xFF, 0xFF)); gf_sc_texture_set_blend_mode(txh, TX_MODULATE); } else if (gf_sc_texture_is_transparent(txh)) { gf_sc_texture_set_blend_mode(txh, TX_REPLACE); } else { visual_3d_set_state(tr_state->visual, V3D_STATE_BLEND, GF_FALSE); } /*ignore texture transform for bitmap*/ tr_state->mesh_num_textures = gf_sc_texture_enable(txh, NULL); if (tr_state->mesh_num_textures) { /*we must check the w & h passed are correct because of bitmap node initialization*/ if (width && height) { if (!stack->mesh) { SFVec2f size; size.x = width; size.y = height; stack->mesh = new_mesh(); mesh_new_rectangle(stack->mesh, size, NULL, GF_FALSE); } } if (stack->mesh) { #ifdef GF_SR_USE_DEPTH if (tr_state->depth_offset) { GF_Matrix mx; Fixed offset; Fixed disp_depth = (compositor->display_depth<0) ? INT2FIX(tr_state->visual->height) : INT2FIX(compositor->display_depth); if (disp_depth) { GF_Matrix bck_mx; if (!tr_state->pixel_metrics) disp_depth = gf_divfix(disp_depth, tr_state->min_hsize); gf_mx_init(mx); /*add recalibration by the scene*/ offset = tr_state->depth_offset; if (tr_state->visual->depth_vp_range) { offset = gf_divfix(offset, tr_state->visual->depth_vp_range/2); } gf_mx_add_translation(&mx, 0, 0, gf_mulfix(offset, disp_depth/2) ); gf_mx_copy(bck_mx, tr_state->model_matrix); gf_mx_add_matrix(&tr_state->model_matrix, &mx); visual_3d_mesh_paint(tr_state, stack->mesh); gf_mx_copy(tr_state->model_matrix, bck_mx); } else { visual_3d_mesh_paint(tr_state, stack->mesh); } } else #endif visual_3d_mesh_paint(tr_state, stack->mesh); } gf_sc_texture_disable(txh); tr_state->mesh_num_textures = 0; } }
void compositor_3d_draw_bitmap(Drawable *stack, DrawAspect2D *asp, GF_TraverseState *tr_state, Fixed width, Fixed height, Fixed bmp_scale_x, Fixed bmp_scale_y) { u8 alpha; #if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) Fixed x, y; Fixed sx, sy; char *data; u32 format; #endif GF_TextureHandler *txh; GF_Compositor *compositor = tr_state->visual->compositor; Bool use_texture = !compositor->bitmap_use_pixels; if (!asp->fill_texture) return; txh = asp->fill_texture; if (!txh || !txh->tx_io || !txh->width || !txh->height) return; if (((txh->pixelformat==GF_PIXEL_RGBD) || (txh->pixelformat==GF_PIXEL_YUVD))) { if (compositor->depth_gl_type) { if (txh->data && gf_sc_texture_convert(txh) ) visual_3d_point_sprite(tr_state->visual, stack, txh, tr_state); return; } else { use_texture = 1; } } alpha = GF_COL_A(asp->fill_color); /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/ if (!alpha) alpha = GF_COL_A(asp->line_color); /*texture is available in hw, use it - if blending, force using texture*/ if (!gf_sc_texture_needs_reload(txh) || (alpha != 0xFF) || use_texture #ifdef GF_SR_USE_DEPTH || tr_state->depth_offset #endif ) { visual_3d_set_state(tr_state->visual, V3D_STATE_LIGHT, 0); visual_3d_enable_antialias(tr_state->visual, 0); if (alpha && (alpha != 0xFF)) { visual_3d_set_material_2d_argb(tr_state->visual, GF_COL_ARGB(alpha, 0xFF, 0xFF, 0xFF)); gf_sc_texture_set_blend_mode(txh, TX_MODULATE); } else if (gf_sc_texture_is_transparent(txh)) { gf_sc_texture_set_blend_mode(txh, TX_REPLACE); } else { visual_3d_set_state(tr_state->visual, V3D_STATE_BLEND, 0); } /*ignore texture transform for bitmap*/ tr_state->mesh_num_textures = gf_sc_texture_enable(txh, NULL); if (tr_state->mesh_num_textures) { /*we must check the w & h passed are correct because of bitmap node initialization*/ if (width && height) { if (!stack->mesh) { SFVec2f size; size.x = width; size.y = height; stack->mesh = new_mesh(); mesh_new_rectangle(stack->mesh, size, NULL, 0); } } if (stack->mesh) { #ifdef GF_SR_USE_DEPTH if (tr_state->depth_offset) { GF_Matrix mx; Fixed offset; Fixed disp_depth = (compositor->display_depth<0) ? INT2FIX(tr_state->visual->height) : INT2FIX(compositor->display_depth); if (disp_depth) { if (!tr_state->pixel_metrics) disp_depth = gf_divfix(disp_depth, tr_state->min_hsize); gf_mx_init(mx); /*add recalibration by the scene*/ offset = tr_state->depth_offset; if (tr_state->visual->depth_vp_range) { offset = gf_divfix(offset, tr_state->visual->depth_vp_range/2); } gf_mx_add_translation(&mx, 0, 0, gf_mulfix(offset, disp_depth/2) ); visual_3d_matrix_push(tr_state->visual); visual_3d_matrix_add(tr_state->visual, mx.m); visual_3d_mesh_paint(tr_state, stack->mesh); visual_3d_matrix_pop(tr_state->visual); } else { visual_3d_mesh_paint(tr_state, stack->mesh); } } else #endif visual_3d_mesh_paint(tr_state, stack->mesh); } gf_sc_texture_disable(txh); tr_state->mesh_num_textures = 0; return; } } /*otherwise use glDrawPixels*/ #if !defined(GPAC_USE_OGL_ES) && !defined(GPAC_USE_TINYGL) data = gf_sc_texture_get_data(txh, &format); if (!data) return; x = INT2FIX(txh->width) / -2; y = INT2FIX(txh->height) / 2; { Fixed g[16]; sx = bmp_scale_x; if (sx<0) sx = FIX_ONE; sy = bmp_scale_y; if (sy<0) sy = FIX_ONE; #ifndef GPAC_DISABLE_VRML compositor_adjust_scale(txh->owner, &sx, &sy); #endif /*add top level scale if any*/ sx = gf_mulfix(sx, compositor->scale_x); sy = gf_mulfix(sy, compositor->scale_y); /*get & apply current transform scale*/ visual_3d_matrix_get(tr_state->visual, V3D_MATRIX_MODELVIEW, g); if (g[0]<0) g[0] *= -FIX_ONE; if (g[5]<0) g[5] *= -FIX_ONE; sx = gf_mulfix(sx, g[0]); sy = gf_mulfix(sy, g[5]); x = gf_mulfix(x, sx); y = gf_mulfix(y, sy); } visual_3d_draw_image(tr_state->visual, x, y, txh->width, txh->height, format, data, sx, sy); #endif }
static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy) { Fixed cx, cy, angle; /*video stack is just an extension of image stack, type-casting is OK*/ SVG_video_stack *stack = (SVG_video_stack*)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGPropertiesPointers backup_props; u32 backup_flags; GF_Matrix2D backup_matrix; GF_Matrix mx_3d; DrawableContext *ctx; SVGAllAttributes all_atts; if (is_destroy) { gf_sc_texture_destroy(&stack->txh); gf_sg_mfurl_del(stack->txurl); drawable_del(stack->graph); if (stack->audio) { gf_node_unregister(stack->audio, NULL); } gf_free(stack); return; } /*TRAVERSE_DRAW is NEVER called in 3D mode*/ if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) { SVG_Draw_bitmap(tr_state); return; } else if (tr_state->traversing_mode==TRAVERSE_PICK) { svg_drawable_pick(node, stack->graph, tr_state); return; } /*flatten attributes and apply animations + inheritance*/ gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags)) return; if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) { gf_term_get_mfurl_from_xlink(node, &stack->txurl); stack->txh.width = stack->txh.height = 0; /*remove associated audio if any*/ if (stack->audio) { svg_audio_smil_evaluate_ex(NULL, 0, SMIL_TIMING_EVAL_REMOVE, stack->audio, stack->txh.owner); gf_node_unregister(stack->audio, NULL); stack->audio = NULL; } stack->audio_dirty = GF_TRUE; if (stack->txurl.count) svg_play_texture(stack, &all_atts); gf_node_dirty_clear(node, GF_SG_SVG_XLINK_HREF_DIRTY); } if (gf_node_dirty_get(node)) { /*do not clear dirty state until the image is loaded*/ if (stack->txh.width) { gf_node_dirty_clear(node, 0); SVG_Build_Bitmap_Graph((SVG_video_stack*)gf_node_get_private(node), tr_state); } } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { if (!compositor_svg_is_display_off(tr_state->svg_props)) { gf_path_get_bounds(stack->graph->path, &tr_state->bounds); compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { GF_Matrix2D mx; tr_state->bounds.width = INT2FIX(stack->txh.width); tr_state->bounds.height = INT2FIX(stack->txh.height); tr_state->bounds.x = cx - tr_state->bounds.width/2; tr_state->bounds.y = cy + tr_state->bounds.height/2; gf_mx2d_init(mx); gf_mx2d_add_rotation(&mx, 0, 0, angle); gf_mx2d_apply_rect(&mx, &tr_state->bounds); } else { gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } } else if (tr_state->traversing_mode == TRAVERSE_SORT) { if (!compositor_svg_is_display_off(tr_state->svg_props) && ( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) { GF_Matrix mx_bck; Bool restore_mx = GF_FALSE; compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); ctx = drawable_init_context_svg(stack->graph, tr_state); if (!ctx || !ctx->aspect.fill_texture ) return; if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) { drawable_reset_path(stack->graph); gf_path_add_rect_center(stack->graph->path, cx, cy, INT2FIX(stack->txh.width), INT2FIX(stack->txh.height)); gf_mx2d_copy(mx_bck, tr_state->transform); restore_mx = GF_TRUE; gf_mx2d_init(tr_state->transform); gf_mx2d_add_rotation(&tr_state->transform, cx, cy, angle); } /*even if set this is not true*/ ctx->aspect.pen_props.width = 0; ctx->flags |= CTX_NO_ANTIALIAS; /*if rotation, transparent*/ ctx->flags &= ~CTX_IS_TRANSPARENT; if (ctx->transform.m[1] || ctx->transform.m[3]) { ctx->flags |= CTX_IS_TRANSPARENT; ctx->flags &= ~CTX_NO_ANTIALIAS; } else if (ctx->aspect.fill_texture->transparent) ctx->flags |= CTX_IS_TRANSPARENT; else if (tr_state->svg_props->opacity && (tr_state->svg_props->opacity->type==SVG_NUMBER_VALUE) && (tr_state->svg_props->opacity->value!=FIX_ONE)) { ctx->flags = CTX_IS_TRANSPARENT; ctx->aspect.fill_color = GF_COL_ARGB(FIX2INT(0xFF * tr_state->svg_props->opacity->value), 0, 0, 0); } #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (!stack->graph->mesh) { stack->graph->mesh = new_mesh(); mesh_from_path(stack->graph->mesh, stack->graph->path); } compositor_3d_draw_bitmap(stack->graph, &ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE); ctx->drawable = NULL; } else #endif { drawable_finalize_sort(ctx, tr_state, NULL); } if (restore_mx) gf_mx2d_copy(tr_state->transform, mx_bck); compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } } if (stack->audio) svg_traverse_audio_ex(stack->audio, rs, GF_FALSE, tr_state->svg_props); memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
GF_Err gf_sr_set_scene(GF_Renderer *sr, GF_SceneGraph *scene_graph) { u32 width, height; Bool do_notif; if (!sr) return GF_BAD_PARAM; gf_sr_lock(sr, 1); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, (scene_graph ? "[Render] Attaching new scene\n" : "[Render] Detaching scene\n")); if (sr->audio_renderer && (sr->scene != scene_graph)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Reseting audio render\n")); gf_sr_ar_reset(sr->audio_renderer); } #ifdef GF_SR_EVENT_QUEUE GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Reseting event queue\n")); gf_mx_p(sr->ev_mx); while (gf_list_count(sr->events)) { GF_Event *ev = (GF_Event*)gf_list_get(sr->events, 0); gf_list_rem(sr->events, 0); free(ev); } #endif GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Reseting render module\n")); /*reset main surface*/ sr->visual_renderer->SceneReset(sr->visual_renderer); /*set current graph*/ sr->scene = scene_graph; do_notif = 0; if (scene_graph) { #ifndef GPAC_DISABLE_SVG SVG_Length *w, *h; #endif const char *opt; Bool is_svg = 0; u32 tag; GF_Node *top_node; Bool had_size_info = sr->has_size_info; /*get pixel size if any*/ gf_sg_get_scene_size_info(sr->scene, &width, &height); sr->has_size_info = (width && height) ? 1 : 0; if (sr->has_size_info != had_size_info) sr->scene_width = sr->scene_height = 0; /*default back color is black*/ if (! (sr->user->init_flags & GF_TERM_WINDOWLESS)) sr->back_color = 0xFF000000; top_node = gf_sg_get_root_node(sr->scene); tag = 0; if (top_node) tag = gf_node_get_tag(top_node); #ifndef GPAC_DISABLE_SVG w = h = NULL; if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) { GF_FieldInfo info; is_svg = 1; if (gf_svg_get_attribute_by_tag(top_node, TAG_SVG_ATT_width, 0, 0, &info)==GF_OK) w = info.far_ptr; if (gf_svg_get_attribute_by_tag(top_node, TAG_SVG_ATT_height, 0, 0, &info)==GF_OK) h = info.far_ptr; } #ifdef GPAC_ENABLE_SVG_SA else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SA) && (tag<=GF_NODE_RANGE_LAST_SVG_SA)) { SVG_SA_svgElement *root = (SVG_SA_svgElement *) top_node; is_svg = 1; w = &root->width; h = &root->height; } #endif #ifdef GPAC_ENABLE_SVG_SANI else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SANI) && (tag<=GF_NODE_RANGE_LAST_SVG_SANI)) { SVG_SANI_svgElement *root = (SVG_SANI_svgElement*) top_node; is_svg = 1; w = &root->width; h = &root->height; } #endif /*default back color is white*/ if (is_svg && ! (sr->user->init_flags & GF_TERM_WINDOWLESS)) sr->back_color = 0xFFFFFFFF; /*hack for SVG where size is set in %*/ if (!sr->has_size_info && w && h) { sr->has_size_info = 1; sr->aspect_ratio = GF_ASPECT_RATIO_FILL_SCREEN; if (w->type!=SVG_NUMBER_PERCENTAGE) { width = FIX2INT(convert_svg_length_to_user(sr, w) ); } else { width = 320; //FIX2INT(root->viewBox.width); } if (h->type!=SVG_NUMBER_PERCENTAGE) { height = FIX2INT(convert_svg_length_to_user(sr, h) ); } else { height = 240; //FIX2INT(root->viewBox.height); } } #endif /*default back color is key color*/ if (sr->user->init_flags & GF_TERM_WINDOWLESS) { opt = gf_cfg_get_key(sr->user->config, "Rendering", "ColorKey"); if (opt) { u32 r, g, b, a; sscanf(opt, "%02X%02X%02X%02X", &a, &r, &g, &b); sr->back_color = GF_COL_ARGB(0xFF, r, g, b); } } /*set scene size only if different, otherwise keep scaling/FS*/ if ( !width || (sr->scene_width!=width) || !height || (sr->scene_height!=height)) { do_notif = sr->has_size_info || (!sr->scene_width && !sr->scene_height); SR_SetSceneSize(sr, width, height); /*get actual size in pixels*/ width = sr->scene_width; height = sr->scene_height; if (!sr->user->os_window_handler) { /*only notify user if we are attached to a window*/ do_notif = 0; if (sr->video_out->max_screen_width && (width > sr->video_out->max_screen_width)) width = sr->video_out->max_screen_width; if (sr->video_out->max_screen_height && (height > sr->video_out->max_screen_height)) height = sr->video_out->max_screen_height; gf_sr_set_size(sr,width, height); } } } SR_ResetFrameRate(sr); #ifdef GF_SR_EVENT_QUEUE gf_mx_v(sr->ev_mx); #endif gf_sr_lock(sr, 0); /*here's a nasty trick: the app may respond to this by calling a gf_sr_set_size from a different thread, but in an atomic way (typically happen on Win32 when changing the window size). WE MUST NOTIFY THE SIZE CHANGE AFTER RELEASING THE RENDERER MUTEX*/ if (do_notif && sr->user->EventProc) { GF_Event evt; evt.type = GF_EVENT_SCENE_SIZE; evt.size.width = width; evt.size.height = height; sr->user->EventProc(sr->user->opaque, &evt); } if (scene_graph) sr->draw_next_frame = 1; return GF_OK; }