Skip to content

Commit

Permalink
Beta 1
Browse files Browse the repository at this point in the history
  • Loading branch information
mwilsnd committed Oct 10, 2020
1 parent f70ba4b commit 1e5e2d7
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 37 deletions.
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## Beta 1
* Bumped module and MCM version number to 9
* Promoted to beta.
* Added shoulder swapping via hotkey.
* Added separable option for swapping the distance clamping X axis when swapping shoulders.
* Fixed issue with `preproc_constexpr_struct.lua` incorrectly assuming all `a.b` syntax was a struct macro to be replaced.

## Alpha 1.7
* Bumped module and MCM version number to 8
* Added a "group edit" tab in the MCM, allowing users to edit all offset groups at once.
Expand Down
Binary file modified MCM/SmoothCamMCM.pex
Binary file not shown.
51 changes: 48 additions & 3 deletions MCM/mcm.psc
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ Import SKSE
string[] interpMethods
string[] presets

Function SmoothCam_SetIntConfig(string member, int value) global native
Function SmoothCam_SetStringConfig(string member, string value) global native
Function SmoothCam_SetBoolConfig(string member, bool value) global native
Function SmoothCam_SetFloatConfig(string member, float value) global native

int Function SmoothCam_GetIntConfig(string member) global native
string Function SmoothCam_GetStringConfig(string member) global native
bool Function SmoothCam_GetBoolConfig(string member) global native
float Function SmoothCam_GetFloatConfig(string member) global native
Expand Down Expand Up @@ -171,8 +173,35 @@ endFunction
}
}

#constexpr_struct KeyBindSetting {
real_int ref = 0
string settingName = ""
string displayName = ""
string desc = ""

MACRO implControl = {
this->ref = AddKeyMapOption(this->displayName, SmoothCam_GetIntConfig(this->settingName))
}

MACRO implSelectHandler = {
if (StringUtil.GetLength(a_conflictControl) == 0)
SmoothCam_SetIntConfig(this->settingName, a_keyCode)
SetKeyMapOptionValue(this->ref, a_keyCode)
else
if (ShowMessage(a_conflictControl + " conflicts with another control assigned to " + a_conflictName + ".\nAre you sure you want to assign this control?"))
SmoothCam_SetIntConfig(this->settingName, a_keyCode)
SetKeyMapOptionValue(this->ref, a_keyCode)
endIf
endIf
}

MACRO implDesc = {
SetInfoText(this->desc)
}
}

ScriptMeta scriptMetaInfo -> {
version: 8
version: 9
}

; Presets
Expand Down Expand Up @@ -294,6 +323,11 @@ ToggleSetting cameraDistanceClampZEnable -> {
displayName: "Enable Z Distance Clamp"
desc: "Clamp the maximum distance the camera may move away from the target position along the Z (up) axis."
}
ToggleSetting swapDistanceClampXAxis -> {
settingName: "ShoulderSwapXClamping"
displayName: "Also Swap X Axis Clamping"
desc: "When shoulder swapping, will also swap the distance clamping X axis range."
}

