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.
get_light_intensity(const unique_side & s,const uint_fast32_t vert)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
get_light_intensity(const unique_segment & segp,const uint_fast32_t sidenum,const uint_fast32_t vert)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
clamp_light_intensity(const fix intensity)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
set_light_intensity(unique_side & s,const uint_fast32_t vert,const fix intensity)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
set_light_intensity(unique_segment & segp,const uint_fast32_t sidenum,const uint_fast32_t vert,const fix intensity)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
add_light_intensity_all_verts(unique_side & s,const fix intensity)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.
apply_light_intensity(const csmusegment segp,const unsigned sidenum,fix intensity,const unsigned depth)104 static void apply_light_intensity(const csmusegment 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 & WALL_IS_DOORWAY_FLAG::rendpast)) {
113 add_light_intensity_all_verts(segp.u.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 csmusegment &&csegp = vmsegptr(segp.s.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).
propagate_light_intensity(const csmusegment segp,const unsigned sidenum)136 static void propagate_light_intensity(const csmusegment segp, const unsigned sidenum)
137 {
138 fix intensity;
139
140 intensity = 0;
141 auto &us = segp.u.sides[sidenum];
142 auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
143 const auto texmap = get_texture_index(us.tmap_num);
144 intensity += TmapInfo[texmap].lighting;
145 intensity += TmapInfo[get_texture_index(us.tmap_num2)].lighting;
146
147 if (intensity > 0) {
148 add_light_intensity_all_verts(us, intensity);
149
150 // Now, for all sides which are not the same as sidenum (the side casting the light),
151 // add a light value to them (if they have no children, ie, they have a wall there).
152 for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
153 if (s != sidenum)
154 apply_light_intensity(segp, s, intensity/2, 1);
155 }
156
157 }
158
159
160 // -----------------------------------------------------------------------------
161 // Highest level function, bound to a key. Apply ambient light to all segments based
162 // on user-defined light sources.
LightAmbientLighting()163 int LightAmbientLighting()
164 {
165 range_for (const auto &&segp, vmsegptr)
166 {
167 for (int side=0;side<MAX_SIDES_PER_SEGMENT;side++)
168 propagate_light_intensity(segp, side);
169 }
170 return 0;
171 }
172
173
174 // -----------------------------------------------------------------------------
LightSelectNextVertex(void)175 int LightSelectNextVertex(void)
176 {
177 Curvert++;
178 if (Curvert >= 4)
179 Curvert = 0;
180
181 Update_flags |= UF_WORLD_CHANGED;
182
183 return 1;
184 }
185
186 // -----------------------------------------------------------------------------
LightSelectNextEdge(void)187 int LightSelectNextEdge(void)
188 {
189 Curedge++;
190 if (Curedge >= 4)
191 Curedge = 0;
192
193 Update_flags |= UF_WORLD_CHANGED;
194
195 return 1;
196 }
197
198 // -----------------------------------------------------------------------------
199 // Copy intensity from current vertex to all other vertices on side.
LightCopyIntensity(void)200 int LightCopyIntensity(void)
201 {
202 int intensity;
203
204 unique_segment &segp = Cursegp;
205 intensity = get_light_intensity(segp, Curside, Curvert);
206
207 range_for (const int v, xrange(4u))
208 if (v != Curvert)
209 set_light_intensity(segp, Curside, v, intensity);
210
211 return 1;
212 }
213
214 // -----------------------------------------------------------------------------
215 // Copy intensity from current vertex to all other vertices on side.
LightCopyIntensitySegment(void)216 int LightCopyIntensitySegment(void)
217 {
218 int intensity;
219
220 unique_segment &segp = Cursegp;
221 intensity = get_light_intensity(segp, Curside, Curvert);
222
223 for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
224 range_for (const int v, xrange(4u))
225 if ((s != Curside) || (v != Curvert))
226 set_light_intensity(segp, s, v, intensity);
227
228 return 1;
229 }
230
231 // -----------------------------------------------------------------------------
LightDecreaseLightVertex(void)232 int LightDecreaseLightVertex(void)
233 {
234 unique_segment &segp = Cursegp;
235 set_light_intensity(segp, Curside, Curvert, get_light_intensity(segp, Curside, Curvert) - F1_0 / NUM_LIGHTING_LEVELS);
236
237 return 1;
238 }
239
240 // -----------------------------------------------------------------------------
LightIncreaseLightVertex(void)241 int LightIncreaseLightVertex(void)
242 {
243 unique_segment &segp = Cursegp;
244 set_light_intensity(segp, Curside, Curvert, get_light_intensity(segp, Curside, Curvert) + F1_0 / NUM_LIGHTING_LEVELS);
245
246 return 1;
247 }
248
249 // -----------------------------------------------------------------------------
LightDecreaseLightSide(void)250 int LightDecreaseLightSide(void)
251 {
252 unique_segment &segp = Cursegp;
253 range_for (const int v, xrange(4u))
254 set_light_intensity(segp, Curside, v, get_light_intensity(segp, Curside, v) - F1_0 / NUM_LIGHTING_LEVELS);
255
256 return 1;
257 }
258
259 // -----------------------------------------------------------------------------
LightIncreaseLightSide(void)260 int LightIncreaseLightSide(void)
261 {
262 unique_segment &segp = Cursegp;
263 range_for (const int v, xrange(4u))
264 set_light_intensity(segp, Curside, v, get_light_intensity(segp, Curside, v) + F1_0 / NUM_LIGHTING_LEVELS);
265
266 return 1;
267 }
268
269 // -----------------------------------------------------------------------------
LightDecreaseLightSegment(void)270 int LightDecreaseLightSegment(void)
271 {
272 unique_segment &segp = Cursegp;
273 for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
274 range_for (const int v, xrange(4u))
275 set_light_intensity(segp, s, v, get_light_intensity(segp, s, v) - F1_0 / NUM_LIGHTING_LEVELS);
276
277 return 1;
278 }
279
280 // -----------------------------------------------------------------------------
LightIncreaseLightSegment(void)281 int LightIncreaseLightSegment(void)
282 {
283 unique_segment &segp = Cursegp;
284 for (int s=0; s<MAX_SIDES_PER_SEGMENT; s++)
285 range_for (const int v, xrange(4u))
286 set_light_intensity(segp, s, v, get_light_intensity(segp, s, v) + F1_0 / NUM_LIGHTING_LEVELS);
287
288 return 1;
289 }
290
291 // -----------------------------------------------------------------------------
LightSetDefault(void)292 int LightSetDefault(void)
293 {
294 unique_segment &segp = Cursegp;
295 range_for (const int v, xrange(4u))
296 set_light_intensity(segp, Curside, v, DEFAULT_LIGHTING);
297
298 return 1;
299 }
300
301
302 // -----------------------------------------------------------------------------
LightSetMaximum(void)303 int LightSetMaximum(void)
304 {
305 unique_segment &segp = Cursegp;
306 range_for (const int v, xrange(4u))
307 set_light_intensity(segp, Curside, v, (NUM_LIGHTING_LEVELS - 1) * F1_0 / NUM_LIGHTING_LEVELS);
308
309 return 1;
310 }
311
312
313 // -----------------------------------------------------------------------------
LightSetDefaultAll(void)314 int LightSetDefaultAll(void)
315 {
316
317 assign_default_lighting_all();
318
319 Update_flags |= UF_WORLD_CHANGED;
320
321 return 1;
322 }
323
324
325
326