📄 visual_surface.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / 3D rendering module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "visual_surface.h"#include "render3d_nodes.h"#include <gpac/options.h>VisualSurface *VS_New(){ VisualSurface *tmp; GF_SAFEALLOC(tmp, VisualSurface); tmp->back_stack = gf_list_new(); tmp->view_stack = gf_list_new(); tmp->alpha_nodes_to_draw = gf_list_new(); tmp->fog_stack = gf_list_new(); tmp->navigation_stack = gf_list_new(); return tmp;}void VS_Delete(VisualSurface *surf){ BindableStackDelete(surf->back_stack); BindableStackDelete(surf->view_stack); BindableStackDelete(surf->fog_stack); BindableStackDelete(surf->navigation_stack); gf_list_del(surf->alpha_nodes_to_draw); free(surf);}DrawableStack *new_drawable(GF_Node *owner, GF_Renderer *compositor){ DrawableStack *tmp = (DrawableStack *)malloc(sizeof(DrawableStack)); if (tmp) stack_setup(tmp, owner, compositor); return tmp;}void delete_drawable(DrawableStack*d){ drawablestack_predestroy(d); free(d);}void drawable_node_destroy(GF_Node *n){ DrawableStack *d = (DrawableStack *)gf_node_get_private(n); if (d) delete_drawable(d);}DrawableStack *BaseDrawableStack(GF_Renderer *sr, GF_Node *node){ DrawableStack *st = new_drawable(node, sr); gf_node_set_private(node, st); return st;}void delete_strikeinfo(StrikeInfo *info){ if (info->outline) mesh_free(info->outline); free(info);}stack2D *new_stack2D(GF_Node *owner, GF_Renderer *compositor){ stack2D *tmp = (stack2D *)malloc(sizeof(stack2D)); if (tmp) { stack_setup(tmp, owner, compositor); tmp->path = gf_path_new(); tmp->strike_list = gf_list_new(); } return tmp;}void stack2D_predestroy(stack2D *d){ Render3D *sr = (Render3D *)d->compositor->visual_renderer->user_priv; if (d->mesh) mesh_free(d->mesh); assert(d->path); gf_path_del(d->path); while (gf_list_count(d->strike_list)) { StrikeInfo *si = (StrikeInfo *)gf_list_get(d->strike_list, 0); gf_list_rem(d->strike_list, 0); /*remove from main strike list*/ gf_list_del_item(sr->strike_bank, si); delete_strikeinfo(si); } gf_list_del(d->strike_list);}void delete_stack2D(stack2D *d){ stack2D_predestroy(d); free(d);}void stack2D_node_predestroy(GF_Node *n){ stack2D *d = (stack2D *)gf_node_get_private(n); if (d) delete_stack2D(d);}stack2D *BaseStack2D(GF_Renderer *sr, GF_Node *node){ stack2D *st = new_stack2D(node, sr); gf_node_set_private(node, st); return st;}void stack2D_setup(stack2D *st, GF_Renderer *sr, GF_Node *node){ stack_setup(st, node, sr); st->path = gf_path_new(); st->strike_list = gf_list_new();}void stack2D_reset(stack2D *d){ Render3D *sr = (Render3D *)d->compositor->visual_renderer->user_priv; if (d->path) gf_path_reset(d->path); while (gf_list_count(d->strike_list)) { StrikeInfo *si = (StrikeInfo *)gf_list_get(d->strike_list, 0); gf_list_rem(d->strike_list, 0); gf_list_del_item(sr->strike_bank, si); delete_strikeinfo(si); }}Bool VS_GetAspect2D(RenderEffect3D *eff, Aspect2D *asp){ M_Material2D *mat; Bool has_mat; /*default values*/ memset(asp, 0, sizeof(Aspect2D)); asp->fill_color.red = asp->fill_color.green = asp->fill_color.blue = FLT2FIX(0.8f); /*this is a bug in the spec: by default line width is 1.0, but in meterMetrics this means half of the screen :)*/ if (eff->is_pixel_metrics) asp->pen_props.width = FIX_ONE; else asp->pen_props.width = gf_invfix(2*eff->min_hsize); asp->line_color = asp->fill_color; asp->pen_props.cap = GF_LINE_CAP_FLAT; asp->pen_props.join = GF_LINE_JOIN_MITER; asp->pen_props.miterLimit = INT2FIX(4); asp->line_alpha = asp->alpha = FIX_ONE; has_mat = 1; if (!eff->appear) goto exit; mat = (M_Material2D *) ((M_Appearance *)eff->appear)->material; /*according to the spec only Material2D shall be used with 2D primitives*/ if (!mat) goto exit; switch (gf_node_get_tag((GF_Node *)mat)) { /*we need to indicate to text if it shall use 2D or 3D material...*/ case TAG_MPEG4_Material: case TAG_X3D_Material: has_mat = 0; asp->filled = 1; asp->pen_props.width = 0; asp->fill_color = ((M_Material*)mat)->diffuseColor; goto exit; case TAG_MPEG4_MaterialKey: goto exit; } asp->line_color = asp->fill_color = mat->emissiveColor; asp->line_alpha = asp->alpha = FIX_ONE - mat->transparency; asp->filled = mat->filled; if (mat->lineProps == NULL) { if (asp->filled || (asp->alpha==0)) asp->pen_props.width =0; } else { asp->lp = mat->lineProps; switch (gf_node_get_tag(mat->lineProps)) { case TAG_MPEG4_LineProperties: { M_LineProperties *lp = (M_LineProperties *)mat->lineProps; asp->pen_props.width = lp->width; asp->pen_props.dash = (u8) lp->lineStyle; asp->line_color = lp->lineColor; } break; case TAG_MPEG4_XLineProperties: { M_XLineProperties *xlp = (M_XLineProperties *)mat->lineProps; asp->pen_props.dash = (u8) xlp->lineStyle; asp->line_color = xlp->lineColor; asp->line_alpha = FIX_ONE - xlp->transparency; asp->pen_props.width = xlp->width; asp->is_scalable = xlp->isScalable; asp->pen_props.align = xlp->isCenterAligned ? GF_PATH_LINE_CENTER : GF_PATH_LINE_INSIDE; asp->pen_props.cap = (u8) xlp->lineCap; asp->pen_props.join = (u8) xlp->lineJoin; asp->pen_props.miterLimit = xlp->miterLimit; asp->pen_props.dash_offset = xlp->dashOffset; /*dash settings strutc is the same as MFFloat from XLP, typecast without storing*/ if (xlp->dashes.count) { asp->pen_props.dash_set = (GF_DashSettings *) &xlp->dashes; } else { asp->pen_props.dash_set = NULL; } asp->txh = R3D_GetTextureHandler(xlp->texture); asp->tx_trans = xlp->textureTransform; } break; } }exit: if (!eff->color_mat.identity) gf_cmx_apply_fixed(&eff->color_mat, &asp->alpha, &asp->fill_color.red, &asp->fill_color.green, &asp->fill_color.blue); /*update line width*/ if (asp->pen_props.width) { /*if pen is not scalable, apply user/viewport transform so that original aspect is kept*/ if (!asp->is_scalable) { GF_Rect rc; rc.x = rc.y = 0; rc.width = rc.height = FIX_ONE; gf_mx_apply_rect(&eff->model_matrix, &rc); asp->line_scale = MAX(rc.width, rc.height); } else { asp->line_scale = FIX_ONE; } if (!eff->color_mat.identity) gf_cmx_apply_fixed(&eff->color_mat, &asp->line_alpha, &asp->line_color.red, &asp->line_color.green, &asp->line_color.blue); } return has_mat;}StrikeInfo *VS_GetStrikeInfo(stack2D *st, Aspect2D *asp, RenderEffect3D *eff){ StrikeInfo *si; u32 now, i; Render3D *sr = (Render3D *)st->compositor->visual_renderer->user_priv; Bool vect_outline = !sr->raster_outlines; if (!asp->pen_props.width || !st->path) return NULL; si = NULL; i=0; while ((si = (StrikeInfo *)gf_list_enum(st->strike_list, &i))) { /*note this includes default LP (NULL)*/ if (si->lineProps == asp->lp) break; si = NULL; } /*not found, add*/ if (!si) { GF_SAFEALLOC(si, StrikeInfo); si->lineProps = asp->lp; si->node2D = st->owner; gf_list_add(st->strike_list, si); gf_list_add(sr->strike_bank, si); } if (vect_outline != si->is_vectorial) { if (si->outline) mesh_free(si->outline); si->outline = NULL; } /*node changed or outline not build*/ now = asp->lp ? (1 + R3D_LP_GetLastUpdateTime(asp->lp)) : si->last_update_time; if (!si->outline || (si->is_vectorial && ((now!=si->last_update_time) || (si->line_scale != asp->line_scale) )) ) { si->last_update_time = now; si->line_scale = asp->line_scale; if (si->outline) mesh_free(si->outline); si->outline = new_mesh(); si->is_vectorial = vect_outline;#ifndef GPAC_USE_OGL_ES if (vect_outline) { u32 i; GF_Path *outline_path; Fixed dash_o = asp->pen_props.dash_offset; Fixed w = asp->pen_props.width; asp->pen_props.width = gf_divfix(asp->pen_props.width, asp->line_scale); asp->pen_props.dash_offset = gf_mulfix(asp->pen_props.dash_offset, asp->pen_props.width); if (asp->pen_props.dash_set) { for(i=0; i<asp->pen_props.dash_set->num_dash; i++) { asp->pen_props.dash_set->dashes[i] = gf_mulfix(asp->pen_props.dash_set->dashes[i], asp->line_scale); } } outline_path = gf_path_get_outline(st->path, asp->pen_props); /*restore*/ asp->pen_props.width = w; asp->pen_props.dash_offset = dash_o; if (asp->pen_props.dash_set) { for(i=0; i<asp->pen_props.dash_set->num_dash; i++) { asp->pen_props.dash_set->dashes[i] = gf_divfix(asp->pen_props.dash_set->dashes[i], asp->line_scale); } } TesselatePath(si->outline, outline_path, asp->txh ? 2 : 1); gf_path_del(outline_path); } else#endif mesh_get_outline(si->outline, st->path); } return si;}StrikeInfo *VS_GetStrikeInfoIFS(stack2D *st, Aspect2D *asp, RenderEffect3D *eff){ StrikeInfo *si; u32 now, i; Render3D *sr = (Render3D *)st->compositor->visual_renderer->user_priv; if (!asp->pen_props.width || !st->path) return NULL; si = NULL; i=0; while ((si = (StrikeInfo *)gf_list_enum(st->strike_list, &i))) { /*note this includes default LP (NULL)*/ if (si->lineProps == asp->lp) break; si = NULL; } /*not found, add*/ if (!si) { GF_SAFEALLOC(si, StrikeInfo); si->lineProps = asp->lp; si->node2D = st->owner; gf_list_add(st->strike_list, si); gf_list_add(sr->strike_bank, si); } /*for this func the strike is always raster*/ if (si->is_vectorial) { if (si->outline) mesh_free(si->outline); si->outline = NULL; } /*node changed or outline not build*/ now = asp->lp ? R3D_LP_GetLastUpdateTime(asp->lp) : si->last_update_time; if ((now!=si->last_update_time) || (si->line_scale != asp->line_scale) ) { si->last_update_time = now; si->line_scale = asp->line_scale; if (si->outline) mesh_free(si->outline); si->outline = NULL; si->is_vectorial = 0; } return si;}Fixed Aspect_GetLineWidth(Aspect2D *asp){ /*for raster outlines are already set to the proper width - note this may not work depending on GL...*/ Fixed width = asp->pen_props.width; if (asp->is_scalable) width = gf_mulfix(width, asp->line_scale); return width;}void VS_Set2DStrikeAspect(RenderEffect3D *eff, Aspect2D *asp){ if (asp->txh) { /*We forgot to specify this in the spec ...*/ tx_set_blend_mode(asp->txh, TX_REPLACE);#if 0 if (asp->line_alpha != FIX_ONE) { VS3D_SetMaterial2D(eff->surface, asp->line_color, asp->line_alpha); tx_set_blend_mode(asp->txh, TX_MODULATE); } else { VS3D_SetState(eff->surface, F3D_BLEND, 0); tx_set_blend_mode(asp->txh, TX_REPLACE); }#endif eff->mesh_has_texture = tx_enable(asp->txh, asp->tx_trans); if (eff->mesh_has_texture) return; } /*no texture or not ready, use color*/ VS3D_SetMaterial2D(eff->surface, asp->line_color, asp->line_alpha);}static GF_TextureHandler *VS_setup_texture_2d(RenderEffect3D *eff, Aspect2D *asp){ GF_TextureHandler *txh; if (!eff->appear) return NULL; txh = R3D_GetTextureHandler(((M_Appearance *)eff->appear)->texture); if (!txh) return NULL; if (!asp->filled) { if (asp->alpha!=FIX_ONE) { VS3D_SetMaterial2D(eff->surface, asp->fill_color, asp->alpha); tx_set_blend_mode(txh, TX_MODULATE); } else { VS3D_SetState(eff->surface, F3D_BLEND, 0); tx_set_blend_mode(txh, TX_REPLACE); } } eff->mesh_has_texture = tx_enable(txh, ((M_Appearance *)eff->appear)->textureTransform); if (eff->mesh_has_texture) return txh; return NULL;}void stack2D_draw(stack2D *st, RenderEffect3D *eff){ Aspect2D asp; StrikeInfo *si; GF_TextureHandler *fill_txh; VS_GetAspect2D(eff, &asp); if (!asp.alpha) { fill_txh = NULL; } else { fill_txh = VS_setup_texture_2d(eff, &asp); } /*fill path*/ if (fill_txh || (asp.alpha && asp.filled) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -