Skip to content

Commit afc1db7

Browse files
authored
Lab camera controls upgrade (#7219)
* Add lab panning controls and align to pof tools * pan based on camera view coords not world coords * reset view option * change scrolling to use mouse wheel * Better ui for controls reference * clang
1 parent 73715b8 commit afc1db7

10 files changed

Lines changed: 225 additions & 49 deletions

File tree

code/io/mouse.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ int Mouse_dx = 0;
5454
int Mouse_dy = 0;
5555
int Mouse_dz = 0;
5656

57+
// Mouse wheel delta tracking movement not position. Resets every frame.
58+
int Mouse_wheel_dx = 0;
59+
int Mouse_wheel_dy = 0;
60+
5761
int Mouse_sensitivity = 4;
5862

5963
// coverity[GLOBAL_INIT_ORDER] -- safe; OptionBuilder::finish() uses Meyers singleton
@@ -525,6 +529,14 @@ void mouse_get_delta(int *dx, int *dy, int *dz)
525529
*dz = Mouse_dz;
526530
}
527531

532+
void mouse_get_wheel_delta(int* dx, int* dy)
533+
{
534+
if (dx)
535+
*dx = Mouse_wheel_dx;
536+
if (dy)
537+
*dy = Mouse_wheel_dy;
538+
}
539+
528540
// Forces the actual windows cursor to be at (x,y). This may be independent of our tracked (x,y) mouse pos.
529541
void mouse_force_pos(int x, int y)
530542
{
@@ -537,6 +549,7 @@ void mouse_force_pos(int x, int y)
537549
void mouse_reset_deltas()
538550
{
539551
Mouse_dx = Mouse_dy = Mouse_dz = 0;
552+
Mouse_wheel_dx = Mouse_wheel_dy = 0;
540553
}
541554

542555
void mouse_event(int x, int y, int dx, int dy)
@@ -637,6 +650,9 @@ void mousewheel_motion(int x, int y, bool reversed) {
637650

638651
Mouse_wheel_x += x;
639652
Mouse_wheel_y += y;
653+
// Used for tracking the actual movement of the wheel, not just the current position
654+
Mouse_wheel_dx += x;
655+
Mouse_wheel_dy += y;
640656

641657
// These nested if's should take care of all edge cases.
642658
// Since x and y's magnitudes can be larger than 1, it is possible to ignore the idle state

code/io/mouse.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ int mouse_down(const CC_bind& bind, bool must_be_wheel = false);
106106
int mouse_down(int btn, bool must_be_wheel = false);
107107

108108
void mouse_reset_deltas();
109-
void mouse_get_delta(int *dx = NULL, int *dy = NULL, int *dz = NULL);
109+
void mouse_get_delta(int* dx = nullptr, int* dy = nullptr, int* dz = nullptr);
110+
void mouse_get_wheel_delta(int* dx = nullptr, int* dy = nullptr);
110111

111112
void mouse_event(int x, int y, int dx, int dy);
112113

code/lab/dialogs/lab_ui.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,45 @@
1212
#include "weapon/weapon.h"
1313
#include "mission/missionload.h"
1414
#include "prop/prop.h"
15+
#include "controlconfig/controlsconfig.h"
1516

1617
using namespace ImGui;
1718

19+
namespace {
20+
SCP_string get_binding_text(int action_id)
21+
{
22+
const auto& action = Control_config[action_id];
23+
24+
if (!action.first.empty() && !action.second.empty()) {
25+
return action.first.textify() + " or " + action.second.textify();
26+
}
27+
28+
if (!action.first.empty()) {
29+
return action.first.textify();
30+
}
31+
32+
if (!action.second.empty()) {
33+
return action.second.textify();
34+
}
35+
36+
return "Unbound";
37+
}
38+
39+
void controls_reference_entry(const char* label, const SCP_string& description)
40+
{
41+
Bullet();
42+
SameLine();
43+
TextWrapped("%s: %s", label, description.c_str());
44+
}
45+
46+
void controls_reference_entry(const char* label, const char* description)
47+
{
48+
Bullet();
49+
SameLine();
50+
TextWrapped("%s: %s", label, description);
51+
}
52+
} // namespace
53+
1854
std::map<animation::ModelAnimationTriggerType, std::map<SCP_string, bool>> manual_animation_triggers = {};
1955
std::map<animation::ModelAnimationTriggerType, bool> manual_animations = {};
2056

@@ -269,6 +305,8 @@ void LabUi::build_options_menu()
269305
MenuItem("Object selector", nullptr, &show_object_selection_dialog);
270306
MenuItem("Background selector", nullptr, &show_background_selection_dialog);
271307
MenuItem("Object options", nullptr, &show_object_options_dialog);
308+
MenuItem("Controls reference", nullptr, &show_controls_reference_dialog);
309+
MenuItem("Reset View", nullptr, &reset_view);
272310
MenuItem("Close lab", "ESC", &close_lab);
273311
}
274312
}
@@ -280,6 +318,11 @@ void LabUi::build_toolbar_entries()
280318
build_options_menu();
281319
}
282320

