2016-09-14 18:01:13 +00:00
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2004-2016 Christoph Oelckers
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
2013-06-23 07:49:34 +00:00
/*
* * a_dynlight . cpp
* * Implements actors representing dynamic lights ( hardware independent )
* *
2016-09-14 18:01:13 +00:00
* *
* * all functions marked with [ TS ] are licensed under
2013-06-23 07:49:34 +00:00
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2003 Timothy Stump
* * 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 .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
2016-03-21 01:57:02 +00:00
# include "gl/system/gl_system.h"
2013-06-23 07:49:34 +00:00
# include "templates.h"
# include "m_random.h"
# include "p_local.h"
# include "c_dispatch.h"
# include "g_level.h"
2016-11-15 10:49:27 +00:00
# include "scripting/thingdef.h"
2013-06-23 07:49:34 +00:00
# include "i_system.h"
2016-01-29 23:45:47 +00:00
# include "templates.h"
2016-02-16 21:01:04 +00:00
# include "doomdata.h"
# include "r_utility.h"
2016-12-06 17:35:34 +00:00
# include "p_local.h"
2016-03-08 20:22:12 +00:00
# include "portal.h"
2016-05-08 07:34:22 +00:00
# include "doomstat.h"
2016-09-23 23:47:44 +00:00
# include "serializer.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2013-06-23 07:49:34 +00:00
# include "gl/renderer/gl_renderer.h"
# include "gl/data/gl_data.h"
# include "gl/dynlights/gl_dynlight.h"
# include "gl/utility/gl_convert.h"
# include "gl/utility/gl_templates.h"
2017-01-02 10:41:27 +00:00
# include "gl/system//gl_interface.h"
2013-06-23 07:49:34 +00:00
2013-08-09 21:38:30 +00:00
EXTERN_CVAR ( Int , vid_renderer )
2013-06-23 07:49:34 +00:00
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY ( type , S , DynamicLight )
{
PROP_STRING_PARM ( str , 0 ) ;
static const char * ltype_names [ ] = {
" Point " , " Pulse " , " Flicker " , " Sector " , " RandomFlicker " , " ColorPulse " , " ColorFlicker " , " RandomColorFlicker " , NULL } ;
static const int ltype_values [ ] = {
PointLight , PulseLight , FlickerLight , SectorLight , RandomFlickerLight , ColorPulseLight , ColorFlickerLight , RandomColorFlickerLight } ;
int style = MatchString ( str , ltype_names ) ;
if ( style < 0 ) I_Error ( " Unknown light type '%s' " , str ) ;
defaults - > lighttype = ltype_values [ style ] ;
}
//==========================================================================
//
// Actor classes
//
// For flexibility all functionality has been packed into a single class
// which is controlled by flags
//
//==========================================================================
2017-01-13 22:17:04 +00:00
IMPLEMENT_CLASS ( ADynamicLight , false , false )
2013-06-23 07:49:34 +00:00
static FRandom randLight ;
//==========================================================================
//
// Base class
//
//==========================================================================
//==========================================================================
//
//
//
//==========================================================================
2016-09-23 23:47:44 +00:00
void ADynamicLight : : Serialize ( FSerializer & arc )
2013-06-23 07:49:34 +00:00
{
Super : : Serialize ( arc ) ;
2016-09-23 23:47:44 +00:00
auto def = static_cast < ADynamicLight * > ( GetDefault ( ) ) ;
arc ( " lightflags " , lightflags , def - > lightflags )
( " lighttype " , lighttype , def - > lighttype )
( " tickcount " , m_tickCount , def - > m_tickCount )
2017-01-18 18:10:25 +00:00
( " currentradius " , m_currentRadius , def - > m_currentRadius ) ;
2016-09-23 23:47:44 +00:00
if ( lighttype = = PulseLight )
arc ( " lastupdate " , m_lastUpdate , def - > m_lastUpdate )
( " cycler " , m_cycler , def - > m_cycler ) ;
2013-06-23 07:49:34 +00:00
}
2016-09-23 23:47:44 +00:00
void ADynamicLight : : PostSerialize ( )
{
Super : : PostSerialize ( ) ;
// The default constructor which is used for creating objects before deserialization will not set this variable.
// It needs to be true for all placed lights.
visibletoplayer = true ;
LinkLight ( ) ;
}
2013-06-23 07:49:34 +00:00
//==========================================================================
//
2016-09-14 18:01:13 +00:00
// [TS]
2013-06-23 07:49:34 +00:00
//
//==========================================================================
void ADynamicLight : : BeginPlay ( )
{
//Super::BeginPlay();
ChangeStatNum ( STAT_DLIGHT ) ;
2016-12-06 17:35:34 +00:00
specialf1 = DAngle ( double ( SpawnAngle ) ) . Normalized360 ( ) . Degrees ;
2016-05-04 09:33:18 +00:00
visibletoplayer = true ;
2017-01-02 10:41:27 +00:00
if ( gl . legacyMode & & ( flags4 & MF4_ATTENUATE ) )
{
2017-01-18 18:10:25 +00:00
args [ LIGHT_INTENSITY ] = args [ LIGHT_INTENSITY ] * 2 / 3 ;
args [ LIGHT_SECONDARY_INTENSITY ] = args [ LIGHT_SECONDARY_INTENSITY ] * 2 / 3 ;
2017-01-02 10:41:27 +00:00
}
2013-06-23 07:49:34 +00:00
}
//==========================================================================
//
2016-09-14 18:01:13 +00:00
// [TS]
2013-06-23 07:49:34 +00:00
//
//==========================================================================
void ADynamicLight : : PostBeginPlay ( )
{
Super : : PostBeginPlay ( ) ;
if ( ! ( SpawnFlags & MTF_DORMANT ) )
{
Activate ( NULL ) ;
}
2016-03-30 18:01:44 +00:00
subsector = R_PointInSubsector ( Pos ( ) ) ;
2013-06-23 07:49:34 +00:00
}
//==========================================================================
//
2016-09-14 18:01:13 +00:00
// [TS]
2013-06-23 07:49:34 +00:00
//
//==========================================================================
void ADynamicLight : : Activate ( AActor * activator )
{
//Super::Activate(activator);
flags2 & = ~ MF2_DORMANT ;
2017-01-18 18:10:25 +00:00
m_currentRadius = float ( args [ LIGHT_INTENSITY ] ) ;
2013-06-23 07:49:34 +00:00
m_tickCount = 0 ;
if ( lighttype = = PulseLight )
{
2016-12-06 17:35:34 +00:00
float pulseTime = specialf1 / TICRATE ;
2013-06-23 07:49:34 +00:00
m_lastUpdate = level . maptime ;
2017-01-18 18:10:25 +00:00
m_cycler . SetParams ( float ( args [ LIGHT_SECONDARY_INTENSITY ] ) , float ( args [ LIGHT_INTENSITY ] ) , pulseTime ) ;
2013-06-23 07:49:34 +00:00
m_cycler . ShouldCycle ( true ) ;
m_cycler . SetCycleType ( CYCLE_Sin ) ;
2016-12-23 14:25:39 +00:00
m_currentRadius = m_cycler . GetVal ( ) ;
2013-06-23 07:49:34 +00:00
}
2017-01-29 11:00:05 +00:00
if ( m_currentRadius < = 0 ) m_currentRadius = 1 ;
2013-06-23 07:49:34 +00:00
}
//==========================================================================
//
2016-09-14 18:01:13 +00:00
// [TS]
2013-06-23 07:49:34 +00:00
//
//==========================================================================
void ADynamicLight : : Deactivate ( AActor * activator )
{
//Super::Deactivate(activator);
flags2 | = MF2_DORMANT ;
}
//==========================================================================
//
2016-09-14 18:01:13 +00:00
// [TS]
2013-06-23 07:49:34 +00:00
//
//==========================================================================
void ADynamicLight : : Tick ( )
{
2013-08-09 21:38:30 +00:00
if ( vid_renderer = = 0 )
{
return ;
}
2013-06-23 07:49:34 +00:00
if ( IsOwned ( ) )
{
if ( ! target | | ! target - > state )
{
this - > Destroy ( ) ;
return ;
}
if ( target - > flags & MF_UNMORPHED ) return ;
2016-05-04 09:33:18 +00:00
visibletoplayer = target - > IsVisibleToPlayer ( ) ; // cache this value for the renderer to speed up calculations.
2013-06-23 07:49:34 +00:00
}
// Don't bother if the light won't be shown
if ( ! IsActive ( ) ) return ;
// I am doing this with a type field so that I can dynamically alter the type of light
// without having to create or maintain multiple objects.
switch ( lighttype )
{
case PulseLight :
{
float diff = ( level . maptime - m_lastUpdate ) / ( float ) TICRATE ;
m_lastUpdate = level . maptime ;
m_cycler . Update ( diff ) ;
2016-04-17 11:53:29 +00:00
m_currentRadius = m_cycler . GetVal ( ) ;
2013-06-23 07:49:34 +00:00
break ;
}
case FlickerLight :
{
BYTE rnd = randLight ( ) ;
2016-12-06 17:35:34 +00:00
float pct = specialf1 / 360.f ;
2013-06-23 07:49:34 +00:00
2017-01-18 18:10:25 +00:00
m_currentRadius = float ( args [ LIGHT_INTENSITY + ( rnd > = pct * 255 ) ] ) ;
2013-06-23 07:49:34 +00:00
break ;
}
case RandomFlickerLight :
{
2017-01-18 18:10:25 +00:00
int flickerRange = args [ LIGHT_SECONDARY_INTENSITY ] - args [ LIGHT_INTENSITY ] ;
2013-06-23 07:49:34 +00:00
float amt = randLight ( ) / 255.f ;
2016-12-06 17:35:34 +00:00
if ( m_tickCount > specialf1 )
2013-06-23 07:49:34 +00:00
{
m_tickCount = 0 ;
}
2017-01-18 18:10:25 +00:00
if ( m_tickCount + + = = 0 | | m_currentRadius > args [ LIGHT_SECONDARY_INTENSITY ] )
2016-12-06 17:35:34 +00:00
{
2017-01-18 18:10:25 +00:00
m_currentRadius = float ( args [ LIGHT_INTENSITY ] + ( amt * flickerRange ) ) ;
2016-12-06 17:35:34 +00:00
}
2013-06-23 07:49:34 +00:00
break ;
}
#if 0
// These need some more work elsewhere
case ColorFlickerLight :
{
BYTE rnd = randLight ( ) ;
2016-12-06 17:35:34 +00:00
float pct = specialf1 / 360.f ;
2013-06-23 07:49:34 +00:00
2016-04-17 11:53:29 +00:00
m_currentRadius = m_Radius [ rnd > = pct * 255 ] ;
2013-06-23 07:49:34 +00:00
break ;
}
case RandomColorFlickerLight :
{
2017-01-18 18:10:25 +00:00
int flickerRange = args [ LIGHT_SECONDARY_INTENSITY ] - args [ LIGHT_INTENSITY ] ;
2013-06-23 07:49:34 +00:00
float amt = randLight ( ) / 255.f ;
m_tickCount + + ;
2016-12-06 17:35:34 +00:00
if ( m_tickCount > specialf1 )
2013-06-23 07:49:34 +00:00
{
2017-01-18 18:10:25 +00:00
m_currentRadius = args [ LIGHT_INTENSITY ] + ( amt * flickerRange ) ;
2013-06-23 07:49:34 +00:00
m_tickCount = 0 ;
}
break ;
}
# endif
case SectorLight :
{
float intensity ;
float scale = args [ LIGHT_SCALE ] / 8.f ;
if ( scale = = 0.f ) scale = 1.f ;
intensity = Sector - > lightlevel * scale ;
intensity = clamp < float > ( intensity , 0.f , 255.f ) ;
2016-04-17 11:53:29 +00:00
m_currentRadius = intensity ;
2013-06-23 07:49:34 +00:00
break ;
}
case PointLight :
2017-01-18 18:10:25 +00:00
m_currentRadius = float ( args [ LIGHT_INTENSITY ] ) ;
2013-06-23 07:49:34 +00:00
break ;
}
2017-01-29 11:00:05 +00:00
if ( m_currentRadius < = 0 ) m_currentRadius = 1 ;
2013-06-23 07:49:34 +00:00
UpdateLocation ( ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void ADynamicLight : : UpdateLocation ( )
{
2016-03-21 01:57:02 +00:00
double oldx = X ( ) ;
double oldy = Y ( ) ;
double oldradius = radius ;
2013-06-23 07:49:34 +00:00
float intensity ;
if ( IsActive ( ) )
{
if ( target )
{
2016-03-24 12:38:37 +00:00
DAngle angle = target - > Angles . Yaw ;
double s = angle . Sin ( ) ;
double c = angle . Cos ( ) ;
DVector3 pos = target - > Vec3Offset ( m_off . X * c + m_off . Y * s , m_off . X * s - m_off . Y * c , m_off . Z + target - > GetBobOffset ( ) ) ;
2016-01-21 11:36:37 +00:00
SetXYZ ( pos ) ; // attached lights do not need to go into the regular blockmap
2016-03-29 09:26:33 +00:00
Prev = target - > Pos ( ) ;
2016-03-30 18:01:44 +00:00
subsector = R_PointInSubsector ( Prev ) ;
2013-06-23 07:49:34 +00:00
Sector = subsector - > sector ;
2016-10-03 14:21:50 +00:00
// Some z-coordinate fudging to prevent the light from getting too close to the floor or ceiling planes. With proper attenuation this would render them invisible.
// A distance of 5 is needed so that the light's effect doesn't become too small.
if ( Z ( ) < target - > floorz + 5. ) SetZ ( target - > floorz + 5. ) ;
else if ( Z ( ) > target - > ceilingz - 5. ) SetZ ( target - > ceilingz - 5. ) ;
}
else
{
if ( Z ( ) < floorz + 5. ) SetZ ( floorz + 5. ) ;
else if ( Z ( ) > ceilingz - 5. ) SetZ ( ceilingz - 5. ) ;
2013-06-23 07:49:34 +00:00
}
// The radius being used here is always the maximum possible with the
// current settings. This avoids constant relinking of flickering lights
2016-04-12 14:01:08 +00:00
if ( lighttype = = FlickerLight | | lighttype = = RandomFlickerLight | | lighttype = = PulseLight )
2013-06-23 07:49:34 +00:00
{
2017-01-18 18:10:25 +00:00
intensity = float ( MAX ( args [ LIGHT_INTENSITY ] , args [ LIGHT_SECONDARY_INTENSITY ] ) ) ;
2013-06-23 07:49:34 +00:00
}
else
{
2016-04-17 11:53:29 +00:00
intensity = m_currentRadius ;
2013-06-23 07:49:34 +00:00
}
2016-09-04 10:45:09 +00:00
radius = intensity * 2.0f ;
2016-12-06 17:35:34 +00:00
assert ( radius > = m_currentRadius * 2 ) ;
2013-06-23 07:49:34 +00:00
2016-03-21 01:57:02 +00:00
if ( X ( ) ! = oldx | | Y ( ) ! = oldy | | radius ! = oldradius )
2013-06-23 07:49:34 +00:00
{
//Update the light lists
LinkLight ( ) ;
}
}
}
//==========================================================================
//
//
//
//==========================================================================
2016-02-02 10:58:00 +00:00
2016-04-03 10:54:47 +00:00
void ADynamicLight : : SetOrigin ( double x , double y , double z , bool moving )
2016-02-02 10:58:00 +00:00
{
Super : : SetOrigin ( x , y , z , moving ) ;
LinkLight ( ) ;
}
//==========================================================================
//
//
//
//==========================================================================
2016-03-24 12:38:37 +00:00
void ADynamicLight : : SetOffset ( const DVector3 & pos )
2013-06-23 07:49:34 +00:00
{
2016-03-24 12:38:37 +00:00
m_off = pos ;
2013-06-23 07:49:34 +00:00
UpdateLocation ( ) ;
}
//==========================================================================
//
// The target pointer in dynamic lights should never be substituted unless
// notOld is NULL (which indicates that the object was destroyed by force.)
//
//==========================================================================
size_t ADynamicLight : : PointerSubstitution ( DObject * old , DObject * notOld )
{
AActor * saved_target = target ;
size_t ret = Super : : PointerSubstitution ( old , notOld ) ;
if ( notOld ! = NULL ) target = saved_target ;
return ret ;
}
//=============================================================================
//
// These have been copied from the secnode code and modified for the light links
//
// P_AddSecnode() searches the current list to see if this sector is
// already there. If not, it adds a sector node at the head of the list of
// sectors this object appears in. This is called when creating a list of
// nodes that will get linked in later. Returns a pointer to the new node.
//
//=============================================================================
FLightNode * AddLightNode ( FLightNode * * thread , void * linkto , ADynamicLight * light , FLightNode * & nextnode )
{
FLightNode * node ;
node = nextnode ;
while ( node )
{
if ( node - > targ = = linkto ) // Already have a node for this sector?
{
node - > lightsource = light ; // Yes. Setting m_thing says 'keep it'.
return ( nextnode ) ;
}
node = node - > nextTarget ;
}
// Couldn't find an existing node for this sector. Add one at the head
// of the list.
2014-09-21 10:40:08 +00:00
node = new FLightNode ;
2013-06-23 07:49:34 +00:00
node - > targ = linkto ;
node - > lightsource = light ;
node - > prevTarget = & nextnode ;
node - > nextTarget = nextnode ;
if ( nextnode ) nextnode - > prevTarget = & node - > nextTarget ;
// Add new node at head of sector thread starting at s->touching_thinglist
node - > prevLight = thread ;
node - > nextLight = * thread ;
if ( node - > nextLight ) node - > nextLight - > prevLight = & node - > nextLight ;
* thread = node ;
return ( node ) ;
}
//=============================================================================
//
// P_DelSecnode() deletes a sector node from the list of
// sectors this object appears in. Returns a pointer to the next node
// on the linked list, or NULL.
//
//=============================================================================
static FLightNode * DeleteLightNode ( FLightNode * node )
{
FLightNode * tn ; // next node on thing thread
if ( node )
{
* node - > prevTarget = node - > nextTarget ;
if ( node - > nextTarget ) node - > nextTarget - > prevTarget = node - > prevTarget ;
* node - > prevLight = node - > nextLight ;
if ( node - > nextLight ) node - > nextLight - > prevLight = node - > prevLight ;
// Return this node to the freelist
tn = node - > nextTarget ;
2014-09-21 10:40:08 +00:00
delete node ;
2013-06-23 07:49:34 +00:00
return ( tn ) ;
}
return ( NULL ) ;
} // phares 3/13/98
//==========================================================================
//
// Gets the light's distance to a line
//
//==========================================================================
2016-03-30 18:01:44 +00:00
double ADynamicLight : : DistToSeg ( const DVector3 & pos , seg_t * seg )
2013-06-23 07:49:34 +00:00
{
2016-03-29 09:26:33 +00:00
double u , px , py ;
2013-06-23 07:49:34 +00:00
2016-03-29 09:26:33 +00:00
double seg_dx = seg - > v2 - > fX ( ) - seg - > v1 - > fX ( ) ;
double seg_dy = seg - > v2 - > fY ( ) - seg - > v1 - > fY ( ) ;
double seg_length_sq = seg_dx * seg_dx + seg_dy * seg_dy ;
2013-06-23 07:49:34 +00:00
2016-04-08 10:38:09 +00:00
u = ( ( ( pos . X - seg - > v1 - > fX ( ) ) * seg_dx ) + ( pos . Y - seg - > v1 - > fY ( ) ) * seg_dy ) / seg_length_sq ;
2016-03-29 09:26:33 +00:00
if ( u < 0. ) u = 0. ; // clamp the test point to the line segment
2016-03-30 18:01:44 +00:00
else if ( u > 1. ) u = 1. ;
2013-06-23 07:49:34 +00:00
2016-03-29 09:26:33 +00:00
px = seg - > v1 - > fX ( ) + ( u * seg_dx ) ;
py = seg - > v1 - > fY ( ) + ( u * seg_dy ) ;
2013-06-23 07:49:34 +00:00
2016-03-30 18:01:44 +00:00
px - = pos . X ;
py - = pos . Y ;
2013-06-23 07:49:34 +00:00
2016-03-08 20:22:12 +00:00
return ( px * px ) + ( py * py ) ;
2013-06-23 07:49:34 +00:00
}
//==========================================================================
//
// Collect all touched sidedefs and subsectors
// to sidedefs and sector parts.
//
//==========================================================================
2016-12-08 11:49:40 +00:00
struct LightLinkEntry
{
subsector_t * sub ;
DVector3 pos ;
} ;
static TArray < LightLinkEntry > collected_ss ;
2013-06-23 07:49:34 +00:00
2016-12-08 11:49:40 +00:00
void ADynamicLight : : CollectWithinRadius ( const DVector3 & opos , subsector_t * subSec , float radius )
2013-06-23 07:49:34 +00:00
{
if ( ! subSec ) return ;
2016-12-08 11:49:40 +00:00
collected_ss . Clear ( ) ;
collected_ss . Push ( { subSec , opos } ) ;
2013-06-23 07:49:34 +00:00
subSec - > validcount = : : validcount ;
2016-12-08 11:49:40 +00:00
for ( unsigned i = 0 ; i < collected_ss . Size ( ) ; i + + )
2014-05-11 20:57:42 +00:00
{
2016-12-08 11:49:40 +00:00
subSec = collected_ss [ i ] . sub ;
2013-06-23 07:49:34 +00:00
2016-12-08 11:49:40 +00:00
touching_subsectors = AddLightNode ( & subSec - > lighthead , subSec , this , touching_subsectors ) ;
if ( subSec - > sector - > validcount ! = : : validcount )
{
touching_sector = AddLightNode ( & subSec - > render_sector - > lighthead , subSec - > sector , this , touching_sector ) ;
subSec - > sector - > validcount = : : validcount ;
}
2013-06-23 07:49:34 +00:00
2016-12-26 09:39:03 +00:00
for ( unsigned int j = 0 ; j < subSec - > numlines ; + + j )
2013-06-23 07:49:34 +00:00
{
2016-12-26 09:39:03 +00:00
auto & pos = collected_ss [ i ] . pos ;
seg_t * seg = subSec - > firstline + j ;
2016-12-08 11:49:40 +00:00
// check distance from x/y to seg and if within radius add this seg and, if present the opposing subsector (lather/rinse/repeat)
// If out of range we do not need to bother with this seg.
if ( DistToSeg ( pos , seg ) < = radius )
2013-06-23 07:49:34 +00:00
{
2016-12-08 11:49:40 +00:00
if ( seg - > sidedef & & seg - > linedef & & seg - > linedef - > validcount ! = : : validcount )
2016-04-08 10:38:09 +00:00
{
2016-12-08 11:49:40 +00:00
// light is in front of the seg
if ( ( pos . Y - seg - > v1 - > fY ( ) ) * ( seg - > v2 - > fX ( ) - seg - > v1 - > fX ( ) ) + ( seg - > v1 - > fX ( ) - pos . X ) * ( seg - > v2 - > fY ( ) - seg - > v1 - > fY ( ) ) < = 0 )
{
seg - > linedef - > validcount = validcount ;
touching_sides = AddLightNode ( & seg - > sidedef - > lighthead , seg - > sidedef , this , touching_sides ) ;
}
2016-04-08 10:38:09 +00:00
}
2016-12-08 11:49:40 +00:00
if ( seg - > linedef )
2016-03-08 20:22:12 +00:00
{
2016-12-08 11:49:40 +00:00
FLinePortal * port = seg - > linedef - > getPortal ( ) ;
if ( port & & port - > mType = = PORTT_LINKED )
2016-03-08 20:22:12 +00:00
{
2016-12-08 11:49:40 +00:00
line_t * other = port - > mDestination ;
if ( other - > validcount ! = : : validcount )
{
subsector_t * othersub = R_PointInSubsector ( other - > v1 - > fPos ( ) + other - > Delta ( ) / 2 ) ;
if ( othersub - > validcount ! = : : validcount )
{
othersub - > validcount = : : validcount ;
collected_ss . Push ( { othersub , PosRelative ( other ) } ) ;
}
}
2016-03-08 20:22:12 +00:00
}
}
2013-06-23 07:49:34 +00:00
2016-12-08 11:49:40 +00:00
seg_t * partner = seg - > PartnerSeg ;
if ( partner )
2013-06-23 07:49:34 +00:00
{
2016-12-08 11:49:40 +00:00
subsector_t * sub = partner - > Subsector ;
if ( sub ! = NULL & & sub - > validcount ! = : : validcount )
{
sub - > validcount = : : validcount ;
collected_ss . Push ( { sub , pos } ) ;
}
2013-06-23 07:49:34 +00:00
}
}
}
2016-12-08 11:49:40 +00:00
sector_t * sec = subSec - > sector ;
if ( ! sec - > PortalBlocksSight ( sector_t : : ceiling ) )
2016-03-08 20:22:12 +00:00
{
2016-12-08 11:49:40 +00:00
line_t * other = subSec - > firstline - > linedef ;
if ( sec - > GetPortalPlaneZ ( sector_t : : ceiling ) < Z ( ) + radius )
{
DVector2 refpos = other - > v1 - > fPos ( ) + other - > Delta ( ) / 2 + sec - > GetPortalDisplacement ( sector_t : : ceiling ) ;
subsector_t * othersub = R_PointInSubsector ( refpos ) ;
if ( othersub - > validcount ! = : : validcount )
{
othersub - > validcount = : : validcount ;
collected_ss . Push ( { othersub , PosRelative ( othersub - > sector ) } ) ;
}
}
2016-03-08 20:22:12 +00:00
}
2016-12-08 11:49:40 +00:00
if ( ! sec - > PortalBlocksSight ( sector_t : : floor ) )
2016-03-08 20:22:12 +00:00
{
2016-12-08 11:49:40 +00:00
line_t * other = subSec - > firstline - > linedef ;
if ( sec - > GetPortalPlaneZ ( sector_t : : floor ) > Z ( ) - radius )
{
DVector2 refpos = other - > v1 - > fPos ( ) + other - > Delta ( ) / 2 + sec - > GetPortalDisplacement ( sector_t : : floor ) ;
subsector_t * othersub = R_PointInSubsector ( refpos ) ;
if ( othersub - > validcount ! = : : validcount )
{
othersub - > validcount = : : validcount ;
collected_ss . Push ( { othersub , PosRelative ( othersub - > sector ) } ) ;
}
}
2016-03-08 20:22:12 +00:00
}
}
2013-06-23 07:49:34 +00:00
}
//==========================================================================
//
// Link the light into the world
//
//==========================================================================
void ADynamicLight : : LinkLight ( )
{
// mark the old light nodes
FLightNode * node ;
node = touching_sides ;
while ( node )
{
node - > lightsource = NULL ;
node = node - > nextTarget ;
}
node = touching_subsectors ;
while ( node )
{
node - > lightsource = NULL ;
node = node - > nextTarget ;
}
2014-05-11 20:57:42 +00:00
node = touching_sector ;
while ( node )
{
node - > lightsource = NULL ;
node = node - > nextTarget ;
}
2013-06-23 07:49:34 +00:00
if ( radius > 0 )
{
2016-03-30 18:01:44 +00:00
// passing in radius*radius allows us to do a distance check without any calls to sqrt
subsector_t * subSec = R_PointInSubsector ( Pos ( ) ) ;
2016-03-08 20:22:12 +00:00
: : validcount + + ;
2016-03-30 18:01:44 +00:00
CollectWithinRadius ( Pos ( ) , subSec , radius * radius ) ;
2016-03-08 20:22:12 +00:00
2013-06-23 07:49:34 +00:00
}
// Now delete any nodes that won't be used. These are the ones where
// m_thing is still NULL.
node = touching_sides ;
while ( node )
{
if ( node - > lightsource = = NULL )
{
node = DeleteLightNode ( node ) ;
}
else
node = node - > nextTarget ;
}
node = touching_subsectors ;
while ( node )
{
if ( node - > lightsource = = NULL )
{
node = DeleteLightNode ( node ) ;
}
else
node = node - > nextTarget ;
}
2014-05-11 20:57:42 +00:00
node = touching_sector ;
while ( node )
{
if ( node - > lightsource = = NULL )
{
node = DeleteLightNode ( node ) ;
}
else
node = node - > nextTarget ;
}
2013-06-23 07:49:34 +00:00
}
//==========================================================================
//
// Deletes the link lists
//
//==========================================================================
void ADynamicLight : : UnlinkLight ( )
{
if ( owned & & target ! = NULL )
{
// Delete reference in owning actor
for ( int c = target - > dynamiclights . Size ( ) - 1 ; c > = 0 ; c - - )
{
if ( target - > dynamiclights [ c ] = = this )
{
target - > dynamiclights . Delete ( c ) ;
break ;
}
}
}
while ( touching_sides ) touching_sides = DeleteLightNode ( touching_sides ) ;
while ( touching_subsectors ) touching_subsectors = DeleteLightNode ( touching_subsectors ) ;
2014-09-21 10:40:08 +00:00
while ( touching_sector ) touching_sector = DeleteLightNode ( touching_sector ) ;
2013-06-23 07:49:34 +00:00
}
2017-01-12 21:49:18 +00:00
void ADynamicLight : : OnDestroy ( )
2013-06-23 07:49:34 +00:00
{
UnlinkLight ( ) ;
2017-01-12 21:49:18 +00:00
Super : : OnDestroy ( ) ;
2013-06-23 07:49:34 +00:00
}
//==========================================================================
//
// Needed for garbage collection
//
//==========================================================================
size_t AActor : : PropagateMark ( )
{
for ( unsigned i = 0 ; i < dynamiclights . Size ( ) ; i + + )
{
GC : : Mark ( dynamiclights [ i ] ) ;
}
return Super : : PropagateMark ( ) ;
}
CCMD ( listlights )
{
2014-05-11 20:57:42 +00:00
int walls , sectors , subsecs ;
int allwalls = 0 , allsectors = 0 , allsubsecs = 0 ;
2013-06-23 07:49:34 +00:00
int i = 0 ;
ADynamicLight * dl ;
TThinkerIterator < ADynamicLight > it ;
while ( ( dl = it . Next ( ) ) )
{
walls = 0 ;
sectors = 0 ;
2014-05-11 20:57:42 +00:00
subsecs = 0 ;
2013-06-23 07:49:34 +00:00
Printf ( " %s at (%f, %f, %f), color = 0x%02x%02x%02x, radius = %f " ,
dl - > target ? dl - > target - > GetClass ( ) - > TypeName . GetChars ( ) : dl - > GetClass ( ) - > TypeName . GetChars ( ) ,
2016-03-21 01:57:02 +00:00
dl - > X ( ) , dl - > Y ( ) , dl - > Z ( ) , dl - > args [ LIGHT_RED ] ,
dl - > args [ LIGHT_GREEN ] , dl - > args [ LIGHT_BLUE ] , dl - > radius ) ;
2013-06-23 07:49:34 +00:00
i + + ;
if ( dl - > target )
{
FTextureID spr = gl_GetSpriteFrame ( dl - > target - > sprite , dl - > target - > frame , 0 , 0 , NULL ) ;
2014-06-01 07:27:16 +00:00
Printf ( " , frame = %s " , TexMan [ spr ] - > Name . GetChars ( ) ) ;
2013-06-23 07:49:34 +00:00
}
FLightNode * node ;
node = dl - > touching_sides ;
while ( node )
{
walls + + ;
allwalls + + ;
node = node - > nextTarget ;
}
node = dl - > touching_subsectors ;
2014-05-11 20:57:42 +00:00
while ( node )
{
allsubsecs + + ;
subsecs + + ;
node = node - > nextTarget ;
}
node = dl - > touching_sector ;
2013-06-23 07:49:34 +00:00
while ( node )
{
allsectors + + ;
sectors + + ;
node = node - > nextTarget ;
}
2014-05-11 20:57:42 +00:00
Printf ( " - %d walls, %d subsectors, %d sectors \n " , walls , subsecs , sectors ) ;
2013-06-23 07:49:34 +00:00
}
2014-05-11 20:57:42 +00:00
Printf ( " %i dynamic lights, %d walls, %d subsectors, %d sectors \n \n \n " , i , allwalls , allsubsecs , allsectors ) ;
2013-06-23 07:49:34 +00:00
}
CCMD ( listsublights )
{
for ( int i = 0 ; i < numsubsectors ; i + + )
{
subsector_t * sub = & subsectors [ i ] ;
int lights = 0 ;
2014-07-15 18:49:21 +00:00
FLightNode * node = sub - > lighthead ;
2013-06-23 07:49:34 +00:00
while ( node ! = NULL )
{
lights + + ;
node = node - > nextLight ;
}
2014-07-15 18:49:21 +00:00
Printf ( PRINT_LOG , " Subsector %d - %d lights \n " , i , lights ) ;
2013-06-23 07:49:34 +00:00
}
}
2014-09-21 10:40:08 +00:00