Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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