static void ILS2D_Draw(GF_Node *node, GF_TraverseState *tr_state) { GF_Path *path; SFVec2f *pts; SFColor col; Fixed alpha; u32 i, count, col_ind, ind, end_at; u32 linear[2], *colors; SFVec2f start, end; u32 j, num_col; GF_STENCIL grad; GF_Raster2D *raster; DrawableContext *ctx = tr_state->ctx; M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node; M_Coordinate2D *coord = (M_Coordinate2D*) ils2D->coord; M_Color *color = (M_Color *) ils2D->color; end.x = end.y = 0; if (!coord->point.count) return; if (! ils2D->color) { /*no texturing*/ visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; pts = coord->point.vals; if (!ils2D->colorPerVertex || (color->color.count<2) ) { count = 0; end_at = ils2D->coordIndex.count; if (!end_at) end_at = coord->point.count; ind = ils2D->coordIndex.count ? ils2D->coordIndex.vals[0] : 0; i=1; path = gf_path_new(); gf_path_add_move_to(path, pts[ind].x, pts[ind].y); for (; i<=end_at; i++) { if ((i==end_at) || (ils2D->coordIndex.count && ils2D->coordIndex.vals[i] == -1)) { /*draw current*/ col_ind = (ils2D->colorIndex.count && (ils2D->colorIndex.vals[count]>=0) ) ? (u32) ils2D->colorIndex.vals[count] : count; if (col_ind>=color->color.count) col_ind=color->color.count-1; col = color->color.vals[col_ind]; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state); i++; if (i>=end_at) break; gf_path_reset(path); ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i; gf_path_add_move_to(path, pts[ind].x, pts[ind].y); if (ils2D->coordIndex.count) count++; continue; } else { ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0) ) ? (u32) ils2D->coordIndex.vals[i] : i; gf_path_add_line_to(path, pts[ind].x, pts[ind].y); } } gf_path_del(path); return; } raster = NULL; end_at = ils2D->coordIndex.count; if (!end_at) end_at = coord->point.count; count = 0; col_ind = 0; ind = 0; i=0; path = gf_path_new(); while (1) { gf_path_reset(path); ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i; start = pts[ind]; num_col = 1; i++; gf_path_add_move_to(path, start.x, start.y); if (ils2D->coordIndex.count) { while (ils2D->coordIndex.vals[i] != -1) { end = pts[ils2D->coordIndex.vals[i]]; gf_path_add_line_to(path, end.x, end.y); i++; num_col++; if (i >= ils2D->coordIndex.count) break; } } else { while (i<end_at) { end = pts[i]; gf_path_add_line_to(path, end.x, end.y); i++; num_col++; } } raster = tr_state->visual->compositor->rasterizer; /*use linear gradient*/ if (num_col==2) { Fixed pos[2]; grad = raster->stencil_new(raster, GF_STENCIL_LINEAR_GRADIENT); if (ils2D->colorIndex.count) { col = color->color.vals[ils2D->colorIndex.vals[col_ind]]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[ils2D->colorIndex.vals[col_ind+1]]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else if (ils2D->coordIndex.count) { col = color->color.vals[ils2D->coordIndex.vals[col_ind]]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[ils2D->coordIndex.vals[col_ind+1]]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { col = color->color.vals[col_ind]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[col_ind+1]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } pos[0] = 0; pos[1] = FIX_ONE; raster->stencil_set_linear_gradient(grad, start.x, start.y, end.x, end.y); raster->stencil_set_gradient_interpolation(grad, pos, linear, 2); } else { grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); if (grad) { raster->stencil_set_vertex_path(grad, path); colors = (u32*)gf_malloc(sizeof(u32) * num_col); for (j=0; j<num_col; j++) { if (ils2D->colorIndex.count>0) { col = color->color.vals[ils2D->colorIndex.vals[col_ind+j]]; } else if (ils2D->coordIndex.count) { col = color->color.vals[ils2D->coordIndex.vals[col_ind+j]]; } else { col = color->color.vals[col_ind+j]; } colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } raster->stencil_set_vertex_colors(grad, colors, num_col); gf_free(colors); } } raster->stencil_set_matrix(grad, &ctx->transform); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, grad, tr_state); if (grad) raster->stencil_delete(grad); i ++; col_ind += num_col + 1; if (i >= ils2D->coordIndex.count) break; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); }
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 IFS2D_Draw(GF_Node *node, GF_TraverseState *tr_state) { u32 i, count, ci_count; u32 j, ind_col, num_col; SFVec2f center, end; SFColor col_cen; GF_STENCIL grad; u32 *colors; GF_Path *path; SFVec2f start; SFVec2f *pts; SFColor col; Fixed alpha; GF_Raster2D *raster; DrawableContext *ctx = tr_state->ctx; M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node; M_Coordinate2D *coord = (M_Coordinate2D*) ifs2D->coord; M_Color *color = (M_Color *) ifs2D->color; col.red = col.green = col.blue = 0; /*simple case, no color specified*/ if (!ifs2D->color) { visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } /*if default face use first color*/ ci_count = ifs2D->coordIndex.count; pts = coord->point.vals; if (ci_count == 0) { col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[0]] : color->color.vals[0]; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255; if (!alpha || !ctx->aspect.pen_props.width) { alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } /*we have color per faces so we need N path :(*/ if (! ifs2D->colorPerVertex) { path = gf_path_new(); count = 0; i = 0; while (1) { gf_path_reset(path); start = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_move_to(path, start.x, start.y); i++; while (ifs2D->coordIndex.vals[i] != -1) { start = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_line_to(path, start.x, start.y); i++; if (i >= ci_count) break; } /*close in ALL cases because even if the start/end points are the same the line join needs to be present*/ gf_path_close(path); col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[count]] : color->color.vals[count]; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255; if (!alpha) { alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } visual_2d_texture_path(tr_state->visual, path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state); count++; i++; if (i >= ci_count) break; ctx->flags &= ~CTX_PATH_FILLED; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); return; } /*final case, color per vertex means gradient fill/strike*/ raster = tr_state->visual->compositor->rasterizer; grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); /*not supported, fill default*/ if (!grad) { visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } path = gf_path_new(); ind_col = 0; i = 0; while (1) { gf_path_reset(path); start = pts[ifs2D->coordIndex.vals[i]]; center = start; gf_path_add_move_to(path, start.x, start.y); num_col = 1; i+=1; while (ifs2D->coordIndex.vals[i] != -1) { end = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_line_to(path, end.x, end.y); i++; center.x += end.x; center.y += end.y; num_col ++; if (i >= ci_count) break; } gf_path_close(path); num_col++; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color) ) / 255; colors = (u32*)gf_malloc(sizeof(u32) * num_col); col_cen.blue = col_cen.red = col_cen.green = 0; for (j=0; j<num_col-1; j++) { if (ifs2D->colorIndex.count > ind_col + j) { col = color->color.vals[ifs2D->colorIndex.vals[ind_col + j]]; } else if (ci_count > ind_col + j) { col = color->color.vals[ifs2D->coordIndex.vals[ind_col + j]]; } colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col_cen.blue += col.blue; col_cen.green += col.green; col_cen.red += col.red; } colors[num_col-1] = colors[0]; if (ifs2D->colorIndex.count > ind_col) { col = color->color.vals[ifs2D->colorIndex.vals[ind_col]]; } else if (ci_count > ind_col) { col = color->color.vals[ifs2D->coordIndex.vals[ind_col]]; } col_cen.blue += col.blue; col_cen.green += col.green; col_cen.red += col.red; raster->stencil_set_vertex_path(grad, path); raster->stencil_set_vertex_colors(grad, colors, num_col); gf_free(colors); col_cen.blue /= num_col; col_cen.green /= num_col; col_cen.red /= num_col; center.x /= num_col; center.y /= num_col; raster->stencil_set_vertex_center(grad, center.x, center.y, GF_COL_ARGB_FIXED(alpha, col_cen.red, col_cen.green, col_cen.blue) ); raster->stencil_set_matrix(grad, &ctx->transform); /*draw*/ visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, grad, grad, tr_state); raster->stencil_delete(grad); //goto next point i++; ind_col += num_col + 1; if (i >= ci_count) break; grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); ctx->flags &= ~CTX_PATH_FILLED; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); }