point_spotlight: initial implementation of this Half-Life 2 entity; also fix env_projectedtexture, func_dustmotes and func_smokevolume not rendering

This commit is contained in:
Marco Cawthorne 2023-09-12 15:00:56 -07:00
parent 071548a000
commit 59748adf86
Signed by: eukara
GPG Key ID: CE2032F0A2882A22
14 changed files with 369 additions and 50 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -0,0 +1,16 @@
// Vera Visions Material
{
surfaceParm trans
surfaceParm nomarks
surfaceParm nolightmap
surfaceParm nonsolid
cull none
{
clampmap "textures/sfx/cone.tga"
rgbGen vertex
alphaGen vertex
blendFunc blend
}
}

View File

@ -0,0 +1,15 @@
// Vera Visions Material
{
surfaceParm trans
surfaceParm nomarks
surfaceParm nolightmap
surfaceParm nonsolid
cull none
{
clampmap "textures/sfx/spot_flare.tga"
rgbGen vertex
blendFunc add
}
}

View File

@ -117,6 +117,9 @@ Entity_EntityUpdate(float type, float new)
}
ept.ReceiveEntity(new, readfloat());
break;
case ENT_SPOTLIGHT:
point_spotlight_ReadEntity(new);
break;
case ENT_FOG:
env_fog_readentity(new);
break;

View File

@ -85,6 +85,7 @@ func_dustmotes::Spawned(void)
setorigin(this, origin);
movetype = MOVETYPE_NONE;
m_iCount = vlen(size) / 10;
drawmask = MASK_ENGINE;
}
void

View File

@ -171,6 +171,7 @@ func_smokevolume::Spawned(void)
setmodel(this, model);
setorigin(this, origin);
movetype = MOVETYPE_NONE;
drawmask = MASK_ENGINE;
if (m_iCount == -1)
m_iCount = (int)(vlen(size) / 100);

View File

@ -67,6 +67,7 @@ public:
virtual void Restore(string,string);
virtual void SpawnKey(string,string);
virtual void Trigger(entity, triggermode_t);
virtual void Input(entity, string, string);
};
@ -208,3 +209,15 @@ game_text::Trigger(entity act, triggermode_t state)
multicast(origin, MULTICAST_ONE_R);
}
}
void
game_text::Input(entity eAct, string strInput, string strData)
{
switch (strInput) {
case "Display":
Trigger(eAct, TRIG_ON);
break;
default:
Input(eAct, strInput, strData);
}
}

View File

@ -26,6 +26,7 @@ shared/info_particle_system.qc
shared/info_waypoint.qc
shared/prop_physics_multiplayer.qc
shared/prop_vehicle_driveable.qc
shared/point_spotlight.qc
shared/trigger_push.qc
shared/func_conveyor.qc
shared/prop_rope.qc

View File

@ -183,25 +183,16 @@ env_bubbles::Trigger(entity eAct, triggermode_t iState)
void
env_bubbles::EvaluateEntity(void)
{
if (ATTR_CHANGED(origin))
SetSendFlags(BUBBLES_ORIGIN);
if (ATTR_CHANGED(angles))
SetSendFlags(BUBBLES_ANGLES);
if (ATTR_CHANGED(m_iDensity))
SetSendFlags(BUBBLES_DENSITY);
if (ATTR_CHANGED(m_flFrequency))
SetSendFlags(BUBBLES_FREQUENCY);
if (ATTR_CHANGED(m_flCurrent))
SetSendFlags(BUBBLES_CURRENT);
if (ATTR_CHANGED(m_bEnabled))
SetSendFlags(BUBBLES_ENABLED);
SAVE_STATE(origin)
SAVE_STATE(angles)
SAVE_STATE(m_iDensity)
SAVE_STATE(m_flFrequency)
SAVE_STATE(m_flCurrent)
SAVE_STATE(m_bEnabled)
EVALUATE_VECTOR(origin, 0, BUBBLES_ORIGIN)
EVALUATE_VECTOR(origin, 1, BUBBLES_ORIGIN)
EVALUATE_VECTOR(origin, 2, BUBBLES_ORIGIN)
EVALUATE_VECTOR(angles, 0, BUBBLES_ANGLES)
EVALUATE_VECTOR(angles, 1, BUBBLES_ANGLES)
EVALUATE_VECTOR(angles, 2, BUBBLES_ANGLES)
EVALUATE_FIELD(m_iDensity, BUBBLES_DENSITY)
EVALUATE_FIELD(m_flFrequency, BUBBLES_FREQUENCY)
EVALUATE_FIELD(m_flCurrent, BUBBLES_CURRENT)
EVALUATE_FIELD(m_bEnabled, BUBBLES_ENABLED)
}
float
env_bubbles::SendEntity(entity ePVSent, float flChanged)

