From cecd65dac685237f701ac67ae7c75a08d789c402 Mon Sep 17 00:00:00 2001 From: Caner Karaca Date: Thu, 8 Oct 2026 05:48:33 +0300 Subject: [PATCH] fix(sirens): support angular falloff for rotator materials and improve IVF detection --- src/features/sirens.cpp | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/features/sirens.cpp b/src/features/sirens.cpp index 76c02ea8..87227e16 100755 --- a/src/features/sirens.cpp +++ b/src/features/sirens.cpp @@ -668,6 +668,8 @@ void __fastcall Sirens::hkServiceHornOrSiren(CAEVehicleAudioEntity* pThis, void* reinterpret_cast(0x4F99D0)(pThis, bHorn, bSiren, bAlarm, pParams); } +static float CalculateRotatorAngle(const VehicleSirenMaterial *material, uint64_t time); + void Sirens::Init() { DataMgr::RegisterListener("sirens", [](int model, const nlohmann::json &data) { @@ -689,13 +691,11 @@ void Sirens::Init() } CRGBA col = *reinterpret_cast(RpMaterialGetColor(pMat)); - if (pMat && pMat->texture && pMat->texture->name && modelData.contains(pVeh->m_nModelIndex)) { - std::string_view texName(pMat->texture->name); - bool isSirenTex = (texName.find("siren") != 0 || texName.find("vehiclelights128") != 0); + if (pMat && modelData.contains(pVeh->m_nModelIndex)) { bool isIVFSiren = modelData[pVeh->m_nModelIndex]->isImVehFtSiren; if (isIVFSiren) { - if (isSirenTex && (col.r >= 240 && col.g == 0 && col.b == 0)) { + if (col.r >= 240 && col.g == 0 && col.b == 0) { return eMaterialType::SirenLight; } } else { @@ -1117,7 +1117,37 @@ void Sirens::Init() EnableDummy((mat.first * 16) + id, e, vehicle, mat.second, type, time); } - ModelInfoMgr::EnableSirenMaterial(vehicle, mat.first, mat.second->InertiaMultiplier); + float sirenMatFactor = mat.second->InertiaMultiplier; + if (mat.second->Type == eLightingMode::Rotator && mat.second->Rotator) { + float vehicleAngle = Util::NormalizeAngle(static_cast(Util::RadToDeg(vehicle->GetHeading()))); + float cameraAngle = Util::NormalizeAngle(static_cast(Util::RadToDeg(TheCamera.GetHeading()))); + float rotAngle = CalculateRotatorAngle(mat.second, time); + float cutoff = (mat.second->Radius / 2.0f); + float maxAngleMul = 0.0f; + + auto calcAngleMul = [&](float baseAngle) { + float dummyAngle = Util::NormalizeAngle(baseAngle + mat.second->Shadow.AngleOffset + rotAngle); + float diffAngle = Util::NormalizeAngle(cameraAngle - (vehicleAngle + dummyAngle)); + float angleFromCenter = std::fabs(diffAngle - 180.0f); + if (angleFromCenter < cutoff) { + float normAngle = (angleFromCenter / cutoff) * 1.57079632679f; + maxAngleMul = std::max(maxAngleMul, std::cos(normAngle)); + } + }; + + if (!data.Dummies[mat.first].empty()) { + for (auto& dummy : data.Dummies[mat.first]) { + if (dummy) calcAngleMul(dummy->Get().rotation.angle); + } + } else { + calcAngleMul(0.0f); + } + sirenMatFactor *= maxAngleMul; + } + + if (sirenMatFactor > 0.001f) { + ModelInfoMgr::EnableSirenMaterial(vehicle, mat.first, sirenMatFactor); + } } });