GF_Err compositor_2d_get_video_access(GF_VisualManager *visual) { GF_Err e; GF_Compositor *compositor = visual->compositor; if (!visual->raster_surface) return GF_BAD_PARAM; #ifdef OPENGL_RASTER if (compositor->opengl_raster && compositor->rasterizer->surface_attach_to_callbacks) { GF_RasterCallback callbacks; callbacks.cbk = visual; callbacks.fill_run_alpha = c2d_gl_fill_alpha; callbacks.fill_run_no_alpha = c2d_gl_fill_no_alpha; callbacks.fill_rect = c2d_gl_fill_rect; visual->DrawBitmap = c2d_gl_draw_bitmap; e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &callbacks, compositor->vp_width, compositor->vp_height); if (e==GF_OK) { GF_Matrix mx; Fixed hh, hw; visual->is_attached = 2; visual_3d_setup(visual); glClear(GL_DEPTH_BUFFER_BIT); glViewport(0, 0, compositor->vp_width, compositor->vp_height); glClear(GL_COLOR_BUFFER_BIT); glLineWidth(1.0f); #ifndef GPAC_USE_OGL_ES glDisable(GL_POLYGON_SMOOTH); #endif glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glDisable(GL_NORMALIZE); glDisable(GL_LINE_SMOOTH); glDisable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthFunc(GL_LEQUAL); hw = INT2FIX(compositor->vp_width)/2; hh = INT2FIX(compositor->vp_height)/2; gf_mx_ortho(&mx, -hw, hw, -hh, hh, 50, -50); visual_3d_set_matrix_mode(visual, V3D_MATRIX_PROJECTION); visual_3d_matrix_load(visual, mx.m); visual_3d_set_matrix_mode(visual, V3D_MATRIX_MODELVIEW); gf_mx_init(mx); gf_mx_add_scale(&mx, 1, -1, 1); gf_mx_add_translation(&mx, -hw, -hh, 0); visual_3d_matrix_load(visual, mx.m); return GF_OK; } } #endif compositor->hw_locked = 0; e = GF_IO_ERR; /*try from video memory handle (WIN32) if supported*/ if ((compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_HWND_HDC) && compositor->rasterizer->surface_attach_to_device && compositor->video_out->LockOSContext ) { compositor->hw_context = compositor->video_out->LockOSContext(compositor->video_out, 1); if (compositor->hw_context) { e = compositor->rasterizer->surface_attach_to_device(visual->raster_surface, compositor->hw_context, compositor->vp_width, compositor->vp_height); if (!e) { visual->is_attached = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface handle attached to raster\n")); return GF_OK; } compositor->video_out->LockOSContext(compositor->video_out, 0); GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface handle to raster: %s\n", gf_error_to_string(e) )); } } if (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_LINE_BLIT) { e = compositor->rasterizer->surface_attach_to_callbacks(visual->raster_surface, &compositor->raster_callbacks, compositor->vp_width, compositor->vp_height); if (!e) { visual->is_attached = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface callbacks attached to raster\n")); return GF_OK; } GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Failed to attach video surface callbacks to raster\n")); } e = GF_NOT_SUPPORTED; if (compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 1)==GF_OK) { compositor->hw_locked = 1; e = compositor->rasterizer->surface_attach_to_buffer(visual->raster_surface, compositor->hw_surface.video_buffer, compositor->hw_surface.width, compositor->hw_surface.height, compositor->hw_surface.pitch_x, compositor->hw_surface.pitch_y, (GF_PixelFormat) compositor->hw_surface.pixel_format); if (!e) { visual->is_attached = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Video surface memory attached to raster - w=%d h=%d pitch_x=%d pitch_y=%d\n", compositor->hw_surface.width, compositor->hw_surface.height, compositor->hw_surface.pitch_x, compositor->hw_surface.pitch_y)); return GF_OK; } GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor2D] Cannot attach video surface memory to raster: %s\n", gf_error_to_string(e) )); compositor->video_out->LockBackBuffer(compositor->video_out, &compositor->hw_surface, 0); } compositor->hw_locked = 0; visual->is_attached = 0; /*if using BlitTexture, return OK to still be able to blit images*/ if (compositor->video_out->BlitTexture) e = GF_OK; return e; }
static void TraverseLayer3D(GF_Node *node, void *rs, Bool is_destroy) { Bool prev_layer, changed = 0; GF_List *oldb, *oldv, *oldf, *oldn; GF_Rect rc; u32 cur_lights; GF_List *node_list_backup; GF_BBox bbox_backup; GF_Matrix model_backup; GF_Matrix2D mx2d_backup; GF_Camera *prev_cam; GF_VisualManager *old_visual; M_Layer3D *l = (M_Layer3D *)node; Layer3DStack *st = (Layer3DStack *) gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { DestroyLayer3D(node); return; } if (st->unsupported) return; if (gf_node_dirty_get(node)) { /*main visual in pixel metrics, use output width*/ if (tr_state->pixel_metrics && (tr_state->visual->compositor->visual==tr_state->visual)) { st->clip.width = INT2FIX(tr_state->visual->compositor->vp_width); st->clip.height = INT2FIX(tr_state->visual->compositor->vp_height); } else { visual_get_size_info(tr_state, &st->clip.width, &st->clip.height); } /*setup bounds in local coord system*/ if (l->size.x>=0) st->clip.width = l->size.x; if (l->size.y>=0) st->clip.height = l->size.y; st->clip = gf_rect_center(st->clip.width, st->clip.height); changed = 1; } switch (tr_state->traversing_mode) { case TRAVERSE_GET_BOUNDS: if (!tr_state->for_node) { tr_state->bounds = st->clip; gf_bbox_from_rect(&tr_state->bbox, &st->clip); return; } case TRAVERSE_PICK: case TRAVERSE_SORT: /*layers can only be used in a 2D context*/ if (tr_state->camera && tr_state->camera->is_3D) return; break; case TRAVERSE_DRAW_2D: layer3d_draw_2d(node, tr_state); return; case TRAVERSE_DRAW_3D: default: return; } /*layer3D maintains its own stacks*/ oldb = tr_state->backgrounds; oldv = tr_state->viewpoints; oldf = tr_state->fogs; oldn = tr_state->navigations; tr_state->backgrounds = st->visual->back_stack; tr_state->viewpoints = st->visual->view_stack; tr_state->navigations = st->visual->navigation_stack; tr_state->fogs = st->visual->fog_stack; prev_layer = tr_state->is_layer; tr_state->is_layer = 1; prev_cam = tr_state->camera; tr_state->camera = &st->visual->camera; old_visual = tr_state->visual; bbox_backup = tr_state->bbox; gf_mx_copy(model_backup, tr_state->model_matrix); gf_mx2d_copy(mx2d_backup, tr_state->transform); /*compute viewport in visual coordinate*/ rc = st->clip; if (prev_cam) { gf_mx_apply_rect(&tr_state->model_matrix, &rc); gf_mx_apply_rect(&prev_cam->modelview, &rc); if (tr_state->camera->flags & CAM_HAS_VIEWPORT) gf_mx_apply_rect(&prev_cam->viewport, &rc); #if 0 if (tr_state->visual->compositor->visual==tr_state->visual) { GF_Matrix mx; gf_mx_init(mx); gf_mx_add_scale(&mx, tr_state->visual->compositor->scale_x, tr_state->visual->compositor->scale_y, FIX_ONE); gf_mx_apply_rect(&mx, &rc); } #endif } else { gf_mx2d_apply_rect(&tr_state->transform, &rc); /* if (tr_state->visual->compositor->visual==tr_state->visual) { gf_mx2d_init(mx2d_backup); gf_mx2d_add_scale(&mx2d_backup, tr_state->visual->compositor->scale_x, tr_state->visual->compositor->scale_y); gf_mx2d_apply_rect(&mx2d_backup, &rc); } */ /*switch visual*/ tr_state->visual = st->visual; } /*check bindables*/ gf_mx_init(tr_state->model_matrix); l3d_CheckBindables(node, tr_state, st->first); if (prev_cam) gf_mx_copy(tr_state->model_matrix, model_backup); /*drawing a layer means drawing all subelements as a whole (no depth sorting with parents)*/ if (tr_state->traversing_mode==TRAVERSE_SORT) { if (gf_node_dirty_get(node)) changed = 1; gf_node_dirty_clear(node, GF_SG_NODE_DIRTY|GF_SG_VRML_BINDABLE_DIRTY); /*!! we were in a 2D mode, setup associated texture !!*/ if (!prev_cam) { switch (layer3d_setup_offscreen(node, st, tr_state, rc.width, rc.height)) { case 0: goto l3d_exit; case 2: if (!changed && !(st->visual->camera.flags & CAM_IS_DIRTY) && !st->visual->camera.anim_len) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer3D] No changes found , skipping 3D draw\n")); goto layer3d_unchanged_2d; } default: break; } #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_make_current(st->tgl_ctx, 0); #endif /*note that we don't backup the state as a layer3D cannot be declared in a layer3D*/ tr_state->layer3d = node; rc = st->vp; /*setup GL*/ visual_3d_setup(tr_state->visual); visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_PROJECTION); visual_3d_matrix_reset(tr_state->visual); visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_TEXTURE); visual_3d_matrix_reset(tr_state->visual); visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_MODELVIEW); visual_3d_matrix_reset(tr_state->visual); } else { visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_PROJECTION); visual_3d_matrix_push(tr_state->visual); visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_TEXTURE); visual_3d_matrix_push(tr_state->visual); visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_MODELVIEW); visual_3d_matrix_push(tr_state->visual); } GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer3D] Redrawing\n")); layer3d_setup_clip(st, tr_state, prev_cam ? 1 : 0, rc); cur_lights = tr_state->visual->num_lights; /*this will init projection. Note that we're binding the viewpoint in the current pixelMetrics context even if the viewpoint was declared in an inline below if no previous camera, we're using offscreen rendering, force clear */ visual_3d_init_draw(tr_state, prev_cam ? 1 : 2); visual_3d_check_collisions(tr_state, l->children); tr_state->traversing_mode = TRAVERSE_SORT; /*shortcut node list*/ node_list_backup = tr_state->visual->alpha_nodes_to_draw; tr_state->visual->alpha_nodes_to_draw = gf_list_new(); /*reset cull flag*/ tr_state->cull_flag = 0; group_3d_traverse(node, (GroupingNode *)st, tr_state); visual_3d_flush_contexts(tr_state->visual, tr_state); gf_list_del(tr_state->visual->alpha_nodes_to_draw); tr_state->visual->alpha_nodes_to_draw = node_list_backup; while (cur_lights < tr_state->visual->num_lights) { visual_3d_remove_last_light(tr_state->visual); } tr_state->traversing_mode = TRAVERSE_SORT; if (prev_cam) { visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_PROJECTION); visual_3d_matrix_pop(tr_state->visual); visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_TEXTURE); visual_3d_matrix_pop(tr_state->visual); visual_3d_set_matrix_mode(tr_state->visual, V3D_MATRIX_MODELVIEW); visual_3d_matrix_pop(tr_state->visual); } /*!! we were in a 2D mode, create drawable context!!*/ if (!prev_cam) { DrawableContext *ctx; /*with TinyGL we draw directly to the offscreen buffer*/ #ifndef GPAC_USE_TINYGL gf_sc_copy_to_stencil(&st->txh); #else if (st->txh.pixelformat==GF_PIXEL_RGBDS) gf_get_tinygl_depth(&st->txh); #endif if (tr_state->visual->compositor->rasterizer->stencil_texture_modified) tr_state->visual->compositor->rasterizer->stencil_texture_modified(gf_sc_texture_get_stencil(&st->txh) ); gf_sc_texture_set_stencil(&st->txh, gf_sc_texture_get_stencil(&st->txh) ); changed = 1; layer3d_unchanged_2d: /*restore visual*/ tr_state->visual = old_visual; tr_state->layer3d = NULL; tr_state->appear = NULL; // tr_state->camera = prev_cam; ctx = drawable_init_context_mpeg4(st->drawable, tr_state); if (!ctx) return; ctx->aspect.fill_texture = &st->txh; ctx->flags |= CTX_NO_ANTIALIAS; if (changed) ctx->flags |= CTX_APP_DIRTY; if (st->txh.transparent) ctx->flags |= CTX_IS_TRANSPARENT; drawable_finalize_sort(ctx, tr_state, NULL); } } /*check picking - we must fall in our 2D clipper except when mvt is grabbed on layer*/ else if (!gf_node_dirty_get(node) && (tr_state->traversing_mode==TRAVERSE_PICK)) { GF_Ray prev_r; SFVec3f start, end; SFVec4f res; Fixed in_x, in_y; Bool do_pick = 0; if (!prev_cam) rc = st->vp; layer3d_setup_clip(st, tr_state, prev_cam ? 1 : 0, rc); if (tr_state->visual->compositor->active_layer==node) { do_pick = (tr_state->visual->compositor->grabbed_sensor || tr_state->visual->compositor->navigation_state) ? 1 : 0; } if (!prev_cam) gf_mx_from_mx2d(&tr_state->model_matrix, &tr_state->transform); if (!do_pick && !gf_list_count(tr_state->visual->compositor->sensors)) do_pick = gf_sc_pick_in_clipper(tr_state, &st->clip); if (!do_pick) goto l3d_exit; prev_r = tr_state->ray; compositor_get_2d_plane_intersection(&tr_state->ray, &start); gf_mx_inverse(&tr_state->model_matrix); gf_mx_apply_vec(&tr_state->model_matrix, &start); if (tr_state->visual->compositor->visual==tr_state->visual) { start.x = gf_mulfix(start.x, tr_state->visual->compositor->scale_x); start.y = gf_mulfix(start.y, tr_state->visual->compositor->scale_y); } else if (!prev_cam) { start.x = gf_muldiv(start.x, st->visual->camera.width, st->clip.width); start.y = gf_muldiv(start.y, st->visual->camera.height, st->clip.height); } visual_3d_setup_projection(tr_state, 1); in_x = 2 * gf_divfix(start.x, st->visual->camera.width); in_y = 2 * gf_divfix(start.y, st->visual->camera.height); res.x = in_x; res.y = in_y; res.z = -FIX_ONE; res.q = FIX_ONE; gf_mx_apply_vec_4x4(&st->visual->camera.unprojection, &res); if (!res.q) goto l3d_exit; start.x = gf_divfix(res.x, res.q); start.y = gf_divfix(res.y, res.q); start.z = gf_divfix(res.z, res.q); res.x = in_x; res.y = in_y; res.z = FIX_ONE; res.q = FIX_ONE; gf_mx_apply_vec_4x4(&st->visual->camera.unprojection, &res); if (!res.q) goto l3d_exit; end.x = gf_divfix(res.x, res.q); end.y = gf_divfix(res.y, res.q); end.z = gf_divfix(res.z, res.q); tr_state->ray = gf_ray(start, end); GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer3D] Picking: cast ray\n\tOrigin %.4f %.4f %.4f - End %.4f %.4f %.4f\n\tDir %.4f %.4f %.4f\n", FIX2FLT(tr_state->ray.orig.x), FIX2FLT(tr_state->ray.orig.y), FIX2FLT(tr_state->ray.orig.z), FIX2FLT(end.x), FIX2FLT(end.y), FIX2FLT(end.z), FIX2FLT(tr_state->ray.dir.x), FIX2FLT(tr_state->ray.dir.y), FIX2FLT(tr_state->ray.dir.z))); group_3d_traverse(node, (GroupingNode *)st, tr_state); tr_state->ray = prev_r; /*store info if navigation allowed - we just override any layer3D picked first since we are picking 2D objects*/ if (tr_state->camera->navigate_mode || (tr_state->camera->navigation_flags & NAV_ANY)) tr_state->layer3d = node; tr_state->traversing_mode = TRAVERSE_PICK; } l3d_exit: /*restore camera*/ tr_state->camera = prev_cam; if (prev_cam) visual_3d_set_viewport(tr_state->visual, tr_state->camera->vp); tr_state->visual = old_visual; /*restore traversing state*/ tr_state->backgrounds = oldb; tr_state->viewpoints = oldv; tr_state->fogs = oldf; tr_state->navigations = oldn; tr_state->bbox = bbox_backup; tr_state->is_layer = prev_layer; gf_mx_copy(tr_state->model_matrix, model_backup); gf_mx2d_copy(tr_state->transform, mx2d_backup); /*in case we missed bindables*/ if (st->first) { st->first = 0; gf_node_dirty_set(node, 0, 0); gf_sc_invalidate(tr_state->visual->compositor, NULL); } }