View File

@ -151,6 +151,7 @@ env_projectedtexture::ReceiveEntity(float flNew, float flFlags)
m_strPattern = readstring();
classname = "env_projectedtexture";
drawmask = MASK_ENGINE;
}
#else
void

View File

@ -0,0 +1,307 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
enumflags
{
PNTSPTLGHT_CHANGED_ORIGIN,
PNTSPTLGHT_CHANGED_ANGLES,
PNTSPTLGHT_CHANGED_COLOR,
PNTSPTLGHT_CHANGED_LENGTH,
PNTSPTLGHT_CHANGED_WIDTH,
PNTSPTLGHT_CHANGED_STATE,
};
/*!QUAKED point_spotlight (1 .5 0) (-8 -8 -8) (8 8 8) PNTSPTLGHT_STARTON PNTSPTLGHT_NOLIGHT
# OVERVIEW
An entity that draws a spotlight, with beam. Will also spawn a dynamic light, unless specifically disabled via the spawnflags field.
# KEYS
- "targetname" : Name
- "target" : Name of an entity in the map that light will point at.
- "spotlightlength" : Beam length
- "spotlightwidth" : Beam width
- "rendercolor" : Beam color
- "HDRColorScale" : Multiplier that's active when running in HDR (unused)
# INPUTS
- "LightOff" : Turns the entity off.
- "LightOn" : Turns the entity on.
# SPAWNFLAGS
- PNTSPTLGHT_STARTON (1) : Start enabled.
- PNTSPTLGHT_NOLIGHT (2) : No dynamic light
# TRIVIA
This entity was introduced in Half-Life 2 (2004).
*/
class point_spotlight:NSPointTrigger
{
private:
PREDICTED_VECTOR(m_vecRenderColor)
PREDICTED_FLOAT(m_flBeamLength)
PREDICTED_FLOAT(m_flBeamWidth)
PREDICTED_INT(m_iState)
public:
void point_spotlight(void);
#ifdef CLIENT
virtual void ReceiveEntity(float,float);
virtual float predraw(void);
#else
virtual void Trigger(entity, triggermode_t);
virtual void Respawn(void);
virtual float SendEntity(entity,float);
virtual void SpawnKey(string,string);
virtual void EvaluateEntity(void);
virtual void Input(entity, string, string);
#endif
};
#ifdef CLIENT
float
point_spotlight::predraw(void)
{
if (!m_iState) {
return (PREDRAW_NEXT);
}
/* beams */
{
vector vecPlayer = g_view.GetCameraOrigin();
vector vecAngle = g_view.GetCameraAngle();
float coneAlpha = 1.0f;
float beamWidth = m_flBeamWidth / 2;
vector beamColor = m_vecRenderColor / 255;
float beamDist = 0.0f;
/* corona */
if (vecAngle[0] < 0)
coneAlpha = bound(0.0, fabs(vecAngle[0]) / 60.0f, 1.0);
else
coneAlpha = 0.0f;
if (coneAlpha > 0.0) {
makevectors(vectoangles(origin - vecPlayer));
R_BeginPolygon("textures/sfx/spot_flare");
R_PolygonVertex(origin + v_right * beamWidth - v_up * beamWidth,
[1,1], beamColor * coneAlpha, 1.0f);
R_PolygonVertex(origin - v_right * beamWidth - v_up * beamWidth,
[0,1], beamColor * coneAlpha, 1.0f);
R_PolygonVertex(origin - v_right * beamWidth + v_up * beamWidth,
[0,0], beamColor * coneAlpha, 1.0f);
R_PolygonVertex(origin + v_right * beamWidth + v_up * beamWidth,
[1,0], beamColor * coneAlpha, 1.0f);
R_EndPolygon();
}
if (vecAngle[0] < 0)
coneAlpha = bound(0.0, fabs(vecAngle[0]) / 45.0f, 1.0);
else
coneAlpha = 0.0f;
coneAlpha = (1.0 - coneAlpha) * 0.5f;
/* beam */
if (coneAlpha > 0.0) {
vecPlayer[2] = origin[2];
makevectors(vectoangles(origin - vecPlayer));
/* figure out the end pos */
other = world;
traceline(origin, origin - [0, 0, m_flBeamLength], MOVE_OTHERONLY, this);
beamDist = fabs(trace_plane_dist);
R_BeginPolygon("textures/sfx/spot_cone");
R_PolygonVertex(origin + (v_right * beamWidth) - (v_up * beamDist),
[1,1], beamColor, coneAlpha);
R_PolygonVertex(origin - (v_right * beamWidth) - (v_up * beamDist),
[0,1], beamColor, coneAlpha);
R_PolygonVertex(origin - (v_right * beamWidth),
[0,0], beamColor, coneAlpha);
R_PolygonVertex(origin + (v_right * beamWidth),
[1,0], beamColor, coneAlpha);
R_EndPolygon();
}
}
/* skip dlight */
if (m_iState == 2)
return (PREDRAW_NEXT);
makevectors(angles);
/* TODO: We need to handle the second cone light */
float p = dynamiclight_add(origin, m_flBeamLength, m_vecRenderColor / 255, 0, "textures/flashlight");
dynamiclight_set(p, LFIELD_ANGLES, angles);
dynamiclight_set(p, LFIELD_FLAGS, LFLAG_NORMALMODE | LFLAG_REALTIMEMODE | LFLAG_SHADOWMAP);
//dynamiclight_set(p, LFIELD_NEARCLIP, 0);
//dynamiclight_set(p, LFIELD_STYLESTRING, m_strPattern);
return (PREDRAW_NEXT);
}
void
point_spotlight::ReceiveEntity(float flNew, float flChanged)
{
READENTITY_COORD(origin[0], PNTSPTLGHT_CHANGED_ORIGIN)
READENTITY_COORD(origin[1], PNTSPTLGHT_CHANGED_ORIGIN)
READENTITY_COORD(origin[2], PNTSPTLGHT_CHANGED_ORIGIN)
READENTITY_ANGLE(angles[0], PNTSPTLGHT_CHANGED_ANGLES)
READENTITY_ANGLE(angles[1], PNTSPTLGHT_CHANGED_ANGLES)
READENTITY_ANGLE(angles[2], PNTSPTLGHT_CHANGED_ANGLES)
READENTITY_BYTE(m_vecRenderColor[0], PNTSPTLGHT_CHANGED_COLOR)
READENTITY_BYTE(m_vecRenderColor[1], PNTSPTLGHT_CHANGED_COLOR)
READENTITY_BYTE(m_vecRenderColor[2], PNTSPTLGHT_CHANGED_COLOR)
READENTITY_FLOAT(m_flBeamLength, PNTSPTLGHT_CHANGED_LENGTH)
READENTITY_FLOAT(m_flBeamWidth, PNTSPTLGHT_CHANGED_WIDTH)
READENTITY_BYTE(m_iState, PNTSPTLGHT_CHANGED_STATE)
setorigin(this, origin);
classname = "point_spotlight";
drawmask = MASK_ENGINE;
}
#else
void
point_spotlight::EvaluateEntity(void)
{
EVALUATE_VECTOR(origin, 0, PNTSPTLGHT_CHANGED_ORIGIN)
EVALUATE_VECTOR(origin, 1, PNTSPTLGHT_CHANGED_ORIGIN)
EVALUATE_VECTOR(origin, 2, PNTSPTLGHT_CHANGED_ORIGIN)
EVALUATE_VECTOR(angles, 0, PNTSPTLGHT_CHANGED_ANGLES)
EVALUATE_VECTOR(angles, 1, PNTSPTLGHT_CHANGED_ANGLES)
EVALUATE_VECTOR(angles, 2, PNTSPTLGHT_CHANGED_ANGLES)
EVALUATE_FIELD(m_flBeamLength, PNTSPTLGHT_CHANGED_LENGTH)
EVALUATE_FIELD(m_flBeamWidth, PNTSPTLGHT_CHANGED_WIDTH)
EVALUATE_FIELD(m_iState, PNTSPTLGHT_CHANGED_STATE)
}
void
point_spotlight::Trigger(entity act, triggermode_t state)
{
switch (state) {
case TRIG_OFF:
m_iState = 0;
break;
case TRIG_ON:
m_iState = 1;
break;
default:
m_iState = 1 - m_iState;
}
if (m_iState && HasSpawnFlags(2))
m_iState = 2;
SendFlags |= PNTSPTLGHT_CHANGED_STATE;
}
float
point_spotlight::SendEntity(entity ePEnt, float flChanged)
{
if (clienttype(ePEnt) != CLIENTTYPE_REAL)
return (0);
WriteByte(MSG_ENTITY, ENT_SPOTLIGHT);
WriteFloat(MSG_ENTITY, flChanged);
SENDENTITY_COORD(origin[0], PNTSPTLGHT_CHANGED_ORIGIN)
SENDENTITY_COORD(origin[1], PNTSPTLGHT_CHANGED_ORIGIN)
SENDENTITY_COORD(origin[2], PNTSPTLGHT_CHANGED_ORIGIN)
SENDENTITY_ANGLE(angles[0], PNTSPTLGHT_CHANGED_ANGLES)
SENDENTITY_ANGLE(angles[1], PNTSPTLGHT_CHANGED_ANGLES)
SENDENTITY_ANGLE(angles[2], PNTSPTLGHT_CHANGED_ANGLES)
SENDENTITY_BYTE(m_vecRenderColor[0], PNTSPTLGHT_CHANGED_COLOR)
SENDENTITY_BYTE(m_vecRenderColor[1], PNTSPTLGHT_CHANGED_COLOR)
SENDENTITY_BYTE(m_vecRenderColor[2], PNTSPTLGHT_CHANGED_COLOR)
SENDENTITY_FLOAT(m_flBeamLength, PNTSPTLGHT_CHANGED_LENGTH)
SENDENTITY_FLOAT(m_flBeamWidth, PNTSPTLGHT_CHANGED_WIDTH)
SENDENTITY_BYTE(m_iState, PNTSPTLGHT_CHANGED_STATE)
return (1);
}
void
point_spotlight::Input(entity eAct, string strInput, string strData)
{
switch (strInput) {
case "LightOn":
Trigger(eAct, TRIG_ON);
break;
case "LightOff":
Trigger(eAct, TRIG_OFF);
break;
case "Toggle":
Trigger(eAct, TRIG_TOGGLE);
break;
default:
super::Input(eAct, strInput, strData);
}
}
void
point_spotlight::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "rendercolor":
m_vecRenderColor = stov(strValue);
break;
case "spotlightlength":
m_flBeamLength = stof(strValue);
break;
case "spotlightwidth":
m_flBeamWidth = stof(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
void
point_spotlight::Respawn(void)
{
SetSolid(SOLID_NOT);
SetSize([-16,-16,-16], [16,16,16]);
SetOrigin(GetSpawnOrigin());
SetAngles(GetSpawnAngles());
m_iState = HasSpawnFlags(1) ? 1 : 0;
if (m_iState && HasSpawnFlags(2))
m_iState = 2;
}
#endif
void
point_spotlight::point_spotlight(void)
{
#ifndef CLIENT
m_flBeamLength = 500.0f;
m_flBeamWidth = 50.0f;
m_vecRenderColor = [255,255,255];
#endif
}
#ifdef CLIENT
void
point_spotlight_ReadEntity(float isNew)
{
point_spotlight ept = (point_spotlight)self;
if (isNew) {
spawnfunc_point_spotlight();
}
ept.ReceiveEntity(isNew, readfloat());
}
#endif

View File

@ -381,41 +381,10 @@ initents(void)
MOTD_Init();
PMove_Init();
/* TODO: turn these effects into sound shaders */
precache_sound("weapons/explode3.wav");
precache_sound("weapons/explode4.wav");
precache_sound("weapons/explode5.wav");
precache_sound("debris/glass1.wav");
precache_sound("debris/glass2.wav");
precache_sound("debris/glass3.wav");
precache_sound("debris/wood1.wav");
precache_sound("debris/wood2.wav");
precache_sound("debris/wood3.wav");
precache_sound("debris/metal1.wav");
precache_sound("debris/metal2.wav");
precache_sound("debris/metal3.wav");
precache_sound("debris/flesh1.wav");
precache_sound("debris/flesh2.wav");
precache_sound("debris/flesh3.wav");
precache_sound("debris/flesh5.wav");
precache_sound("debris/flesh6.wav");
precache_sound("debris/flesh7.wav");
precache_sound("debris/concrete1.wav");
precache_sound("debris/concrete2.wav");
precache_sound("debris/concrete3.wav");
/** compat... */
precache_sound("misc/null.wav");
precache_sound("common/null.wav");
precache_sound("player/pl_fallpain3.wav");
precache_sound("items/9mmclip1.wav");
precache_sound("items/gunpickup2.wav");
precache_sound("common/wpn_select.wav");
precache_sound("common/wpn_denyselect.wav");
precache_sound("player/sprayer.wav");
precache_sound("items/flashlight1.wav");
Sound_Precache("player.gasplight");
Sound_Precache("player.gaspheavy");
Sound_Precache("player.waterenter");

View File

@ -33,6 +33,7 @@ typedef enum
ENT_BEAM, /**< of type env_beam */
ENT_DLIGHT, /**< of type light_dynamic */
ENT_PROJECTEDTEXTURE, /**< of type env_projectedtexture */
ENT_SPOTLIGHT, /**< of type point_spotlight */
ENT_FOG, /*<< of type env_fog */
ENT_FOGCONTROLLER, /**< of type env_fog_controller */
ENT_LASER, /**< of type env_laser */