321+
if (reset_view) {
322+
getLabManager()->Renderer->resetView();
323+
reset_view = false;
324+
}
325+
283326
if (close_lab) {
284327
getLabManager()->notify_close();
285328
close_lab = false;
@@ -330,9 +373,45 @@ void LabUi::create_ui()
330373
if (show_object_selection_dialog)
331374
show_object_selector();
332375

376+
if (show_controls_reference_dialog)
377+
show_controls_reference();
378+
333379
rebuild_after_object_change = false;
334380
}
335381

382+
void LabUi::show_controls_reference()
383+
{
384+
with_Window("Lab controls reference")
385+
{
386+
TextWrapped("Mouse controls");
387+
controls_reference_entry("LMB + drag", "Orient the displayed object.");
388+
controls_reference_entry("RMB + drag", "Rotate the camera.");
389+
controls_reference_entry("Shift + RMB + drag", "Pan the camera on the X/Y plane.");
390+
controls_reference_entry("Mouse wheel", "Zoom the camera in or out.");
391+
TextWrapped("Rotation axis limits and rotation speed apply only to object orientation (LMB), not "
392+
"camera controls (RMB).");
393+
394+
Separator();
395+
TextWrapped("Keyboard shortcuts");
396+
controls_reference_entry("R", "Cycle object orientation (LMB) axis mode (Yaw, Pitch, Roll, or Both).");
397+
controls_reference_entry("S", "Cycle object orientation (LMB) speed.");
398+
controls_reference_entry("V", "Reset camera view.");
399+
controls_reference_entry("T / Y", "Cycle team color presets.");
400+
controls_reference_entry("1-9", "Switch anti-aliasing presets.");
401+
controls_reference_entry("M", "Export an environment map.");
402+
controls_reference_entry("ESC", "Close the lab.");
403+
404+
if (getLabManager()->CurrentMode == LabMode::Ship) {
405+
Separator();
406+
TextWrapped("Ship-only controls (from current control bindings)");
407+
// These don't work in the new lab yet
408+
//controls_reference_entry("Increase throttle by 5%", get_binding_text(PLUS_5_PERCENT_THROTTLE));
409+
//controls_reference_entry("Decrease throttle by 5%", get_binding_text(MINUS_5_PERCENT_THROTTLE));
410+
controls_reference_entry("Afterburner", get_binding_text(AFTERBURNER));
411+
}
412+
}
413+
}
414+
336415
const char* antialiasing_settings[] = {
337416
"None",
338417
"FXAA Low",
@@ -604,7 +683,7 @@ void LabUi::show_render_options()
604683
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::NoLighting, no_lighting);
605684
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::ShowFullDetail, show_full_detail);
606685
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::ShowThrusters, show_thrusters);
607-
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::ShowAfterburners, show_afterburners);
686+
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::ShowAfterburners, show_afterburners || getLabManager()->Lab_thrust_afterburn);
608687
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::ShowWeapons, show_weapons);
609688
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::ShowEmissiveLighting, show_emissive_lighting);
610689
getLabManager()->Renderer->setRenderFlag(LabRenderFlag::MoveSubsystems, animate_subsystems);

