Files
dustinspace217andDustinspace217 499b3fb38b P4: qtFRED: rotate around the centre of a multi-selection (#7843)
* qtFRED: rotate around the centre of a multi-selection

Rotate Around Object (Alt+R) and the orbit pivot both used the current
object's position, so with several ships marked the camera still
circled whichever one happened to be current. Add
EditorViewport::selectionCenter(), which returns the centroid of the
marked objects when more than one is marked and the given object's
position otherwise, and use it at the three places that chose the
point: the look-at camera update, orbitCameraGetPivot(), and the Alt+R
handler that turns the camera toward the target when the mode is
switched on.

orbitCameraGetPivot() also serves middle-mouse orbit and wheel zoom in
normal mode, so those pivot on the selection centre as well. Every
marked type counts at full weight, including waypoints and jump nodes.
With a single object marked nothing changes.

Fixes #7724

* Make EditorViewport::selectionCenter const

It only reads the marked-object list and the editor's marked count;
clang-tidy (readability-make-member-function-const) flagged it in CI.

* Mirror the multi-selection orbit pivot to FRED, trim comments

FRED gets the same selection_center() as qtFRED's selectionCenter(),
used at the same three places: the look-at camera update, the orbit
pivot, and the Rotate Around Object toggle. Also removes the qtFRED
comments flagged in review.

* Make the selection-center pivot optional and share object bounds

Look-at and orbit use the current object again unless the new option is
on (qtFRED: Preferences > Controls; FRED: View menu), and the selection
center is now the bounding-box midpoint. view_universe in both editors,
the pivot, and qtFRED's selection radius all use get_object_bounds() in
missioneditor/common.

* Reset the cached orbit pivot when the selection-center option changes

Wheel zoom reuses the orbit pivot until the camera moves, so without this
the option only took effect for scrolling after the next camera move.

* Address review: move and rename the selection-centroid option

- FRED: the option moves from the View menu to Settings (and Misc in the
  classic layout), under Move Ships When Undocking, with hover help, and is
  renamed Rotate Around Selection Centroid.
- qtFRED: the checkbox moves next to Move Ships When Undocking in the
  preferences dialog, with the same name.
- setOrbitSelectionCenter only resets the orbit when the value changes.
- get_object_bounds iterates with list_range.
- The bounds test resets the object system with obj_init and takes objects
  off the free list, so it leaves a valid state for other tests.

* Rename the option to Selection Midpoint, move it to qtFRED's Controls tab, and document it

* Fix overlapping Appearance rows in qtFRED Preferences, realign a settings line

The last commit renumbered the Viewport label size row of the Appearance
group from 4 to 3, which is the Long list menu style row, so the label
size pair fell out of the layout and its spin box drew over the group
title. Put it back at row 4.

---------

Co-authored-by: Dustinspace217 <[email protected]>
2026-11-04 01:17:00 -05:00

118 lines
5.2 KiB
C

/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include "globalincs/pstypes.h"
#include "physics/physics.h"
#define BRIEFING_LOOKAT_POINT_ID 99999
extern int Aa_gridlines; //!< Bool. If nonzero, draw anti-aliased gridlines
extern int Editing_mode; //!< Enum. The edit mode. 0 = Select; 1 = Select and Move; 2 = Select and Rotate
extern int Control_mode; //!< Bool. Control mode. 0 = Camera/Viewpoint control. 1 = Object control
extern int Show_grid; //!< Bool. If nonzero, draw the grid
extern int Show_grid_positions; //!< Bool. If nonzero, draw an elevation line from each object to the grid.
extern int Show_coordinates; //!< Bool. If nonzero, draw the coordinates of each object on their label
extern int Show_outlines; //!< Bool. If nonzero, draw each object's mesh. If models are shown, highlight them in white.
extern bool Draw_outlines_on_selected_ships; // If a ship is selected, draw mesh lines
extern bool Draw_outline_at_warpin_position; // Project an outline at the place where the ship will arrive after warping in
extern bool Orbit_selection_midpoint;
extern int Outline_lod; // The LOD to use for wireframe outlines (0 = highest detail, default 1)
extern float Fred_label_font_scale; // Multiplier applied to viewport text labels
extern bool Always_save_display_names; // When saving a mission, always write display names to the mission file even if the display name is not set.
// But ships in wings are excepted, because a display name will cause a ship to have the same name in every wave.
// Wings now support display names, or the ship-change-display-name SEXP can be used, to handle that case.
extern bool Error_checker_checks_potential_issues; // Error checker checks not only outright errors but also potential issues
extern bool Error_checker_checks_potential_issues_once; // Same as above, but only once, and independent of the selected option
extern bool Classic_menu_layout; // Use the classic main menu layout instead of the qtFRED-style layout
extern int Show_stars; //!< Bool. If nonzero, draw the starfield, nebulas, and suns. Might also handle skyboxes
extern int Single_axis_constraint; //!< Bool. If nonzero, constrain movement to one axis
extern int Show_distances; //!< Bool. If nonzero, draw lines between each object and display their distance on the middle of each line
extern int Universal_heading; //!< Bool. Unknown.
extern int Flying_controls_mode; //!< Bool. Unknown.
extern int Group_rotate; //!< Bool. If nonzero, each object rotates around the leader. If zero. rotate
extern int Show_horizon; //!< Bool. If nonzero, draw a line representing the horizon (XZ plane)
extern int Lookat_mode; //!< Bool. Unknown.
// Orbit camera state
extern vec3d Orbit_pivot;
extern matrix Orbit_grid_orient;
extern float Orbit_distance;
extern float Orbit_phi;
extern float Orbit_theta;
extern bool Orbit_active;
extern int True_rw; //!< Unsigned. The width of the render area
extern int True_rh; //!< Unsigned. The height of the render area
extern int Fixed_briefing_size; //!< Bool. If nonzero then expand the briefing preview as much as we can, maintaining the aspect ratio.
extern vec3d Constraint; //!< Which axis (or axes) we can move/rotate on
extern vec3d Anticonstraint; //!< Which axis (or axes) we can't move/rotate on
extern physics_info view_physics; //!< Physics info of the camera/controlled object
extern vec3d view_pos;
extern vec3d eye_pos;
extern matrix view_orient;
extern matrix eye_orient;
/**
* @brief Initializes the renderer.
*
* @details Called every time a new mission is created (and erasing old mission from memory). New mission should be
* blank at this point.
*/
void fred_render_init();
/**
* @brief Handler for Mouse movement
*
* @param[in] btn Bitfield of mousebuttons
* @param[in] mdx X delta
* @param[in] mdy Y delta
*/
void move_mouse(int btn, int mdx, int mdy);
/**
* @brief Handler for OnIdle. Does a game frame within the editor
*/
void game_do_frame();
/**
* @brief Handler for OnPaint. Renders the game frame
*/
void render_frame();
/**
* @brief Reset the angles of the controlled object to be "wings level" with the grid, either the camera or the selection
*/
void level_controlled();
/**
* @brief Similar to level_controlled, aligns the controlled object to the closest axis
*/
void verticalize_controlled();
/**
* @brief Finds the closest object or waypoint under the mouse cursor and returns its index.
*
* @param[in] cx X coordinate on the viewport
* @param[in] cy Y coordinate on the viewport
*
* @return Object index number of the object, if any. or
* @return -1 if no object found
*/
int select_object(int cx, int cy);
vec3d selection_midpoint();
// Orbit camera functions
vec3d orbit_camera_get_pivot();
void orbit_camera_init_from_current_view(const vec3d *pivot, const matrix *grid_orient);
void orbit_camera_apply();
void orbit_camera_rotate(int dx, int dy);
void orbit_camera_pan(int dx, int dy);
void orbit_camera_zoom(float delta);