static Bool compositor_handle_navigation_3d(GF_Compositor *compositor, GF_Event *ev) { Fixed x, y, trans_scale; Fixed dx, dy, key_trans, key_pan, key_exam; s32 key_inv; u32 keys; #ifdef SCALE_NAV Bool is_pixel_metrics; #endif GF_Camera *cam; Fixed zoom = compositor->zoom; cam = NULL; #ifndef GPAC_DISABLE_VRML if (compositor->active_layer) { cam = compositor_layer3d_get_camera(compositor->active_layer); #ifdef SCALE_NAV is_pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(compositor->active_layer)); #endif } #endif if (!cam) { cam = &compositor->visual->camera; assert(compositor); assert(compositor->scene); #ifdef SCALE_NAV is_pixel_metrics = compositor->traverse_state->pixel_metrics; #endif } if (!cam || (cam->navigate_mode==GF_NAVIGATE_NONE)) return 0; keys = compositor->key_states; if (!cam->navigate_mode && !(keys & GF_KEY_MOD_ALT) ) return 0; x = y = 0; /*renorm between -1, 1*/ if (ev->type<=GF_EVENT_MOUSEWHEEL) { x = gf_divfix( INT2FIX(ev->mouse.x - (s32) compositor->visual->width/2), INT2FIX(compositor->visual->width)); y = gf_divfix( INT2FIX(ev->mouse.y - (s32) compositor->visual->height/2), INT2FIX(compositor->visual->height)); } dx = (x - compositor->grab_x); dy = (compositor->grab_y - y); #ifdef SCALE_NAV trans_scale = is_pixel_metrics ? cam->width/2 : INT2FIX(10); key_trans = is_pixel_metrics ? INT2FIX(10) : cam->avatar_size.x; #else trans_scale = cam->width/20; key_trans = cam->avatar_size.x/2; //if default VP is quite far from center use larger dz/dy moves if (cam->vp_dist>100) trans_scale *= 10; #endif if (cam->world_bbox.is_set && (key_trans*5 > cam->world_bbox.radius)) { key_trans = cam->world_bbox.radius / 100; } key_pan = FIX_ONE/25; key_exam = FIX_ONE/20; key_inv = 1; if (keys & GF_KEY_MOD_SHIFT) { dx *= 4; dy *= 4; key_pan *= 4; key_exam *= 4; key_trans*=4; } switch (ev->type) { case GF_EVENT_MOUSEDOWN: /*left*/ if (ev->mouse.button==GF_MOUSE_LEFT) { compositor->grab_x = x; compositor->grab_y = y; compositor->navigation_state = 1; /*change vp and examine center to current location*/ if ((keys & GF_KEY_MOD_CTRL) && compositor->hit_square_dist) { cam->vp_position = cam->position; cam->vp_orientation = camera_get_orientation(cam->position, cam->target, cam->up); cam->vp_fov = cam->fieldOfView; cam->examine_center = compositor->hit_world_point; camera_changed(compositor, cam); return 1; } } /*right*/ else if (ev->mouse.button==GF_MOUSE_RIGHT) { if (compositor->navigation_state && (cam->navigate_mode==GF_NAVIGATE_WALK)) { camera_jump(cam); gf_sc_invalidate(compositor, NULL); return 1; } else if (keys & GF_KEY_MOD_CTRL) gf_sc_fit_world_to_screen(compositor); } break; /* note: shortcuts are mostly the same as blaxxun contact, I don't feel like remembering 2 sets...*/ case GF_EVENT_MOUSEMOVE: if (!compositor->navigation_state) { if (cam->navigate_mode==GF_NAVIGATE_GAME) { /*init mode*/ compositor->grab_x = x; compositor->grab_y = y; compositor->navigation_state = 1; } return 0; } compositor->navigation_state++; switch (cam->navigate_mode) { /*FIXME- we'll likely need a "step" value for walk at some point*/ case GF_NAVIGATE_WALK: case GF_NAVIGATE_FLY: view_pan_x(compositor, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_pan_y(compositor, cam, dy); else view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); break; case GF_NAVIGATE_VR: view_pan_x(compositor, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_zoom(compositor, cam, dy); else view_pan_y(compositor, cam, dy); break; case GF_NAVIGATE_PAN: view_pan_x(compositor, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); else view_pan_y(compositor, cam, dy); break; case GF_NAVIGATE_SLIDE: view_translate_x(compositor, cam, gf_mulfix(dx, trans_scale)); if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); else view_translate_y(compositor, cam, gf_mulfix(dy, trans_scale)); break; case GF_NAVIGATE_EXAMINE: if (keys & GF_KEY_MOD_CTRL) { view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); view_roll(compositor, cam, gf_mulfix(dx, trans_scale)); } else { if (ABS(dx) > ABS(dy)) { view_exam_x(compositor, cam, -gf_mulfix(GF_PI, dx)); } else { view_exam_y(compositor, cam, gf_mulfix(GF_PI, dy)); } } break; case GF_NAVIGATE_ORBIT: if (keys & GF_KEY_MOD_CTRL) { view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); } else { view_orbit_x(compositor, cam, -gf_mulfix(GF_PI, dx)); view_orbit_y(compositor, cam, gf_mulfix(GF_PI, dy)); } break; case GF_NAVIGATE_GAME: view_pan_x(compositor, cam, -dx); view_pan_y(compositor, cam, dy); break; } compositor->grab_x = x; compositor->grab_y = y; return 1; case GF_EVENT_MOUSEWHEEL: switch (cam->navigate_mode) { /*FIXME- we'll likely need a "step" value for walk at some point*/ case GF_NAVIGATE_WALK: case GF_NAVIGATE_FLY: view_pan_y(compositor, cam, gf_mulfix(key_pan, ev->mouse.wheel_pos)); break; case GF_NAVIGATE_VR: view_zoom(compositor, cam, gf_mulfix(key_pan, ev->mouse.wheel_pos)); break; case GF_NAVIGATE_SLIDE: case GF_NAVIGATE_EXAMINE: case GF_NAVIGATE_ORBIT: case GF_NAVIGATE_PAN: if (cam->is_3D) { view_translate_z(compositor, cam, gf_mulfix(trans_scale, ev->mouse.wheel_pos) * ((keys & GF_KEY_MOD_SHIFT) ? 4 : 1)); } else { nav_set_zoom_trans_2d(compositor->visual, zoom + INT2FIX(ev->mouse.wheel_pos)/10, 0, 0); } } return 1; case GF_EVENT_MOUSEUP: if (ev->mouse.button==GF_MOUSE_LEFT) compositor->navigation_state = 0; break; case GF_EVENT_KEYDOWN: switch (ev->key.key_code) { case GF_KEY_BACKSPACE: gf_sc_reset_graphics(compositor); return 1; case GF_KEY_C: compositor->collide_mode = compositor->collide_mode ? GF_COLLISION_NONE : GF_COLLISION_DISPLACEMENT; return 1; case GF_KEY_J: if (cam->navigate_mode==GF_NAVIGATE_WALK) { camera_jump(cam); gf_sc_invalidate(compositor, NULL); return 1; } break; case GF_KEY_HOME: if (!compositor->navigation_state) { compositor->visual->camera.start_zoom = compositor->zoom; compositor->zoom = FIX_ONE; compositor->interoccular_offset = 0; compositor->focus_distance = 0; compositor->interoccular_offset = 0; compositor->focus_distance = 0; compositor_3d_reset_camera(compositor); } break; case GF_KEY_END: if (cam->navigate_mode==GF_NAVIGATE_GAME) { cam->navigate_mode = GF_NAVIGATE_WALK; compositor->navigation_state = 0; return 1; } break; case GF_KEY_LEFT: key_inv = -1; case GF_KEY_RIGHT: if (keys & GF_KEY_MOD_ALT) { if ( (keys & GF_KEY_MOD_SHIFT) && (compositor->visual->nb_views > 1) ) { /*+ or - 10 cm*/ compositor->focus_distance += INT2FIX(key_inv); cam->flags |= CAM_IS_DIRTY; fprintf(stderr, "AutoStereo view distance %f - focus %f\n", FIX2FLT(compositor->video_out->view_distance)/100, FIX2FLT(compositor->focus_distance)/100); gf_sc_invalidate(compositor, NULL); return 1; } return 0; } switch (cam->navigate_mode) { case GF_NAVIGATE_SLIDE: if (keys & GF_KEY_MOD_CTRL) view_pan_x(compositor, cam, key_inv * key_pan); else view_translate_x(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_EXAMINE: if (keys & GF_KEY_MOD_CTRL) view_roll(compositor, cam, gf_mulfix(dx, trans_scale)); else view_exam_x(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_ORBIT: if (keys & GF_KEY_MOD_CTRL) view_translate_x(compositor, cam, key_inv * key_trans); else view_orbit_x(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_GAME: view_translate_x(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_VR: view_pan_x(compositor, cam, -key_inv * key_pan); break; /*walk/fly/pan*/ default: if (keys & GF_KEY_MOD_CTRL) view_translate_x(compositor, cam, key_inv * key_trans); else view_pan_x(compositor, cam, -key_inv * key_pan); break; } return 1; case GF_KEY_DOWN: key_inv = -1; case GF_KEY_UP: if (keys & GF_KEY_MOD_ALT) { if ( (keys & GF_KEY_MOD_SHIFT) && (compositor->visual->nb_views > 1) ) { compositor->interoccular_offset += FLT2FIX(0.5) * key_inv; fprintf(stderr, "AutoStereo interoccular distance %f\n", FIX2FLT(compositor->interoccular_distance + compositor->interoccular_offset)); cam->flags |= CAM_IS_DIRTY; gf_sc_invalidate(compositor, NULL); return 1; } return 0; } switch (cam->navigate_mode) { case GF_NAVIGATE_SLIDE: if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, key_inv * key_trans); else view_translate_y(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_EXAMINE: if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, key_inv * key_trans); else view_exam_y(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_ORBIT: if (keys & GF_KEY_MOD_CTRL) view_translate_y(compositor, cam, key_inv * key_trans); else view_orbit_y(compositor, cam, -key_inv * key_exam); break; case GF_NAVIGATE_PAN: if (keys & GF_KEY_MOD_CTRL) view_translate_y(compositor, cam, key_inv * key_trans); else view_pan_y(compositor, cam, key_inv * key_pan); break; case GF_NAVIGATE_GAME: view_translate_z(compositor, cam, key_inv * key_trans); break; case GF_NAVIGATE_VR: if (keys & GF_KEY_MOD_CTRL) view_zoom(compositor, cam, key_inv * key_pan); else view_pan_y(compositor, cam, key_inv * key_pan); break; /*walk/fly*/ default: if (keys & GF_KEY_MOD_CTRL) view_pan_y(compositor, cam, key_inv * key_pan); else view_translate_z(compositor, cam, key_inv * key_trans); break; } return 1; case GF_KEY_PAGEDOWN: if (keys & GF_KEY_MOD_CTRL) { view_zoom(compositor, cam, FIX_ONE/10); return 1; } break; case GF_KEY_PAGEUP: if (keys & GF_KEY_MOD_CTRL) { view_zoom(compositor, cam, -FIX_ONE/10); return 1; } break; } break; } return 0; }
Bool compositor_compositetexture_handle_event(GF_Compositor *compositor, GF_Node *composite_appear, GF_Event *ev, Bool is_flush) { GF_Ray ray; Fixed dist; Bool had_text_sel=0; GF_Matrix mx; GF_TraverseState *tr_state; GF_ChildNodeItem *children, *l; Bool res; SFVec3f txcoord, loc_pt, world_pt; GF_Matrix l2w_mx, w2l_mx; CompositeTextureStack *stack; GF_Node *appear, *prev_appear; M_Appearance *ap = (M_Appearance *)composite_appear; assert(ap && ap->texture); if (ev->type > GF_EVENT_MOUSEMOVE) return 0; stack = gf_node_get_private(ap->texture); if (!stack->txh.tx_io) return 0; tr_state = NULL; children = NULL; if (!is_flush) { txcoord.x = compositor->hit_texcoords.x; txcoord.y = compositor->hit_texcoords.y; txcoord.z = 0; if (gf_sc_texture_get_transform(&stack->txh, ap->textureTransform, &mx, 1)) { /*tx coords are inverted when mapping, thus applying directly the matrix will give us the untransformed coords*/ gf_mx_apply_vec(&mx, &txcoord); while (txcoord.x<0) txcoord.x += FIX_ONE; while (txcoord.x>FIX_ONE) txcoord.x -= FIX_ONE; while (txcoord.y<0) txcoord.y += FIX_ONE; while (txcoord.y>FIX_ONE) txcoord.y -= FIX_ONE; } /*convert to tx space*/ ev->mouse.x = FIX2INT( (txcoord.x - FIX_ONE/2) * stack->visual->width + FIX_ONE/2); ev->mouse.y = FIX2INT( (txcoord.y - FIX_ONE/2) * stack->visual->height + FIX_ONE/2); GF_SAFEALLOC(tr_state, GF_TraverseState); tr_state->vrml_sensors = gf_list_new(); tr_state->visual = stack->visual; tr_state->traversing_mode = TRAVERSE_PICK; tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(ap->texture)); tr_state->vp_size.x = INT2FIX(stack->txh.width); tr_state->vp_size.y = INT2FIX(stack->txh.height); tr_state->color_mat.identity = 1; gf_mx2d_init(tr_state->transform); #ifndef GPAC_DISABLE_3D gf_mx_init(tr_state->model_matrix); #endif /*collect sensors*/ l = children = ((M_CompositeTexture2D*)ap->texture)->children; while (l) { GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler(l->node); if (hsens) gf_list_add(tr_state->vrml_sensors, hsens); l = l->next; } } stack->temp_sensors = compositor->sensors; stack->temp_previous_sensors = compositor->previous_sensors; compositor->sensors = stack->sensors; compositor->previous_sensors = stack->previous_sensors; ray = compositor->hit_world_ray; dist = compositor->hit_square_dist; prev_appear = compositor->prev_hit_appear; /*protect against destrucion in case of self-destroy*/ if (prev_appear) { gf_node_register(prev_appear, NULL); } compositor->prev_hit_appear = stack->prev_hit_appear; appear = compositor->hit_appear; compositor->hit_appear = NULL; /*also backup current hit state in case we hit a node in the texture but don't consume the event*/ loc_pt = compositor->hit_local_point; world_pt = compositor->hit_world_point; gf_mx_copy(l2w_mx, compositor->hit_local_to_world); gf_mx_copy(w2l_mx, compositor->hit_world_to_local); if (compositor->text_selection) had_text_sel=1; if (is_flush) { res = 0; gf_list_reset(stack->sensors); gf_sc_exec_event_vrml(compositor, ev); } else { res = visual_execute_event(stack->visual, tr_state, ev, children); } if (!had_text_sel && compositor->edited_text) { stack->visual->has_text_edit = 1; } else if (!compositor->text_selection) { stack->visual->has_text_edit = 0; } if (!res) { compositor->hit_local_point = loc_pt; gf_mx_copy(compositor->hit_local_to_world, l2w_mx); gf_mx_copy(compositor->hit_world_to_local, w2l_mx); } stack->prev_hit_appear = compositor->prev_hit_appear; if (prev_appear) { if (prev_appear->sgprivate->num_instances>1) { compositor->prev_hit_appear = prev_appear; compositor->hit_appear = appear; } else { compositor->prev_hit_appear = NULL; compositor->hit_appear = NULL; } gf_node_unregister(prev_appear, NULL); } else { compositor->prev_hit_appear = prev_appear; compositor->hit_appear = appear; } compositor->hit_world_point = world_pt; compositor->hit_world_ray = ray; compositor->hit_square_dist = dist; stack->sensors = compositor->sensors; stack->previous_sensors = compositor->previous_sensors; compositor->sensors = stack->temp_sensors; stack->temp_sensors = NULL; compositor->previous_sensors = stack->temp_previous_sensors; stack->temp_previous_sensors = NULL; if (!is_flush) { gf_list_del(tr_state->vrml_sensors); #ifndef GPAC_DISABLE_3D if (tr_state->layer3d) compositor->traverse_state->layer3d = tr_state->layer3d; #endif gf_free(tr_state); } return res; }
static void composite_update(GF_TextureHandler *txh) { s32 w, h; GF_STENCIL stencil; M_Background2D *back; GF_TraverseState *tr_state; Bool invalidate_all; u32 new_pixel_format; GF_Compositor *compositor = (GF_Compositor *)txh->compositor; CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(txh->owner); GF_Raster2D *raster = st->visual->compositor->rasterizer; if (st->unsupported) return; /* if (compositor->recompute_ar) { gf_node_dirty_set(txh->owner, 0, 0); return; } */ if (!compositor->rebuild_offscreen_textures && (!compositor->text_edit_changed || !st->visual->has_text_edit ) && !gf_node_dirty_get(txh->owner)) { txh->needs_refresh = 0; return; } gf_node_dirty_clear(st->txh.owner, 0); new_pixel_format = 0; back = gf_list_get(st->visual->back_stack, 0); if (back && back->isBound) new_pixel_format = GF_PIXEL_RGB_24; else new_pixel_format = GF_PIXEL_RGBA; #ifdef GPAC_USE_TINYGL /*TinyGL pixel format is fixed at compile time, we cannot override it !*/ if (st->visual->type_3d) new_pixel_format = GF_PIXEL_RGBA; #else #ifndef GPAC_DISABLE_3D /*no alpha support in offscreen rendering*/ if ( (st->visual->type_3d) && !(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA)) new_pixel_format = GF_PIXEL_RGB_24; #endif /*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/ #ifdef GPAC_USE_OGL_ES new_pixel_format = GF_PIXEL_RGBA; #endif #endif /*FIXME - we assume RGB+Depth+bitshape, we should check with the video out module*/ #if defined(GF_SR_USE_DEPTH) && !defined(GPAC_DISABLE_3D) if (st->visual->type_3d && (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_DEPTH) ) new_pixel_format = GF_PIXEL_RGBDS; #endif #ifndef GPAC_DISABLE_3D if (st->visual->type_3d>1) { w = ((M_CompositeTexture3D*)txh->owner)->pixelWidth; h = ((M_CompositeTexture3D*)txh->owner)->pixelHeight; } else #endif { w = ((M_CompositeTexture2D*)txh->owner)->pixelWidth; h = ((M_CompositeTexture2D*)txh->owner)->pixelHeight; } /*internal GPAC hacks for testing color spaces*/ if (w<-1) { w = -w; if (h<0) { h = -h; if (new_pixel_format==GF_PIXEL_RGBA) { new_pixel_format=GF_PIXEL_ARGB; } else { new_pixel_format=GF_PIXEL_BGR_24; } } else { if (new_pixel_format==GF_PIXEL_RGB_24) { new_pixel_format=GF_PIXEL_RGB_32; } } } else if (h<-1) { h = -h; if (new_pixel_format==GF_PIXEL_RGB_24) { new_pixel_format=GF_PIXEL_RGB_32; } } if (w<0) w = 0; if (h<0) h = 0; if (!w || !h) { if (txh->tx_io) { #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx); #endif gf_sc_texture_release(txh); if (txh->data) gf_free(txh->data); txh->data = NULL; txh->width = txh->height = txh->stride = 0; } return; } invalidate_all = compositor->rebuild_offscreen_textures; /*rebuild stencil*/ if (!txh->tx_io || (w != (s32) txh->width) || ( h != (s32) txh->height) || (new_pixel_format != txh->pixelformat) ) { Bool needs_stencil = 1; if (txh->tx_io) { #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx); #endif gf_sc_texture_release(txh); if (txh->data) gf_free(txh->data); txh->data = NULL; } /*we don't use rect ext because of no support for texture transforms*/ if (1 #ifndef GPAC_DISABLE_3D || compositor->gl_caps.npot_texture #endif ) { st->txh.width = w; st->txh.height = h; st->sx = st->sy = FIX_ONE; } else { st->txh.width = 2; while (st->txh.width<(u32)w) st->txh.width*=2; st->txh.height = 2; while (st->txh.height<(u32)h) st->txh.height*=2; st->sx = INT2FIX(st->txh.width) / w; st->sy = INT2FIX(st->txh.height) / h; } gf_sc_texture_allocate(txh); txh->pixelformat = new_pixel_format; switch (new_pixel_format) { case GF_PIXEL_RGBA: case GF_PIXEL_ARGB: txh->stride = txh->width * 4; txh->transparent = 1; break; case GF_PIXEL_RGB_565: txh->stride = txh->width * 2; txh->transparent = 0; break; case GF_PIXEL_RGBDS: txh->stride = txh->width * 4; txh->transparent = 1; break; case GF_PIXEL_RGB_24: txh->stride = txh->width * 3; txh->transparent = 0; break; } st->visual->width = txh->width; st->visual->height = txh->height; stencil = raster->stencil_new(raster, GF_STENCIL_TEXTURE); /*TODO - add support for compositeTexture3D when root is 2D visual*/ #ifndef GPAC_DISABLE_3D if (st->visual->type_3d) { GF_Compositor *compositor = st->visual->compositor; /*figure out what to do if main visual (eg video out) is not in OpenGL ...*/ if (!compositor->visual->type_3d) { /*create an offscreen window for OpenGL rendering*/ if ((compositor->offscreen_width < st->txh.width) || (compositor->offscreen_height < st->txh.height)) { #ifndef GPAC_USE_TINYGL GF_Err e; GF_Event evt; compositor->offscreen_width = MAX(compositor->offscreen_width, st->txh.width); compositor->offscreen_height = MAX(compositor->offscreen_height, st->txh.height); evt.type = GF_EVENT_VIDEO_SETUP; evt.setup.width = compositor->offscreen_width; evt.setup.height = compositor->offscreen_height; evt.setup.back_buffer = 0; evt.setup.opengl_mode = 2; e = compositor->video_out->ProcessEvent(compositor->video_out, &evt); if (e) { gf_sc_texture_release(txh); st->unsupported = 1; return; } /*reload openGL ext*/ gf_sc_load_opengl_extensions(compositor, 1); #endif } } else { needs_stencil = 0; } } #endif if (needs_stencil) { txh->data = (char*)gf_malloc(sizeof(unsigned char) * txh->stride * txh->height); memset(txh->data, 0, sizeof(unsigned char) * txh->stride * txh->height); /*set stencil texture - we don't check error as an image could not be supported by the rasterizer but still supported by the blitter (case of RGBD/RGBDS)*/ raster->stencil_set_texture(stencil, txh->data, txh->width, txh->height, txh->stride, txh->pixelformat, txh->pixelformat, 0); #ifdef GPAC_USE_TINYGL if (st->visual->type_3d && !compositor->visual->type_3d) { st->tgl_ctx = ostgl_create_context(txh->width, txh->height, txh->transparent ? 32 : 24, &txh->data, 1); GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Creating TinyGL Offscreen context %p (%d %d - pf %s)\n", st->tgl_ctx, txh->width, txh->width, gf_4cc_to_str(txh->pixelformat))); } #endif } invalidate_all = 1; gf_sc_texture_set_stencil(txh, stencil); } if (!txh->tx_io) return; stencil = gf_sc_texture_get_stencil(txh); if (!stencil) return; #ifdef GPAC_USE_TINYGL if (st->tgl_ctx) ostgl_make_current(st->tgl_ctx, 0); #endif GF_SAFEALLOC(tr_state, GF_TraverseState); tr_state->vrml_sensors = gf_list_new(); tr_state->visual = st->visual; tr_state->invalidate_all = invalidate_all; tr_state->immediate_draw = st->visual->compositor->traverse_state->immediate_draw; gf_mx2d_init(tr_state->transform); gf_cmx_init(&tr_state->color_mat); tr_state->backgrounds = st->visual->back_stack; tr_state->viewpoints = st->visual->view_stack; tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner)); tr_state->min_hsize = INT2FIX( MIN(txh->width, txh->height) ) / 2; tr_state->vp_size.x = INT2FIX(txh->width); tr_state->vp_size.y = INT2FIX(txh->height); composite_do_bindable(st->txh.owner, tr_state, st->first); st->first = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Entering draw cycle\n")); txh->needs_refresh = visual_draw_frame(st->visual, st->txh.owner, tr_state, 0); txh->transparent = (st->visual->last_had_back==2) ? 0 : 1; if (!compositor->edited_text && st->visual->has_text_edit) st->visual->has_text_edit = 0; /*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/ if (0 && gf_list_count(st->visual->view_stack)) { M_Viewport *vp = (M_Viewport *)gf_list_get(st->visual->view_stack, 0); if (vp->isBound) { SFVec2f size = vp->size; if (size.x >=0 && size.y>=0) { /*FIXME - we need tracking of VP changes*/ txh->needs_refresh = 1; } } } if (txh->needs_refresh) { #ifndef GPAC_DISABLE_3D if (st->visual->camera.is_3D) { if (st->visual->compositor->visual->type_3d) { #ifndef GPAC_USE_TINYGL gf_sc_copy_to_texture(&st->txh); #else /*in TinyGL we only need to push associated bitmap to the texture*/ gf_sc_texture_push_image(&st->txh, 0, 0); #endif } else { #ifndef GPAC_USE_TINYGL gf_sc_copy_to_stencil(&st->txh); #else if (txh->pixelformat==GF_PIXEL_RGBDS) gf_get_tinygl_depth(&st->txh); #endif } } else #endif { if (raster->stencil_texture_modified) raster->stencil_texture_modified(stencil); gf_sc_texture_set_stencil(txh, stencil); } gf_sc_invalidate(st->txh.compositor, NULL); } gf_list_del(tr_state->vrml_sensors); gf_free(tr_state); GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Leaving draw cycle\n")); }
static void UpdateComposite2D(GF_TextureHandler *txh) { GF_Err e; u32 i; SensorHandler *hsens; RenderEffect2D *eff; M_CompositeTexture2D *ct2D = (M_CompositeTexture2D *)txh->owner; Composite2DStack *st = (Composite2DStack *) gf_node_get_private(txh->owner); GF_Raster2D *r2d = st->surf->render->compositor->r2d; if (!gf_node_dirty_get(txh->owner)) { txh->needs_refresh = 0; return; } /*rebuild stencil*/ if (!st->surf->the_surface || !txh->hwtx || ((s32) st->width != ct2D->pixelWidth) || ( (s32) st->height != ct2D->pixelHeight) ) { if (txh->hwtx) r2d->stencil_delete(txh->hwtx); txh->hwtx = NULL; if (ct2D->pixelWidth<=0) return; if (ct2D->pixelHeight<=0) return; st->width = ct2D->pixelWidth; st->height = ct2D->pixelHeight; txh->hwtx = r2d->stencil_new(r2d, GF_STENCIL_TEXTURE); e = r2d->stencil_create_texture(txh->hwtx, st->width, st->height, GF_PIXEL_ARGB); if (e) { if (txh->hwtx) r2d->stencil_delete(txh->hwtx); txh->hwtx = NULL; } } if (!txh->hwtx) return; GF_SAFEALLOC(eff, RenderEffect2D); eff->sensors = gf_list_new(); eff->surface = st->surf; if (st->surf->render->top_effect->trav_flags & TF_RENDER_DIRECT) { eff->trav_flags = TF_RENDER_DIRECT; } gf_mx2d_init(eff->transform); gf_cmx_init(&eff->color_mat); st->surf->width = st->width; st->surf->height = st->height; eff->back_stack = st->surf->back_stack; eff->view_stack = st->surf->view_stack; eff->is_pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner)); eff->min_hsize = INT2FIX( MIN(st->width, st->height) ) / 2; Composite_CheckBindables(st->txh.owner, eff, st->first); st->first = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Entering CompositeTexture2D Render Cycle\n")); e = VS2D_InitDraw(st->surf, eff); if (e) { effect_delete(eff); return; } /*render children*/ if (gf_node_dirty_get(st->txh.owner) & GF_SG_NODE_DIRTY) { GF_ChildNodeItem *l = ct2D->children; /*rebuild sensor list */ if (gf_list_count(st->sensors)) { gf_list_del(st->sensors); st->sensors = gf_list_new(); } while (l) { if (l->node && is_sensor_node(l->node) ) { hsens = get_sensor_handler(l->node); if (hsens) gf_list_add(st->sensors, hsens); } l = l->next; } /*if we have an active sensor at this level discard all sensors in current render context (cf VRML)*/ if (gf_list_count(st->sensors)) { effect_reset_sensors(eff); } } /*add sensor to effects*/ i=0; while ((hsens = (SensorHandler*)gf_list_enum(st->sensors, &i))) { effect_add_sensor(eff, hsens, &eff->transform); } gf_node_dirty_clear(st->txh.owner, 0); /*render*/ gf_node_render_children(st->txh.owner, eff); /*finalize draw*/ txh->needs_refresh = VS2D_TerminateDraw(st->surf, eff); st->txh.transparent = st->surf->last_had_back ? 0 : 1; /* st->txh.active_window.x = 0; st->txh.active_window.y = 0; st->txh.active_window.width = st->width; st->txh.active_window.height = st->height; */ st->txh.width = st->width; st->txh.height = st->height; /*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/ if (gf_list_count(st->surf->view_stack)) { M_Viewport *vp = (M_Viewport *)gf_list_get(st->surf->view_stack, 0); if (vp->isBound) { SFVec2f size = vp->size; if (size.x >=0 && size.y>=0) { /* st->txh.active_window.width = size.x; st->txh.active_window.height = size.y; st->txh.active_window.x = (st->width - size.x) / 2; st->txh.active_window.y = (st->height - size.y) / 2; */ /*FIXME - we need tracking of VP changes*/ txh->needs_refresh = 1; } } } if (txh->needs_refresh) { if (r2d->stencil_texture_modified) r2d->stencil_texture_modified(st->txh.hwtx); gf_sr_invalidate(st->txh.compositor, NULL); } effect_delete(eff); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Leaving CompositeTexture2D Render Cycle\n")); }
static Bool OnPlaneSensor(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor) { Bool is_mouse = (ev->type<=GF_EVENT_MOUSEWHEEL) ? 1 : 0; M_PlaneSensor *ps = (M_PlaneSensor *)sh->sensor; PSStack *stack = (PSStack *) gf_node_get_private(sh->sensor); if (ps->isActive && ( /*mouse*/((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT)) || /*keyboar*/(!is_mouse && (!is_over|| ((ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER))) ) ) ) { if (ps->autoOffset) { ps->offset = ps->translation_changed; if (!is_cancel) gf_node_event_out(sh->sensor, 4/*"offset"*/); } ps->isActive = 0; if (!is_cancel) gf_node_event_out(sh->sensor, 5/*"isActive"*/); sh->grabbed = 0; return is_cancel ? 0 : 1; } /*mouse*/ else if (is_mouse) { if (!ps->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT) ) { gf_mx_copy(stack->initial_matrix, compositor->hit_local_to_world); gf_vec_diff(stack->start_drag, compositor->hit_local_point, ps->offset); stack->tracker.normal.x = stack->tracker.normal.y = 0; stack->tracker.normal.z = FIX_ONE; stack->tracker.d = - gf_vec_dot(stack->start_drag, stack->tracker.normal); ps->isActive = 1; gf_node_event_out(sh->sensor, 5/*"isActive"*/); sh->grabbed = 1; return 1; } else if (ps->isActive) { GF_Ray loc_ray; SFVec3f res; loc_ray = compositor->hit_world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); gf_plane_intersect_line(&stack->tracker, &loc_ray.orig, &loc_ray.dir, &res); ps->trackPoint_changed = res; gf_node_event_out(sh->sensor, 6/*"trackPoint_changed"*/); gf_vec_diff(res, res, stack->start_drag); /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed = res; gf_node_event_out(sh->sensor, 7/*"translation_changed"*/); return 1; } } else { if (!ps->isActive && is_over && (ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) { ps->isActive = 1; stack->start_drag = ps->offset; gf_node_event_out(sh->sensor, 5/*"isActive"*/); return 1; } else if (ps->isActive && (ev->type==GF_EVENT_KEYDOWN)) { SFVec3f res; Fixed diff = (ev->key.flags & GF_KEY_MOD_SHIFT) ? 5*FIX_ONE : FIX_ONE; if (!gf_sg_use_pixel_metrics(gf_node_get_graph(sh->sensor))) diff = gf_divfix(diff, INT2FIX(compositor->vp_width/2)); res = stack->start_drag; switch (ev->key.key_code) { case GF_KEY_LEFT: res.x -= diff; break; case GF_KEY_RIGHT: res.x += diff; break; case GF_KEY_UP: res.y += diff; break; case GF_KEY_DOWN: res.y -= diff; break; case GF_KEY_HOME: res = ps->offset; break; default: return 0; } /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } stack->start_drag = res; ps->translation_changed = res; gf_node_event_out(sh->sensor, 7/*"translation_changed"*/); return 1; } } return 0; }
static Bool OnPlaneSensor2D(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor) { Bool is_mouse = (ev->type<=GF_EVENT_MOUSEWHEEL) ? 1 : 0; M_PlaneSensor2D *ps = (M_PlaneSensor2D *)sh->sensor; PS2DStack *stack = (PS2DStack *) gf_node_get_private(sh->sensor); if (ps->isActive && (!ps->enabled || /*mouse*/((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT)) || /*keyboar*/(!is_mouse && (!is_over|| ((ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER))) ) ) ) { if (ps->autoOffset) { ps->offset = ps->translation_changed; if (!is_cancel) gf_node_event_out_str(sh->sensor, "offset"); } ps->isActive = 0; if (!is_cancel) gf_node_event_out_str(sh->sensor, "isActive"); sh->grabbed = 0; return is_cancel ? 0 : 1; } else if (is_mouse) { if (!ps->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) { gf_mx_copy(stack->initial_matrix, compositor->hit_local_to_world); stack->start_drag.x = compositor->hit_local_point.x - ps->offset.x; stack->start_drag.y = compositor->hit_local_point.y - ps->offset.y; ps->isActive = 1; gf_node_event_out_str(sh->sensor, "isActive"); sh->grabbed = 1; /*fallthrough to fire mouse coords*/ //return 1; } if (ps->isActive) { SFVec3f res; GF_Ray loc_ray; loc_ray = compositor->hit_world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); compositor_get_2d_plane_intersection(&loc_ray, &res); ps->trackPoint_changed.x = res.x; ps->trackPoint_changed.y = res.y; gf_node_event_out_str(sh->sensor, "trackPoint_changed"); res.x -= stack->start_drag.x; res.y -= stack->start_drag.y; /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed.x = res.x; ps->translation_changed.y = res.y; gf_node_event_out_str(sh->sensor, "translation_changed"); return 1; } } else { if (!ps->isActive && is_over && (ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) { ps->isActive = 1; stack->start_drag = ps->offset; gf_node_event_out_str(sh->sensor, "isActive"); return 1; } else if (ps->isActive && (ev->type==GF_EVENT_KEYDOWN)) { SFVec2f res; Fixed diff = (ev->key.flags & GF_KEY_MOD_SHIFT) ? 5*FIX_ONE : FIX_ONE; if (!gf_sg_use_pixel_metrics(gf_node_get_graph(sh->sensor))) diff = gf_divfix(diff, compositor->vp_width/2); res = stack->start_drag; switch (ev->key.key_code) { case GF_KEY_LEFT: res.x += -diff; break; case GF_KEY_RIGHT: res.x += diff; break; case GF_KEY_UP: res.y += diff; break; case GF_KEY_DOWN: res.y += -diff; break; case GF_KEY_HOME: res = ps->offset; break; default: return 0; } /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed = res; gf_node_event_out_str(sh->sensor, "translation_changed"); ps->trackPoint_changed.x = res.x + stack->start_drag.x; ps->trackPoint_changed.y = res.y + stack->start_drag.y; gf_node_event_out_str(sh->sensor, "trackPoint_changed"); stack->start_drag = res; return 1; } } return 0; }