2006-03-20 16:43:15 +00:00
|
|
|
/*
|
2014-06-01 17:55:23 +00:00
|
|
|
* Portions of this file are copyright Rebirth contributors and licensed as
|
|
|
|
* described in COPYING.txt.
|
|
|
|
* Portions of this file are copyright Parallax Software and licensed
|
|
|
|
* according to the Parallax license below.
|
|
|
|
* See COPYING.txt for license details.
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
|
|
|
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
|
|
|
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
|
|
|
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
|
|
|
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
|
|
|
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
|
|
|
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
|
|
|
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
2010-12-24 04:26:24 +00:00
|
|
|
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
2006-03-20 16:43:15 +00:00
|
|
|
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
|
|
*/
|
2008-04-06 20:23:28 +00:00
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
/*
|
|
|
|
*
|
2008-04-06 20:23:28 +00:00
|
|
|
* Editor lighting functions.
|
2006-03-20 16:43:15 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "inferno.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "editor.h"
|
2013-03-16 03:10:55 +00:00
|
|
|
#include "editor/esegment.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
#include "seguvs.h"
|
|
|
|
#include "wall.h"
|
|
|
|
#include "textures.h"
|
2012-07-01 02:54:33 +00:00
|
|
|
#include "maths.h"
|
2012-07-07 18:35:06 +00:00
|
|
|
#include "dxxerror.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
#include "kdefs.h"
|
|
|
|
#include "gameseg.h"
|
|
|
|
#include "texmap.h"
|
|
|
|
|
2014-10-12 23:10:05 +00:00
|
|
|
#include "compiler-range_for.h"
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Return light intensity at an instance of a vertex on a side in a segment.
|
2018-06-24 05:06:15 +00:00
|
|
|
static fix get_light_intensity(const unique_side &s, const uint_fast32_t vert)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
Assert(vert <= 3);
|
2015-06-13 22:42:19 +00:00
|
|
|
return s.uvls[vert].l;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2015-06-13 22:42:19 +00:00
|
|
|
static fix get_light_intensity(const vcsegptr_t segp, const uint_fast32_t sidenum, const uint_fast32_t vert)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
Assert(sidenum <= MAX_SIDES_PER_SEGMENT);
|
2015-06-13 22:42:19 +00:00
|
|
|
return get_light_intensity(segp->sides[sidenum], vert);
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2015-06-13 22:42:19 +00:00
|
|
|
static fix clamp_light_intensity(const fix intensity)
|
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
if (intensity < MIN_LIGHTING_VALUE)
|
2015-06-13 22:42:19 +00:00
|
|
|
return MIN_LIGHTING_VALUE;
|
2006-03-20 16:43:15 +00:00
|
|
|
if (intensity > MAX_LIGHTING_VALUE)
|
2015-06-13 22:42:19 +00:00
|
|
|
return MAX_LIGHTING_VALUE;
|
|
|
|
return intensity;
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2015-06-13 22:42:19 +00:00
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Set light intensity at a vertex, saturating in .5 to 15.5
|
2018-06-24 05:06:15 +00:00
|
|
|
static void set_light_intensity(unique_side &s, const uint_fast32_t vert, const fix intensity)
|
2015-06-13 22:42:19 +00:00
|
|
|
{
|
|
|
|
Assert(vert <= 3);
|
|
|
|
s.uvls[vert].l = clamp_light_intensity(intensity);
|
2006-03-20 16:43:15 +00:00
|
|
|
Update_flags |= UF_WORLD_CHANGED;
|
|
|
|
}
|
|
|
|
|
2017-06-10 03:31:02 +00:00
|
|
|
static void set_light_intensity(const vmsegptr_t segp, const uint_fast32_t sidenum, const uint_fast32_t vert, const fix intensity)
|
2015-06-13 22:42:19 +00:00
|
|
|
{
|
|
|
|
Assert(sidenum <= MAX_SIDES_PER_SEGMENT);
|
|
|
|
set_light_intensity(segp->sides[sidenum], vert, intensity);
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Add light intensity to a vertex, saturating in .5 to 15.5
|
2018-06-24 05:06:15 +00:00
|
|
|
static void add_light_intensity_all_verts(unique_side &s, const fix intensity)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2015-06-13 22:42:19 +00:00
|
|
|
range_for (auto &u, s.uvls)
|
|
|
|
u.l = clamp_light_intensity(u.l + intensity);
|
|
|
|
Update_flags |= UF_WORLD_CHANGED;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Recursively apply light to segments.
|
|
|
|
// If current side is a wall, apply light there.
|
|
|
|
// If not a wall, apply light to child through that wall.
|
|
|
|
// Notes:
|
|
|
|
// It is possible to enter a segment twice by taking different paths. It is easy
|
|
|
|
// to prevent this by maintaining a list of visited segments, but it is important
|
|
|
|
// to reach segments with the greatest light intensity. This can be done by doing
|
|
|
|
// a breadth-first-search, or by storing the applied intensity with a visited segment,
|
|
|
|
// and if the current intensity is brighter, then apply the difference between it and
|
|
|
|
// the previous intensity.
|
|
|
|
// Note that it is also possible to visit the original light-casting segment, for example
|
|
|
|
// going from segment 0 to 2, then from 2 to 0. This is peculiar and probably not
|
|
|
|
// desired, but not entirely invalid. 2 reflects some light back to 0.
|
2017-06-10 03:31:02 +00:00
|
|
|
static void apply_light_intensity(const vmsegptr_t segp, int sidenum, fix intensity, int depth)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
if (intensity == 0)
|
|
|
|
return;
|
|
|
|
|
2014-09-06 22:26:11 +00:00
|
|
|
auto wid_result = WALL_IS_DOORWAY(segp, sidenum);
|
|
|
|
if (!(wid_result & WID_RENDPAST_FLAG)) {
|
2015-06-13 22:42:19 +00:00
|
|
|
add_light_intensity_all_verts(segp->sides[sidenum], intensity);
|
2006-03-20 16:43:15 +00:00
|
|
|
return; // we return because there is a wall here, and light does not shine through walls
|
|
|
|
}
|
|
|
|
|
|
|
|
// No wall here, so apply light recursively
|
|
|
|
if (depth < 3) {
|
2015-06-13 22:42:19 +00:00
|
|
|
intensity /= 3;
|
|
|
|
if (!intensity)
|
|
|
|
return;
|
2017-06-10 03:31:02 +00:00
|
|
|
const auto &&csegp = vmsegptr(segp->children[sidenum]);
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
|
2015-06-13 22:42:19 +00:00
|
|
|
apply_light_intensity(csegp, s, intensity, depth+1);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Top level recursive function for applying light.
|
|
|
|
// Calls apply_light_intensity.
|
|
|
|
// Uses light value on segp:sidenum (tmap_num2 defines light value) and applies
|
|
|
|
// the associated intensity to segp. It calls apply_light_intensity to apply intensity/3
|
|
|
|
// to all neighbors. apply_light_intensity recursively calls itself to apply light to
|
|
|
|
// subsequent neighbors (and forming loops, see above).
|
2017-06-10 03:31:02 +00:00
|
|
|
static void propagate_light_intensity(const vmsegptr_t segp, int sidenum)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
fix intensity;
|
|
|
|
short texmap;
|
|
|
|
|
|
|
|
intensity = 0;
|
|
|
|
texmap = segp->sides[sidenum].tmap_num;
|
|
|
|
intensity += TmapInfo[texmap].lighting;
|
|
|
|
texmap = (segp->sides[sidenum].tmap_num2) & 0x3fff;
|
|
|
|
intensity += TmapInfo[texmap].lighting;
|
|
|
|
|
|
|
|
if (intensity > 0) {
|
2015-06-13 22:42:19 +00:00
|
|
|
add_light_intensity_all_verts(segp->sides[sidenum], intensity);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
// Now, for all sides which are not the same as sidenum (the side casting the light),
|
|
|
|
// add a light value to them (if they have no children, ie, they have a wall there).
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
|
2006-03-20 16:43:15 +00:00
|
|
|
if (s != sidenum)
|
|
|
|
apply_light_intensity(segp, s, intensity/2, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Highest level function, bound to a key. Apply ambient light to all segments based
|
|
|
|
// on user-defined light sources.
|
|
|
|
int LightAmbientLighting()
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
range_for (const auto &&segp, vmsegptr)
|
2015-06-13 22:42:16 +00:00
|
|
|
{
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int side=0;side<MAX_SIDES_PER_SEGMENT;side++)
|
2015-06-13 22:42:16 +00:00
|
|
|
propagate_light_intensity(segp, side);
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightSelectNextVertex(void)
|
|
|
|
{
|
|
|
|
Curvert++;
|
|
|
|
if (Curvert >= 4)
|
|
|
|
Curvert = 0;
|
|
|
|
|
|
|
|
Update_flags |= UF_WORLD_CHANGED;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightSelectNextEdge(void)
|
|
|
|
{
|
|
|
|
Curedge++;
|
|
|
|
if (Curedge >= 4)
|
|
|
|
Curedge = 0;
|
|
|
|
|
|
|
|
Update_flags |= UF_WORLD_CHANGED;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Copy intensity from current vertex to all other vertices on side.
|
|
|
|
int LightCopyIntensity(void)
|
|
|
|
{
|
2014-09-26 02:42:11 +00:00
|
|
|
int intensity;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2015-07-12 01:04:18 +00:00
|
|
|
intensity = get_light_intensity(segp, Curside, Curvert);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int v=0; v<4; v++)
|
2006-03-20 16:43:15 +00:00
|
|
|
if (v != Curvert)
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, Curside, v, intensity);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// Copy intensity from current vertex to all other vertices on side.
|
|
|
|
int LightCopyIntensitySegment(void)
|
|
|
|
{
|
2014-09-26 02:42:11 +00:00
|
|
|
int intensity;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2015-07-12 01:04:18 +00:00
|
|
|
intensity = get_light_intensity(segp, Curside, Curvert);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
|
|
|
|
for (int v=0; v<4; v++)
|
2006-03-20 16:43:15 +00:00
|
|
|
if ((s != Curside) || (v != Curvert))
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, s, v, intensity);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightDecreaseLightVertex(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, Curside, Curvert, get_light_intensity(segp, Curside, Curvert) - F1_0 / NUM_LIGHTING_LEVELS);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightIncreaseLightVertex(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, Curside, Curvert, get_light_intensity(segp, Curside, Curvert) + F1_0 / NUM_LIGHTING_LEVELS);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightDecreaseLightSide(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int v=0; v<4; v++)
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, Curside, v, get_light_intensity(segp, Curside, v) - F1_0 / NUM_LIGHTING_LEVELS);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightIncreaseLightSide(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int v=0; v<4; v++)
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, Curside, v, get_light_intensity(segp, Curside, v) + F1_0 / NUM_LIGHTING_LEVELS);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightDecreaseLightSegment(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
|
|
|
|
for (int v=0; v<4; v++)
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, s, v, get_light_intensity(segp, s, v) - F1_0 / NUM_LIGHTING_LEVELS);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightIncreaseLightSegment(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
|
|
|
|
for (int v=0; v<4; v++)
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, s, v, get_light_intensity(segp, s, v) + F1_0 / NUM_LIGHTING_LEVELS);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightSetDefault(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int v=0; v<4; v++)
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, Curside, v, DEFAULT_LIGHTING);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightSetMaximum(void)
|
|
|
|
{
|
2017-06-10 03:31:02 +00:00
|
|
|
const vmsegptr_t segp = Cursegp;
|
2014-09-26 02:42:11 +00:00
|
|
|
for (int v=0; v<4; v++)
|
2015-07-12 01:04:18 +00:00
|
|
|
set_light_intensity(segp, Curside, v, (NUM_LIGHTING_LEVELS - 1) * F1_0 / NUM_LIGHTING_LEVELS);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
int LightSetDefaultAll(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
assign_default_lighting_all();
|
|
|
|
|
|
|
|
Update_flags |= UF_WORLD_CHANGED;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|