Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/ModelExtrasAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ enum ME_LightID
ME_ReverseLightRight,
ME_BrakeLightLeft,
ME_BrakeLightRight,
ME_HighBeamLeft,
ME_HighBeamRight,
ME_AllDayLight,
ME_DayLight,
ME_NightLight,
Expand Down
2 changes: 2 additions & 0 deletions src/enums/materialtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ enum eMaterialType
ReverseLightRight,
BrakeLightLeft,
BrakeLightRight,
HighBeamLeft,
HighBeamRight,
AllDayLight,
DayLight,
NightLight,
Expand Down
3 changes: 3 additions & 0 deletions src/features/core/colors.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#define VEHCOL_HEADLIGHT_LEFT CRGBA(255, 175, 0, 255)
#define VEHCOL_HEADLIGHT_RIGHT CRGBA(0, 255, 200, 255)

#define VEHCOL_HIGHBEAM_LEFT CRGBA(255, 172, 0, 255)
#define VEHCOL_HIGHBEAM_RIGHT CRGBA(0, 255, 197, 255)

#define VEHCOL_TAILLIGHT_LEFT CRGBA(185, 255, 0, 255)
#define VEHCOL_TAILLIGHT_RIGHT CRGBA(255, 60, 0, 255)

Expand Down
123 changes: 99 additions & 24 deletions src/features/lights/components/headlight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ extern bool gbProperShadersDetected;
void HeadlightComponent::RegisterMaterials(std::unordered_map<uint32_t, eMaterialType>& matMap) {
matMap[VEHCOL_HEADLIGHT_LEFT.ToInt()] = eMaterialType::HeadLightLeft;
matMap[VEHCOL_HEADLIGHT_RIGHT.ToInt()] = eMaterialType::HeadLightRight;
matMap[VEHCOL_HIGHBEAM_LEFT.ToInt()] = eMaterialType::HighBeamLeft;
matMap[VEHCOL_HIGHBEAM_RIGHT.ToInt()] = eMaterialType::HighBeamRight;
}

eMaterialType HeadlightComponent::GetMatType(CRGBA matCol) {
if (matCol == VEHCOL_HEADLIGHT_LEFT) return eMaterialType::HeadLightLeft;
if (matCol == VEHCOL_HEADLIGHT_RIGHT) return eMaterialType::HeadLightRight;
if (matCol == VEHCOL_HIGHBEAM_LEFT) return eMaterialType::HighBeamLeft;
if (matCol == VEHCOL_HIGHBEAM_RIGHT) return eMaterialType::HighBeamRight;
return eMaterialType::UnknownMaterial;
}

Expand Down Expand Up @@ -73,6 +77,72 @@ bool HeadlightComponent::TryRegisterDummy(CVehicle* pVeh, RwFrame* pFrame, const
return true;
}

if (name == "headlight_l" || name == "headlight_r") {
if (pFrame && !rwLinkListEmpty(&pFrame->objectList)) {
return false;
}
DummyConfig c = LightManager::CreateBaseConfig(pVeh, pFrame);
c.dummyPos = eDummyPos::Front;
c.lightType = (name == "headlight_l") ? eMaterialType::HeadLightLeft : eMaterialType::HeadLightRight;
c.corona.size = LightsConfig::Get().gfHeadLightCoronaSize;
c.corona.color = {250, 250, 250, static_cast<unsigned char>(LightsConfig::Get().gHeadLightCoronaIntensity)};
c.shadow.color = {250, 250, 250, static_cast<unsigned char>(LightsConfig::Get().gHeadLightShadowIntensity)};
c.shadow.size = LightsConfig::Get().gfHeadLightShadowSize;
c.corona.lightingType = eLightingMode::Directional;
c.shadow.render = true;
c.mirroredX = false;

data.dummies[c.lightType].push_back(VehicleDummy(c));
return true;
}

if (name == "highbeam_l" || name == "highbeam_r" || name == "highbeams_l" || name == "highbeams_r") {
if (pFrame && !rwLinkListEmpty(&pFrame->objectList)) {
return false;
}
DummyConfig c = LightManager::CreateBaseConfig(pVeh, pFrame);
c.dummyPos = eDummyPos::Front;
bool isLeft = (name == "highbeam_l" || name == "highbeams_l");
c.lightType = isLeft ? eMaterialType::HighBeamLeft : eMaterialType::HighBeamRight;
c.corona.size = LightsConfig::Get().gfHeadLightCoronaSize;
c.corona.color = {250, 250, 250, static_cast<unsigned char>(LightsConfig::Get().gHeadLightCoronaIntensity)};
c.shadow.color = {250, 250, 250, static_cast<unsigned char>(LightsConfig::Get().gHeadLightShadowIntensity)};
c.shadow.size = LightsConfig::Get().gfHeadLightShadowSize;
c.corona.lightingType = eLightingMode::Directional;
c.shadow.render = false;
c.mirroredX = false;

data.dummies[c.lightType].push_back(VehicleDummy(c));
return true;
}

