mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-20 12:40:25 +02:00
Light equation changes and weapon and ai spawn proper muzzle flashes.
This commit is contained in:
+371
-43
@@ -110,6 +110,202 @@ CLASS_DECLARATION( idAnimatedEntity, idWeapon )
|
|||||||
EVENT(EV_Weapon_NetEndReload, idWeapon::Event_NetEndReload)
|
EVENT(EV_Weapon_NetEndReload, idWeapon::Event_NetEndReload)
|
||||||
END_CLASS
|
END_CLASS
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
Weapon fire muzzle light
|
||||||
|
|
||||||
|
This is intentionally separate from idWeapon::MuzzleFlashLight(). The old
|
||||||
|
MuzzleFlashLight path is used by weapon scripts as a flashlight / persistent
|
||||||
|
weapon light, so projectile firing gets its own short-lived light here.
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
struct weaponFireMuzzleLightLocal_t {
|
||||||
|
int viewHandle;
|
||||||
|
int worldHandle;
|
||||||
|
int startTime;
|
||||||
|
int endTime;
|
||||||
|
int duration;
|
||||||
|
idVec3 baseColor;
|
||||||
|
float baseRadius;
|
||||||
|
renderLight_t viewLight;
|
||||||
|
renderLight_t worldLight;
|
||||||
|
};
|
||||||
|
|
||||||
|
static weaponFireMuzzleLightLocal_t weaponFireMuzzleLights[MAX_GENTITIES];
|
||||||
|
static bool weaponFireMuzzleLightsInitialized = false;
|
||||||
|
|
||||||
|
static void InitWeaponFireMuzzleLights(void) {
|
||||||
|
if (weaponFireMuzzleLightsInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_GENTITIES; i++) {
|
||||||
|
memset(&weaponFireMuzzleLights[i], 0, sizeof(weaponFireMuzzleLights[i]));
|
||||||
|
weaponFireMuzzleLights[i].viewHandle = -1;
|
||||||
|
weaponFireMuzzleLights[i].worldHandle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
weaponFireMuzzleLightsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeWeaponFireMuzzleLight(int entityNum) {
|
||||||
|
InitWeaponFireMuzzleLights();
|
||||||
|
|
||||||
|
if (entityNum < 0 || entityNum >= MAX_GENTITIES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
weaponFireMuzzleLightLocal_t& fireLight = weaponFireMuzzleLights[entityNum];
|
||||||
|
|
||||||
|
if (fireLight.viewHandle != -1) {
|
||||||
|
gameRenderWorld->FreeLightDef(fireLight.viewHandle);
|
||||||
|
fireLight.viewHandle = -1;
|
||||||
|
}
|
||||||
|
if (fireLight.worldHandle != -1) {
|
||||||
|
gameRenderWorld->FreeLightDef(fireLight.worldHandle);
|
||||||
|
fireLight.worldHandle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fireLight.startTime = 0;
|
||||||
|
fireLight.endTime = 0;
|
||||||
|
fireLight.duration = 0;
|
||||||
|
fireLight.baseColor.Zero();
|
||||||
|
fireLight.baseRadius = 0.0f;
|
||||||
|
memset(&fireLight.viewLight, 0, sizeof(fireLight.viewLight));
|
||||||
|
memset(&fireLight.worldLight, 0, sizeof(fireLight.worldLight));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void StartWeaponFireMuzzleLight(int entityNum, int ownerEntityNum, const idVec3& viewOrigin, const idMat3& viewAxis, const idVec3& worldOrigin, const idMat3& worldAxis, const idMaterial* shader, const idVec3& color, float radius, int duration, float diversity) {
|
||||||
|
InitWeaponFireMuzzleLights();
|
||||||
|
|
||||||
|
if (entityNum < 0 || entityNum >= MAX_GENTITIES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (radius <= 0.0f || duration <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
weaponFireMuzzleLightLocal_t& fireLight = weaponFireMuzzleLights[entityNum];
|
||||||
|
|
||||||
|
memset(&fireLight.viewLight, 0, sizeof(fireLight.viewLight));
|
||||||
|
memset(&fireLight.worldLight, 0, sizeof(fireLight.worldLight));
|
||||||
|
|
||||||
|
fireLight.startTime = gameLocal.time;
|
||||||
|
fireLight.endTime = gameLocal.time + duration;
|
||||||
|
fireLight.duration = duration;
|
||||||
|
fireLight.baseColor = color;
|
||||||
|
fireLight.baseRadius = radius * 5;
|
||||||
|
|
||||||
|
fireLight.viewLight.pointLight = true;
|
||||||
|
fireLight.viewLight.noShadows = true;
|
||||||
|
fireLight.viewLight.shader = shader;
|
||||||
|
fireLight.viewLight.origin = viewOrigin;
|
||||||
|
fireLight.viewLight.axis = viewAxis;
|
||||||
|
fireLight.viewLight.lightRadius[0] = radius;
|
||||||
|
fireLight.viewLight.lightRadius[1] = radius;
|
||||||
|
fireLight.viewLight.lightRadius[2] = radius;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_RED] = color.x;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_GREEN] = color.y;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_BLUE] = color.z;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_ALPHA] = 1.0f;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_TIMESCALE] = 1.0f;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC(gameLocal.time);
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_DIVERSITY] = diversity;
|
||||||
|
|
||||||
|
// Only the owning player should see the view-model light. This is what
|
||||||
|
// makes the light appear attached to the first-person muzzle flash joint.
|
||||||
|
if (ownerEntityNum >= 0) {
|
||||||
|
fireLight.viewLight.allowLightInViewID = ownerEntityNum + 1;
|
||||||
|
// Keep this separate from the old LIGHTID_VIEW_MUZZLE_FLASH path used by
|
||||||
|
// MuzzleFlashLight/flashlight so the two systems never fight each other.
|
||||||
|
fireLight.viewLight.lightId = LIGHTID_VIEW_MUZZLE_FLASH + ownerEntityNum + 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
fireLight.worldLight = fireLight.viewLight;
|
||||||
|
fireLight.worldLight.origin = worldOrigin;
|
||||||
|
fireLight.worldLight.axis = worldAxis;
|
||||||
|
fireLight.worldLight.allowLightInViewID = 0;
|
||||||
|
if (ownerEntityNum >= 0) {
|
||||||
|
fireLight.worldLight.suppressLightInViewID = ownerEntityNum + 1;
|
||||||
|
fireLight.worldLight.lightId = LIGHTID_WORLD_MUZZLE_FLASH + ownerEntityNum + 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fireLight.viewHandle != -1) {
|
||||||
|
gameRenderWorld->UpdateLightDef(fireLight.viewHandle, &fireLight.viewLight);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fireLight.viewHandle = gameRenderWorld->AddLightDef(&fireLight.viewLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fireLight.worldHandle != -1) {
|
||||||
|
gameRenderWorld->UpdateLightDef(fireLight.worldHandle, &fireLight.worldLight);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fireLight.worldHandle = gameRenderWorld->AddLightDef(&fireLight.worldLight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool UpdateWeaponFireMuzzleLight(int entityNum, const idVec3& viewOrigin, const idMat3& viewAxis, const idVec3& worldOrigin, const idMat3& worldAxis) {
|
||||||
|
InitWeaponFireMuzzleLights();
|
||||||
|
|
||||||
|
if (entityNum < 0 || entityNum >= MAX_GENTITIES) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
weaponFireMuzzleLightLocal_t& fireLight = weaponFireMuzzleLights[entityNum];
|
||||||
|
|
||||||
|
if (fireLight.viewHandle == -1 && fireLight.worldHandle == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameLocal.time >= fireLight.endTime || fireLight.duration <= 0) {
|
||||||
|
FreeWeaponFireMuzzleLight(entityNum);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float frac = (float)(fireLight.endTime - gameLocal.time) / (float)fireLight.duration;
|
||||||
|
if (frac < 0.0f) {
|
||||||
|
frac = 0.0f;
|
||||||
|
}
|
||||||
|
else if (frac > 1.0f) {
|
||||||
|
frac = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A squared falloff gives a hot first frame and then a quick natural fade.
|
||||||
|
float fade = frac * frac;
|
||||||
|
float radius = fireLight.baseRadius * (0.35f + 0.65f * fade);
|
||||||
|
|
||||||
|
fireLight.viewLight.origin = viewOrigin;
|
||||||
|
fireLight.viewLight.axis = viewAxis;
|
||||||
|
fireLight.viewLight.lightRadius[0] = radius;
|
||||||
|
fireLight.viewLight.lightRadius[1] = radius;
|
||||||
|
fireLight.viewLight.lightRadius[2] = radius;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_RED] = fireLight.baseColor.x * fade;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_GREEN] = fireLight.baseColor.y * fade;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_BLUE] = fireLight.baseColor.z * fade;
|
||||||
|
fireLight.viewLight.shaderParms[SHADERPARM_ALPHA] = fade;
|
||||||
|
|
||||||
|
fireLight.worldLight.origin = worldOrigin;
|
||||||
|
fireLight.worldLight.axis = worldAxis;
|
||||||
|
fireLight.worldLight.lightRadius[0] = radius;
|
||||||
|
fireLight.worldLight.lightRadius[1] = radius;
|
||||||
|
fireLight.worldLight.lightRadius[2] = radius;
|
||||||
|
fireLight.worldLight.shaderParms[SHADERPARM_RED] = fireLight.baseColor.x * fade;
|
||||||
|
fireLight.worldLight.shaderParms[SHADERPARM_GREEN] = fireLight.baseColor.y * fade;
|
||||||
|
fireLight.worldLight.shaderParms[SHADERPARM_BLUE] = fireLight.baseColor.z * fade;
|
||||||
|
fireLight.worldLight.shaderParms[SHADERPARM_ALPHA] = fade;
|
||||||
|
|
||||||
|
if (fireLight.viewHandle != -1) {
|
||||||
|
gameRenderWorld->UpdateLightDef(fireLight.viewHandle, &fireLight.viewLight);
|
||||||
|
}
|
||||||
|
if (fireLight.worldHandle != -1) {
|
||||||
|
gameRenderWorld->UpdateLightDef(fireLight.worldHandle, &fireLight.worldLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
||||||
init
|
init
|
||||||
@@ -427,14 +623,16 @@ void idWeapon::Restore( idRestoreGame *savefile ) {
|
|||||||
const idDeclEntityDef* projectileDef = gameLocal.FindEntityDef(weaponDef->dict.GetString("def_projectile"), false);
|
const idDeclEntityDef* projectileDef = gameLocal.FindEntityDef(weaponDef->dict.GetString("def_projectile"), false);
|
||||||
if (projectileDef) {
|
if (projectileDef) {
|
||||||
projectileDict = projectileDef->dict;
|
projectileDict = projectileDef->dict;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
projectileDict.Clear();
|
projectileDict.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const idDeclEntityDef* brassDef = gameLocal.FindEntityDef(weaponDef->dict.GetString("def_ejectBrass"), false);
|
const idDeclEntityDef* brassDef = gameLocal.FindEntityDef(weaponDef->dict.GetString("def_ejectBrass"), false);
|
||||||
if (brassDef) {
|
if (brassDef) {
|
||||||
brassDict = brassDef->dict;
|
brassDict = brassDef->dict;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
brassDict.Clear();
|
brassDict.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,6 +758,7 @@ void idWeapon::Clear( void ) {
|
|||||||
gameRenderWorld->FreeLightDef(worldMuzzleFlashHandle);
|
gameRenderWorld->FreeLightDef(worldMuzzleFlashHandle);
|
||||||
worldMuzzleFlashHandle = -1;
|
worldMuzzleFlashHandle = -1;
|
||||||
}
|
}
|
||||||
|
FreeWeaponFireMuzzleLight(entityNumber);
|
||||||
if (guiLightHandle != -1) {
|
if (guiLightHandle != -1) {
|
||||||
gameRenderWorld->FreeLightDef(guiLightHandle);
|
gameRenderWorld->FreeLightDef(guiLightHandle);
|
||||||
guiLightHandle = -1;
|
guiLightHandle = -1;
|
||||||
@@ -739,7 +938,8 @@ void idWeapon::InitWorldModel( const idDeclEntityDef *def ) {
|
|||||||
worldModelRenderEntity->suppressShadowInViewID = owner->entityNumber + 1;
|
worldModelRenderEntity->suppressShadowInViewID = owner->entityNumber + 1;
|
||||||
worldModelRenderEntity->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
|
worldModelRenderEntity->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
ent->SetModel("");
|
ent->SetModel("");
|
||||||
ent->Hide();
|
ent->Hide();
|
||||||
}
|
}
|
||||||
@@ -795,7 +995,8 @@ void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) {
|
|||||||
smokeName = weaponDef->dict.GetString("smoke_muzzle");
|
smokeName = weaponDef->dict.GetString("smoke_muzzle");
|
||||||
if (*smokeName != '\0') {
|
if (*smokeName != '\0') {
|
||||||
weaponSmoke = static_cast<const idDeclParticle*>(declManager->FindType(DECL_PARTICLE, smokeName));
|
weaponSmoke = static_cast<const idDeclParticle*>(declManager->FindType(DECL_PARTICLE, smokeName));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
weaponSmoke = NULL;
|
weaponSmoke = NULL;
|
||||||
}
|
}
|
||||||
continuousSmoke = weaponDef->dict.GetBool("continuousSmoke");
|
continuousSmoke = weaponDef->dict.GetBool("continuousSmoke");
|
||||||
@@ -804,7 +1005,8 @@ void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) {
|
|||||||
smokeName = weaponDef->dict.GetString("smoke_strike");
|
smokeName = weaponDef->dict.GetString("smoke_strike");
|
||||||
if (*smokeName != '\0') {
|
if (*smokeName != '\0') {
|
||||||
strikeSmoke = static_cast<const idDeclParticle*>(declManager->FindType(DECL_PARTICLE, smokeName));
|
strikeSmoke = static_cast<const idDeclParticle*>(declManager->FindType(DECL_PARTICLE, smokeName));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
strikeSmoke = NULL;
|
strikeSmoke = NULL;
|
||||||
}
|
}
|
||||||
strikeSmokeStartTime = 0;
|
strikeSmokeStartTime = 0;
|
||||||
@@ -850,12 +1052,14 @@ void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) {
|
|||||||
const idDeclEntityDef* projectileDef = gameLocal.FindEntityDef(projectileName, false);
|
const idDeclEntityDef* projectileDef = gameLocal.FindEntityDef(projectileName, false);
|
||||||
if (!projectileDef) {
|
if (!projectileDef) {
|
||||||
gameLocal.Warning("Unknown projectile '%s' in weapon '%s'", projectileName, objectname);
|
gameLocal.Warning("Unknown projectile '%s' in weapon '%s'", projectileName, objectname);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
const char* spawnclass = projectileDef->dict.GetString("spawnclass");
|
const char* spawnclass = projectileDef->dict.GetString("spawnclass");
|
||||||
idTypeInfo* cls = idClass::GetClass(spawnclass);
|
idTypeInfo* cls = idClass::GetClass(spawnclass);
|
||||||
if (!cls || !cls->IsType(idProjectile::Type)) {
|
if (!cls || !cls->IsType(idProjectile::Type)) {
|
||||||
gameLocal.Warning("Invalid spawnclass '%s' on projectile '%s' (used by weapon '%s')", spawnclass, projectileName, objectname);
|
gameLocal.Warning("Invalid spawnclass '%s' on projectile '%s' (used by weapon '%s')", spawnclass, projectileName, objectname);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
projectileDict = projectileDef->dict;
|
projectileDict = projectileDef->dict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,7 +1143,8 @@ void idWeapon::GetWeaponDef( const char *objectname, int ammoinclip ) {
|
|||||||
const idDeclEntityDef* brassDef = gameLocal.FindEntityDef(brassDefName, false);
|
const idDeclEntityDef* brassDef = gameLocal.FindEntityDef(brassDefName, false);
|
||||||
if (!brassDef) {
|
if (!brassDef) {
|
||||||
gameLocal.Warning("Unknown brass '%s'", brassDefName);
|
gameLocal.Warning("Unknown brass '%s'", brassDefName);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
brassDict = brassDef->dict;
|
brassDict = brassDef->dict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1049,7 +1254,8 @@ void idWeapon::UpdateGUI( void ) {
|
|||||||
if (!p->spectating || p->spectator != owner->entityNumber) {
|
if (!p->spectating || p->spectator != owner->entityNumber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1060,7 +1266,8 @@ void idWeapon::UpdateGUI( void ) {
|
|||||||
if (ammoamount < 0) {
|
if (ammoamount < 0) {
|
||||||
// show infinite ammo
|
// show infinite ammo
|
||||||
renderEntity.gui[0]->SetStateString("player_ammo", "");
|
renderEntity.gui[0]->SetStateString("player_ammo", "");
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// show remaining ammo
|
// show remaining ammo
|
||||||
renderEntity.gui[0]->SetStateString("player_totalammo", va("%i", ammoamount - inclip));
|
renderEntity.gui[0]->SetStateString("player_totalammo", va("%i", ammoamount - inclip));
|
||||||
renderEntity.gui[0]->SetStateString("player_ammo", ClipSize() ? va("%i", inclip) : "--");
|
renderEntity.gui[0]->SetStateString("player_ammo", ClipSize() ? va("%i", inclip) : "--");
|
||||||
@@ -1129,7 +1336,8 @@ void idWeapon::MuzzleFlashLight( void ) {
|
|||||||
if (muzzleFlashHandle != -1) {
|
if (muzzleFlashHandle != -1) {
|
||||||
gameRenderWorld->UpdateLightDef(muzzleFlashHandle, &muzzleFlash);
|
gameRenderWorld->UpdateLightDef(muzzleFlashHandle, &muzzleFlash);
|
||||||
gameRenderWorld->UpdateLightDef(worldMuzzleFlashHandle, &worldMuzzleFlash);
|
gameRenderWorld->UpdateLightDef(worldMuzzleFlashHandle, &worldMuzzleFlash);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
muzzleFlashHandle = gameRenderWorld->AddLightDef(&muzzleFlash);
|
muzzleFlashHandle = gameRenderWorld->AddLightDef(&muzzleFlash);
|
||||||
worldMuzzleFlashHandle = gameRenderWorld->AddLightDef(&worldMuzzleFlash);
|
worldMuzzleFlashHandle = gameRenderWorld->AddLightDef(&worldMuzzleFlash);
|
||||||
}
|
}
|
||||||
@@ -1176,7 +1384,8 @@ void idWeapon::SetModel( const char *modelname ) {
|
|||||||
if (renderEntity.hModel) {
|
if (renderEntity.hModel) {
|
||||||
renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin();
|
renderEntity.customSkin = animator.ModelDef()->GetDefaultSkin();
|
||||||
animator.GetJoints(&renderEntity.numJoints, &renderEntity.joints);
|
animator.GetJoints(&renderEntity.numJoints, &renderEntity.joints);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
renderEntity.customSkin = NULL;
|
renderEntity.customSkin = NULL;
|
||||||
renderEntity.callback = NULL;
|
renderEntity.callback = NULL;
|
||||||
renderEntity.numJoints = 0;
|
renderEntity.numJoints = 0;
|
||||||
@@ -1202,7 +1411,8 @@ bool idWeapon::GetGlobalJointTransform( bool viewModel, const jointHandle_t join
|
|||||||
axis = axis * viewWeaponAxis;
|
axis = axis * viewWeaponAxis;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// world model
|
// world model
|
||||||
if (worldModel.GetEntity() && worldModel.GetEntity()->GetAnimator()->GetJointTransform(jointHandle, gameLocal.time, offset, axis)) {
|
if (worldModel.GetEntity() && worldModel.GetEntity()->GetAnimator()->GetJointTransform(jointHandle, gameLocal.time, offset, axis)) {
|
||||||
offset = worldModel.GetEntity()->GetPhysics()->GetOrigin() + offset * worldModel.GetEntity()->GetPhysics()->GetAxis();
|
offset = worldModel.GetEntity()->GetPhysics()->GetOrigin() + offset * worldModel.GetEntity()->GetPhysics()->GetAxis();
|
||||||
@@ -1286,7 +1496,8 @@ void idWeapon::LowerWeapon( void ) {
|
|||||||
hideEnd = hideDistance;
|
hideEnd = hideDistance;
|
||||||
if (gameLocal.time - hideStartTime < hideTime) {
|
if (gameLocal.time - hideStartTime < hideTime) {
|
||||||
hideStartTime = gameLocal.time - (hideTime - (gameLocal.time - hideStartTime));
|
hideStartTime = gameLocal.time - (hideTime - (gameLocal.time - hideStartTime));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
hideStartTime = gameLocal.time;
|
hideStartTime = gameLocal.time;
|
||||||
}
|
}
|
||||||
hide = true;
|
hide = true;
|
||||||
@@ -1306,7 +1517,8 @@ void idWeapon::RaiseWeapon( void ) {
|
|||||||
hideEnd = 0.0f;
|
hideEnd = 0.0f;
|
||||||
if (gameLocal.time - hideStartTime < hideTime) {
|
if (gameLocal.time - hideStartTime < hideTime) {
|
||||||
hideStartTime = gameLocal.time - (hideTime - (gameLocal.time - hideStartTime));
|
hideStartTime = gameLocal.time - (hideTime - (gameLocal.time - hideStartTime));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
hideStartTime = gameLocal.time;
|
hideStartTime = gameLocal.time;
|
||||||
}
|
}
|
||||||
hide = false;
|
hide = false;
|
||||||
@@ -1324,6 +1536,7 @@ void idWeapon::HideWeapon( void ) {
|
|||||||
worldModel.GetEntity()->Hide();
|
worldModel.GetEntity()->Hide();
|
||||||
}
|
}
|
||||||
muzzleFlashEnd = 0;
|
muzzleFlashEnd = 0;
|
||||||
|
FreeWeaponFireMuzzleLight(entityNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1829,7 +2042,8 @@ void idWeapon::AlertMonsters( void ) {
|
|||||||
ent = gameLocal.GetTraceEntity(tr);
|
ent = gameLocal.GetTraceEntity(tr);
|
||||||
if (ent->IsType(idAI::Type)) {
|
if (ent->IsType(idAI::Type)) {
|
||||||
static_cast<idAI*>(ent)->TouchedByFlashlight(owner);
|
static_cast<idAI*>(ent)->TouchedByFlashlight(owner);
|
||||||
} else if ( ent->IsType( idTrigger::Type ) ) {
|
}
|
||||||
|
else if (ent->IsType(idTrigger::Type)) {
|
||||||
ent->Signal(SIG_TOUCH);
|
ent->Signal(SIG_TOUCH);
|
||||||
ent->ProcessEvent(&EV_Touch, owner, &tr);
|
ent->ProcessEvent(&EV_Touch, owner, &tr);
|
||||||
}
|
}
|
||||||
@@ -1848,7 +2062,8 @@ void idWeapon::AlertMonsters( void ) {
|
|||||||
ent = gameLocal.GetTraceEntity(tr);
|
ent = gameLocal.GetTraceEntity(tr);
|
||||||
if (ent->IsType(idAI::Type)) {
|
if (ent->IsType(idAI::Type)) {
|
||||||
static_cast<idAI*>(ent)->TouchedByFlashlight(owner);
|
static_cast<idAI*>(ent)->TouchedByFlashlight(owner);
|
||||||
} else if ( ent->IsType( idTrigger::Type ) ) {
|
}
|
||||||
|
else if (ent->IsType(idTrigger::Type)) {
|
||||||
ent->Signal(SIG_TOUCH);
|
ent->Signal(SIG_TOUCH);
|
||||||
ent->ProcessEvent(&EV_Touch, owner, &tr);
|
ent->ProcessEvent(&EV_Touch, owner, &tr);
|
||||||
}
|
}
|
||||||
@@ -1874,11 +2089,13 @@ void idWeapon::PresentWeapon( bool showViewModel ) {
|
|||||||
if (hideStart < hideEnd) {
|
if (hideStart < hideEnd) {
|
||||||
frac = 1.0f - frac;
|
frac = 1.0f - frac;
|
||||||
frac = 1.0f - frac * frac;
|
frac = 1.0f - frac * frac;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
frac = frac * frac;
|
frac = frac * frac;
|
||||||
}
|
}
|
||||||
hideOffset = hideStart + (hideEnd - hideStart) * frac;
|
hideOffset = hideStart + (hideEnd - hideStart) * frac;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
hideOffset = hideEnd;
|
hideOffset = hideEnd;
|
||||||
if (hide && disabled) {
|
if (hide && disabled) {
|
||||||
Hide();
|
Hide();
|
||||||
@@ -1911,7 +2128,8 @@ void idWeapon::PresentWeapon( bool showViewModel ) {
|
|||||||
// present the model
|
// present the model
|
||||||
if (showViewModel) {
|
if (showViewModel) {
|
||||||
Present();
|
Present();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
FreeModelDef();
|
FreeModelDef();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1920,7 +2138,8 @@ void idWeapon::PresentWeapon( bool showViewModel ) {
|
|||||||
// don't show shadows of the world model in first person
|
// don't show shadows of the world model in first person
|
||||||
if (gameLocal.isMultiplayer || g_showPlayerShadow.GetBool() || pm_thirdPerson.GetBool()) {
|
if (gameLocal.isMultiplayer || g_showPlayerShadow.GetBool() || pm_thirdPerson.GetBool()) {
|
||||||
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = 0;
|
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = 0;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = owner->entityNumber + 1;
|
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInViewID = owner->entityNumber + 1;
|
||||||
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
|
worldModel.GetEntity()->GetRenderEntity()->suppressShadowInLightID = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
|
||||||
}
|
}
|
||||||
@@ -1935,7 +2154,8 @@ void idWeapon::PresentWeapon( bool showViewModel ) {
|
|||||||
// use the barrel joint if available
|
// use the barrel joint if available
|
||||||
if (barrelJointView) {
|
if (barrelJointView) {
|
||||||
GetGlobalJointTransform(true, barrelJointView, muzzleOrigin, muzzleAxis);
|
GetGlobalJointTransform(true, barrelJointView, muzzleOrigin, muzzleAxis);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// default to going straight out the view
|
// default to going straight out the view
|
||||||
muzzleOrigin = playerViewOrigin;
|
muzzleOrigin = playerViewOrigin;
|
||||||
muzzleAxis = playerViewAxis;
|
muzzleAxis = playerViewAxis;
|
||||||
@@ -1953,7 +2173,41 @@ void idWeapon::PresentWeapon( bool showViewModel ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the muzzle flash light when it's done
|
// Update the separate weapon-fire muzzle light. This is the actual light
|
||||||
|
// spawned by firing the gun, and it stays attached to the flash joint while
|
||||||
|
// fading out independently from the flashlight/script light.
|
||||||
|
if (IsHidden()) {
|
||||||
|
FreeWeaponFireMuzzleLight(entityNumber);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
idVec3 fireViewOrigin;
|
||||||
|
idMat3 fireViewAxis;
|
||||||
|
idVec3 fireWorldOrigin;
|
||||||
|
idMat3 fireWorldAxis;
|
||||||
|
|
||||||
|
if (flashJointView != INVALID_JOINT && GetGlobalJointTransform(true, flashJointView, fireViewOrigin, fireViewAxis)) {
|
||||||
|
idVec3 fireStart = fireViewOrigin - playerViewAxis[0] * 16.0f;
|
||||||
|
idVec3 fireEnd = fireViewOrigin + playerViewAxis[0] * 8.0f;
|
||||||
|
trace_t fireTr;
|
||||||
|
gameLocal.clip.TracePoint(fireTr, fireStart, fireEnd, MASK_SHOT_RENDERMODEL, owner);
|
||||||
|
fireViewOrigin = fireTr.endpos - playerViewAxis[0] * 8.0f;
|
||||||
|
|
||||||
|
if (flashJointWorld != INVALID_JOINT && GetGlobalJointTransform(false, flashJointWorld, fireWorldOrigin, fireWorldAxis)) {
|
||||||
|
// valid world joint
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fireWorldOrigin = fireViewOrigin;
|
||||||
|
fireWorldAxis = fireViewAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateWeaponFireMuzzleLight(entityNumber, fireViewOrigin, fireViewAxis, fireWorldOrigin, fireWorldAxis);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FreeWeaponFireMuzzleLight(entityNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the old script/flashlight muzzle light when it's done
|
||||||
if ((!lightOn && (gameLocal.time >= muzzleFlashEnd)) || IsHidden()) {
|
if ((!lightOn && (gameLocal.time >= muzzleFlashEnd)) || IsHidden()) {
|
||||||
if (muzzleFlashHandle != -1) {
|
if (muzzleFlashHandle != -1) {
|
||||||
gameRenderWorld->FreeLightDef(muzzleFlashHandle);
|
gameRenderWorld->FreeLightDef(muzzleFlashHandle);
|
||||||
@@ -1983,7 +2237,8 @@ void idWeapon::PresentWeapon( bool showViewModel ) {
|
|||||||
|
|
||||||
if ((guiLightHandle != -1)) {
|
if ((guiLightHandle != -1)) {
|
||||||
gameRenderWorld->UpdateLightDef(guiLightHandle, &guiLight);
|
gameRenderWorld->UpdateLightDef(guiLightHandle, &guiLight);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
guiLightHandle = gameRenderWorld->AddLightDef(&guiLight);
|
guiLightHandle = gameRenderWorld->AddLightDef(&guiLight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2186,7 +2441,8 @@ idWeapon::AmmoAvailable
|
|||||||
int idWeapon::AmmoAvailable(void) const {
|
int idWeapon::AmmoAvailable(void) const {
|
||||||
if (owner) {
|
if (owner) {
|
||||||
return owner->inventory.HasAmmo(ammoType, ammoRequired);
|
return owner->inventory.HasAmmo(ammoType, ammoRequired);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2370,7 +2626,8 @@ void idWeapon::Event_WeaponState( const char *statename, int blendFrames ) {
|
|||||||
|
|
||||||
if (!idealState.Icmp("Fire")) {
|
if (!idealState.Icmp("Fire")) {
|
||||||
isFiring = true;
|
isFiring = true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
isFiring = false;
|
isFiring = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2585,7 +2842,8 @@ void idWeapon::Event_PlayAnim( int channel, const char *animname ) {
|
|||||||
gameLocal.Warning("missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName());
|
gameLocal.Warning("missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName());
|
||||||
animator.Clear(channel, gameLocal.time, FRAME2MS(animBlendFrames));
|
animator.Clear(channel, gameLocal.time, FRAME2MS(animBlendFrames));
|
||||||
animDoneTime = 0;
|
animDoneTime = 0;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (!(owner && owner->GetInfluenceLevel())) {
|
if (!(owner && owner->GetInfluenceLevel())) {
|
||||||
Show();
|
Show();
|
||||||
}
|
}
|
||||||
@@ -2615,7 +2873,8 @@ void idWeapon::Event_PlayCycle( int channel, const char *animname ) {
|
|||||||
gameLocal.Warning("missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName());
|
gameLocal.Warning("missing '%s' animation on '%s' (%s)", animname, name.c_str(), GetEntityDefName());
|
||||||
animator.Clear(channel, gameLocal.time, FRAME2MS(animBlendFrames));
|
animator.Clear(channel, gameLocal.time, FRAME2MS(animBlendFrames));
|
||||||
animDoneTime = 0;
|
animDoneTime = 0;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (!(owner && owner->GetInfluenceLevel())) {
|
if (!(owner && owner->GetInfluenceLevel())) {
|
||||||
Show();
|
Show();
|
||||||
}
|
}
|
||||||
@@ -2638,7 +2897,8 @@ idWeapon::Event_AnimDone
|
|||||||
void idWeapon::Event_AnimDone(int channel, int blendFrames) {
|
void idWeapon::Event_AnimDone(int channel, int blendFrames) {
|
||||||
if (animDoneTime - FRAME2MS(blendFrames) <= gameLocal.time) {
|
if (animDoneTime - FRAME2MS(blendFrames) <= gameLocal.time) {
|
||||||
idThread::ReturnInt(true);
|
idThread::ReturnInt(true);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
idThread::ReturnInt(false);
|
idThread::ReturnInt(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2681,7 +2941,8 @@ void idWeapon::Event_SetSkin( const char *skinname ) {
|
|||||||
|
|
||||||
if (!skinname || !skinname[0]) {
|
if (!skinname || !skinname[0]) {
|
||||||
skinDecl = NULL;
|
skinDecl = NULL;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
skinDecl = declManager->FindSkin(skinname);
|
skinDecl = declManager->FindSkin(skinname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2711,7 +2972,8 @@ void idWeapon::Event_Flashlight( int enable ) {
|
|||||||
if (enable) {
|
if (enable) {
|
||||||
lightOn = true;
|
lightOn = true;
|
||||||
MuzzleFlashLight();
|
MuzzleFlashLight();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lightOn = false;
|
lightOn = false;
|
||||||
muzzleFlashEnd = 0;
|
muzzleFlashEnd = 0;
|
||||||
}
|
}
|
||||||
@@ -2779,7 +3041,8 @@ void idWeapon::Event_CreateProjectile( void ) {
|
|||||||
projectileEnt->Hide();
|
projectileEnt->Hide();
|
||||||
}
|
}
|
||||||
idThread::ReturnEntity(projectileEnt);
|
idThread::ReturnEntity(projectileEnt);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
idThread::ReturnEntity(NULL);
|
idThread::ReturnEntity(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2860,7 +3123,8 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float
|
|||||||
if (barrelJointView != INVALID_JOINT && projectileDict.GetBool("launchFromBarrel")) {
|
if (barrelJointView != INVALID_JOINT && projectileDict.GetBool("launchFromBarrel")) {
|
||||||
// there is an explicit joint for the muzzle
|
// there is an explicit joint for the muzzle
|
||||||
GetGlobalJointTransform(true, barrelJointView, muzzleOrigin, muzzleAxis);
|
GetGlobalJointTransform(true, barrelJointView, muzzleOrigin, muzzleAxis);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// go straight out of the view
|
// go straight out of the view
|
||||||
muzzleOrigin = playerViewOrigin;
|
muzzleOrigin = playerViewOrigin;
|
||||||
muzzleAxis = playerViewAxis;
|
muzzleAxis = playerViewAxis;
|
||||||
@@ -2893,7 +3157,8 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
ownerBounds = owner->GetPhysics()->GetAbsBounds();
|
ownerBounds = owner->GetPhysics()->GetAbsBounds();
|
||||||
|
|
||||||
@@ -2911,7 +3176,8 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float
|
|||||||
ent->Show();
|
ent->Show();
|
||||||
ent->Unbind();
|
ent->Unbind();
|
||||||
projectileEnt = NULL;
|
projectileEnt = NULL;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
gameLocal.SpawnEntityDef(projectileDict, &ent, false);
|
gameLocal.SpawnEntityDef(projectileDict, &ent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2935,7 +3201,8 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float
|
|||||||
muzzle_pos = muzzleOrigin + playerViewAxis[0] * 2.0f;
|
muzzle_pos = muzzleOrigin + playerViewAxis[0] * 2.0f;
|
||||||
if ((ownerBounds - projBounds).RayIntersection(muzzle_pos, playerViewAxis[0], distance)) {
|
if ((ownerBounds - projBounds).RayIntersection(muzzle_pos, playerViewAxis[0], distance)) {
|
||||||
start = muzzle_pos + distance * playerViewAxis[0];
|
start = muzzle_pos + distance * playerViewAxis[0];
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
start = ownerBounds.GetCenter();
|
start = ownerBounds.GetCenter();
|
||||||
}
|
}
|
||||||
gameLocal.clip.Translation(tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner);
|
gameLocal.clip.Translation(tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner);
|
||||||
@@ -2949,9 +3216,66 @@ void idWeapon::Event_LaunchProjectiles( int num_projectiles, float spread, float
|
|||||||
PostEventMS(&EV_Weapon_EjectBrass, brassDelay);
|
PostEventMS(&EV_Weapon_EjectBrass, brassDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the light for the muzzleflash
|
// Add a separate short-lived weapon-fire light. Do not use
|
||||||
if ( !lightOn ) {
|
// MuzzleFlashLight() here; that path is also used by the flashlight / script
|
||||||
MuzzleFlashLight();
|
// weapon light and it should not own normal muzzle-flash firing.
|
||||||
|
if (flashJointView != INVALID_JOINT) {
|
||||||
|
idVec3 fireViewOrigin;
|
||||||
|
idMat3 fireViewAxis;
|
||||||
|
idVec3 fireWorldOrigin;
|
||||||
|
idMat3 fireWorldAxis;
|
||||||
|
|
||||||
|
GetGlobalJointTransform(true, flashJointView, fireViewOrigin, fireViewAxis);
|
||||||
|
|
||||||
|
// Keep the view light on the muzzle flash joint, but back it away from
|
||||||
|
// walls the same way the old muzzle flash code did so it does not spawn
|
||||||
|
// inside opaque geometry.
|
||||||
|
idVec3 fireStart = fireViewOrigin - playerViewAxis[0] * 16.0f;
|
||||||
|
idVec3 fireEnd = fireViewOrigin + playerViewAxis[0] * 8.0f;
|
||||||
|
trace_t fireTr;
|
||||||
|
gameLocal.clip.TracePoint(fireTr, fireStart, fireEnd, MASK_SHOT_RENDERMODEL, owner);
|
||||||
|
fireViewOrigin = fireTr.endpos - playerViewAxis[0] * 8.0f;
|
||||||
|
|
||||||
|
if (flashJointWorld != INVALID_JOINT) {
|
||||||
|
GetGlobalJointTransform(false, flashJointWorld, fireWorldOrigin, fireWorldAxis);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fireWorldOrigin = fireViewOrigin;
|
||||||
|
fireWorldAxis = fireViewAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* fireShaderName = weaponDef->dict.GetString("mtr_weaponFireLightShader");
|
||||||
|
if (!fireShaderName || !fireShaderName[0]) {
|
||||||
|
fireShaderName = weaponDef->dict.GetString("mtr_flashShader");
|
||||||
|
}
|
||||||
|
|
||||||
|
const idMaterial* fireShader = NULL;
|
||||||
|
if (fireShaderName && fireShaderName[0]) {
|
||||||
|
fireShader = declManager->FindMaterial(fireShaderName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
idVec3 fireColor = weaponDef->dict.GetVector("weaponFireLightColor", flashColor.ToString());
|
||||||
|
if (fireColor.x <= 0.0f && fireColor.y <= 0.0f && fireColor.z <= 0.0f) {
|
||||||
|
fireColor.Set(1.0f, 0.72f, 0.38f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fireIntensity = weaponDef->dict.GetFloat("weaponFireLightIntensity", "1.0");
|
||||||
|
if (fireIntensity <= 0.0f) {
|
||||||
|
fireIntensity = 1.0f;
|
||||||
|
}
|
||||||
|
fireColor *= fireIntensity;
|
||||||
|
|
||||||
|
float fireRadius = weaponDef->dict.GetFloat("weaponFireLightRadius", va("%f", muzzleFlash.lightRadius[0]));
|
||||||
|
if (fireRadius <= 0.0f) {
|
||||||
|
fireRadius = 96.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fireTime = SEC2MS(weaponDef->dict.GetFloat("weaponFireLightTime", weaponDef->dict.GetString("flashTime", "0.08")));
|
||||||
|
if (fireTime <= 0) {
|
||||||
|
fireTime = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartWeaponFireMuzzleLight(entityNumber, owner ? owner->entityNumber : -1, fireViewOrigin, fireViewAxis, fireWorldOrigin, fireWorldAxis, fireShader, fireColor, fireRadius, fireTime, renderEntity.shaderParms[SHADERPARM_DIVERSITY]);
|
||||||
}
|
}
|
||||||
|
|
||||||
owner->WeaponFireFeedback(&weaponDef->dict);
|
owner->WeaponFireFeedback(&weaponDef->dict);
|
||||||
@@ -2979,7 +3303,8 @@ void idWeapon::Event_Melee( void ) {
|
|||||||
gameLocal.clip.TracePoint(tr, start, end, MASK_SHOT_RENDERMODEL, owner);
|
gameLocal.clip.TracePoint(tr, start, end, MASK_SHOT_RENDERMODEL, owner);
|
||||||
if (tr.fraction < 1.0f) {
|
if (tr.fraction < 1.0f) {
|
||||||
ent = gameLocal.GetTraceEntity(tr);
|
ent = gameLocal.GetTraceEntity(tr);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
ent = NULL;
|
ent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3031,7 +3356,8 @@ void idWeapon::Event_Melee( void ) {
|
|||||||
|
|
||||||
ent->AddDamageEffect(tr, impulse, meleeDef->dict.GetString("classname"));
|
ent->AddDamageEffect(tr, impulse, meleeDef->dict.GetString("classname"));
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
int type = tr.c.material->GetSurfaceType();
|
int type = tr.c.material->GetSurfaceType();
|
||||||
if (type == SURFTYPE_NONE) {
|
if (type == SURFTYPE_NONE) {
|
||||||
@@ -3054,7 +3380,8 @@ void idWeapon::Event_Melee( void ) {
|
|||||||
gameLocal.ProjectDecal(tr.c.point, -tr.c.normal, 8.0f, true, 6.0, decal);
|
gameLocal.ProjectDecal(tr.c.point, -tr.c.normal, 8.0f, true, 6.0, decal);
|
||||||
}
|
}
|
||||||
nextStrikeFx = gameLocal.time + 200;
|
nextStrikeFx = gameLocal.time + 200;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
hitSound = "";
|
hitSound = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3096,7 +3423,8 @@ idWeapon::Event_AllowDrop
|
|||||||
void idWeapon::Event_AllowDrop(int allow) {
|
void idWeapon::Event_AllowDrop(int allow) {
|
||||||
if (allow) {
|
if (allow) {
|
||||||
allowDrop = true;
|
allowDrop = true;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
allowDrop = false;
|
allowDrop = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+352
-137
File diff suppressed because it is too large
Load Diff
@@ -519,6 +519,15 @@ void idAI::MuzzleFlash(const char* jointname) {
|
|||||||
idVec3 muzzle;
|
idVec3 muzzle;
|
||||||
idMat3 axis;
|
idMat3 axis;
|
||||||
|
|
||||||
|
// Match the idWeapon behavior: the short-lived muzzle light should attach
|
||||||
|
// to the same joint the script fired from, not blindly to a hardcoded joint.
|
||||||
|
if (jointname && jointname[0]) {
|
||||||
|
jointHandle_t joint = animator.GetJointHandle(jointname);
|
||||||
|
if (joint != INVALID_JOINT) {
|
||||||
|
flashJointWorld = joint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GetMuzzle(jointname, muzzle, axis);
|
GetMuzzle(jointname, muzzle, axis);
|
||||||
TriggerWeaponEffects(muzzle);
|
TriggerWeaponEffects(muzzle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2308,7 +2308,12 @@ cbuffer DrawCB : register(b0)
|
|||||||
// Full object-space displacement amplitude for the tessellation domain shader.
|
// Full object-space displacement amplitude for the tessellation domain shader.
|
||||||
// The CPU side keeps this conservative, but clamp here too so a bad material
|
// The CPU side keeps this conservative, but clamp here too so a bad material
|
||||||
// strength cannot explode the mesh.
|
// strength cannot explode the mesh.
|
||||||
#define gTessellationDisplacement clamp(gMaterialMapPad.w, 0.0, 0.35)
|
// Raised from the old 0.35 cap so stronger materials can push deeper, while
|
||||||
|
// the hull shader below uses shared-edge tess factors to prevent crack artifacts.
|
||||||
|
#define gTessellationDisplacement clamp(gMaterialMapPad.w, 0.0, 0.50)
|
||||||
|
#define QD3D12_TESS_MIN_FACTOR 2.0
|
||||||
|
#define QD3D12_TESS_MAX_FACTOR 15.0
|
||||||
|
#define QD3D12_TESS_TARGET_EDGE_PIXELS 28.0
|
||||||
|
|
||||||
Texture2D gTex0 : register(t0);
|
Texture2D gTex0 : register(t0);
|
||||||
Texture2D gTex1 : register(t1);
|
Texture2D gTex1 : register(t1);
|
||||||
@@ -2565,6 +2570,38 @@ float QD3D12_GetHeightFromNormalMapLOD(float2 uv, float lod)
|
|||||||
return QD3D12_HeightFromNormalSample(gNormalMap.SampleLevel(gSamp2, uv, lod));
|
return QD3D12_HeightFromNormalSample(gNormalMap.SampleLevel(gSamp2, uv, lod));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float2 QD3D12_NormalMapTexelSize()
|
||||||
|
{
|
||||||
|
uint w = 1;
|
||||||
|
uint h = 1;
|
||||||
|
gNormalMap.GetDimensions(w, h);
|
||||||
|
return rcp(max(float2((float)w, (float)h), float2(1.0, 1.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
float QD3D12_GetFilteredTessHeight(float2 uv)
|
||||||
|
{
|
||||||
|
// Hardware tessellation magnifies tiny normal-map compression errors.
|
||||||
|
// A light cross filter keeps the deeper displacement stable without
|
||||||
|
// blurring the color/normal sampling path used by the pixel shader.
|
||||||
|
float2 texel = QD3D12_NormalMapTexelSize();
|
||||||
|
float center = QD3D12_GetHeightFromNormalMapLOD(uv, 0.0);
|
||||||
|
float hx0 = QD3D12_GetHeightFromNormalMapLOD(uv - float2(texel.x, 0.0), 0.0);
|
||||||
|
float hx1 = QD3D12_GetHeightFromNormalMapLOD(uv + float2(texel.x, 0.0), 0.0);
|
||||||
|
float hy0 = QD3D12_GetHeightFromNormalMapLOD(uv - float2(0.0, texel.y), 0.0);
|
||||||
|
float hy1 = QD3D12_GetHeightFromNormalMapLOD(uv + float2(0.0, texel.y), 0.0);
|
||||||
|
return saturate(center * 0.50 + (hx0 + hx1 + hy0 + hy1) * 0.125);
|
||||||
|
}
|
||||||
|
|
||||||
|
float QD3D12_CleanCenteredTessHeight(float height)
|
||||||
|
{
|
||||||
|
// Suppress barely-visible single-texel noise before applying the now deeper
|
||||||
|
// displacement. This removes acne-like spikes while preserving real relief.
|
||||||
|
float centered = (height - 0.5) * 2.0;
|
||||||
|
float s = (centered < 0.0) ? -1.0 : 1.0;
|
||||||
|
float a = saturate((abs(centered) - 0.015) * (1.0 / 0.985));
|
||||||
|
return s * a;
|
||||||
|
}
|
||||||
|
|
||||||
float3 QD3D12_BuildFallbackTangent(float3 n)
|
float3 QD3D12_BuildFallbackTangent(float3 n)
|
||||||
{
|
{
|
||||||
float3 up = (abs(n.z) < 0.999) ? float3(0.0, 0.0, 1.0) : float3(0.0, 1.0, 0.0);
|
float3 up = (abs(n.z) < 0.999) ? float3(0.0, 0.0, 1.0) : float3(0.0, 1.0, 0.0);
|
||||||
@@ -2721,7 +2758,8 @@ float4 BuildGlowEmission(VSOut i)
|
|||||||
{
|
{
|
||||||
return QD3D12_SampleGlow(i);
|
return QD3D12_SampleGlow(i);
|
||||||
}
|
}
|
||||||
|
)HLSL"
|
||||||
|
R"HLSL(
|
||||||
float4 BuildSpecularAlbedo(VSOut i)
|
float4 BuildSpecularAlbedo(VSOut i)
|
||||||
{
|
{
|
||||||
if (gUseSpecularMap <= 0.0)
|
if (gUseSpecularMap <= 0.0)
|
||||||
@@ -2838,29 +2876,68 @@ TessCP QD3D12_MakeTessCP(VSOut i)
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
float QD3D12_ComputeNormalMapTessFactor(InputPatch<VSOut, 3> patch)
|
float2 QD3D12_ClipXYToNdc(float4 clipPos)
|
||||||
{
|
{
|
||||||
float h0 = QD3D12_GetHeightFromNormalMapLOD(patch[0].uv0, 0.0);
|
return clipPos.xy / max(abs(clipPos.w), 1.0e-6);
|
||||||
float h1 = QD3D12_GetHeightFromNormalMapLOD(patch[1].uv0, 0.0);
|
}
|
||||||
float h2 = QD3D12_GetHeightFromNormalMapLOD(patch[2].uv0, 0.0);
|
|
||||||
float heightRange = max(abs(h0 - h1), max(abs(h1 - h2), abs(h2 - h0)));
|
float QD3D12_EdgeLengthPixels(float4 clipA, float4 clipB)
|
||||||
|
{
|
||||||
|
float2 ndcA = QD3D12_ClipXYToNdc(clipA);
|
||||||
|
float2 ndcB = QD3D12_ClipXYToNdc(clipB);
|
||||||
|
return length((ndcA - ndcB) * max(gRenderSize, float2(1.0, 1.0)) * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
float QD3D12_ComputeNormalMapTessEdgeFactor(VSOut a, VSOut b)
|
||||||
|
{
|
||||||
|
if (gUseNormalMap <= 0.5)
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
|
float ha = QD3D12_GetFilteredTessHeight(a.uv0);
|
||||||
|
float hb = QD3D12_GetFilteredTessHeight(b.uv0);
|
||||||
|
float hm = QD3D12_GetFilteredTessHeight((a.uv0 + b.uv0) * 0.5);
|
||||||
|
|
||||||
|
// This edge-only factor is the crack fix: neighboring triangles that share
|
||||||
|
// this edge compute the same tessellation factor because they use only the
|
||||||
|
// two shared vertices and the same midpoint sample.
|
||||||
|
float heightRange = max(abs(ha - hb), abs(hm - (ha + hb) * 0.5) * 2.0);
|
||||||
|
float edgePixels = QD3D12_EdgeLengthPixels(a.currClip, b.currClip);
|
||||||
|
float uvSpan = length(a.uv0 - b.uv0);
|
||||||
|
|
||||||
// Give displaced normal-mapped surfaces enough subdivision to show the larger
|
|
||||||
// height push. fractional_odd will quantize these into stable odd partitions,
|
|
||||||
// so 3/5/7 are the practical quality tiers for default/strong materials.
|
|
||||||
float strength = clamp(max(gNormalMapStrength, 0.0), 0.0, 4.0);
|
float strength = clamp(max(gNormalMapStrength, 0.0), 0.0, 4.0);
|
||||||
float factor = 2.0 + strength * 1.0 + heightRange * 8.0;
|
float screenTerm = sqrt(max(edgePixels, 1.0) / QD3D12_TESS_TARGET_EDGE_PIXELS);
|
||||||
return (gUseNormalMap > 0.5) ? clamp(factor, 2.0, 7.0) : 1.0;
|
float heightTerm = heightRange * (10.0 + strength * 4.0);
|
||||||
|
float uvTerm = saturate(uvSpan * 4.0) * 2.0;
|
||||||
|
float displacementTerm = saturate(gTessellationDisplacement * 6.0) * 2.0;
|
||||||
|
|
||||||
|
float factor = 1.0 + strength * 0.75 + screenTerm * 3.0 + heightTerm + uvTerm + displacementTerm;
|
||||||
|
return clamp(factor, QD3D12_TESS_MIN_FACTOR, QD3D12_TESS_MAX_FACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
HSConstOut HSMainConstants(InputPatch<VSOut, 3> patch)
|
HSConstOut HSMainConstants(InputPatch<VSOut, 3> patch)
|
||||||
{
|
{
|
||||||
HSConstOut o;
|
HSConstOut o;
|
||||||
float factor = QD3D12_ComputeNormalMapTessFactor(patch);
|
|
||||||
o.edge[0] = factor;
|
if (gUseNormalMap <= 0.5)
|
||||||
o.edge[1] = factor;
|
{
|
||||||
o.edge[2] = factor;
|
o.edge[0] = 1.0;
|
||||||
o.inside = factor;
|
o.edge[1] = 1.0;
|
||||||
|
o.edge[2] = 1.0;
|
||||||
|
o.inside = 1.0;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
// D3D tri patch edge order is opposite the named control point:
|
||||||
|
// edge 0 = CP1-CP2, edge 1 = CP2-CP0, edge 2 = CP0-CP1.
|
||||||
|
float e0 = QD3D12_ComputeNormalMapTessEdgeFactor(patch[1], patch[2]);
|
||||||
|
float e1 = QD3D12_ComputeNormalMapTessEdgeFactor(patch[2], patch[0]);
|
||||||
|
float e2 = QD3D12_ComputeNormalMapTessEdgeFactor(patch[0], patch[1]);
|
||||||
|
float maxEdge = max(e0, max(e1, e2));
|
||||||
|
|
||||||
|
o.edge[0] = e0;
|
||||||
|
o.edge[1] = e1;
|
||||||
|
o.edge[2] = e2;
|
||||||
|
o.inside = clamp((e0 + e1 + e2 + maxEdge) * 0.25, QD3D12_TESS_MIN_FACTOR, QD3D12_TESS_MAX_FACTOR);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2869,6 +2946,7 @@ HSConstOut HSMainConstants(InputPatch<VSOut, 3> patch)
|
|||||||
[outputtopology("triangle_ccw")]
|
[outputtopology("triangle_ccw")]
|
||||||
[outputcontrolpoints(3)]
|
[outputcontrolpoints(3)]
|
||||||
[patchconstantfunc("HSMainConstants")]
|
[patchconstantfunc("HSMainConstants")]
|
||||||
|
[maxtessfactor(15.0)]
|
||||||
TessCP HSMain(InputPatch<VSOut, 3> patch, uint cpId : SV_OutputControlPointID)
|
TessCP HSMain(InputPatch<VSOut, 3> patch, uint cpId : SV_OutputControlPointID)
|
||||||
{
|
{
|
||||||
return QD3D12_MakeTessCP(patch[cpId]);
|
return QD3D12_MakeTessCP(patch[cpId]);
|
||||||
@@ -2911,8 +2989,8 @@ VSOut DSMain(HSConstOut tessFactors, float3 bary : SV_DomainLocation, const Outp
|
|||||||
VSOut o;
|
VSOut o;
|
||||||
|
|
||||||
float3 objNormal = QD3D12_SafeNormalize(i.objNormal, float3(0.0, 0.0, 1.0));
|
float3 objNormal = QD3D12_SafeNormalize(i.objNormal, float3(0.0, 0.0, 1.0));
|
||||||
float height = QD3D12_GetHeightFromNormalMapLOD(i.uv0, 0.0);
|
float height = QD3D12_GetFilteredTessHeight(i.uv0);
|
||||||
float centeredHeight = (height - 0.5) * 2.0;
|
float centeredHeight = QD3D12_CleanCenteredTessHeight(height);
|
||||||
float displacement = centeredHeight * gTessellationDisplacement;
|
float displacement = centeredHeight * gTessellationDisplacement;
|
||||||
float3 displacedObjPos = i.objPos + objNormal * displacement;
|
float3 displacedObjPos = i.objPos + objNormal * displacement;
|
||||||
|
|
||||||
@@ -7629,7 +7707,7 @@ static void QD3D12_FilterMipPixelGammaAware(
|
|||||||
center[1] /= centerA;
|
center[1] /= centerA;
|
||||||
center[2] /= centerA;
|
center[2] /= centerA;
|
||||||
|
|
||||||
const float sharpen = 0.22f;
|
const float sharpen = 1.0f;
|
||||||
filtered[0] = ClampValue<float>(filtered[0] + (center[0] - filtered[0]) * sharpen, 0.0f, 1.0f);
|
filtered[0] = ClampValue<float>(filtered[0] + (center[0] - filtered[0]) * sharpen, 0.0f, 1.0f);
|
||||||
filtered[1] = ClampValue<float>(filtered[1] + (center[1] - filtered[1]) * sharpen, 0.0f, 1.0f);
|
filtered[1] = ClampValue<float>(filtered[1] + (center[1] - filtered[1]) * sharpen, 0.0f, 1.0f);
|
||||||
filtered[2] = ClampValue<float>(filtered[2] + (center[2] - filtered[2]) * sharpen, 0.0f, 1.0f);
|
filtered[2] = ClampValue<float>(filtered[2] + (center[2] - filtered[2]) * sharpen, 0.0f, 1.0f);
|
||||||
@@ -8935,14 +9013,15 @@ static void QD3D12_FlushQueuedBatches()
|
|||||||
dc->materialMapPad[1] = batch.key.specularMapStrength;
|
dc->materialMapPad[1] = batch.key.specularMapStrength;
|
||||||
dc->materialMapPad[2] = QD3D12_PipelineUsesAlphaBlend(batch.key.pipeline) ? 1.0f : 0.0f;
|
dc->materialMapPad[2] = QD3D12_PipelineUsesAlphaBlend(batch.key.pipeline) ? 1.0f : 0.0f;
|
||||||
// Normal-map strength now drives a visibly stronger object-space displacement.
|
// Normal-map strength now drives a visibly stronger object-space displacement.
|
||||||
// Keep a hard upper bound because old RGB-only normal maps are often noisy and
|
// The hull shader can now subdivide much deeper, so the CPU side permits a
|
||||||
// are not authored as true height maps. Default strength 1.0 gives about
|
// deeper push too while the shader filters/suppresses tiny bump-map noise.
|
||||||
// +/-0.08 object units for authored alpha-height maps and outward lift for
|
// Default strength 1.0 gives about +/-0.12 object units for authored alpha
|
||||||
// RGB-only bump detail; glNormalMapStrengthf() can push it higher.
|
// height maps and outward lift for RGB-only bump detail; glNormalMapStrengthf()
|
||||||
|
// can push it higher up to the hard 0.50 object-unit safety cap.
|
||||||
const float tessStrength = ClampValue<float>(batch.key.normalMapStrength, 0.0f, 4.0f);
|
const float tessStrength = ClampValue<float>(batch.key.normalMapStrength, 0.0f, 4.0f);
|
||||||
const float tessDisplacementScale = 0.08f;
|
const float tessDisplacementScale = 0.12f;
|
||||||
dc->materialMapPad[3] = QD3D12_UseNormalMapTessellationPSO(batch.key, nativeColorOnly) ?
|
dc->materialMapPad[3] = QD3D12_UseNormalMapTessellationPSO(batch.key, nativeColorOnly) ?
|
||||||
ClampValue<float>(tessStrength * tessDisplacementScale, 0.0f, 0.35f) : 0.0f;
|
ClampValue<float>(tessStrength * tessDisplacementScale, 0.0f, 0.50f) : 0.0f;
|
||||||
|
|
||||||
if (batch.key.useARBPrograms)
|
if (batch.key.useARBPrograms)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ void RB_DXDrawInteractions(void)
|
|||||||
const float r = srcLight.shaderParms[SHADERPARM_RED];
|
const float r = srcLight.shaderParms[SHADERPARM_RED];
|
||||||
const float g = srcLight.shaderParms[SHADERPARM_GREEN];
|
const float g = srcLight.shaderParms[SHADERPARM_GREEN];
|
||||||
const float b = srcLight.shaderParms[SHADERPARM_BLUE];
|
const float b = srcLight.shaderParms[SHADERPARM_BLUE];
|
||||||
const float intensity = 6.0f;
|
const float intensity = 4.0f;
|
||||||
|
|
||||||
glRaytracingLight_t light = {};
|
glRaytracingLight_t light = {};
|
||||||
bool supported = true;
|
bool supported = true;
|
||||||
@@ -187,8 +187,8 @@ void RB_DXDrawInteractions(void)
|
|||||||
vLight->globalLightOrigin.x,
|
vLight->globalLightOrigin.x,
|
||||||
vLight->globalLightOrigin.y,
|
vLight->globalLightOrigin.y,
|
||||||
vLight->globalLightOrigin.z,
|
vLight->globalLightOrigin.z,
|
||||||
srcLight.lightRadius[0] * 1.4f,
|
srcLight.lightRadius[0] * 1.25f,
|
||||||
srcLight.lightRadius[1] * 1.4f,
|
srcLight.lightRadius[1] * 1.25f,
|
||||||
srcLight.lightRadius[2] * 1.4f,
|
srcLight.lightRadius[2] * 1.4f,
|
||||||
r, g, b,
|
r, g, b,
|
||||||
intensity);
|
intensity);
|
||||||
|
|||||||
Reference in New Issue
Block a user