📄 render3d.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.h"#include "visual_surface.h"#include "render3d_nodes.h"#include <gpac/options.h>void effect3d_reset(RenderEffect3D *eff){ GF_List *sbck = eff->sensors; GF_List *dbck = eff->local_lights; memset(eff, 0, sizeof(RenderEffect3D)); gf_mx_init(eff->model_matrix); gf_cmx_init(&eff->color_mat); eff->sensors = sbck; eff->local_lights = dbck; gf_list_reset(eff->sensors); while (gf_list_count(eff->local_lights)) { DLightContext *dl = (DLightContext *)gf_list_get(eff->local_lights, 0); gf_list_rem(eff->local_lights, 0); free(dl); }}RenderEffect3D *effect3d_new(){ RenderEffect3D *eff; GF_SAFEALLOC(eff, RenderEffect3D); eff->sensors = gf_list_new(); eff->local_lights = gf_list_new(); return eff;}void effect3d_delete(RenderEffect3D *eff){ effect3d_reset(eff); gf_list_del(eff->sensors); gf_list_del(eff->local_lights); free(eff);}GF_Rect R3D_UpdateClipper(RenderEffect3D *eff, GF_Rect this_clip, Bool *need_restore, GF_Rect *original, Bool for_layer){ GF_Rect clip, orig; if (for_layer) { orig = eff->layer_clipper; *need_restore = eff->has_layer_clip; } else { orig = eff->clipper; *need_restore = eff->has_clip; } *original = orig; clip = this_clip; if (*need_restore) { GF_Matrix mx; gf_mx_copy(mx, eff->model_matrix); gf_mx_inverse(&mx); gf_mx_apply_rect(&mx, &orig); if (clip.x < orig.x) { clip.width -= (orig.x - clip.x); clip.x = orig.x; } if (clip.x + clip.width > orig.x + orig.width) { clip.width = orig.x + orig.width - clip.x; } if (clip.y > orig.y) { clip.height -= (clip.y - orig.y); clip.y = orig.y; } if (clip.y - clip.height < orig.y - orig.height) { clip.height = clip.y - orig.y + orig.height; } } if (for_layer) { eff->layer_clipper = clip; eff->has_layer_clip = 1; } else { eff->clipper = clip; /*retranslate to world coords*/ gf_mx_apply_rect(&eff->model_matrix, &eff->clipper); /*if 2D, also update with user zoom and translation*/ if (!eff->camera->is_3D) gf_mx_apply_rect(&eff->camera->modelview, &eff->clipper); eff->has_clip = 1; } return clip;}Bool R3D_GetSurfaceSizeInfo(RenderEffect3D *eff, Fixed *surf_width, Fixed *surf_height){ u32 w, h; w = eff->surface->width; h = eff->surface->height; /*no size info, use main render output size*/ if (!w || !h) { w = eff->surface->render->out_width; h = eff->surface->render->out_height; } if (eff->is_pixel_metrics) { *surf_width = INT2FIX(w); *surf_height = INT2FIX(h); return 1; } if (h > w) { *surf_width = 2*FIX_ONE; *surf_height = gf_divfix(2*INT2FIX(h), INT2FIX(w)); } else { *surf_width = gf_divfix(2*INT2FIX(w), INT2FIX(h)); *surf_height = 2*FIX_ONE; } return 0;}SensorHandler *r3d_get_sensor_handler(GF_Node *n){ SensorHandler *hs; if (!n) return NULL; switch (gf_node_get_tag(n)) { case TAG_MPEG4_DiscSensor: hs = r3d_ds_get_handler(n); break; case TAG_MPEG4_PlaneSensor2D: hs = r3d_ps2D_get_handler(n); break; case TAG_MPEG4_ProximitySensor2D: hs = r3d_prox2D_get_handler(n); break; case TAG_MPEG4_Anchor: case TAG_X3D_Anchor: hs = r3d_anchor_get_handler(n); break; case TAG_MPEG4_TouchSensor: case TAG_X3D_TouchSensor: hs = r3d_touch_sensor_get_handler(n); break; case TAG_MPEG4_PlaneSensor: case TAG_X3D_PlaneSensor: hs = r3d_ps_get_handler(n); break; case TAG_MPEG4_CylinderSensor: case TAG_X3D_CylinderSensor: hs = r3d_cs_get_handler(n); break; case TAG_MPEG4_SphereSensor: case TAG_X3D_SphereSensor: hs = r3d_sphere_get_handler(n); break; default: return NULL; } if (hs && hs->IsEnabled(n)) return hs; return NULL;}void R3D_SensorDeleted(GF_Renderer *rend, SensorHandler *hdl){ Render3D *sr = (Render3D *)rend->visual_renderer->user_priv; gf_list_del_item(sr->prev_sensors, hdl); if (rend->interaction_sensors) rend->interaction_sensors--;}void R3D_SetGrabbed(GF_Renderer *rend, Bool bOn) { ((Render3D *)rend->visual_renderer->user_priv)->is_grabbed = bOn; }GF_Node *R3D_PickNode(GF_VisualRenderer *vr, s32 X, s32 Y){ return NULL;}static void DestroyLineProps(GF_Node *n, void *rs, Bool is_destroy){ StrikeInfo *si; u32 i; LinePropStack *st = (LinePropStack *)gf_node_get_private(n); Render3D *sr = (Render3D *)st->sr; if (!is_destroy) return; i=0; while ((si = (StrikeInfo*)gf_list_enum(sr->strike_bank, &i))) { if (si->lineProps == n) { /*remove from node*/ if (si->node2D) { stack2D *st = (stack2D *) gf_node_get_private(si->node2D); gf_list_del_item(st->strike_list, si); } i--; gf_list_rem(sr->strike_bank, i); delete_strikeinfo(si); } } free(st);}void R3D_InitLineProps(Render3D *sr, GF_Node *node){ LinePropStack *st = (LinePropStack *)malloc(sizeof(LinePropStack)); st->sr = sr; st->last_mod_time = 1; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroyLineProps);}u32 R3D_LP_GetLastUpdateTime(GF_Node *node){ LinePropStack *st = (LinePropStack *)gf_node_get_private(node); if (!st) return 0; if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { st->last_mod_time ++; gf_node_dirty_clear(node, 0); } return st->last_mod_time;}void R3D_DrawScene(GF_VisualRenderer *vr){ u32 i, tag; GF_SceneGraph *sg; RenderEffect3D static_eff; Render3D *sr = (Render3D *)vr->user_priv; GF_Node *top_node = NULL; if (sr->compositor->scene) top_node = gf_sg_get_root_node(sr->compositor->scene); /*setup GL*/ VS3D_Setup(sr->surface); memcpy(&static_eff, sr->top_effect, sizeof(RenderEffect3D)); if (top_node) { if (!sr->main_surface_setup) { tag = gf_node_get_tag(top_node); if (!sr->compositor->has_size_info) { sr->surface->width = sr->out_width; sr->surface->height = sr->out_height; } else { sr->surface->width = sr->compositor->scene_width; sr->surface->height = sr->compositor->scene_height; } if ((tag>=GF_NODE_RANGE_FIRST_X3D) && (tag<=GF_NODE_RANGE_LAST_X3D)) { sr->surface->camera.is_3D = 1; sr->root_is_3D = 2; } else { sr->surface->camera.is_3D = sr->root_is_3D = ((tag==TAG_MPEG4_Group) || (tag==TAG_MPEG4_Layer3D) ) ? 1 : 0; } camera_invalidate(&sr->surface->camera); sr->main_surface_setup = 1; } sr->top_effect->is_pixel_metrics = gf_sg_use_pixel_metrics(sr->compositor->scene); /*setup our effects*/ VS_SetupEffects(sr->surface, sr->top_effect); VS_NodeRender(sr->top_effect, top_node); sr->top_effect->surface = NULL; } i=0; while ((sg = (GF_SceneGraph*)gf_list_enum(sr->compositor->extra_scenes, &i))) { GF_Node *n = gf_sg_get_root_node(sg); if (!n) continue; tag = gf_node_get_tag(n); if (!sr->main_surface_setup) { sr->surface->width = sr->compositor->scene_width; sr->surface->height = sr->compositor->scene_height; }/* if ((tag>=GF_NODE_RANGE_FIRST_X3D) && (tag<=GF_NODE_RANGE_LAST_X3D)) { sr->surface->camera.is_3D = 1; } else { sr->surface->camera.is_3D = ((tag==TAG_MPEG4_Group) || (tag==TAG_MPEG4_Layer3D) ) ? 1 : 0; } sr->surface->camera.flags |= CAM_IS_DIRTY;*/ sr->top_effect->is_pixel_metrics = gf_sg_use_pixel_metrics(sg); VS_SetupEffects(sr->surface, sr->top_effect); //VS_NodeRender(sr->top_effect, n); sr->top_effect->traversing_mode = TRAVERSE_SORT; gf_node_render(n, sr->top_effect); } //if (i) sr->main_surface_setup = 0; memcpy(sr->top_effect, &static_eff, sizeof(RenderEffect3D)); if (!i && !top_node) { /*default color is VRML default background color*/ SFColor c; c.red = c.green = c.blue = 0; VS3D_ClearSurface(sr->surface, c, FIX_ONE); } sr->compositor->video_out->Flush(sr->compositor->video_out, NULL);}static Bool R3D_ExecuteEvent(GF_VisualRenderer *vr, GF_Event *event){ GF_Event evt; Render3D *sr = (Render3D *)vr->user_priv; /*revert to BIFS like*/ evt = *event; if (evt.type<=GF_EVENT_MOUSEMOVE) { evt.mouse.x = event->mouse.x - sr->compositor->width/2; evt.mouse.y = sr->compositor->height/2 - event->mouse.y; } sr->top_effect->is_pixel_metrics = gf_sg_use_pixel_metrics(sr->compositor->scene); /*process regular events*/ if ((sr->compositor->interaction_level & GF_INTERACT_NORMAL) && VS_ExecuteEvent(sr->surface, sr->top_effect, &evt, NULL)) return 1; /*remember active layer on mouse click - may be NULL*/ if ((event->type==GF_EVENT_MOUSEDOWN) && (event->mouse.button==GF_MOUSE_LEFT)) sr->active_layer = sr->top_effect->collect_layer; /*process navigation events*/ if (sr->compositor->interaction_level & GF_INTERACT_NAVIGATION) return R3D_HandleUserEvent(sr, &evt); return 0;}static void R3D_SetScaling(Render3D *sr, Fixed sx, Fixed sy){ sr->scale_x = sx; sr->scale_y = sy;}GF_Err R3D_RecomputeAR(GF_VisualRenderer *vr){ Double ratio; Fixed scaleX, scaleY; Render3D *sr = (Render3D *)vr->user_priv; sr->surface->camera.flags |= CAM_IS_DIRTY; if (!sr->compositor->height || !sr->compositor->width) return GF_OK; /*we're inside a resetup of the window, indocate HW reset */ if (sr->compositor->new_width || sr->compositor->new_height) { GF_Event evt; evt.type = GF_EVENT_VIDEO_SETUP; evt.size.width = sr->compositor->width; evt.size.height = sr->compositor->height; sr->compositor->video_out->ProcessEvent(sr->compositor->video_out, &evt); } sr->out_width = sr->compositor->width; sr->out_height = sr->compositor->height; sr->out_x = 0; sr->out_y = 0; if (!sr->compositor->has_size_info) { R3D_SetScaling(sr, FIX_ONE, FIX_ONE); sr->surface->width = sr->out_width; sr->surface->height = sr->out_height; return GF_OK; } switch (sr->compositor->aspect_ratio) { case GF_ASPECT_RATIO_FILL_SCREEN: break; case GF_ASPECT_RATIO_16_9: sr->out_height = 9 * sr->out_width / 16; break; case GF_ASPECT_RATIO_4_3: sr->out_height = 3 * sr->out_width / 4; break; default: ratio = sr->compositor->scene_height; ratio /= sr->compositor->scene_width; if (sr->out_width * ratio > sr->out_height) { sr->out_width = sr->out_height * sr->compositor->scene_width; sr->out_width /= sr->compositor->scene_height; } else { sr->out_height = sr->out_width * sr->compositor->scene_height; sr->out_height /= sr->compositor->scene_width; } break; } sr->out_x = (sr->compositor->width - sr->out_width) / 2; sr->out_y = (sr->compositor->height - sr->out_height) / 2; /*update size info for main surface*/ if (sr->surface) { sr->surface->width = sr->compositor->scene_width; sr->surface->height = sr->compositor->scene_height; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -