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