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