2013-06-23 07:49:34 +00:00
|
|
|
/*
|
2017-03-12 15:56:00 +00:00
|
|
|
** _gl_dynlight.cpp
|
2013-06-23 07:49:34 +00:00
|
|
|
** Light definitions for actors.
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
** Copyright 2003 Timothy Stump
|
|
|
|
** Copyright 2005 Christoph Oelckers
|
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
**
|
|
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "doomtype.h"
|
|
|
|
#include "c_cvars.h"
|
|
|
|
#include "c_dispatch.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "sc_man.h"
|
|
|
|
#include "templates.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
#include "gi.h"
|
|
|
|
#include "r_state.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "zstring.h"
|
|
|
|
#include "d_dehacked.h"
|
2017-01-01 23:28:30 +00:00
|
|
|
#include "v_text.h"
|
2017-01-08 17:45:30 +00:00
|
|
|
#include "g_levellocals.h"
|
2017-03-12 15:56:00 +00:00
|
|
|
#include "a_dynlight.h"
|
2017-03-17 20:12:09 +00:00
|
|
|
#include "textures/skyboxtexture.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Dehacked aliasing
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2016-02-05 11:31:41 +00:00
|
|
|
inline PClassActor * GetRealType(PClassActor * ti)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2016-02-05 11:31:41 +00:00
|
|
|
PClassActor *rep = ti->GetReplacement(false);
|
2017-02-08 14:47:22 +00:00
|
|
|
if (rep != ti && rep != NULL && rep->IsDescendantOf(NAME_DehackedPickup))
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2016-02-05 11:31:41 +00:00
|
|
|
return rep;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
return ti;
|
|
|
|
}
|
|
|
|
|
2017-03-12 19:04:46 +00:00
|
|
|
TDeletingArray<FLightDefaults *> LightDefaults;
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
FLightDefaults::FLightDefaults(FName name, ELightType type)
|
|
|
|
{
|
|
|
|
m_Name = name;
|
|
|
|
m_type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FLightDefaults::ApplyProperties(ADynamicLight * light) const
|
|
|
|
{
|
2016-12-23 14:25:39 +00:00
|
|
|
auto oldtype = light->lighttype;
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
light->lighttype = m_type;
|
2016-12-06 17:35:34 +00:00
|
|
|
light->specialf1 = m_Param;
|
2016-03-24 12:38:37 +00:00
|
|
|
light->SetOffset(m_Pos);
|
2013-06-23 07:49:34 +00:00
|
|
|
light->halo = m_halo;
|
2016-09-04 10:45:09 +00:00
|
|
|
for (int a = 0; a < 3; a++) light->args[a] = clamp<int>((int)(m_Args[a]), 0, 255);
|
2017-03-01 19:54:37 +00:00
|
|
|
light->args[LIGHT_INTENSITY] = m_Args[LIGHT_INTENSITY];
|
|
|
|
light->args[LIGHT_SECONDARY_INTENSITY] = m_Args[LIGHT_SECONDARY_INTENSITY];
|
2017-06-18 08:15:31 +00:00
|
|
|
light->lightflags &= ~(LF_ADDITIVE | LF_SUBTRACTIVE | LF_DONTLIGHTSELF);
|
|
|
|
if (m_subtractive) light->lightflags |= LF_SUBTRACTIVE;
|
|
|
|
if (m_additive) light->lightflags |= LF_ADDITIVE;
|
|
|
|
if (m_dontlightself) light->lightflags |= LF_DONTLIGHTSELF;
|
|
|
|
if (m_dontlightactors) light->lightflags |= LF_DONTLIGHTACTORS;
|
2018-01-04 16:58:11 +00:00
|
|
|
if (m_spot)
|
|
|
|
light->lightflags |= LF_SPOT;
|
|
|
|
light->SpotInnerAngle = m_spotInnerAngle;
|
|
|
|
light->SpotOuterAngle = m_spotOuterAngle;
|
2016-12-06 17:35:34 +00:00
|
|
|
light->m_tickCount = 0;
|
2016-12-23 14:25:39 +00:00
|
|
|
if (m_type == PulseLight)
|
|
|
|
{
|
|
|
|
float pulseTime = float(m_Param / TICRATE);
|
|
|
|
|
|
|
|
light->m_lastUpdate = level.maptime;
|
2017-03-01 19:54:37 +00:00
|
|
|
if (m_swapped) light->m_cycler.SetParams(float(light->args[LIGHT_SECONDARY_INTENSITY]), float(light->args[LIGHT_INTENSITY]), pulseTime, oldtype == PulseLight);
|
|
|
|
else light->m_cycler.SetParams(float(light->args[LIGHT_INTENSITY]), float(light->args[LIGHT_SECONDARY_INTENSITY]), pulseTime, oldtype == PulseLight);
|
2016-12-23 14:25:39 +00:00
|
|
|
light->m_cycler.ShouldCycle(true);
|
|
|
|
light->m_cycler.SetCycleType(CYCLE_Sin);
|
2017-03-12 15:56:00 +00:00
|
|
|
light->m_currentRadius = (float)light->m_cycler.GetVal();
|
2017-01-29 11:00:05 +00:00
|
|
|
if (light->m_currentRadius <= 0) light->m_currentRadius = 1;
|
2017-03-01 19:54:37 +00:00
|
|
|
light->swapped = m_swapped;
|
2016-12-23 14:25:39 +00:00
|
|
|
}
|
|
|
|
|
2016-12-07 22:17:18 +00:00
|
|
|
switch (m_attenuate)
|
|
|
|
{
|
2017-06-18 08:15:31 +00:00
|
|
|
case 0: light->lightflags &= ~LF_ATTENUATE; break;
|
|
|
|
case 1: light->lightflags |= LF_ATTENUATE; break;
|
|
|
|
default: if (level.flags3 & LEVEL3_ATTENUATE) light->lightflags |= LF_ATTENUATE; else light->lightflags &= ~LF_ATTENUATE; break;
|
2016-12-07 22:17:18 +00:00
|
|
|
}
|
|
|
|
}
|
2013-06-23 07:49:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// light definition file parser
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
|
|
extern int ScriptDepth;
|
|
|
|
|
2018-04-02 10:28:20 +00:00
|
|
|
void AddLightDefaults(FLightDefaults *defaults)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
|
|
|
FLightDefaults *temp;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
// remove duplicates
|
|
|
|
for (i = 0; i < LightDefaults.Size(); i++)
|
|
|
|
{
|
|
|
|
temp = LightDefaults[i];
|
|
|
|
if (temp->GetName() == defaults->GetName())
|
|
|
|
{
|
|
|
|
delete temp;
|
|
|
|
LightDefaults.Delete(i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LightDefaults.Push(defaults);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FInternalLightAssociation::FInternalLightAssociation(FLightAssociation * asso)
|
|
|
|
{
|
|
|
|
|
|
|
|
m_AssocLight=NULL;
|
|
|
|
for(unsigned int i=0;i<LightDefaults.Size();i++)
|
|
|
|
{
|
|
|
|
if (LightDefaults[i]->GetName() == asso->Light())
|
|
|
|
{
|
|
|
|
m_AssocLight = LightDefaults[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_sprite=-1;
|
|
|
|
m_frame = -1;
|
|
|
|
for (unsigned i = 0; i < sprites.Size (); ++i)
|
|
|
|
{
|
|
|
|
if (strncmp (sprites[i].name, asso->FrameName(), 4) == 0)
|
|
|
|
{
|
|
|
|
m_sprite = (int)i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only handle lights for full frames.
|
|
|
|
// I won't bother with special lights for single rotations
|
|
|
|
// because there is no decent use for them!
|
|
|
|
if (strlen(asso->FrameName())==5 || asso->FrameName()[5]=='0')
|
|
|
|
{
|
|
|
|
m_frame = toupper(asso->FrameName()[4])-'A';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// State lights
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2018-04-02 10:28:20 +00:00
|
|
|
static TArray<FName> ParsedStateLights;
|
2013-06-23 07:49:34 +00:00
|
|
|
TArray<FLightDefaults *> StateLights;
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2018-04-02 10:28:20 +00:00
|
|
|
void InitializeActorLights(TArray<FLightAssociation> &LightAssociations)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
|
|
|
for(unsigned int i=0;i<LightAssociations.Size();i++)
|
|
|
|
{
|
2016-02-05 11:31:41 +00:00
|
|
|
PClassActor * ti = PClass::FindActor(LightAssociations[i].ActorName());
|
2013-06-23 07:49:34 +00:00
|
|
|
if (ti)
|
|
|
|
{
|
|
|
|
ti = GetRealType(ti);
|
2017-03-12 15:56:00 +00:00
|
|
|
// put this in the class data arena so that we do not have to worry about deleting it ourselves.
|
|
|
|
void *mem = ClassDataAllocator.Alloc(sizeof(FInternalLightAssociation));
|
|
|
|
FInternalLightAssociation * iasso = new(mem) FInternalLightAssociation(&LightAssociations[i]);
|
|
|
|
if (iasso->Light() != nullptr)
|
2017-04-11 17:37:56 +00:00
|
|
|
ti->ActorInfo()->LightAssociations.Push(iasso);
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StateLights.Resize(ParsedStateLights.Size()+1);
|
|
|
|
for(unsigned i=0; i<ParsedStateLights.Size();i++)
|
|
|
|
{
|
|
|
|
if (ParsedStateLights[i] != NAME_None)
|
|
|
|
{
|
|
|
|
StateLights[i] = (FLightDefaults*)-1; // something invalid that's not NULL.
|
|
|
|
for(unsigned int j=0;j<LightDefaults.Size();j++)
|
|
|
|
{
|
|
|
|
if (LightDefaults[j]->GetName() == ParsedStateLights[i])
|
|
|
|
{
|
|
|
|
StateLights[i] = LightDefaults[j];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else StateLights[i] = NULL;
|
|
|
|
}
|
|
|
|
StateLights[StateLights.Size()-1] = NULL; // terminator
|
|
|
|
ParsedStateLights.Clear();
|
|
|
|
ParsedStateLights.ShrinkToFit();
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void AddStateLight(FState *State, const char *lname)
|
|
|
|
{
|
|
|
|
if (State->Light == 0)
|
|
|
|
{
|
|
|
|
ParsedStateLights.Push(NAME_None);
|
|
|
|
State->Light = ParsedStateLights.Push(FName(lname));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ParsedStateLights.Push(FName(lname));
|
|
|
|
}
|
|
|
|
}
|