Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Editor lighting functions.
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include "inferno.h"
  28. #include "segment.h"
  29. #include "editor.h"
  30. #include "editor/esegment.h"
  31. #include "seguvs.h"
  32. #include "wall.h"
  33. #include "textures.h"
  34. #include "maths.h"
  35. #include "dxxerror.h"
  36. #include "kdefs.h"
  37. #include "gameseg.h"
  38. #include "texmap.h"
  39.  
  40. #include "compiler-range_for.h"
  41. #include "d_range.h"
  42.  
  43. // -----------------------------------------------------------------------------
  44. //      Return light intensity at an instance of a vertex on a side in a segment.
  45. static fix get_light_intensity(const unique_side &s, const uint_fast32_t vert)
  46. {
  47.         Assert(vert <= 3);
  48.         return s.uvls[vert].l;
  49. }
  50.  
  51. static fix get_light_intensity(const unique_segment &segp, const uint_fast32_t sidenum, const uint_fast32_t vert)
  52. {
  53.         Assert(sidenum <= MAX_SIDES_PER_SEGMENT);
  54.         return get_light_intensity(segp.sides[sidenum], vert);
  55. }
  56.  
  57. static fix clamp_light_intensity(const fix intensity)
  58. {
  59.         if (intensity < MIN_LIGHTING_VALUE)
  60.                 return MIN_LIGHTING_VALUE;
  61.         if (intensity > MAX_LIGHTING_VALUE)
  62.                 return MAX_LIGHTING_VALUE;
  63.         return intensity;
  64. }
  65.  
  66. // -----------------------------------------------------------------------------
  67. //      Set light intensity at a vertex, saturating in .5 to 15.5
  68. static void set_light_intensity(unique_side &s, const uint_fast32_t vert, const fix intensity)
  69. {
  70.         Assert(vert <= 3);
  71.         s.uvls[vert].l = clamp_light_intensity(intensity);
  72.         Update_flags |= UF_WORLD_CHANGED;
  73. }
  74.  
  75. static void set_light_intensity(unique_segment &segp, const uint_fast32_t sidenum, const uint_fast32_t vert, const fix intensity)
  76. {
  77.         Assert(sidenum <= MAX_SIDES_PER_SEGMENT);
  78.         set_light_intensity(segp.sides[sidenum], vert, intensity);
  79. }
  80.  
  81. // -----------------------------------------------------------------------------
  82. //      Add light intensity to a vertex, saturating in .5 to 15.5
  83. static void add_light_intensity_all_verts(unique_side &s, const fix intensity)
  84. {
  85.         range_for (auto &u, s.uvls)
  86.                 u.l = clamp_light_intensity(u.l + intensity);
  87.         Update_flags |= UF_WORLD_CHANGED;
  88. }
  89.  
  90. // -----------------------------------------------------------------------------
  91. //      Recursively apply light to segments.
  92. //      If current side is a wall, apply light there.
  93. //      If not a wall, apply light to child through that wall.
  94. //      Notes:
  95. //              It is possible to enter a segment twice by taking different paths.  It is easy
  96. //              to prevent this by maintaining a list of visited segments, but it is important
  97. //              to reach segments with the greatest light intensity.  This can be done by doing
  98. //              a breadth-first-search, or by storing the applied intensity with a visited segment,
  99. //              and if the current intensity is brighter, then apply the difference between it and
  100. //              the previous intensity.
  101. //              Note that it is also possible to visit the original light-casting segment, for example
  102. //              going from segment 0 to 2, then from 2 to 0.  This is peculiar and probably not
  103. //              desired, but not entirely invalid.  2 reflects some light back to 0.
  104. static void apply_light_intensity(const vmsegptr_t segp, const unsigned sidenum, fix intensity, const unsigned depth)
  105. {
  106.         if (intensity == 0)
  107.                 return;
  108.  
  109.         auto &Walls = LevelUniqueWallSubsystemState.Walls;
  110.         auto &vcwallptr = Walls.vcptr;
  111.         const auto wid_result = WALL_IS_DOORWAY(GameBitmaps, Textures, vcwallptr, segp, sidenum);
  112.         if (!(wid_result & WID_RENDPAST_FLAG)) {
  113.                 add_light_intensity_all_verts(segp->unique_segment::sides[sidenum], intensity);
  114.                 return;                                                                         // we return because there is a wall here, and light does not shine through walls
  115.         }
  116.  
  117.         //      No wall here, so apply light recursively
  118.         if (depth < 3) {
  119.                 intensity /= 3;
  120.                 if (!intensity)
  121.                         return;
  122.                 const auto &&csegp = vmsegptr(segp->children[sidenum]);
  123.                 for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  124.                         apply_light_intensity(csegp, s, intensity, depth+1);
  125.         }
  126.  
  127. }
  128.  
  129. // -----------------------------------------------------------------------------
  130. //      Top level recursive function for applying light.
  131. //      Calls apply_light_intensity.
  132. //      Uses light value on segp:sidenum (tmap_num2 defines light value) and applies
  133. //      the associated intensity to segp.  It calls apply_light_intensity to apply intensity/3
  134. //      to all neighbors.  apply_light_intensity recursively calls itself to apply light to
  135. //      subsequent neighbors (and forming loops, see above).
  136. static void propagate_light_intensity(const vmsegptr_t segp, int sidenum)
  137. {
  138.         fix             intensity;
  139.         short           texmap;
  140.  
  141.         intensity = 0;
  142.         auto &us = segp->unique_segment::sides[sidenum];
  143.         auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
  144.         texmap = us.tmap_num;
  145.         intensity += TmapInfo[texmap].lighting;
  146.         texmap = us.tmap_num2 & 0x3fff;
  147.         intensity += TmapInfo[texmap].lighting;
  148.  
  149.         if (intensity > 0) {
  150.                 add_light_intensity_all_verts(us, intensity);
  151.        
  152.                 //      Now, for all sides which are not the same as sidenum (the side casting the light),
  153.                 //      add a light value to them (if they have no children, ie, they have a wall there).
  154.                 for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  155.                         if (s != sidenum)
  156.                                 apply_light_intensity(segp, s, intensity/2, 1);
  157.         }
  158.  
  159. }
  160.  
  161.  
  162. // -----------------------------------------------------------------------------
  163. //      Highest level function, bound to a key.  Apply ambient light to all segments based
  164. //      on user-defined light sources.
  165. int LightAmbientLighting()
  166. {
  167.         range_for (const auto &&segp, vmsegptr)
  168.         {
  169.                 for (int side=0;side<MAX_SIDES_PER_SEGMENT;side++)
  170.                         propagate_light_intensity(segp, side);
  171.         }
  172.         return 0;
  173. }
  174.  
  175.  
  176. // -----------------------------------------------------------------------------
  177. int LightSelectNextVertex(void)
  178. {
  179.         Curvert++;
  180.         if (Curvert >= 4)
  181.                 Curvert = 0;
  182.  
  183.         Update_flags |= UF_WORLD_CHANGED;
  184.  
  185.         return  1;
  186. }
  187.  
  188. // -----------------------------------------------------------------------------
  189. int LightSelectNextEdge(void)
  190. {
  191.         Curedge++;
  192.         if (Curedge >= 4)
  193.                 Curedge = 0;
  194.  
  195.         Update_flags |= UF_WORLD_CHANGED;
  196.  
  197.         return  1;
  198. }
  199.  
  200. // -----------------------------------------------------------------------------
  201. //      Copy intensity from current vertex to all other vertices on side.
  202. int LightCopyIntensity(void)
  203. {
  204.         int     intensity;
  205.  
  206.         const vmsegptr_t segp = Cursegp;
  207.         intensity = get_light_intensity(segp, Curside, Curvert);
  208.  
  209.         range_for (const int v, xrange(4u))
  210.                 if (v != Curvert)
  211.                         set_light_intensity(segp, Curside, v, intensity);
  212.  
  213.         return  1;
  214. }
  215.  
  216. // -----------------------------------------------------------------------------
  217. //      Copy intensity from current vertex to all other vertices on side.
  218. int LightCopyIntensitySegment(void)
  219. {
  220.         int     intensity;
  221.  
  222.         const vmsegptr_t segp = Cursegp;
  223.         intensity = get_light_intensity(segp, Curside, Curvert);
  224.  
  225.         for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  226.                 range_for (const int v, xrange(4u))
  227.                         if ((s != Curside) || (v != Curvert))
  228.                                 set_light_intensity(segp, s, v, intensity);
  229.  
  230.         return  1;
  231. }
  232.  
  233. // -----------------------------------------------------------------------------
  234. int LightDecreaseLightVertex(void)
  235. {
  236.         const vmsegptr_t segp = Cursegp;
  237.         set_light_intensity(segp, Curside, Curvert, get_light_intensity(segp, Curside, Curvert) - F1_0 / NUM_LIGHTING_LEVELS);
  238.  
  239.         return  1;
  240. }
  241.  
  242. // -----------------------------------------------------------------------------
  243. int LightIncreaseLightVertex(void)
  244. {
  245.         const vmsegptr_t segp = Cursegp;
  246.         set_light_intensity(segp, Curside, Curvert, get_light_intensity(segp, Curside, Curvert) + F1_0 / NUM_LIGHTING_LEVELS);
  247.  
  248.         return  1;
  249. }
  250.  
  251. // -----------------------------------------------------------------------------
  252. int LightDecreaseLightSide(void)
  253. {
  254.         const vmsegptr_t segp = Cursegp;
  255.         range_for (const int v, xrange(4u))
  256.                 set_light_intensity(segp, Curside, v, get_light_intensity(segp, Curside, v) - F1_0 / NUM_LIGHTING_LEVELS);
  257.  
  258.         return  1;
  259. }
  260.  
  261. // -----------------------------------------------------------------------------
  262. int LightIncreaseLightSide(void)
  263. {
  264.         const vmsegptr_t segp = Cursegp;
  265.         range_for (const int v, xrange(4u))
  266.                 set_light_intensity(segp, Curside, v, get_light_intensity(segp, Curside, v) + F1_0 / NUM_LIGHTING_LEVELS);
  267.  
  268.         return  1;
  269. }
  270.  
  271. // -----------------------------------------------------------------------------
  272. int LightDecreaseLightSegment(void)
  273. {
  274.         const vmsegptr_t segp = Cursegp;
  275.         for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  276.                 range_for (const int v, xrange(4u))
  277.                         set_light_intensity(segp, s, v, get_light_intensity(segp, s, v) - F1_0 / NUM_LIGHTING_LEVELS);
  278.  
  279.         return  1;
  280. }
  281.  
  282. // -----------------------------------------------------------------------------
  283. int LightIncreaseLightSegment(void)
  284. {
  285.         const vmsegptr_t segp = Cursegp;
  286.         for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
  287.                 range_for (const int v, xrange(4u))
  288.                         set_light_intensity(segp, s, v, get_light_intensity(segp, s, v) + F1_0 / NUM_LIGHTING_LEVELS);
  289.  
  290.         return  1;
  291. }
  292.  
  293. // -----------------------------------------------------------------------------
  294. int LightSetDefault(void)
  295. {
  296.         const vmsegptr_t segp = Cursegp;
  297.         range_for (const int v, xrange(4u))
  298.                 set_light_intensity(segp, Curside, v, DEFAULT_LIGHTING);
  299.  
  300.         return  1;
  301. }
  302.  
  303.  
  304. // -----------------------------------------------------------------------------
  305. int LightSetMaximum(void)
  306. {
  307.         const vmsegptr_t segp = Cursegp;
  308.         range_for (const int v, xrange(4u))
  309.                 set_light_intensity(segp, Curside, v, (NUM_LIGHTING_LEVELS - 1) * F1_0 / NUM_LIGHTING_LEVELS);
  310.  
  311.         return  1;
  312. }
  313.  
  314.  
  315. // -----------------------------------------------------------------------------
  316. int LightSetDefaultAll(void)
  317. {
  318.  
  319.         assign_default_lighting_all();
  320.  
  321.         Update_flags |= UF_WORLD_CHANGED;
  322.  
  323.         return  1;
  324. }
  325.  
  326.  
  327.  
  328.