ListSetting interpMethod -> {
settingName: "InterpolationMethod"
Expand Down Expand Up @@ -490,6 +524,12 @@ SliderSetting sepLocalSpaceInterpRate -> {
displayFormat: "{2}"
}

KeyBindSetting shoulderSwapKey -> {
settingName: "ShoulderSwapKeyCode"
displayName: "Shoulder Swap Key"
desc: "Inverts the current X offset of the camera"
}

; Crosshair
ToggleSetting crosshair3DBowEnabled -> {
settingName: "Enable3DBowCrosshair"
Expand Down Expand Up @@ -1366,7 +1406,7 @@ event OnPageReset(string a_page)

AddHeaderOption("Misc")
IMPL_STRUCT_MACRO_INVOKE_GROUP(implControl, {
zoomMul, disableDeltaTime
shoulderSwapKey, swapDistanceClampXAxis, zoomMul, disableDeltaTime
})
elseIf (a_page == " Crosshair")
AddHeaderOption("3D Crosshair Settings")
Expand Down Expand Up @@ -1645,12 +1685,17 @@ event OnOptionInputAccept(int a_option, string a_input)
IMPL_IFCHAIN_MACRO_INVOKE(a_option, ref, implAcceptHandler, {IMPL_ALL_IMPLS_OF_STRUCT(SavePresetSetting)})
endEvent

event OnOptionKeyMapChange(int a_option, int a_keyCode, string a_conflictControl, string a_conflictName)
IMPL_IFCHAIN_MACRO_INVOKE(a_option, ref, implSelectHandler, {IMPL_ALL_IMPLS_OF_STRUCT(KeyBindSetting)})
endEvent

event OnOptionHighlight(int a_option)
IMPL_IFCHAIN_MACRO_INVOKE(a_option, ref, implDesc, {
IMPL_ALL_IMPLS_OF_STRUCT(SliderSetting),
IMPL_ALL_IMPLS_OF_STRUCT(ToggleSetting),
IMPL_ALL_IMPLS_OF_STRUCT(ListSetting),
IMPL_ALL_IMPLS_OF_STRUCT(SavePresetSetting),
IMPL_ALL_IMPLS_OF_STRUCT(LoadPresetSetting)
IMPL_ALL_IMPLS_OF_STRUCT(LoadPresetSetting),
IMPL_ALL_IMPLS_OF_STRUCT(KeyBindSetting)
})
endEvent
32 changes: 17 additions & 15 deletions MCM/preproc/preproc_constexpr_struct.lua
Original file line number Diff line number Diff line change
Expand Up @@ -168,25 +168,27 @@ do class "ConstexprStructToVars" : namespace "papyrus.preproc" {
gen_member = gen_member:trim()

if not generated[member.."."..gen_decl.."."..gen_member] then
local typeInfo = self.m_tblStructTypes[self.m_tblStructImpls[gen_decl].type]

local usage = self.m_tblStructMemberUsage[gen_decl.."."..gen_member]
if usage then
code = code:replace( gen_decl.."."..gen_member, usage.name )
else
if typeInfo.members[gen_member].isreal then
code = code:replace( gen_decl.."."..gen_member, gen_decl.. "_".. gen_member )
if self.m_tblStructImpls[gen_decl] and self.m_tblStructTypes[self.m_tblStructImpls[gen_decl].type] then
local typeInfo = self.m_tblStructTypes[self.m_tblStructImpls[gen_decl].type]

local usage = self.m_tblStructMemberUsage[gen_decl.."."..gen_member]
if usage then
code = code:replace( gen_decl.."."..gen_member, usage.name )
else
-- Value literal
local value = self.m_tblStructImpls[gen_decl].members[gen_member]
if not value then
value = typeInfo.members[gen_member].value
if typeInfo.members[gen_member].isreal then
code = code:replace( gen_decl.."."..gen_member, gen_decl.. "_".. gen_member )
else
-- Value literal
local value = self.m_tblStructImpls[gen_decl].members[gen_member]
if not value then
value = typeInfo.members[gen_member].value
end
code = code:replace( gen_decl.."."..gen_member, value )
end
code = code:replace( gen_decl.."."..gen_member, value )
end
end

generated[member.."."..gen_decl.."."..gen_member] = true
generated[member.."."..gen_decl.."."..gen_member] = true
end
end
end

Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ Depending on the age of your processor (~2011 and earlier), you might need to us

## Installing
If using one of the pre-compiled releases, just copy the `Data` folder in the archive into your skyrim folder or install via a mod manager.
If installing after a build, copy `SmoothCam.dll` to `Data/SKSE/Plugins`, `hudmenu.swf` to `Data/interface`, `SmoothCam.esp` to `Data/` and `SmoothCamMCM.pex` to `Data/Scripts`. Enable the esp file if you wish to use the MCM, otherwise the module will generate a json file in the plugins folder you can edit to manually configure the camera.
If installing after a build, copy `SmoothCam.dll` to `Data/SKSE/Plugins` (along with the address library database file), `SmoothCam.esp` to `Data/` and `SmoothCamMCM.pex` to `Data/Scripts`. Enable the esp file if you wish to use the MCM, otherwise the module will generate a json file in the plugins folder you can edit to manually configure the camera.

## Building
To build the project, clone the repo (remember to include `--recurse-submodules`), then run `make_vs2019.bat` or `make_vs2017.bat`.
The build scripts require `premake5` and `7-Zip` to be installed and available on the system PATH. Currently only Visual Studio Community 2017 and 2019 are supported for building.

Once premake has finished, open the generated Visual Studio solution, select `Debug` or `Release` and select `Build Solution` from the build dropdown.

Built files are placed in `SmoothCam/bin/<target>/SmoothCam`. Be sure to also copy `hudmenu.swf` from the UI folder into `Data/interface` for the 3D crosshair to work. Copy the esp to `Data/` and the pex file to `Data/Scripts`.
Built files are placed in `SmoothCam/bin/<target>/SmoothCam`.

To build the papyrus script, you'll need `lua` on the system path. To run the code generation just run `MCM/run_preprocess.bat` which will generate `SmoothCamMCM.psc`.
From there just compile the generated code like any normal papyrus script.
Expand All @@ -46,6 +46,7 @@ use3DBowAimCrosshair | Enables the raycasted crosshair while aiming with a bow
use3DMagicCrosshair | Enables the raycasted crosshair when magic is equiped
hideNonCombatCrosshair | Hides the crosshair when no weapon is drawn
hideCrosshairMeleeCombat | Hides the crosshair when melee weapons are drawn
enableCrosshairSizeManip | Enable size manipulation of the crosshair
crosshairNPCHitGrowSize | When the 3D crosshair is over an NPC, grow the size of the crosshair by this amount
crosshairMinDistSize | Sets the size of the 3D crosshair when the player's aim ray is at the maximum distance
crosshairMaxDistSize | Sets the size of the 3D crosshair when the player's aim ray is at the minimum distance
Expand All @@ -54,6 +55,8 @@ disableDuringDialog | Disables SmoothCam during character-NPC conversations
comaptIC_FirstPersonHorse | Enables compat code for dealing with issue when running the Improved Camera mod
comaptIC_FirstPersonDragon | Enables compat code for dealing with issue when running the Improved Camera mod
compatIC_FirstPersonSitting | Enables compat code for dealing with issue when running the Improved Camera mod
shoulderSwapKey | The key code used for swapping the X axis when pressed
swapXClamping | When swapping the shoulder/X axis, also flips the distance clamping X values
currentScalar | A value from 0 - 21: The scalar function to use for interpolation
minCameraFollowDistance | The distance the camera follows the player from when at the lowest zoom level
minCameraFollowRate | The amount of camera latency when the camera is close to the player (lower = more latency)
Expand Down Expand Up @@ -100,14 +103,19 @@ OffsetSetting | Description
--- | ---
sideOffset | The amount to move the camera to the right
upOffset | The amount to move the camera up
zoomOffset | The amount to zoom the camera by
combatRangedSideOffset | The amount to move the camera to the right during ranged combat
combatRangedUpOffset | The amount to move the camera up during ranged combat
combatRangedZoomOffset | The amount to zoom the camera by
combatMagicSideOffset | The amount to move the camera to the right during magic combat
combatMagicUpOffset | The amount to move the camera up during magic combat
combatMagicZoomOffset | The amount to zoom the camera by
combatMeleeSideOffset | The amount to move the camera to the right during melee combat
combatMeleeUpOffset | The amount to move the camera up during melee combat
combatMeleeZoomOffset | The amount to zoom the camera by
horseSideOffset | The amount to move the camera to the right when on horseback
horseUpOffset | The amount to move the camera up when on horseback
horseZoomOffset | The amount to zoom the camera by
interp | Enable smoothing during this state
interpRangedCombat | Enable smoothing during this state when in ranged combat
interpMagicCombat | Enable smoothing during this state when in magic combat
Expand Down
5 changes: 5 additions & 0 deletions SmoothCam/include/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ namespace Camera {
void UpdateCamera(PlayerCharacter* player, CorrectedPlayerCamera* camera);
// Called when the player toggles the POV
void OnTogglePOV(const ButtonEvent* ev) noexcept;
// Called when any other key is pressed
void OnKeyPress(const ButtonEvent* ev) noexcept;
// Called when the dialog menu is shown or hidden
void OnDialogMenuChanged(const MenuOpenCloseEvent* const ev) noexcept;
// Returns our most recent camera position
Expand Down Expand Up @@ -108,6 +110,8 @@ namespace Camera {
glm::vec3 GetCurrentCameraOffset(PlayerCharacter* player, const CorrectedPlayerCamera* camera) const noexcept;
// Returns the current smoothing scalar to use for the given distance to the player
float GetCurrentSmoothingScalar(const float distance, ScalarSelector method = ScalarSelector::Normal) const;
// Returns the user defined distance clamping vector pair
std::tuple<glm::vec3, glm::vec3> GetDistanceClamping() const noexcept;
// Returns true if interpolation is allowed in the current state
bool IsInterpAllowed(PlayerCharacter* player) const noexcept;
// Constructs the view matrix for the camera
Expand Down Expand Up @@ -230,6 +234,7 @@ namespace Camera {
bool povIsThird = false;
bool povWasPressed = false;
bool dialogMenuOpen = false;
int shoulderSwap = 1;

friend class State::BaseCameraState;
};
Expand Down
14 changes: 8 additions & 6 deletions SmoothCam/include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ namespace Config {

// Misc
bool disableDeltaTime = false;
int shoulderSwapKey = -1;
bool swapXClamping = true;

// Comapt
bool disableDuringDialog = false;
Expand All @@ -133,21 +135,21 @@ namespace Config {
bool enableInterp = true;
ScalarMethods currentScalar = ScalarMethods::SINE_IN;
float minCameraFollowDistance = 64.0f;
float minCameraFollowRate = 0.2f;
float maxCameraFollowRate = 0.5f;
float minCameraFollowRate = 0.15f;
float maxCameraFollowRate = 0.4f;
float zoomMul = 500.0f;
float zoomMaxSmoothingDistance = 650.0f;

// Separate local space interpolation
bool separateLocalInterp = false;
bool separateLocalInterp = true;
ScalarMethods separateLocalScalar = ScalarMethods::CIRC_IN;
float localScalarRate = 1.0f;
float localScalarRate = 0.75f;

// Separate Z
bool separateZInterp = false;
bool separateZInterp = true;
ScalarMethods separateZScalar = ScalarMethods::SINE_IN;
float separateZMaxSmoothingDistance = 60.0f;
float separateZMinFollowRate = 0.25f;
float separateZMinFollowRate = 0.15f;
float separateZMaxFollowRate = 0.4f;

// Offset interpolation
Expand Down
1 change: 1 addition & 0 deletions SmoothCam/include/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <fstream>
#include <array>
#include <mutex>
#include <tuple>

#include <codeanalysis\warnings.h>
#pragma warning( push )
Expand Down
31 changes: 27 additions & 4 deletions SmoothCam/source/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ void Camera::SmoothCamera::OnTogglePOV(const ButtonEvent* ev) noexcept {
povWasPressed = true;
}

void Camera::SmoothCamera::OnKeyPress(const ButtonEvent* ev) noexcept {
if (config->shoulderSwapKey >= 0 && config->shoulderSwapKey == ev->keyMask && ev->timer <= 0.000001f) {
shoulderSwap = shoulderSwap == 1 ? -1 : 1;
}
}

void Camera::SmoothCamera::OnDialogMenuChanged(const MenuOpenCloseEvent* const ev) noexcept {
dialogMenuOpen = ev->opening;
}
Expand Down Expand Up @@ -397,9 +403,9 @@ float Camera::SmoothCamera::GetCurrentCameraSideOffset(PlayerCharacter* player,
switch (currentState) {
case GameState::CameraState::Horseback: {
if (GameState::IsBowDrawn(player)) {
return config->bowAim.horseSideOffset;
return config->bowAim.horseSideOffset * shoulderSwap;
} else {
return GetActiveWeaponStateSideOffset(player, &config->horseback);
return GetActiveWeaponStateSideOffset(player, &config->horseback) * shoulderSwap;
}
}
default:
Expand All @@ -412,14 +418,14 @@ float Camera::SmoothCamera::GetCurrentCameraSideOffset(PlayerCharacter* player,
case CameraActionState::Sitting:
case CameraActionState::Aiming:
case CameraActionState::Swimming: {
return offsetState.currentGroup->sideOffset;
return offsetState.currentGroup->sideOffset * shoulderSwap;
}
case CameraActionState::Sneaking:
case CameraActionState::Sprinting:
case CameraActionState::Walking:
case CameraActionState::Running:
case CameraActionState::Standing: {
return GetActiveWeaponStateSideOffset(player, offsetState.currentGroup);
return GetActiveWeaponStateSideOffset(player, offsetState.currentGroup) * shoulderSwap;
}
default: {
break;
Expand Down Expand Up @@ -557,6 +563,23 @@ float Camera::SmoothCamera::GetCurrentSmoothingScalar(const float distance, Scal
return mmath::RunScalarFunction<float>(scalarMethod, interpValue);
}

// Returns the user defined distance clamping vector pair
std::tuple<glm::vec3, glm::vec3> Camera::SmoothCamera::GetDistanceClamping() const noexcept {
float minsX = config->cameraDistanceClampXMin;
float maxsX = config->cameraDistanceClampXMax;

if (config->swapXClamping && shoulderSwap < 1) {
std::swap(minsX, maxsX);
maxsX *= -1.0f;
minsX *= -1.0f;
}

return std::tie(
glm::vec3{ minsX, config->cameraDistanceClampYMin, config->cameraDistanceClampZMin },
glm::vec3{ maxsX, config->cameraDistanceClampYMax, config->cameraDistanceClampZMax }
);
}

// Returns true if interpolation is allowed in the current state
bool Camera::SmoothCamera::IsInterpAllowed(PlayerCharacter* player) const noexcept {
auto ofs = offsetState.currentGroup;
Expand Down
16 changes: 10 additions & 6 deletions SmoothCam/source/camera_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,15 @@ glm::vec3 Camera::State::BaseCameraState::ComputeOffsetClamping(PlayerCharacter*
forward, right, up, coef
);

auto [mins, maxs] = camera->GetDistanceClamping();

// Now we can do whatever we want to the interp vector in axis aligned space
if (camera->config->cameraDistanceClampXEnable)
coef.x = glm::clamp(coef.x, camera->config->cameraDistanceClampXMin, camera->config->cameraDistanceClampXMax);
coef.x = glm::clamp(coef.x, mins.x, maxs.x);
if (camera->config->cameraDistanceClampYEnable)
coef.y = glm::clamp(coef.y, camera->config->cameraDistanceClampYMin, camera->config->cameraDistanceClampYMax);
coef.y = glm::clamp(coef.y, mins.y, maxs.y);
if (camera->config->cameraDistanceClampZEnable)
coef.z = glm::clamp(coef.z, camera->config->cameraDistanceClampZMin, camera->config->cameraDistanceClampZMax);
coef.z = glm::clamp(coef.z, mins.z, maxs.z);

// Now recompose with the new coefficients and add back the world position
return (forward * coef.x) + (right * coef.y) + (up * coef.z) + expectedPosition;
Expand All @@ -80,13 +82,15 @@ glm::vec3 Camera::State::BaseCameraState::ComputeOffsetClamping(PlayerCharacter*
forward, right, up, coef
);

auto [mins, maxs] = camera->GetDistanceClamping();

// Now we can do whatever we want to the interp vector in axis aligned space
if (camera->config->cameraDistanceClampXEnable)
coef.x = glm::clamp(coef.x, camera->config->cameraDistanceClampXMin, camera->config->cameraDistanceClampXMax);
coef.x = glm::clamp(coef.x, mins.x, maxs.x);
if (camera->config->cameraDistanceClampYEnable)
coef.y = glm::clamp(coef.y, camera->config->cameraDistanceClampYMin, camera->config->cameraDistanceClampYMax);
coef.y = glm::clamp(coef.y, mins.y, maxs.y);
if (camera->config->cameraDistanceClampZEnable)
coef.z = glm::clamp(coef.z, camera->config->cameraDistanceClampZMin, camera->config->cameraDistanceClampZMax);
coef.z = glm::clamp(coef.z, mins.z, maxs.z);

// Now recompose with the new coefficients and add back the world position
return (forward * coef.x) + (right * coef.y) + (up * coef.z) + cameraWorldTarget/* + expectedPosition*/;
Expand Down
Loading

0 comments on commit 1e5e2d7

Please sign in to comment.