if (name == "highbeam" || name == "highbeams") {
if (pFrame && !rwLinkListEmpty(&pFrame->objectList)) {
return false;
}
DummyConfig c = LightManager::CreateBaseConfig(pVeh, pFrame);
c.dummyPos = eDummyPos::Front;
c.corona.size = LightsConfig::Get().gfHeadLightCoronaSize;
c.corona.color = {250, 250, 250, static_cast<unsigned char>(LightsConfig::Get().gHeadLightCoronaIntensity)};
c.shadow.color = {250, 250, 250, static_cast<unsigned char>(LightsConfig::Get().gHeadLightShadowIntensity)};
c.shadow.size = LightsConfig::Get().gfHeadLightShadowSize;
c.corona.lightingType = eLightingMode::Directional;
c.shadow.render = false;

bool dummyIsLeft = (c.frame->modelling.pos.x < 0.0f);

c.mirroredX = !dummyIsLeft;
c.lightType = eMaterialType::HighBeamLeft;
data.dummies[eMaterialType::HighBeamLeft].push_back(VehicleDummy(c));

if (pVeh->m_nVehicleSubClass != VEHICLE_BIKE || std::abs(c.frame->modelling.pos.x) > 0.05f) {
c.mirroredX = dummyIsLeft;
c.lightType = eMaterialType::HighBeamRight;
data.dummies[eMaterialType::HighBeamRight].push_back(VehicleDummy(c));
}
return true;
}

std::string lowerName;
lowerName.reserve(name.size());
for (char ch : name) {
Expand All @@ -98,7 +168,7 @@ void HeadlightComponent::Process(CVehicle* pVeh, VehLightData& data) {
}

if (pVeh->IsDriver(FindPlayerPed())) {
if (!isHeadlightsActive && data.fLightFactor[eMaterialType::HeadLightLeft] <= 0.001f) {
if (!isHeadlightsActive && data.fLightFactor[eMaterialType::HeadLightLeft] <= 0.001f && data.fLightFactor[eMaterialType::HeadLightRight] <= 0.001f) {
data.bLongLightsOn = false;
}

Expand All @@ -107,26 +177,6 @@ void HeadlightComponent::Process(CVehicle* pVeh, VehLightData& data) {
data.bLongLightsOn = !data.bLongLightsOn;
AudioMgr::PlaySwitchSound(pVeh);
}
} else if (pVeh->m_fHealth > 0.0f) {
if (CarUtil::IsLightsForcedOff(pVeh) || (Util::IsEngineOff(pVeh) && !CarUtil::IsLightsForcedOn(pVeh) && !pVeh->bLightsOn && !isAlarmActive)) {
return;
}

if (CVector::Distance(pVeh->GetPosition(), TheCamera.GetPosition()) < 300.0f || pVeh->GetIsOnScreen()) {
bool isLeftFrontOk = !Util::IsLightDamaged(pVeh, eLights::LIGHT_FRONT_LEFT);
bool isRightFrontOk = !Util::IsLightDamaged(pVeh, eLights::LIGHT_FRONT_RIGHT);

if (isHeadlightsActive && AreHeadlightsOpen(pVeh, data)) {
bool isFoggy = Util::IsFoggy();
std::string texName = data.bLongLightsOn ? "headlight_long" : "headlight_short";
bool shadow = !gbProperShadersDetected;
bool highlight = isFoggy || data.bLongLightsOn;

LightManager::RenderLight(pVeh, data, eMaterialType::HeadLightLeft, isLeftFrontOk, shadow ? texName : "", LightsConfig::Get().headlightSz, highlight);
LightManager::RenderLight(pVeh, data, eMaterialType::HeadLightRight, isRightFrontOk, shadow ? texName : "", LightsConfig::Get().headlightSz, highlight);
data.nHeadlightTickFrame = CTimer::m_FrameCounter;
}
}
}
}

Expand All @@ -150,7 +200,6 @@ void HeadlightComponent::Render(CVehicle* pControlVeh, CVehicle* pTowedVeh, VehL
bool isHeadlightLeftOk = damage.isHeadlightLeftOk;
bool isHeadlightRightOk = damage.isHeadlightRightOk;

bool bTickRegistered = (data.nHeadlightTickFrame == CTimer::m_FrameCounter);
bool isFoggy = Util::IsFoggy();
std::string texName = data.bLongLightsOn ? "headlight_long" : "headlight_short";
bool shadow = !gbProperShadersDetected;
Expand All @@ -160,10 +209,16 @@ void HeadlightComponent::Render(CVehicle* pControlVeh, CVehicle* pTowedVeh, VehL
pControlVeh->m_renderLights.m_bLeftFront = isHeadlightLeftOk;
pControlVeh->m_renderLights.m_bRightFront = isHeadlightRightOk;
if (isHeadlightLeftOk) {
LightManager::RenderLights(pControlVeh, pTowedVeh, data, eMaterialType::HeadLightLeft, true, shadow ? texName : "", LightsConfig::Get().headlightSz, highlight, true, bTickRegistered);
LightManager::RenderLights(pControlVeh, pTowedVeh, data, eMaterialType::HeadLightLeft, true, shadow ? texName : "", LightsConfig::Get().headlightSz, highlight, true);
if (data.bLongLightsOn) {
LightManager::RenderLights(pControlVeh, pTowedVeh, data, eMaterialType::HighBeamLeft, true, "", LightsConfig::Get().headlightSz, isFoggy, true);
}
}
if (isHeadlightRightOk) {
LightManager::RenderLights(pControlVeh, pTowedVeh, data, eMaterialType::HeadLightRight, true, shadow ? texName : "", LightsConfig::Get().headlightSz, highlight, true, bTickRegistered);
LightManager::RenderLights(pControlVeh, pTowedVeh, data, eMaterialType::HeadLightRight, true, shadow ? texName : "", LightsConfig::Get().headlightSz, highlight, true);
if (data.bLongLightsOn) {
LightManager::RenderLights(pControlVeh, pTowedVeh, data, eMaterialType::HighBeamRight, true, "", LightsConfig::Get().headlightSz, isFoggy, true);
}
}
}
}
Expand Down Expand Up @@ -192,6 +247,26 @@ void HeadlightComponent::ProcessPointLights(CVehicle* pVeh, VehLightData& data)
RenderUtil::RegisterHeadlightPointLight(&e->Get(), rangeMul);
}
}

