📄 viewport.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 "render3d_nodes.h"#include <gpac/options.h>/*for default viewport*/#include <gpac/internal/terminal_dev.h>GF_Err R3D_GetViewpoint(GF_VisualRenderer *vr, u32 viewpoint_idx, const char **outName, Bool *is_bound){ u32 count; GF_Node *n; Render3D *sr = (Render3D *) vr->user_priv; if (!sr->surface) return GF_BAD_PARAM; count = gf_list_count(sr->surface->view_stack); if (!viewpoint_idx) return GF_BAD_PARAM; if (viewpoint_idx>count) return GF_EOS; n = (GF_Node*)gf_list_get(sr->surface->view_stack, viewpoint_idx-1); switch (gf_node_get_tag(n)) { case TAG_MPEG4_Viewport: *outName = ((M_Viewport*)n)->description.buffer; *is_bound = ((M_Viewport*)n)->isBound;return GF_OK; case TAG_MPEG4_Viewpoint: case TAG_X3D_Viewpoint: *outName = ((M_Viewpoint*)n)->description.buffer; *is_bound = ((M_Viewpoint*)n)->isBound; return GF_OK; default: *outName = NULL; return GF_OK; }}GF_Err R3D_SetViewpoint(GF_VisualRenderer *vr, u32 viewpoint_idx, const char *viewpoint_name){ u32 count, i; GF_Node *n; Render3D *sr = (Render3D *) vr->user_priv; if (!sr->surface) return GF_BAD_PARAM; count = gf_list_count(sr->surface->view_stack); if (viewpoint_idx>count) return GF_BAD_PARAM; if (!viewpoint_idx && !viewpoint_name) return GF_BAD_PARAM; if (viewpoint_idx) { Bool bind; n = (GF_Node*)gf_list_get(sr->surface->view_stack, viewpoint_idx-1); bind = Bindable_GetIsBound(n); Bindable_SetSetBind(n, !bind); return GF_OK; } for (i=0; i<count;i++) { char *name = NULL; n = (GF_Node*)gf_list_get(sr->surface->view_stack, viewpoint_idx-1); switch (gf_node_get_tag(n)) { case TAG_MPEG4_Viewport: name = ((M_Viewport*)n)->description.buffer; break; case TAG_MPEG4_Viewpoint: case TAG_X3D_Viewpoint: name = ((M_Viewpoint*)n)->description.buffer; break; default: break; } if (name && !stricmp(name, viewpoint_name)) { Bool bind = Bindable_GetIsBound(n); Bindable_SetSetBind(n, !bind); return GF_OK; } } return GF_BAD_PARAM;}#define VPCHANGED(__comp) { GF_Event evt; evt.type = GF_EVENT_VIEWPOINTS; GF_USER_SENDEVENT(__comp->user, &evt); }static void DestroyViewStack(GF_Node *node){ ViewStack *st = (ViewStack *) gf_node_get_private(node); PreDestroyBindable(node, st->reg_stacks); gf_list_del(st->reg_stacks); VPCHANGED(st->compositor); free(st);}static void viewport_set_bind(GF_Node *node){ ViewStack *st = (ViewStack *) gf_node_get_private(node); Bindable_OnSetBind(node, st->reg_stacks); gf_sr_invalidate(st->compositor, NULL); /*notify change of vp stack*/ VPCHANGED(st->compositor); /*and dirty ourselves to force frustrum update*/ gf_node_dirty_set(node, 0, 0);}static void RenderViewport(GF_Node *node, void *rs, Bool is_destroy){ Fixed ar, sx, sy, w, h, tx, ty; GF_Matrix2D mat; GF_Matrix mx; GF_Rect rc, rc_bckup; Bool is_layer; RenderEffect3D *eff = (RenderEffect3D *)rs; M_Viewport *vp = (M_Viewport*) node; ViewStack *st = (ViewStack *) gf_node_get_private(node); if (is_destroy) { DestroyViewStack(node); return; } assert(eff->viewpoints); if (eff->camera->is_3D) return; /*first traverse, bound if needed*/ if (gf_list_find(eff->viewpoints, node) < 0) { gf_list_add(eff->viewpoints, node); assert(gf_list_find(st->reg_stacks, eff->viewpoints)==-1); gf_list_add(st->reg_stacks, eff->viewpoints); if (gf_list_get(eff->viewpoints, 0) == vp) { if (!vp->isBound) Bindable_SetIsBound(node, 1); } else { if (gf_is_default_scene_viewpoint(node)) Bindable_SetSetBind(node, 1); } VPCHANGED(st->compositor); /*in any case don't draw the first time (since the viewport could have been declared last)*/ gf_sr_invalidate(st->compositor, NULL); return; } /*not bound ignore*/ if (!vp->isBound) return; if (eff->traversing_mode != TRAVERSE_RENDER_BINDABLE) return; is_layer = (eff->viewpoints == eff->surface->view_stack) ? 0 : 1; /*if no parent this is the main viewport, don't update if not changed*/ if (!is_layer && !gf_node_dirty_get(node)) return; gf_node_dirty_clear(node, 0); gf_mx2d_init(mat); gf_mx2d_add_translation(&mat, vp->position.x, vp->position.y); gf_mx2d_add_rotation(&mat, 0, 0, vp->orientation); //compute scaling ratio rc = gf_rect_center(vp->size.x, vp->size.y); gf_mx2d_apply_rect(&mat, &rc); w = eff->bbox.max_edge.x - eff->bbox.min_edge.x; h = eff->bbox.max_edge.y - eff->bbox.min_edge.y; ar = gf_divfix(h, w); rc_bckup = rc; switch (vp->fit) { /*covers all area and respect aspect ratio*/ case 2: if (gf_divfix(rc.width, w) > gf_divfix(rc.height, h)) { rc.width = gf_muldiv(rc.width, h, rc.height); rc.height = h; } else { rc.height = gf_muldiv(rc.height , w, rc.width); rc.width = w; } break; /*fits inside the area and respect AR*/ case 1: if (gf_divfix(rc.width, w)> gf_divfix(rc.height, h)) { rc.height = gf_muldiv(rc.height, w, rc.width); rc.width = w; } else { rc.width = gf_muldiv(rc.width, h, rc.height); rc.height = h; } break; /*fit entirely: nothing to change*/ case 0: rc.width = w; rc.height = h; break; default: return; } sx = gf_divfix(rc_bckup.width , rc.width); sy = gf_divfix(rc_bckup.height , rc.height); rc.x = - rc.width/2; rc.y = rc.height/2; tx = ty = 0; if (vp->fit) { /*left alignment*/ if (vp->alignment.vals[0] == -1) tx = rc.width/2 - w/2; else if (vp->alignment.vals[0] == 1) tx = w/2 - rc.width/2; /*top-alignment*/ if (vp->alignment.vals[1]==-1) ty = rc.height/2 - h/2; else if (vp->alignment.vals[1]==1) ty = h/2 - rc.height/2; } gf_mx_from_mx2d(&mx, &mat); gf_mx_add_scale(&mx, sx, sy, FIX_ONE); gf_mx_add_translation(&mx, -tx, -ty, 0); gf_mx_inverse(&mx); /*in layers directly modify the model matrix*/ if (eff->viewpoints != eff->surface->view_stack) { gf_mx_add_matrix(&eff->model_matrix, &mx); } else { gf_mx_copy(eff->camera->viewport, mx); eff->camera->flags = (CAM_HAS_VIEWPORT | CAM_IS_DIRTY); }}void R3D_InitViewport(Render3D *sr, GF_Node *node){ ViewStack *st; GF_SAFEALLOC(st, ViewStack); st->reg_stacks = gf_list_new(); gf_sr_traversable_setup(st, node, sr->compositor); gf_node_set_private(node, st); gf_node_set_callback_function(node, RenderViewport); ((M_Viewport*)node)->on_set_bind = viewport_set_bind;}static void viewpoint_set_bind(GF_Node *node){ ViewStack *st = (ViewStack *) gf_node_get_private(node); if (!((M_Viewpoint*)node)->isBound ) st->prev_was_bound = 0; Bindable_OnSetBind(node, st->reg_stacks); gf_sr_invalidate(st->compositor, NULL); /*notify change of vp stack*/ VPCHANGED(st->compositor); /*and dirty ourselves to force frustrum update*/ gf_node_dirty_set(node, 0, 0);}static void RenderViewpoint(GF_Node *node, void *rs, Bool is_destroy){ SFVec3f pos, v1, v2; SFRotation ori; GF_Matrix mx;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -