Skip to content
This repository has been archived by the owner on Apr 24, 2024. It is now read-only.

Commit

Permalink
Support multiple mouth controllers and negative mouth start range, pr…
Browse files Browse the repository at this point in the history
…operly identify mouth controllers
  • Loading branch information
SamVanheer committed Aug 16, 2023
1 parent cd21624 commit bedd783
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 112 deletions.
63 changes: 2 additions & 61 deletions src/hlam/entity/StudioModelEntity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,73 +591,14 @@ void StudioModelEntity::SetController(const int controller, float value)
_controller[controller] = setting;
}

void StudioModelEntity::SetMouth(float value)
void StudioModelEntity::SetMouth(std::uint8_t value)
{
if (!_editableModel)
{
return;
}

int i;

// find first controller that matches the mouth
for (i = 0; i < _editableModel->BoneControllers.size(); ++i)
{
if (_editableModel->BoneControllers[i]->Index == STUDIO_MOUTH_CONTROLLER)
{
break;
}
}

if (i >= _editableModel->BoneControllers.size())
{
return;
}

_mouthValue = value;

const auto& boneController = *_editableModel->BoneControllers[i];

// wrap 0..360 if it's a rotational controller
if (boneController.Type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR))
{
// ugly hack, invert value if end < start
if (boneController.End < boneController.Start)
{
value = -value;
}

// does the controller not wrap?
if (boneController.Start + 359.0 >= boneController.End)
{
if (value > ((static_cast<double>(boneController.Start) + boneController.End) / 2.0) + 180)
{
value = value - 360;
}

if (value < ((static_cast<double>(boneController.Start) + boneController.End) / 2.0) - 180)
{
value = value + 360;
}
}
else
{
if (value > 360)
{
value = static_cast<float>(value - (int)(value / 360.0) * 360.0);
}
else if (value < 0)
{
value = static_cast<float>(value + (int)((value / -360.0) + 1) * 360.0);
}
}
}

int setting = (int)(64 * (value - boneController.Start) / (boneController.End - boneController.Start));

setting = std::clamp(setting, 0, 64);

_mouth = setting;
_mouth = value;
}

std::uint8_t StudioModelEntity::GetBlendingByIndex(const int blender) const
Expand Down
12 changes: 1 addition & 11 deletions src/hlam/entity/StudioModelEntity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ class StudioModelEntity : public BaseAnimating
std::uint8_t _controller[STUDIO_MAX_CONTROLLERS] = {0, 0, 0, 0}; // bone controllers
float _controllerValues[STUDIO_MAX_CONTROLLERS] = {};
std::uint8_t _mouth = 0; // mouth position
float _mouthValue = 0;
std::uint8_t _blending[STUDIO_MAX_BLENDERS] = {0, 0}; // animation blending
float _blendingValues[STUDIO_MAX_BLENDERS] = {};

Expand Down Expand Up @@ -193,18 +192,9 @@ class StudioModelEntity : public BaseAnimating
*/
void SetController(const int controller, float value);

/**
* Gets the mouth controller. This is the stored value, not the computed value.
*/
std::uint8_t GetMouth() const { return _mouth; }

float GetMouthValue() const { return _mouthValue; }

/**
* Sets the mouth controller value. The value is processed into a value that is in the range [0, 255]
* @param value Value to set.
*/
void SetMouth(float value);
void SetMouth(std::uint8_t value);

void SetBlendMode(StudioBlendMode blendMode)
{
Expand Down
2 changes: 1 addition & 1 deletion src/hlam/plugins/halflife/studiomodel/StudioModelAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ void StudioModelAsset::LoadEntityFromSnapshot(StateSnapshot* snapshot)
_modelEntity->SetController(i, snapshot->Value(QString{"entity.bonecontroller%1"}.arg(i)).toFloat());
}

_modelEntity->SetMouth(snapshot->Value("entity.mouth").toFloat());
_modelEntity->SetMouth(snapshot->Value("entity.mouth").toInt());