if (data.bLongLightsOn) {
for (eMaterialType type : {eMaterialType::HighBeamLeft, eMaterialType::HighBeamRight}) {
if (!LightManager::IsDummyAvailable(data, type) || !data.bLightStates[type]) {
continue;
}

bool isLeft = (type == eMaterialType::HighBeamLeft);
eLights lightEnum = isLeft ? eLights::LIGHT_FRONT_LEFT : eLights::LIGHT_FRONT_RIGHT;
ePanels wingEnum = isLeft ? ePanels::WING_FRONT_LEFT : ePanels::WING_FRONT_RIGHT;
if (Util::IsLightDamaged(pVeh, lightEnum) || Util::IsPanelDamaged(pVeh, wingEnum)) {
continue;
}

for (auto& e : data.dummies[type]) {
e->Update();
RenderUtil::RegisterHeadlightPointLight(&e->Get(), rangeMul);
}
}
}
}
}

7 changes: 5 additions & 2 deletions src/features/lights/components/tail_light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ bool TailLightComponent::TryRegisterDummy(CVehicle* pVeh, RwFrame* pFrame, const
c.shadow.size = LightsConfig::Get().gfTailLightShadowSize;
c.corona.lightingType = eLightingMode::Directional;
c.shadow.render = name != "taillights2";
c.mirroredX = false;
bool dummyIsLeft = (c.frame->modelling.pos.x < 0.0f);

c.mirroredX = dummyIsLeft;
c.lightType = eMaterialType::TailLightRight;
data.dummies[c.lightType].push_back(VehicleDummy(c));

if (pVeh->m_nVehicleSubClass != VEHICLE_BIKE || std::abs(c.frame->modelling.pos.x) > 0.05f) {
c.mirroredX = true;
c.mirroredX = !dummyIsLeft;
c.lightType = eMaterialType::TailLightLeft;
data.dummies[c.lightType].push_back(VehicleDummy(c));
}
Expand Down
8 changes: 4 additions & 4 deletions src/features/lights/damage.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ struct LightDamageState {

static LightDamageState Get(CVehicle* pControlVeh, CVehicle* pTowedVeh) {
LightDamageState state;
state.isHeadlightLeftOk = !(Util::IsLightDamaged(pControlVeh, eLights::LIGHT_FRONT_LEFT) || Util::IsPanelDamaged(pControlVeh, ePanels::WING_FRONT_LEFT));
state.isHeadlightRightOk = !(Util::IsLightDamaged(pControlVeh, eLights::LIGHT_FRONT_RIGHT) || Util::IsPanelDamaged(pControlVeh, ePanels::WING_FRONT_RIGHT));
state.isHeadlightLeftOk = !Util::IsLightDamaged(pControlVeh, eLights::LIGHT_FRONT_LEFT);
state.isHeadlightRightOk = !Util::IsLightDamaged(pControlVeh, eLights::LIGHT_FRONT_RIGHT);
state.isFrontLeftOk = state.isHeadlightLeftOk || pControlVeh->bSirenOrAlarm;
state.isFrontRightOk = state.isHeadlightRightOk || pControlVeh->bSirenOrAlarm;
state.isRearLeftOk = !(Util::IsLightDamaged(pTowedVeh, eLights::LIGHT_REAR_LEFT) || Util::IsPanelDamaged(pTowedVeh, ePanels::WING_REAR_LEFT));
state.isRearRightOk = !(Util::IsLightDamaged(pTowedVeh, eLights::LIGHT_REAR_RIGHT) || Util::IsPanelDamaged(pTowedVeh, ePanels::WING_REAR_RIGHT));
state.isRearLeftOk = !Util::IsLightDamaged(pTowedVeh, eLights::LIGHT_REAR_LEFT);
state.isRearRightOk = !Util::IsLightDamaged(pTowedVeh, eLights::LIGHT_REAR_RIGHT);
state.isMiddleLeftOk = !Util::IsPanelDamaged(pControlVeh, ePanels::WING_FRONT_LEFT);
state.isMiddleRightOk = !Util::IsPanelDamaged(pControlVeh, ePanels::WING_FRONT_RIGHT);
state.isFrontBumperOk = !Util::IsPanelDamaged(pControlVeh, ePanels::BUMP_FRONT);
Expand Down
2 changes: 0 additions & 2 deletions src/features/lights/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ struct VehLightData {
std::array<std::vector<VehicleDummy>, eMaterialType::TotalMaterial> dummies;

bool bLightStates[eMaterialType::TotalMaterial];
unsigned int nHeadlightTickFrame = 0;
bool bHasVehFuncsPopUp = false;
std::array<float, eMaterialType::TotalMaterial> fLightFactor = {};
std::array<bool, eMaterialType::TotalMaterial> bLightRenderedThisFrame = {};
Expand Down Expand Up @@ -161,7 +160,6 @@ struct VehLightData {
vec.clear();
}
std::copy(std::begin(other.bLightStates), std::end(other.bLightStates), std::begin(bLightStates));
nHeadlightTickFrame = other.nHeadlightTickFrame;
}
return *this;
}
Expand Down
25 changes: 19 additions & 6 deletions src/features/lights/manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,14 @@ void LightManager::Render(CVehicle* pControlVeh, CVehicle* pTowedVeh) {
RwFrame *parent = RwFrameGetParent(dummy->Get().frame);
bool isBike = pVeh->m_nVehicleSubClass == VEHICLE_BIKE;
bool isDamaged = Util::IsFrameDamaged(pVeh, parent) || !FrameUtil::IsOkAtomicVisible(parent);
bool atomicCheck = !isBike && pVeh->GetIsOnScreen() && type != eMaterialType::HeadLightLeft && type != eMaterialType::HeadLightRight && isDamaged;
bool atomicCheck = !isBike && pVeh->GetIsOnScreen() && type != eMaterialType::HeadLightLeft && type != eMaterialType::HeadLightRight && type != eMaterialType::HighBeamLeft && type != eMaterialType::HighBeamRight && isDamaged;
if (atomicCheck || (c.dummyPos == eDummyPos::Rear && pVeh->m_pTrailer)) continue;

float szMul = 1.0f;
if (type == eMaterialType::HeadLightLeft || type == eMaterialType::HeadLightRight) {
szMul = 1.0f + 2.0f * vData.fHighBeamFactor;
if (!LightManager::IsDummyAvailable(vData, {eMaterialType::HighBeamLeft, eMaterialType::HighBeamRight})) {
szMul = 1.0f + 2.0f * vData.fHighBeamFactor;
}
}
EnableDummy((int)pVeh + 42 + id++, &dummy, pVeh, szMul, factor);

Expand All @@ -171,7 +173,9 @@ void LightManager::Render(CVehicle* pControlVeh, CVehicle* pTowedVeh) {
}
}
} else {
if (type == eMaterialType::HeadLightLeft || type == eMaterialType::HeadLightRight) {
if ((type == eMaterialType::HeadLightLeft || type == eMaterialType::HeadLightRight) &&
vData.fLightFactor[eMaterialType::HeadLightLeft] <= 0.001f &&
vData.fLightFactor[eMaterialType::HeadLightRight] <= 0.001f) {
vData.fHighBeamFactor = 0.0f;
vData.bLongLightsOn = false;
}
Expand Down Expand Up @@ -215,7 +219,7 @@ void LightManager::RenderLight(CVehicle* pVeh, VehLightData& data, eMaterialType
}
bool isAvailable = IsDummyAvailable(data, type);

if (type == eMaterialType::HeadLightLeft) {
if (type == eMaterialType::HeadLightLeft || (type == eMaterialType::HeadLightRight && data.fLightFactor[eMaterialType::HeadLightLeft] <= 0.001f)) {
float target = (data.bLongLightsOn && isOn) ? 1.0f : 0.0f;
if (inertia > 0.0001f) {
float hbStep = (CTimer::ms_fTimeStep / 50.0f) / inertia;
Expand Down Expand Up @@ -248,7 +252,7 @@ void LightManager::RenderLight(CVehicle* pVeh, VehLightData& data, eMaterialType
if (!isDamaged && parent) {
isDamaged = !FrameUtil::IsOkAtomicVisible(parent);
}
bool atomicCheck = !isBike && pVeh->GetIsOnScreen() && type != eMaterialType::HeadLightLeft && type != eMaterialType::HeadLightRight && isDamaged;
bool atomicCheck = !isBike && pVeh->GetIsOnScreen() && type != eMaterialType::HeadLightLeft && type != eMaterialType::HeadLightRight && type != eMaterialType::HighBeamLeft && type != eMaterialType::HighBeamRight && isDamaged;

if (atomicCheck || (c.dummyPos == eDummyPos::Rear && pVeh->m_pTrailer) || !isDummyOk) {
continue;
Expand Down Expand Up @@ -276,7 +280,9 @@ void LightManager::RenderLight(CVehicle* pVeh, VehLightData& data, eMaterialType

float szMul = 1.0f;
if (type == eMaterialType::HeadLightLeft || type == eMaterialType::HeadLightRight) {
szMul = 1.0f + 2.0f * data.fHighBeamFactor;
if (!LightManager::IsDummyAvailable(data, {eMaterialType::HighBeamLeft, eMaterialType::HighBeamRight})) {
szMul = 1.0f + 2.0f * data.fHighBeamFactor;
}
if (highlight && !data.bLongLightsOn) {
szMul = std::max(szMul, 3.00f);
}
Expand Down Expand Up @@ -413,6 +419,8 @@ const char* LightManager::GetLightGroupKey(eMaterialType type) {
switch (type) {
case eMaterialType::HeadLightLeft:
case eMaterialType::HeadLightRight:
case eMaterialType::HighBeamLeft:
case eMaterialType::HighBeamRight:
return "headlights";
case eMaterialType::TailLightLeft:
case eMaterialType::TailLightRight:
Expand Down Expand Up @@ -455,6 +463,8 @@ const char* LightManager::GetLightSpecificKey(eMaterialType type) {
switch (type) {
case eMaterialType::HeadLightLeft: return "headlight_l";
case eMaterialType::HeadLightRight: return "headlight_r";
case eMaterialType::HighBeamLeft: return "highbeam_l";
case eMaterialType::HighBeamRight: return "highbeam_r";
case eMaterialType::TailLightLeft: return "taillight_l";
case eMaterialType::TailLightRight: return "taillight_r";
case eMaterialType::STTLightLeft: return "sttlight_l";
Expand Down Expand Up @@ -564,6 +574,9 @@ MatStateColor LightManager::GetMaterialColor(CVehicle* pVeh, eMaterialType type)
if (type == eMaterialType::FogLightRight) checkKey("fogl_r");
if (type == eMaterialType::ReverseLightLeft) { checkKey("revl_l"); checkKey("rev_l"); }
if (type == eMaterialType::ReverseLightRight) { checkKey("revl_r"); checkKey("rev_r"); }
if (type == eMaterialType::HighBeamLeft || type == eMaterialType::HighBeamRight) {
checkKey("highbeam");
}
if (grpKey) checkKey(grpKey);
}

Expand Down
Loading