code/lab/dialogs/lab_ui.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class LabUi {
3737
static void build_background_list();
3838
void show_render_options();
3939
void show_object_options() const;
40+
static void show_controls_reference();
4041
void show_object_selector() const;
4142
void show_background_selector() const;
4243
void build_toolbar_entries();
@@ -88,6 +89,10 @@ class LabUi {
8889
bool show_object_selection_dialog = true;
8990
bool show_object_options_dialog = false;
9091
bool show_background_selection_dialog = true;
92+
bool show_controls_reference_dialog = false;
93+
94+
// used to track the "Reset View" function
95+
bool reset_view = false;
9196

9297
// used to track the "Close Lab" function
9398
bool close_lab = false;

code/lab/manager/lab_manager.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,13 @@ void LabManager::onFrame(float frametime) {
123123

124124
int key = game_check_key();
125125

126-
int dx, dy;
126+
int dx, dy, dz;
127127
mouse_get_delta(&dx, &dy);
128-
Renderer->getCurrentCamera()->handleInput(dx, dy, mouse_down(MOUSE_LEFT_BUTTON) != 0, mouse_down(MOUSE_RIGHT_BUTTON) != 0, key_get_shift_status());
128+
mouse_get_wheel_delta(nullptr, &dz);
129+
if (dz != 0 && ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) {
130+
dz = 0;
131+
}
132+
Renderer->getCurrentCamera()->handleInput(dx, dy, dz, mouse_down(MOUSE_LEFT_BUTTON) != 0, mouse_down(MOUSE_RIGHT_BUTTON) != 0, key_get_shift_status());
129133

130134
if (!Renderer->getCurrentCamera()->handlesObjectPlacement()) {
131135
if (mouse_down(MOUSE_LEFT_BUTTON)) {
@@ -162,6 +166,12 @@ void LabManager::onFrame(float frametime) {
162166
}
163167
}
164168

169+
if (CurrentMode == LabMode::Ship) {
170+
Lab_thrust_afterburn = check_control(AFTERBURNER) != 0;
171+
} else {
172+
Lab_thrust_afterburn = false;
173+
}
174+
165175
if (key != 0) {
166176
// handle any key presses
167177
switch (key) {
@@ -219,15 +229,15 @@ void LabManager::onFrame(float frametime) {
219229
default:
220230
// check for game-specific controls
221231
if (CurrentMode == LabMode::Ship) {
222-
if (check_control(PLUS_5_PERCENT_THROTTLE, key))
232+
// These don't work because the lab is a lie and ships don't actually move
233+
// Also the ships are AI and don't really respond to player input anyway so
234+
// getting these working will be tricky
235+
/*if (check_control(PLUS_5_PERCENT_THROTTLE, key))
223236
Lab_thrust_len += 0.05f;
224237
else if (check_control(MINUS_5_PERCENT_THROTTLE, key))
225238
Lab_thrust_len -= 0.05f;
226239
227-
CLAMP(Lab_thrust_len, 0.0f, 1.0f);
228-
229-
if (check_control(AFTERBURNER, key))
230-
Lab_thrust_afterburn = !Lab_thrust_afterburn;
240+
CLAMP(Lab_thrust_len, 0.0f, 1.0f);*/
231241
}
232242
break;
233243
}

code/lab/manager/lab_manager.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ class LabManager {
148148
float RotationSpeedDivisor = 100.0f;
149149
bool AllowWeaponDestruction = false;
150150
bool ShowingTechModel = false;
151+
bool Lab_thrust_afterburn = false;
151152

152153
flagset<ManagerFlags> Flags;
153154

154155
gfx_options graphicsSettings;
155156
private:
156-
float Lab_thrust_len = 0.0f;
157-
bool Lab_thrust_afterburn = false;
157+
//float Lab_thrust_len = 0.0f; // Unused
158158
bool Weapons_loaded = false;
159159
bool CloseThis = false;
160160
LabUi labUi;

code/lab/renderer/lab_cameras.cpp

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "globalincs/pstypes.h"
22
#include "io/key.h"
3+
#include "io/mouse.h"
34
#include "lab/renderer/lab_cameras.h"
45
#include "lab/labv2_internal.h"
56

@@ -8,18 +9,53 @@ LabCamera::~LabCamera() {
89
cam_delete(FS_camera);
910
}
1011

11-
void OrbitCamera::handleInput(int dx, int dy, bool, bool rmbDown, int modifierKeys) {
12-
if (dx == 0 && dy == 0)
12+
void OrbitCamera::handleInput(int dx, int dy, int dz, bool, bool rmbDown, int modifierKeys) {
13+
if (dx == 0 && dy == 0 && dz == 0)
1314
return;
1415

16+
if (dz > 0) {
17+
for (int i = 0; i < dz; ++i) {
18+
distance *= 0.9f;
19+
}
20+
} else if (dz < 0) {
21+
for (int i = 0; i < -dz; ++i) {
22+
distance *= 1.1f;
23+
}
24+
}
25+
CLAMP(distance, 1.0f, 10000000.0f);
26+
1527
if (rmbDown) {
1628
if (modifierKeys & KEY_SHIFTED) {
17-
distance *= 1.0f + (dy / 200.0f);
18-
CLAMP(distance, 1.0f, 10000000.0f);
19-
}
20-
else {
21-
theta += dx / 100.0f;
22-
phi += dy / 100.0f;
29+
const float pan_factor = distance / 500.0f;
30+
31+
vec3d camera_offset;
32+
camera_offset.xyz.x = sinf(phi) * cosf(theta);
33+
camera_offset.xyz.y = cosf(phi);
34+
camera_offset.xyz.z = sinf(phi) * sinf(theta);
35+
36+
vec3d view_forward;
37+
vm_vec_copy_scale(&view_forward, &camera_offset, -1.0f);
38+
39+
vec3d world_up = vmd_y_vector;
40+
vec3d view_right;
41+
vm_vec_cross(&view_right, &world_up, &view_forward);
42+
43+
if (vm_vec_mag_squared(&view_right) <= 1e-6f) {
44+
world_up = vmd_x_vector;
45+
vm_vec_cross(&view_right, &world_up, &view_forward);
46+
}
47+
48+
vm_vec_normalize_safe(&view_right);
49+
50+
vec3d view_up;
51+
vm_vec_cross(&view_up, &view_forward, &view_right);
52+
vm_vec_normalize_safe(&view_up);
53+
54+
vm_vec_scale_add2(&pan_offset, &view_right, -dx * pan_factor);
55+
vm_vec_scale_add2(&pan_offset, &view_up, dy * pan_factor);
56+
} else {
57+
theta -= dx / 100.0f;
58+
phi -= dy / 100.0f;
2359

2460
CLAMP(phi, 0.01f, PI - 0.01f);
2561
}
@@ -28,11 +64,24 @@ void OrbitCamera::handleInput(int dx, int dy, bool, bool rmbDown, int modifierKe
2864
updateCamera();
2965
}
3066

67+
void OrbitCamera::resetView()
68+
{
69+
phi = DEFAULT_PHI;
70+
theta = DEFAULT_THETA;
71+
distance = DEFAULT_DISTANCE;
72+
pan_offset = vmd_zero_vector;
73+
74+
displayedObjectChanged();
75+
}
76+
3177
void OrbitCamera::displayedObjectChanged() {
3278
float distance_multiplier = 1.6f;
3379

3480
if (getLabManager()->CurrentObject != -1) {
3581
object* obj = &Objects[getLabManager()->CurrentObject];
82+
83+
// Reset camera panning
84+
pan_offset = vmd_zero_vector;
3685

3786
// Ships and Missiles use the object radius to get a camera distance
3887
distance = obj->radius * distance_multiplier;
@@ -75,10 +124,11 @@ void OrbitCamera::updateCamera() {
75124
vm_vec_copy_normalize(&forward, &obj->orient.vec.fvec);
76125
vm_vec_scale_add2(&target, &forward, wip->laser_length * 0.5f);
77126
}
78-
79-
vm_vec_add2(&new_position, &target);
80127
}
81128

129+
vm_vec_add2(&target, &pan_offset);
130+
vm_vec_add2(&new_position, &target);
131+
82132
cam->set_position(&new_position);
83133

84134
// If these are the same then that's not great so do nothing and use the last facing value

0 commit comments

Comments
 (0)