for (int i = 0; i < STUDIO_MAX_BLENDERS; ++i)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class BoneControllersItemModel final : public BaseStudioModelItemModel<std::uniq
{
const auto& boneController = *(*_items)[index.row()];

if (boneController.Index == STUDIO_MOUTH_CONTROLLER)
if (boneController.Index >= STUDIO_MOUTH_CONTROLLER)
{
return "Mouth";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ QCDataDialog::QCDataDialog(StudioModelAssetProvider* provider, QWidget* parent)
{
QString result{"$controller %1"};

if (boneController->Index == STUDIO_MOUTH_CONTROLLER)
if (boneController->Index >= STUDIO_MOUTH_CONTROLLER)
{
result = result.arg("mouth");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,56 +137,67 @@ void BoneControllersPanel::UpdateControllerRange(const studiomdl::StudioBoneCont
{
const auto entity = _asset->GetEntity();

float start, end;
// Don't let the changes ripple back to change the current setting,
// because this will result in a loss of accuracy due to casting to integer
const QSignalBlocker slider{_ui.BoneControllerValueSlider};
const QSignalBlocker spinner{_ui.BoneControllerValueSpinner};

//Swap values if the range is inverted
if (boneController.End < boneController.Start)
if (boneController.Index >= STUDIO_MOUTH_CONTROLLER)
{
start = boneController.End;
end = boneController.Start;
}
else
{
start = boneController.Start;
end = boneController.End;
}
_controllerSliderScale = 1.0f;

//Should probably scale as needed so the range is sufficiently large
//This prevents ranges that cover less than a whole integer from not doing anything
if ((end - start) < 1.0f)
{
_controllerSliderScale = 100.0f;
const int value = entity->GetMouth();

_ui.BoneControllerValueSlider->setRange(0, 64);
_ui.BoneControllerValueSlider->setValue(value);

_ui.BoneControllerValueSpinner->setDecimals(0);
_ui.BoneControllerValueSpinner->setRange(0, 64);
_ui.BoneControllerValueSpinner->setValue(value);
}
else
{
_controllerSliderScale = 1.0f;
}
float start, end;

{
// Don't let the changes ripple back to change the current setting,
// because this will result in a loss of accuracy due to casting to integer
const QSignalBlocker slider{_ui.BoneControllerValueSlider};
const QSignalBlocker spinner{_ui.BoneControllerValueSpinner};
//Swap values if the range is inverted
if (boneController.End < boneController.Start)
{
start = boneController.End;
end = boneController.Start;
}
else
{
start = boneController.Start;
end = boneController.End;
}

const double value = entity->GetControllerValue(_ui.BoneControllers->currentIndex());
//Should probably scale as needed so the range is sufficiently large
//This prevents ranges that cover less than a whole integer from not doing anything
if ((end - start) < 1.0f)
{
_controllerSliderScale = 100.0f;
}
else
{
_controllerSliderScale = 1.0f;
}

_ui.BoneControllerValueSlider->setRange(
(int)(start * _controllerSliderScale), (int)(end * _controllerSliderScale));
_ui.BoneControllerValueSlider->setValue(static_cast<int>(value * _controllerSliderScale));
{
const double value = entity->GetControllerValue(boneController.Index);

_ui.BoneControllerValueSpinner->setRange(start, end);
_ui.BoneControllerValueSpinner->setValue(value);
_ui.BoneControllerValueSlider->setRange(
(int)(start * _controllerSliderScale), (int)(end * _controllerSliderScale));
_ui.BoneControllerValueSlider->setValue(static_cast<int>(value * _controllerSliderScale));

_ui.BoneControllerValueSpinner->setDecimals(2);
_ui.BoneControllerValueSpinner->setRange(start, end);
_ui.BoneControllerValueSpinner->setValue(value);
}
}
}

void BoneControllersPanel::OnBoneControllerChanged(int index)
{
// Don't refresh the UI if this is getting called in response to a change we made.
if (_changingBoneControllerProperties)
{
return;
}

const auto model = _asset->GetEntity()->GetEditableModel();

static constexpr studiomdl::StudioBoneController EmptyController{};
Expand All @@ -195,6 +206,12 @@ void BoneControllersPanel::OnBoneControllerChanged(int index)

UpdateControllerRange(boneController);

// Don't refresh the rest of the UI if this is getting called in response to a change we made.
if (_changingBoneControllerProperties)
{
return;
}

const QSignalBlocker boneName{_ui.BoneControllerBone};
const QSignalBlocker axis{_ui.BoneControllerBoneAxis};
const QSignalBlocker start{_ui.BoneControllerStart};
Expand Down Expand Up @@ -228,8 +245,7 @@ void BoneControllersPanel::OnBoneControllerValueSpinnerChanged(double value)
const auto model = entity->GetEditableModel();
const auto& boneController = *model->BoneControllers[boneControllerLogicalIndex];

//TODO: support multiple mouth controllers somehow.
if (boneController.Index == STUDIO_MOUTH_CONTROLLER)
if (boneController.Index >= STUDIO_MOUTH_CONTROLLER)
{
entity->SetMouth(value);
}
Expand Down

0 comments on commit bedd783

Please sign in to comment.