@@ -304,36 +304,61 @@ void linear_pitch_test()
304304}
305305#endif // DEBUG
306306
307+ static float convert_pitch_delta_to_non_linear_space (
308+ const float current_yaw,
309+ const float current_pitch_non_lin,
310+ const float pitch_delta,
311+ const float yaw_delta
312+ ) {
313+ // Convert to linear space. See `physics_make_orient`.
314+ const rf::Vector3 fvec =
315+ fw_vector_from_non_linear_yaw_pitch (current_yaw, current_pitch_non_lin);
316+ const float current_pitch_lin = linear_pitch_from_forward_vector (fvec);
317+
318+ // Calculate in linear space.
319+ constexpr float HALF_PI = 1 .5707964f ;
320+ const float new_pitch_lin =
321+ std::clamp (current_pitch_lin + pitch_delta, -HALF_PI, HALF_PI);
322+ const float new_yaw = current_yaw + yaw_delta;
323+
324+ // Convert back to non-linear space.
325+ const rf::Vector3 fvec_new =
326+ fw_vector_from_linear_yaw_pitch (new_yaw, new_pitch_lin);
327+ const float new_pitch_non_lin = non_linear_pitch_from_fw_vector (fvec_new);
328+
329+ // Update non-linear pitch delta.
330+ const float new_pitch_delta = new_pitch_non_lin - current_pitch_non_lin;
331+ xlog::trace (
332+ " non-lin {} lin {} delta {} new {}" ,
333+ current_pitch_non_lin,
334+ current_pitch_lin,
335+ pitch_delta,
336+ new_pitch_delta
337+ );
338+
339+ return new_pitch_delta;
340+ }
341+
307342CodeInjection linear_pitch_patch{
308343 0x0049DEC9 ,
309- []( auto & regs) {
310- if (!g_alpine_game_config.mouse_linear_pitch )
344+ [] ( const auto & regs) {
345+ if (!g_alpine_game_config.mouse_linear_pitch ) {
311346 return ;
312- // Non-linear pitch value and delta from RF
313- rf::Entity* entity = regs.esi ;
314- float current_yaw = entity->control_data .phb .y ;
315- float current_pitch_non_lin = entity->control_data .eye_phb .x ;
316- float & pitch_delta = *reinterpret_cast <float *>(regs.esp + 0x44 - 0x34 );
317- float & yaw_delta = *reinterpret_cast <float *>(regs.esp + 0x44 + 0x4 );
318- if (pitch_delta == 0 )
347+ }
348+ float & pitch_delta = addr_as_ref<float >(regs.esp + 0x44 - 0x34 );
349+ if (pitch_delta == .0f ) {
319350 return ;
320- // Convert to linear space (see RotMatixFromEuler function at 004A0D70)
321- auto fvec = fw_vector_from_non_linear_yaw_pitch (current_yaw, current_pitch_non_lin);
322- float current_pitch_lin = linear_pitch_from_forward_vector (fvec);
323- // Calculate new pitch in linear space
324- float new_pitch_lin = current_pitch_lin + pitch_delta;
325- float new_yaw = current_yaw + yaw_delta;
326- // Clamp to [-pi, pi]
327- constexpr float half_pi = 1 .5707964f ;
328- new_pitch_lin = std::clamp (new_pitch_lin, -half_pi, half_pi);
329- // Convert back to non-linear space
330- auto fvec_new = fw_vector_from_linear_yaw_pitch (new_yaw, new_pitch_lin);
331- float new_pitch_non_lin = non_linear_pitch_from_fw_vector (fvec_new);
332- // Update non-linear pitch delta
333- float new_pitch_delta = new_pitch_non_lin - current_pitch_non_lin;
334- xlog::trace (" non-lin {} lin {} delta {} new {}" , current_pitch_non_lin, current_pitch_lin, pitch_delta,
335- new_pitch_delta);
336- pitch_delta = new_pitch_delta;
351+ }
352+ const rf::Entity* const entity = regs.esi ;
353+ const float current_yaw = entity->control_data .phb .y ;
354+ const float current_pitch_non_lin = entity->control_data .eye_phb .x ;
355+ const float yaw_delta = addr_as_ref<float >(regs.esp + 0x44 + 0x4 );
356+ pitch_delta = convert_pitch_delta_to_non_linear_space (
357+ current_yaw,
358+ current_pitch_non_lin,
359+ pitch_delta,
360+ yaw_delta
361+ );
337362 },
338363};
339364
0 commit comments