📄 navigate.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>static void camera_changed(Render3D *sr, GF_Camera *cam){ cam->flags |= CAM_IS_DIRTY; gf_sr_invalidate(sr->compositor, NULL);}/*shortcut*/void gf_mx_rotation_matrix(GF_Matrix *mx, SFVec3f axis_pt, SFVec3f axis, Fixed angle){ gf_mx_init(*mx); gf_mx_add_translation(mx, axis_pt.x, axis_pt.y, axis_pt.z); gf_mx_add_rotation(mx, angle, axis.x, axis.y, axis.z); gf_mx_add_translation(mx, -axis_pt.x, -axis_pt.y, -axis_pt.z);} void view_orbit_x(Render3D *sr, GF_Camera *cam, Fixed dx){ GF_Matrix mx; if (!dx) return; gf_mx_rotation_matrix(&mx, cam->target, cam->up, dx); gf_mx_apply_vec(&mx, &cam->position); camera_changed(sr, cam);}void view_orbit_y(Render3D *sr, GF_Camera *cam, Fixed dy){ GF_Matrix mx; SFVec3f axis; if (!dy) return; axis = camera_get_right_dir(cam); gf_mx_rotation_matrix(&mx, cam->target, axis, dy); gf_mx_apply_vec(&mx, &cam->position); /*update up vector*/ cam->up = gf_vec_cross(camera_get_pos_dir(cam), axis); gf_vec_norm(&cam->up); camera_changed(sr, cam);}void view_exam_x(Render3D *sr, GF_Camera *cam, Fixed dx){ GF_Matrix mx; if (!dx) return; gf_mx_rotation_matrix(&mx, cam->examine_center, cam->up, dx); gf_mx_apply_vec(&mx, &cam->position); gf_mx_apply_vec(&mx, &cam->target); camera_changed(sr, cam);}void view_exam_y(Render3D *sr, GF_Camera *cam, Fixed dy){ GF_Matrix mx; SFVec3f axis; if (!dy) return; axis = camera_get_right_dir(cam); gf_mx_rotation_matrix(&mx, cam->examine_center, axis, dy); gf_mx_apply_vec(&mx, &cam->position); gf_mx_apply_vec(&mx, &cam->target); /*update up vector*/ cam->up = gf_vec_cross(camera_get_pos_dir(cam), axis); gf_vec_norm(&cam->up); camera_changed(sr, cam);}void view_roll(Render3D *sr, GF_Camera *cam, Fixed dd){ GF_Matrix mx; SFVec3f delta; if (!dd) return; gf_vec_add(delta, cam->target, cam->up); gf_mx_rotation_matrix(&mx, cam->target, camera_get_pos_dir(cam), dd); gf_mx_apply_vec(&mx, &delta); gf_vec_diff(cam->up, delta, cam->target); gf_vec_norm(&cam->up); camera_changed(sr, cam);}void view_pan_x(Render3D *sr, GF_Camera *cam, Fixed dx){ GF_Matrix mx; if (!dx) return; gf_mx_rotation_matrix(&mx, cam->position, cam->up, dx); gf_mx_apply_vec(&mx, &cam->target); camera_changed(sr, cam);}void view_pan_y(Render3D *sr, GF_Camera *cam, Fixed dy){ GF_Matrix mx; SFVec3f axis; if (!dy) return; axis = camera_get_right_dir(cam); gf_mx_rotation_matrix(&mx, cam->position, axis, dy); gf_mx_apply_vec(&mx, &cam->target); /*update up vector*/ cam->up = gf_vec_cross(camera_get_pos_dir(cam), axis); gf_vec_norm(&cam->up); camera_changed(sr, cam);}/*for translation moves when jumping*/#define JUMP_SCALE_FACTOR 4void view_translate_x(Render3D *sr, GF_Camera *cam, Fixed dx){ SFVec3f v; if (!dx) return; if (cam->jumping) dx *= JUMP_SCALE_FACTOR; v = gf_vec_scale(camera_get_right_dir(cam), dx); gf_vec_add(cam->target, cam->target, v); gf_vec_add(cam->position, cam->position, v); camera_changed(sr, cam);}void view_translate_y(Render3D *sr, GF_Camera *cam, Fixed dy){ SFVec3f v; if (!dy) return; if (cam->jumping) dy *= JUMP_SCALE_FACTOR; v = gf_vec_scale(cam->up, dy); gf_vec_add(cam->target, cam->target, v); gf_vec_add(cam->position, cam->position, v); camera_changed(sr, cam);}void view_translate_z(Render3D *sr, GF_Camera *cam, Fixed dz){ SFVec3f v; if (!dz) return; if (cam->jumping) dz *= JUMP_SCALE_FACTOR; dz = gf_mulfix(dz, cam->speed); v = gf_vec_scale(camera_get_target_dir(cam), dz); gf_vec_add(cam->target, cam->target, v); gf_vec_add(cam->position, cam->position, v); camera_changed(sr, cam);}void view_zoom(Render3D *sr, GF_Camera *cam, Fixed z){ Fixed oz; if ((z>FIX_ONE) || (z<-FIX_ONE)) return; oz = gf_divfix(cam->vp_fov, cam->fieldOfView); if (oz<FIX_ONE) z/=4; oz += z; if (oz<=0) return; cam->fieldOfView = gf_divfix(cam->vp_fov, oz); if (cam->fieldOfView>GF_PI) cam->fieldOfView=GF_PI; camera_changed(sr, cam);}void R3D_FitScene(Render3D *sr){ RenderEffect3D eff; SFVec3f pos, diff; Fixed dist, d; GF_Camera *cam; GF_Node *top; if (gf_list_count(sr->surface->back_stack)) return; if (gf_list_count(sr->surface->view_stack)) return; gf_mx_p(sr->compositor->mx); top = gf_sg_get_root_node(sr->compositor->scene); if (!top) { gf_mx_v(sr->compositor->mx); return; } memset(&eff, 0, sizeof(RenderEffect3D)); eff.traversing_mode = TRAVERSE_GET_BOUNDS; gf_node_render(top, &eff); if (!eff.bbox.is_set) { gf_mx_v(sr->compositor->mx); return; } cam = &sr->surface->camera; /*fit is based on bounding sphere*/ dist = gf_divfix(eff.bbox.radius, gf_sin(cam->fieldOfView/2) ); gf_vec_diff(diff, cam->center, eff.bbox.center); /*do not update if camera is outside the scene bounding sphere and dist is too close*/ if (gf_vec_len(diff) > eff.bbox.radius + cam->radius) { gf_vec_diff(diff, cam->vp_position, eff.bbox.center); d = gf_vec_len(diff); if (d<dist) { gf_mx_v(sr->compositor->mx); return; } } diff = gf_vec_scale(camera_get_pos_dir(cam), dist); gf_vec_add(pos, eff.bbox.center, diff); diff = cam->position; camera_set_vectors(cam, pos, cam->vp_orientation, cam->fieldOfView); cam->position = diff; camera_move_to(cam, pos, cam->target, cam->up); cam->examine_center = eff.bbox.center; cam->flags |= CF_STORE_VP; camera_changed(sr, cam); gf_mx_v(sr->compositor->mx);}static Bool R3D_HandleEvents3D(Render3D *sr, GF_Event *ev){ Fixed x, y, trans_scale; Fixed dx, dy, key_trans, key_pan, key_exam; s32 key_inv; u32 keys; Bool is_pixel_metrics; GF_Camera *cam; if (sr->active_layer) { cam = l3d_get_camera(sr->active_layer); is_pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(sr->active_layer)); } else { cam = &sr->surface->camera; assert(sr->compositor); assert(sr->compositor->scene); is_pixel_metrics = gf_sg_use_pixel_metrics(sr->compositor->scene); } if (!cam->navigate_mode) return 0; keys = sr->compositor->key_states; x = y = 0; /*renorm between -1, 1*/ if (ev->type<=GF_EVENT_MOUSEWHEEL) { x = gf_divfix( INT2FIX(ev->mouse.x + (s32) sr->surface->width/2), INT2FIX(sr->surface->width)); y = gf_divfix( INT2FIX(ev->mouse.y + (s32) sr->surface->height/2), INT2FIX(sr->surface->height)); } dx = (x - sr->grab_x); dy = (y - sr->grab_y); trans_scale = is_pixel_metrics ? cam->width/2 : INT2FIX(10); key_trans = is_pixel_metrics ? INT2FIX(10) : cam->avatar_size.x; key_pan = FIX_ONE/25; key_exam = FIX_ONE/10; 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) { sr->grab_x = x; sr->grab_y = y; sr->nav_is_grabbed = 1; /*change vp and examine center to current location*/ if ((keys & GF_KEY_MOD_CTRL) && sr->sq_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 = sr->hit_info.world_point; camera_changed(sr, cam); return 1; } } /*right*/ else if (ev->mouse.button==GF_MOUSE_RIGHT) { if (sr->nav_is_grabbed && (cam->navigate_mode==GF_NAVIGATE_WALK)) { camera_jump(cam); gf_sr_invalidate(sr->compositor, NULL); return 1; } else if (keys & GF_KEY_MOD_CTRL) R3D_FitScene(sr); } break; /* note: shortcuts are mostly the same as blaxxun contact, I don't feel like remembering 2 sets...*/ case GF_EVENT_MOUSEMOVE: if (!sr->nav_is_grabbed) { if (cam->navigate_mode==GF_NAVIGATE_GAME) { /*init mode*/ sr->grab_x = x; sr->grab_y = y; sr->nav_is_grabbed = 1; } return 0; } 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(sr, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_pan_y(sr, cam, dy); else view_translate_z(sr, cam, gf_mulfix(dy, trans_scale)); break; case GF_NAVIGATE_VR: view_pan_x(sr, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_zoom(sr, cam, dy); else view_pan_y(sr, cam, dy); break; case GF_NAVIGATE_PAN: view_pan_x(sr, cam, -dx); if (keys & GF_KEY_MOD_CTRL) view_translate_z(sr, cam, gf_mulfix(dy, trans_scale)); else view_pan_y(sr, cam, dy); break; case GF_NAVIGATE_SLIDE: view_translate_x(sr, cam, gf_mulfix(dx, trans_scale)); if (keys & GF_KEY_MOD_CTRL) view_translate_z(sr, cam, gf_mulfix(dy, trans_scale)); else view_translate_y(sr, cam, gf_mulfix(dy, trans_scale)); break; case GF_NAVIGATE_EXAMINE: if (keys & GF_KEY_MOD_CTRL) { view_translate_z(sr, cam, gf_mulfix(dy, trans_scale)); view_roll(sr, cam, gf_mulfix(dx, trans_scale)); } else { view_exam_x(sr, cam, -gf_mulfix(GF_PI, dx)); view_exam_y(sr, cam, gf_mulfix(GF_PI, dy)); } break; case GF_NAVIGATE_ORBIT: if (keys & GF_KEY_MOD_CTRL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -