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
 * u,v coordinate computation for segment faces
23
 *
24
 */
25
 
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <stdarg.h>
29
#include <math.h>
30
#include <string.h>
31
#include "inferno.h"
32
#include "segment.h"
33
#include "editor/editor.h"
34
#include "editor/esegment.h"
35
#include "gameseg.h"
36
#include "maths.h"
37
#include "dxxerror.h"
38
#include "wall.h"
39
#include "editor/kdefs.h"
40
#include "bm.h"         //      Needed for TmapInfo
41
#include        "effects.h"     //      Needed for effects_bm_num
42
#include "fvi.h"
43
#include "seguvs.h"
44
 
45
#include "compiler-range_for.h"
46
#include "d_enumerate.h"
47
#include "d_range.h"
48
#include "d_zip.h"
49
 
50
namespace dcx {
51
static void cast_all_light_in_mine(int quick_flag);
52
}
53
//--rotate_uvs-- vms_vector Rightvec;
54
 
55
#define MAX_LIGHT_SEGS 16
56
 
57
//      ---------------------------------------------------------------------------------------------
58
//      Scan all polys in all segments, return average light value for vnum.
59
//      segs = output array for segments containing vertex, terminated by -1.
60
static fix get_average_light_at_vertex(int vnum, segnum_t *segs)
61
{
62
        fix     total_light;
63
        int     num_occurrences;
64
//      #ifndef NDEBUG //Removed this ifdef because the version of Assert that I used to get it to compile doesn't work without this symbol. -KRB
65
        segnum_t   *original_segs;
66
 
67
        original_segs = segs;
68
//      #endif
69
 
70
 
71
        num_occurrences = 0;
72
        total_light = 0;
73
 
74
        range_for (const auto &&segp, vcsegptridx)
75
        {
76
                auto e = end(segp->verts);
77
                auto relvnum = std::distance(std::find(begin(segp->verts), e, vnum), e);
78
                if (relvnum < MAX_VERTICES_PER_SEGMENT) {
79
 
80
                        *segs++ = segp;
81
                        Assert(segs - original_segs < MAX_LIGHT_SEGS);
82
                        (void)original_segs;
83
 
84
                        range_for (const auto &&z, zip(segp->children, segp->unique_segment::sides, Side_to_verts))
85
                        {
86
                                if (!IS_CHILD(std::get<0>(z))) {
87
                                        auto &uside = std::get<1>(z);
88
                                        auto &vp = std::get<2>(z);
89
                                        const auto vb = begin(vp);
90
                                        const auto ve = end(vp);
91
                                        const auto vi = std::find(vb, ve, relvnum);
92
                                        if (vi != ve)
93
                                        {
94
                                                const auto v = std::distance(vb, vi);
95
                                                total_light += uside.uvls[v].l;
96
                                                        num_occurrences++;
97
                                                }
98
                                }       // end if
99
                        }       // end sidenum
100
                }
101
        }       // end segnum
102
 
103
        *segs = segment_none;
104
 
105
        if (num_occurrences)
106
                return total_light/num_occurrences;
107
        else
108
                return 0;
109
 
110
}
111
 
112
static void set_average_light_at_vertex(int vnum)
113
{
114
        int     relvnum;
115
        segnum_t        Segment_indices[MAX_LIGHT_SEGS];
116
        int     segind;
117
 
118
        fix average_light;
119
 
120
        average_light = get_average_light_at_vertex(vnum, Segment_indices);
121
 
122
        if (!average_light)
123
                return;
124
 
125
        segind = 0;
126
        while (Segment_indices[segind] != segment_none) {
127
                auto segnum = Segment_indices[segind++];
128
 
129
                auto &ssegp = *vcsegptr(segnum);
130
                unique_segment &usegp = *vmsegptr(segnum);
131
 
132
                for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
133
                        if (ssegp.verts[relvnum] == vnum)
134
                                break;
135
 
136
                if (relvnum < MAX_VERTICES_PER_SEGMENT) {
137
                        range_for (const auto &&z, zip(ssegp.children, usegp.sides, Side_to_verts))
138
                        {
139
                                if (!IS_CHILD(std::get<0>(z))) {
140
                                        unique_side &sidep = std::get<1>(z);
141
                                        auto &vp = std::get<2>(z);
142
                                        const auto vb = begin(vp);
143
                                        const auto ve = end(vp);
144
                                        const auto vi = std::find(vb, ve, relvnum);
145
                                        if (vi != ve)
146
                                        {
147
                                                const auto v = std::distance(vb, vi);
148
                                                sidep.uvls[v].l = average_light;
149
                                        }
150
                                }       // end if
151
                        }       // end sidenum
152
                }       // end if
153
        }       // end while
154
 
155
        Update_flags |= UF_WORLD_CHANGED;
156
}
157
 
158
static void set_average_light_on_side(const vmsegptr_t segp, int sidenum)
159
{
160
        if (!IS_CHILD(segp->children[sidenum]))
161
                range_for (const auto v, Side_to_verts[sidenum])
162
                {
163
                        set_average_light_at_vertex(segp->verts[v]);
164
                }
165
 
166
}
167
 
168
int set_average_light_on_curside(void)
169
{
170
        set_average_light_on_side(Cursegp, Curside);
171
        return 0;
172
}
173
 
174
int set_average_light_on_all(void)
175
{
176
        Doing_lighting_hack_flag = 1;
177
        cast_all_light_in_mine(0);
178
        Doing_lighting_hack_flag = 0;
179
        Update_flags |= UF_WORLD_CHANGED;
180
 
181
//      int seg, side;
182
 
183
//      for (seg=0; seg<=Highest_segment_index; seg++)
184
//              for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
185
//                      if (Segments[seg].segnum != -1)
186
//                              set_average_light_on_side(&Segments[seg], side);
187
        return 0;
188
}
189
 
190
int set_average_light_on_all_quick(void)
191
{
192
        cast_all_light_in_mine(1);
193
        Update_flags |= UF_WORLD_CHANGED;
194
 
195
        return 0;
196
}
197
 
198
//      ---------------------------------------------------------------------------------------------
199
//      Given a polygon, compress the uv coordinates so that they are as close to 0 as possible.
200
//      Do this by adding a constant u and v to each uv pair.
201
static void compress_uv_coordinates(std::array<uvl, 4> &uvls)
202
{
203
        fix     uc, vc;
204
 
205
        uc = 0;
206
        vc = 0;
207
 
208
        range_for (auto &uvl, uvls)
209
        {
210
                uc += uvl.u;
211
                vc += uvl.v;
212
        }
213
 
214
        uc /= 4;
215
        vc /= 4;
216
        uc = uc & 0xffff0000;
217
        vc = vc & 0xffff0000;
218
 
219
        range_for (auto &uvl, uvls)
220
        {
221
                uvl.u -= uc;
222
                uvl.v -= vc;
223
        }
224
}
225
 
226
static void assign_default_lighting_on_side(std::array<uvl, 4> &uvls)
227
{
228
        range_for (auto &uvl, uvls)
229
                uvl.l = DEFAULT_LIGHTING;
230
}
231
 
232
static void assign_default_lighting(unique_segment &segp)
233
{
234
        range_for (auto &side, segp.sides)
235
                assign_default_lighting_on_side(side.uvls);
236
}
237
 
238
void assign_default_lighting_all(void)
239
{
240
        range_for (const auto &&segp, vmsegptr)
241
        {
242
                if (segp->segnum != segment_none)
243
                        assign_default_lighting(segp);
244
        }
245
}
246
 
247
//      ---------------------------------------------------------------------------------------------
248
static void validate_uv_coordinates(unique_segment &segp)
249
{
250
        range_for (auto &side, segp.sides)
251
        {
252
                compress_uv_coordinates(side.uvls);
253
        }
254
 
255
}
256
 
257
#ifdef __WATCOMC__
258
fix zhypot(fix a,fix b);
259
#pragma aux zhypot parm [eax] [ebx] value [eax] modify [eax ebx ecx edx] = \
260
        "imul   eax" \
261
        "xchg eax,ebx" \
262
        "mov    ecx,edx" \
263
        "imul eax" \
264
        "add    eax,ebx" \
265
        "adc    edx,ecx" \
266
        "call   quad_sqrt";
267
#else
268
static fix zhypot(fix a,fix b) {
269
        double x = static_cast<double>(a) / 65536;
270
        double y = static_cast<double>(b) / 65536;
271
        return static_cast<long>(sqrt(x * x + y * y) * 65536);
272
}
273
#endif
274
 
275
//      ---------------------------------------------------------------------------------------------
276
//      Assign lighting value to side, a function of the normal vector.
277
void assign_light_to_side(unique_side &s)
278
{
279
        range_for (auto &v, s.uvls)
280
                v.l = DEFAULT_LIGHTING;
281
}
282
 
283
fix     Stretch_scale_x = F1_0;
284
fix     Stretch_scale_y = F1_0;
285
 
286
//      ---------------------------------------------------------------------------------------------
287
//      Given u,v coordinates at two vertices, assign u,v coordinates to other two vertices on a side.
288
//      (Actually, assign them to the coordinates in the faces.)
289
//      va, vb = face-relative vertex indices corresponding to uva, uvb.  Ie, they are always in 0..3 and should be looked up in
290
//      Side_to_verts[side] to get the segment relative index.
291
static void assign_uvs_to_side(fvcvertptr &vcvertptr, const vmsegptridx_t segp, int sidenum, uvl *uva, uvl *uvb, int va, int vb)
292
{
293
        int                     vlo,vhi;
294
        unsigned v0, v1, v2, v3;
295
        std::array<uvl, 4> uvls;
296
        uvl ruvmag,fuvmag,uvlo,uvhi;
297
        fix                     fmag,mag01;
298
        Assert( (va<4) && (vb<4) );
299
        Assert((abs(va - vb) == 1) || (abs(va - vb) == 3));             // make sure the verticies specify an edge
300
 
301
        auto &vp = Side_to_verts[sidenum];
302
 
303
        // We want vlo precedes vhi, ie vlo < vhi, or vlo = 3, vhi = 0
304
        if (va == ((vb + 1) % 4)) {             // va = vb + 1
305
                vlo = vb;
306
                vhi = va;
307
                uvlo = *uvb;
308
                uvhi = *uva;
309
        } else {
310
                vlo = va;
311
                vhi = vb;
312
                uvlo = *uva;
313
                uvhi = *uvb;
314
        }
315
 
316
        Assert(((vlo+1) % 4) == vhi);   // If we are on an edge, then uvhi is one more than uvlo (mod 4)
317
        uvls[vlo] = uvlo;
318
        uvls[vhi] = uvhi;
319
 
320
        // Now we have vlo precedes vhi, compute vertices ((vhi+1) % 4) and ((vhi+2) % 4)
321
 
322
        // Assign u,v scale to a unit length right vector.
323
        fmag = zhypot(uvhi.v - uvlo.v,uvhi.u - uvlo.u);
324
        if (fmag < 64) {                // this is a fix, so 64 = 1/1024
325
                ruvmag.u = F1_0*256;
326
                ruvmag.v = F1_0*256;
327
                fuvmag.u = F1_0*256;
328
                fuvmag.v = F1_0*256;
329
        } else {
330
                ruvmag.u = uvhi.v - uvlo.v;
331
                ruvmag.v = uvlo.u - uvhi.u;
332
 
333
                fuvmag.u = uvhi.u - uvlo.u;
334
                fuvmag.v = uvhi.v - uvlo.v;
335
        }
336
 
337
        v0 = segp->verts[vp[vlo]];
338
        v1 = segp->verts[vp[vhi]];
339
        v2 = segp->verts[vp[(vhi+1)%4]];
340
        v3 = segp->verts[vp[(vhi+2)%4]];
341
 
342
        //      Compute right vector by computing orientation matrix from:
343
        //              forward vector = vlo:vhi
344
        //                right vector = vlo:(vhi+2) % 4
345
        const auto &&vp0 = vcvertptr(v0);
346
        const auto &vv1v0 = vm_vec_sub(vcvertptr(v1), vp0);
347
        mag01 = vm_vec_mag(vv1v0);
348
        mag01 = fixmul(mag01, (va == 0 || va == 2) ? Stretch_scale_x : Stretch_scale_y);
349
 
350
        if (unlikely(mag01 < F1_0/1024))
351
                editor_status_fmt("U, V bogosity in segment #%hu, probably on side #%i.  CLEAN UP YOUR MESS!", static_cast<uint16_t>(segp), sidenum);
352
        else {
353
                struct frvec {
354
                        vms_vector fvec, rvec;
355
                        frvec(const vms_vector &tfvec, const vms_vector &trvec) {
356
                                if ((tfvec.x == 0 && tfvec.y == 0 && tfvec.z == 0) ||
357
                                        (trvec.x == 0 && trvec.y == 0 && trvec.z == 0))
358
                                {
359
                                        fvec = vmd_identity_matrix.fvec;
360
                                        rvec = vmd_identity_matrix.rvec;
361
                                }
362
                                else
363
                                {
364
                                        const auto &m = vm_vector_2_matrix(tfvec, nullptr, &trvec);
365
                                        fvec = m.fvec;
366
                                        rvec = m.rvec;
367
                                }
368
                                vm_vec_negate(rvec);
369
                        }
370
                };
371
                const auto &vv3v0 = vm_vec_sub(vcvertptr(v3), vp0);
372
                const frvec fr{
373
                        vv1v0,
374
                        vv3v0
375
                };
376
                const auto assign_uvl = [&](const vms_vector &tvec, const uvl &uvi) {
377
                        const auto drt = vm_vec_dot(fr.rvec, tvec);
378
                        const auto dft = vm_vec_dot(fr.fvec, tvec);
379
                        return uvl{
380
                                uvi.u +
381
                                        fixdiv(fixmul(ruvmag.u, drt), mag01) +
382
                                        fixdiv(fixmul(fuvmag.u, dft), mag01),
383
                                uvi.v +
384
                                        fixdiv(fixmul(ruvmag.v, drt), mag01) +
385
                                        fixdiv(fixmul(fuvmag.v, dft), mag01),
386
                                uvi.l
387
                        };
388
                };
389
                uvls[(vhi+1)%4] = assign_uvl(vm_vec_sub(vcvertptr(v2), vcvertptr(v1)), uvhi);
390
                uvls[(vhi+2)%4] = assign_uvl(vv3v0, uvlo);
391
                //      For all faces in side, copy uv coordinates from uvs array to face.
392
                segp->unique_segment::sides[sidenum].uvls = uvls;
393
        }
394
}
395
 
396
 
397
int Vmag = VMAG;
398
 
399
namespace dsx {
400
 
401
// -----------------------------------------------------------------------------------------------------------
402
//      Assign default uvs to side.
403
//      This means:
404
//              v0 = 0,0
405
//              v1 = k,0 where k is 3d size dependent
406
//      v2, v3 assigned by assign_uvs_to_side
407
void assign_default_uvs_to_side(const vmsegptridx_t segp, const unsigned side)
408
{
409
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
410
        auto &Vertices = LevelSharedVertexState.get_vertices();
411
        uvl                     uv0,uv1;
412
        uv0.u = 0;
413
        uv0.v = 0;
414
        auto &vp = Side_to_verts[side];
415
        uv1.u = 0;
416
        auto &vcvertptr = Vertices.vcptr;
417
        uv1.v = Num_tilings * fixmul(Vmag, vm_vec_dist(vcvertptr(segp->verts[vp[1]]), vcvertptr(segp->verts[vp[0]])));
418
 
419
        assign_uvs_to_side(vcvertptr, segp, side, &uv0, &uv1, 0, 1);
420
}
421
 
422
// -----------------------------------------------------------------------------------------------------------
423
//      Assign default uvs to side.
424
//      This means:
425
//              v0 = 0,0
426
//              v1 = k,0 where k is 3d size dependent
427
//      v2, v3 assigned by assign_uvs_to_side
428
void stretch_uvs_from_curedge(const vmsegptridx_t segp, int side)
429
{
430
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
431
        auto &Vertices = LevelSharedVertexState.get_vertices();
432
        uvl                     uv0,uv1;
433
        int                     v0, v1;
434
 
435
        v0 = Curedge;
436
        v1 = (v0 + 1) % 4;
437
 
438
        auto &uvls = segp->unique_segment::sides[side].uvls;
439
        uv0.u = uvls[v0].u;
440
        uv0.v = uvls[v0].v;
441
 
442
        uv1.u = uvls[v1].u;
443
        uv1.v = uvls[v1].v;
444
 
445
        auto &vcvertptr = Vertices.vcptr;
446
        assign_uvs_to_side(vcvertptr, segp, side, &uv0, &uv1, v0, v1);
447
}
448
 
449
// --------------------------------------------------------------------------------------------------------------
450
//      Assign default uvs to a segment.
451
void assign_default_uvs_to_segment(const vmsegptridx_t segp)
452
{
453
        range_for (const uint_fast32_t s, xrange(MAX_SIDES_PER_SEGMENT))
454
        {
455
                assign_default_uvs_to_side(segp,s);
456
                assign_light_to_side(segp, s);
457
        }
458
}
459
 
460
 
461
// -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
462
// -- mk021394 -- //    Find the face:poly:vertex index in base_seg:base_common_side which is segment relative vertex v1
463
// -- mk021394 -- //    This very specific routine is subsidiary to med_assign_uvs_to_side.
464
// -- mk021394 -- void get_face_and_vert(segment *base_seg, int base_common_side, int v1, int *ff, int *vv, int *pi)
465
// -- mk021394 -- {
466
// -- mk021394 --       int     p,f,v;
467
// -- mk021394 -- 
468
// -- mk021394 --       for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
469
// -- mk021394 --               face *fp = &base_seg->sides[base_common_side].faces[f];
470
// -- mk021394 --               for (p=0; p<fp->num_polys; p++) {
471
// -- mk021394 --                       poly *pp = &fp->polys[p];
472
// -- mk021394 --                       for (v=0; v<pp->num_vertices; v++)
473
// -- mk021394 --                               if (pp->verts[v] == v1) {
474
// -- mk021394 --                                       *ff = f;
475
// -- mk021394 --                                       *vv = v;
476
// -- mk021394 --                                       *pi = p;
477
// -- mk021394 --                                       return;
478
// -- mk021394 --                               }
479
// -- mk021394 --               }
480
// -- mk021394 --       }
481
// -- mk021394 -- 
482
// -- mk021394 --       Assert(0);      // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
483
// -- mk021394 -- }
484
 
485
// -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
486
// -- mk021394 -- //    Find the vertex index in base_seg:base_common_side which is segment relative vertex v1
487
// -- mk021394 -- //    This very specific routine is subsidiary to med_assign_uvs_to_side.
488
// -- mk021394 -- void get_side_vert(segment *base_seg,int base_common_side,int v1,int *vv)
489
// -- mk021394 -- {
490
// -- mk021394 --       int     p,f,v;
491
// -- mk021394 -- 
492
// -- mk021394 --       Assert((base_seg->sides[base_common_side].tri_edge == 0) || (base_seg->sides[base_common_side].tri_edge == 1));
493
// -- mk021394 --       Assert(base_seg->sides[base_common_side].num_faces <= 2);
494
// -- mk021394 -- 
495
// -- mk021394 --       for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
496
// -- mk021394 --               face *fp = &base_seg->sides[base_common_side].faces[f];
497
// -- mk021394 --               for (p=0; p<fp->num_polys; p++) {
498
// -- mk021394 --                       poly    *pp = &fp->polys[p];
499
// -- mk021394 --                       for (v=0; v<pp->num_vertices; v++)
500
// -- mk021394 --                               if (pp->verts[v] == v1) {
501
// -- mk021394 --                                       if (pp->num_vertices == 4) {
502
// -- mk021394 --                                               *vv = v;
503
// -- mk021394 --                                               return;
504
// -- mk021394 --                                       }
505
// -- mk021394 -- 
506
// -- mk021394 --                                       if (base_seg->sides[base_common_side].tri_edge == 0) {  // triangulated 012, 023, so if f==0, *vv = v, if f==1, *vv = v if v=0, else v+1
507
// -- mk021394 --                                               if ((f == 1) && (v > 0))
508
// -- mk021394 --                                                       v++;
509
// -- mk021394 --                                               *vv = v;
510
// -- mk021394 --                                               return;
511
// -- mk021394 --                                       } else {                                                                // triangulated 013, 123
512
// -- mk021394 --                                               if (f == 0) {
513
// -- mk021394 --                                                       if (v == 2)
514
// -- mk021394 --                                                               v++;
515
// -- mk021394 --                                               } else
516
// -- mk021394 --                                                       v++;
517
// -- mk021394 --                                               *vv = v;
518
// -- mk021394 --                                               return;
519
// -- mk021394 --                                       }
520
// -- mk021394 --                               }
521
// -- mk021394 --               }
522
// -- mk021394 --       }
523
// -- mk021394 -- 
524
// -- mk021394 --       Assert(0);      // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
525
// -- mk021394 -- }
526
 
527
//--rotate_uvs-- // --------------------------------------------------------------------------------------------------------------
528
//--rotate_uvs-- //     Rotate uvl coordinates uva, uvb about their center point by heading
529
//--rotate_uvs-- void rotate_uvs(uvl *uva, uvl *uvb, vms_vector *rvec)
530
//--rotate_uvs-- {
531
//--rotate_uvs--        uvl     uvc, uva1, uvb1;
532
//--rotate_uvs-- 
533
//--rotate_uvs--        uvc.u = (uva->u + uvb->u)/2;
534
//--rotate_uvs--        uvc.v = (uva->v + uvb->v)/2;
535
//--rotate_uvs-- 
536
//--rotate_uvs--        uva1.u = fixmul(uva->u - uvc.u, rvec->x) - fixmul(uva->v - uvc.v, rvec->z);
537
//--rotate_uvs--        uva1.v = fixmul(uva->u - uvc.u, rvec->z) + fixmul(uva->v - uvc.v, rvec->x);
538
//--rotate_uvs-- 
539
//--rotate_uvs--        uva->u = uva1.u + uvc.u;
540
//--rotate_uvs--        uva->v = uva1.v + uvc.v;
541
//--rotate_uvs-- 
542
//--rotate_uvs--        uvb1.u = fixmul(uvb->u - uvc.u, rvec->x) - fixmul(uvb->v - uvc.v, rvec->z);
543
//--rotate_uvs--        uvb1.v = fixmul(uvb->u - uvc.u, rvec->z) + fixmul(uvb->v - uvc.v, rvec->x);
544
//--rotate_uvs-- 
545
//--rotate_uvs--        uvb->u = uvb1.u + uvc.u;
546
//--rotate_uvs--        uvb->v = uvb1.v + uvc.v;
547
//--rotate_uvs-- }
548
 
549
 
550
// --------------------------------------------------------------------------------------------------------------
551
void med_assign_uvs_to_side(const vmsegptridx_t con_seg, const unsigned con_common_side, const vmsegptr_t base_seg, const unsigned base_common_side, const unsigned abs_id1, const unsigned abs_id2)
552
{
553
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
554
        auto &Vertices = LevelSharedVertexState.get_vertices();
555
        uvl             uv1,uv2;
556
        int             v,bv1,bv2, vv1, vv2;
557
        int             cv1=0, cv2=0;
558
 
559
        bv1 = -1;       bv2 = -1;
560
 
561
        // Find which vertices in segment match abs_id1, abs_id2
562
        for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
563
                if (base_seg->verts[v] == abs_id1)
564
                        bv1 = v;
565
                if (base_seg->verts[v] == abs_id2)
566
                        bv2 = v;
567
                if (con_seg->verts[v] == abs_id1)
568
                        cv1 = v;
569
                if (con_seg->verts[v] == abs_id2)
570
                        cv2 = v;
571
        }
572
 
573
        //      Now, bv1, bv2 are segment relative vertices in base segment which are the same as absolute vertices abs_id1, abs_id2
574
        //           cv1, cv2 are segment relative vertices in conn segment which are the same as absolute vertices abs_id1, abs_id2
575
 
576
        Assert((bv1 != -1) && (bv2 != -1) && (cv1 != -1) && (cv2 != -1));
577
 
578
        //      Now, scan 4 vertices in base side and 4 vertices in connected side.
579
        //      Set uv1, uv2 to uv coordinates from base side which correspond to vertices bv1, bv2.
580
        //      Set vv1, vv2 to relative vertex ids (in 0..3) in connecting side which correspond to cv1, cv2
581
        vv1 = -1;       vv2 = -1;
582
        auto &base_uvls = base_seg->unique_segment::sides[base_common_side].uvls;
583
        for (v=0; v<4; v++) {
584
                if (bv1 == Side_to_verts[base_common_side][v])
585
                        uv1 = base_uvls[v];
586
 
587
                if (bv2 == Side_to_verts[base_common_side][v])
588
                        uv2 = base_uvls[v];
589
 
590
                if (cv1 == Side_to_verts[con_common_side][v])
591
                        vv1 = v;
592
 
593
                if (cv2 == Side_to_verts[con_common_side][v])
594
                        vv2 = v;
595
        }
596
 
597
        Assert((uv1.u != uv2.u) || (uv1.v != uv2.v));
598
        Assert( (vv1 != -1) && (vv2 != -1) );
599
        auto &vcvertptr = Vertices.vcptr;
600
        assign_uvs_to_side(vcvertptr, con_seg, con_common_side, &uv1, &uv2, vv1, vv2);
601
}
602
 
603
 
604
// -----------------------------------------------------------------------------
605
//      Given a base and a connecting segment, a side on each of those segments and two global vertex ids,
606
//      determine which side in each of the segments shares those two vertices.
607
//      This is used to propagate a texture map id to a connecting segment in an expected and desired way.
608
//      Since we can attach any side of a segment to any side of another segment, and do so in each case in
609
//      four different rotations (for a total of 6*6*4 = 144 ways), not having this nifty function will cause
610
//      great confusion.
611
static void get_side_ids(const vmsegptr_t base_seg, const vmsegptr_t con_seg, int base_side, int con_side, int abs_id1, int abs_id2, int *base_common_side, int *con_common_side)
612
{
613
        int             v0;
614
 
615
        *base_common_side = -1;
616
 
617
        //      Find side in base segment which contains the two global vertex ids.
618
        range_for (const auto &&es, enumerate(Side_to_verts))
619
        {
620
                if (es.idx != base_side) {
621
                        auto &base_vp = es.value;
622
                        for (v0=0; v0<4; v0++)
623
                                if (((base_seg->verts[static_cast<int>(base_vp[v0])] == abs_id1) && (base_seg->verts[static_cast<int>(base_vp[(v0+1) % 4])] == abs_id2)) || ((base_seg->verts[static_cast<int>(base_vp[v0])] == abs_id2) && (base_seg->verts[static_cast<int>(base_vp[ (v0+1) % 4])] == abs_id1))) {
624
                                        Assert(*base_common_side == -1);                // This means two different sides shared the same edge with base_side == impossible!
625
                                        *base_common_side = es.idx;
626
                                }
627
                }
628
        }
629
 
630
        // Note: For connecting segment, process vertices in reversed order.
631
        *con_common_side = -1;
632
 
633
        //      Find side in connecting segment which contains the two global vertex ids.
634
        range_for (const auto &&es, enumerate(Side_to_verts))
635
        {
636
                if (es.idx != con_side) {
637
                        auto &con_vp = es.value;
638
                        for (v0=0; v0<4; v0++)
639
                                if (((con_seg->verts[static_cast<int>(con_vp[(v0 + 1) % 4])] == abs_id1) && (con_seg->verts[static_cast<int>(con_vp[v0])] == abs_id2)) || ((con_seg->verts[static_cast<int>(con_vp[(v0 + 1) % 4])] == abs_id2) && (con_seg->verts[static_cast<int>(con_vp[v0])] == abs_id1))) {
640
                                        Assert(*con_common_side == -1);         // This means two different sides shared the same edge with con_side == impossible!
641
                                        *con_common_side = es.idx;
642
                                }
643
                }
644
        }
645
 
646
        Assert((*base_common_side != -1) && (*con_common_side != -1));
647
}
648
 
649
// -----------------------------------------------------------------------------
650
//      Propagate texture map u,v coordinates from base_seg:base_side to con_seg:con_side.
651
//      The two vertices abs_id1 and abs_id2 are the only two vertices common to the two sides.
652
//      If uv_only_flag is 1, then don't assign texture map ids, only update the uv coordinates
653
//      If uv_only_flag is -1, then ONLY assign texture map ids, don't update the uv coordinates
654
static void propagate_tmaps_to_segment_side(const vmsegptridx_t base_seg, int base_side, const vmsegptridx_t con_seg, int con_side, int abs_id1, int abs_id2, int uv_only_flag)
655
{
656
        int             base_common_side,con_common_side;
657
        int             tmap_num;
658
 
659
        Assert ((uv_only_flag == -1) || (uv_only_flag == 0) || (uv_only_flag == 1));
660
 
661
        // Set base_common_side = side in base_seg which contains edge abs_id1:abs_id2
662
        // Set con_common_side = side in con_seg which contains edge abs_id1:abs_id2
663
        if (base_seg != con_seg)
664
                get_side_ids(base_seg, con_seg, base_side, con_side, abs_id1, abs_id2, &base_common_side, &con_common_side);
665
        else {
666
                base_common_side = base_side;
667
                con_common_side = con_side;
668
        }
669
 
670
        // Now, all faces in con_seg which are on side con_common_side get their tmap_num set to whatever tmap is assigned
671
        // to whatever face I find which is on side base_common_side.
672
        // First, find tmap_num for base_common_side.  If it doesn't exist (ie, there is a connection there), look at the segment
673
        // that is connected through it.
674
        if (!IS_CHILD(con_seg->children[con_common_side])) {
675
                if (!IS_CHILD(base_seg->children[base_common_side])) {
676
                        // There is at least one face here, so get the tmap_num from there.
677
                        tmap_num = base_seg->unique_segment::sides[base_common_side].tmap_num;
678
 
679
                        // Now assign all faces in the connecting segment on side con_common_side to tmap_num.
680
                        if ((uv_only_flag == -1) || (uv_only_flag == 0))
681
                                con_seg->unique_segment::sides[con_common_side].tmap_num = tmap_num;
682
 
683
                        if (uv_only_flag != -1)
684
                                med_assign_uvs_to_side(con_seg, con_common_side, base_seg, base_common_side, abs_id1, abs_id2);
685
 
686
                } else {                        // There are no faces here, there is a connection, trace through the connection.
687
                        const auto &&csegp = base_seg.absolute_sibling(base_seg->children[base_common_side]);
688
                        auto cside = find_connect_side(base_seg, csegp);
689
                        propagate_tmaps_to_segment_side(csegp, cside, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
690
                }
691
        }
692
 
693
}
694
 
695
}
696
 
697
namespace dcx {
698
 
699
constexpr int8_t Edge_between_sides[MAX_SIDES_PER_SEGMENT][MAX_SIDES_PER_SEGMENT][2] = {
700
//              left            top             right           bottom  back            front
701
        { {-1,-1}, { 3, 7}, {-1,-1}, { 2, 6}, { 6, 7}, { 2, 3} },       // left
702
        { { 3, 7}, {-1,-1}, { 0, 4}, {-1,-1}, { 4, 7}, { 0, 3} },       // top
703
        { {-1,-1}, { 0, 4}, {-1,-1}, { 1, 5}, { 4, 5}, { 0, 1} },       // right
704
        { { 2, 6}, {-1,-1}, { 1, 5}, {-1,-1}, { 5, 6}, { 1, 2} },       // bottom
705
        { { 6, 7}, { 4, 7}, { 4, 5}, { 5, 6}, {-1,-1}, {-1,-1} },       // back
706
        { { 2, 3}, { 0, 3}, { 0, 1}, { 1, 2}, {-1,-1}, {-1,-1} }};      // front
707
 
708
}
709
 
710
namespace dsx {
711
 
712
// -----------------------------------------------------------------------------
713
//      Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side
714
//      There is no easy way to figure out which side is adjacent to another side along some edge, so we do a bit of searching.
715
void med_propagate_tmaps_to_back_side(const vmsegptridx_t base_seg, int back_side, int uv_only_flag)
716
{
717
        int     v1=0,v2=0;
718
 
719
        if (IS_CHILD(base_seg->children[back_side]))
720
                return;         // connection, so no sides here.
721
 
722
        //      Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side]
723
        range_for (const auto &&es, enumerate(Edge_between_sides))
724
        {
725
                const auto s = es.idx;
726
                if ((s != back_side) && (s != Side_opposite[back_side])) {
727
                        auto &ebs = es.value;
728
                        v1 = ebs[back_side][0];
729
                        v2 = ebs[back_side][1];
730
                        propagate_tmaps_to_segment_side(base_seg, s, base_seg, back_side, base_seg->verts[v1], base_seg->verts[v2], uv_only_flag);
731
                        goto found1;
732
                }
733
        }
734
        Assert(0);              // Error -- couldn't find edge != back_side and Side_opposite[back_side]
735
found1: ;
736
        Assert( (v1 != -1) && (v2 != -1));              // This means there was no shared edge between the two sides.
737
 
738
        //      Assign an unused tmap id to the back side.
739
        //      Note that this can get undone by the caller if this was not part of a new attach, but a rotation or a scale (which
740
        //      both do attaches).
741
        //      First see if tmap on back side is anywhere else.
742
        if (!uv_only_flag) {
743
                const auto back_side_tmap = base_seg->unique_segment::sides[back_side].tmap_num;
744
                range_for (const auto &&es, enumerate(base_seg->unique_segment::sides))
745
                {
746
                        if (es.idx != back_side)
747
                                if (es.value.tmap_num == back_side_tmap)
748
                                {
749
                                        range_for (const uint_fast32_t tmap_num, xrange(MAX_SIDES_PER_SEGMENT))
750
                                        {
751
                                                range_for (const uint_fast32_t ss, xrange(MAX_SIDES_PER_SEGMENT))
752
                                                        if (ss != back_side)
753
                                                                if (base_seg->unique_segment::sides[ss].tmap_num == New_segment.unique_segment::sides[tmap_num].tmap_num)
754
                                                                        goto found2;            // current texture map (tmap_num) is used on current (ss) side, so try next one
755
                                                // Current texture map (tmap_num) has not been used, assign to all faces on back_side.
756
                                                base_seg->unique_segment::sides[back_side].tmap_num = New_segment.unique_segment::sides[tmap_num].tmap_num;
757
                                                goto done1;
758
                                        found2: ;
759
                                        }
760
                                }
761
                }
762
        done1: ;
763
        }
764
 
765
}
766
 
767
int fix_bogus_uvs_on_side(void)
768
{
769
        med_propagate_tmaps_to_back_side(Cursegp, Curside, 1);
770
        return 0;
771
}
772
 
773
static void fix_bogus_uvs_on_side1(const vmsegptridx_t sp, const unsigned sidenum, const int uvonly_flag)
774
{
775
        auto &uvls = sp->unique_segment::sides[sidenum].uvls;
776
        if (uvls[0].u == 0 && uvls[1].u == 0 && uvls[2].u == 0)
777
        {
778
                med_propagate_tmaps_to_back_side(sp, sidenum, uvonly_flag);
779
        }
780
}
781
 
782
static void fix_bogus_uvs_seg(const vmsegptridx_t segp)
783
{
784
        range_for (const auto &&es, enumerate(segp->children))
785
        {
786
                if (!IS_CHILD(es.value))
787
                        fix_bogus_uvs_on_side1(segp, es.idx, 1);
788
        }
789
}
790
 
791
int fix_bogus_uvs_all(void)
792
{
793
        range_for (const auto &&segp, vmsegptridx)
794
        {
795
                if (segp->segnum != segment_none)
796
                        fix_bogus_uvs_seg(segp);
797
        }
798
        return 0;
799
}
800
 
801
// -----------------------------------------------------------------------------
802
//      Segment base_seg is connected through side base_side to segment con_seg on con_side.
803
//      For all walls in con_seg, find the wall in base_seg which shares an edge.  Copy tmap_num
804
//      from that side in base_seg to the wall in con_seg.  If the wall in base_seg is not present
805
//      (ie, there is another segment connected through it), follow the connection through that
806
//      segment to get the wall in the connected segment which shares the edge, and get tmap_num from there.
807
static void propagate_tmaps_to_segment_sides(const vmsegptridx_t base_seg, int base_side, const vmsegptridx_t con_seg, int con_side, int uv_only_flag)
808
{
809
        int             abs_id1,abs_id2;
810
        int             v;
811
 
812
        auto &base_vp = Side_to_verts[base_side];
813
 
814
        // Do for each edge on connecting face.
815
        for (v=0; v<4; v++) {
816
                abs_id1 = base_seg->verts[static_cast<int>(base_vp[v])];
817
                abs_id2 = base_seg->verts[static_cast<int>(base_vp[(v+1) % 4])];
818
                propagate_tmaps_to_segment_side(base_seg, base_side, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
819
        }
820
 
821
}
822
 
823
// -----------------------------------------------------------------------------
824
//      Propagate texture maps in base_seg to con_seg.
825
//      For each wall in con_seg, find the wall in base_seg which shared an edge.  Copy tmap_num from that
826
//      wall in base_seg to the wall in con_seg.  If the wall in base_seg is not present, then look at the
827
//      segment connected through base_seg through the wall.  The wall with a common edge is the new wall
828
//      of interest.  Continue searching in this way until a wall of interest is present.
829
void med_propagate_tmaps_to_segments(const vmsegptridx_t base_seg,const vmsegptridx_t con_seg, int uv_only_flag)
830
{
831
        range_for (const auto &&es, enumerate(base_seg->children))
832
                if (es.value == con_seg)
833
                        propagate_tmaps_to_segment_sides(base_seg, es.idx, con_seg, find_connect_side(base_seg, con_seg), uv_only_flag);
834
 
835
        con_seg->static_light = base_seg->static_light;
836
 
837
        validate_uv_coordinates(con_seg);
838
}
839
 
840
 
841
// -------------------------------------------------------------------------------
842
//      Copy texture map uvs from srcseg to destseg.
843
//      If two segments have different face structure (eg, destseg has two faces on side 3, srcseg has only 1)
844
//      then assign uvs according to side vertex id, not face vertex id.
845
void copy_uvs_seg_to_seg(unique_segment &destseg, const unique_segment &srcseg)
846
{
847
        range_for (const auto &&z, zip(destseg.sides, srcseg.sides))
848
        {
849
                auto &ds = std::get<0>(z);
850
                auto &ss = std::get<1>(z);
851
                ds.tmap_num = ss.tmap_num;
852
                ds.tmap_num2 = ss.tmap_num2;
853
        }
854
 
855
        destseg.static_light = srcseg.static_light;
856
}
857
 
858
}
859
 
860
namespace dcx {
861
 
862
//      _________________________________________________________________________________________________________________________
863
//      Maximum distance between a segment containing light to a segment to receive light.
864
#define LIGHT_DISTANCE_THRESHOLD        (F1_0*80)
865
fix     Magical_light_constant = (F1_0*16);
866
 
867
// int  Seg0, Seg1;
868
 
869
//int   Bugseg = 27;
870
 
871
struct hash_info {
872
        sbyte                   flag, hit_type;
873
        vms_vector      vector;
874
};
875
 
876
#define FVI_HASH_SIZE 8
877
#define FVI_HASH_AND_MASK (FVI_HASH_SIZE - 1)
878
 
879
//      Note: This should be malloced.
880
//                      Also, the vector should not be 12 bytes, you should only care about some smaller portion of it.
881
static std::array<hash_info, FVI_HASH_SIZE> fvi_cache;
882
static int Hash_hits=0, Hash_retries=0, Hash_calcs=0;
883
 
884
//      -----------------------------------------------------------------------------------------
885
//      Set light from a light source.
886
//      Light incident on a surface is defined by the light incident at its points.
887
//      Light at a point = K * (V . N) / d
888
//      where:
889
//              K = some magical constant to make everything look good
890
//              V = normalized vector from light source to point
891
//              N = surface normal at point
892
//              d = distance from light source to point
893
//      (Note that the above equation can be simplified to K * (VV . N) / d^2 where VV = non-normalized V)
894
//      Light intensity emitted from a light source is defined to be cast from four points.
895
//      These four points are 1/64 of the way from the corners of the light source to the center
896
//      of its segment.  By assuming light is cast from these points, rather than from on the
897
//      light surface itself, light will be properly cast on the light surface.  Otherwise, the
898
//      vector V would be the null vector.
899
//      If quick_light set, then don't use find_vector_intersection
900
static void cast_light_from_side(const vmsegptridx_t segp, int light_side, fix light_intensity, int quick_light)
901
{
902
        int                     vertnum;
903
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
904
        auto &Vertices = LevelSharedVertexState.get_vertices();
905
        auto &vcvertptr = Vertices.vcptr;
906
        auto &Walls = LevelUniqueWallSubsystemState.Walls;
907
        auto &vcwallptr = Walls.vcptr;
908
        const auto segment_center = compute_segment_center(vcvertptr, segp);
909
        //      Do for four lights, one just inside each corner of side containing light.
910
        range_for (const auto lightnum, Side_to_verts[light_side])
911
        {
912
                // fix                  inverse_segment_magnitude;
913
 
914
                const auto light_vertex_num = segp->verts[lightnum];
915
                auto light_location = *vcvertptr(light_vertex_num);
916
 
917
        //      New way, 5/8/95: Move towards center irrespective of size of segment.
918
                const auto vector_to_center = vm_vec_normalized_quick(vm_vec_sub(segment_center, light_location));
919
        vm_vec_add2(light_location, vector_to_center);
920
 
921
// -- Old way, before 5/8/95 --         // -- This way was kind of dumb.  In larger segments, you move LESS towards the center.
922
// -- Old way, before 5/8/95 --         //    Main problem, though, is vertices don't illuminate themselves well in oblong segments because the dot product is small.
923
// -- Old way, before 5/8/95 --         vm_vec_sub(&vector_to_center, &segment_center, &light_location);
924
// -- Old way, before 5/8/95 --         inverse_segment_magnitude = fixdiv(F1_0/5, vm_vec_mag(&vector_to_center));
925
// -- Old way, before 5/8/95 --         vm_vec_scale_add(&light_location, &light_location, &vector_to_center, inverse_segment_magnitude);
926
 
927
                range_for (const auto &&rsegp, vmsegptr)
928
                {
929
                        fix                     dist_to_rseg;
930
 
931
                        range_for (auto &i, fvi_cache)
932
                                i.flag = 0;
933
 
934
                        //      efficiency hack (I hope!), for faraway segments, don't check each point.
935
                        const auto r_segment_center = compute_segment_center(vcvertptr, rsegp);
936
                        dist_to_rseg = vm_vec_dist_quick(r_segment_center, segment_center);
937
 
938
                        if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
939
                                for (const auto &&[sidenum, srside, urside] : enumerate(zip(rsegp->shared_segment::sides, rsegp->unique_segment::sides)))
940
                                {
941
                                        if (WALL_IS_DOORWAY(GameBitmaps, Textures, vcwallptr, rsegp, sidenum) != WID_NO_WALL)
942
                                        {
943
                                                auto &side_normalp = srside.normals[0]; //      kinda stupid? always use vector 0.
944
 
945
                                                for (vertnum=0; vertnum<4; vertnum++) {
946
                                                        fix                     distance_to_point, light_at_point, light_dot;
947
 
948
                                                        const auto abs_vertnum = rsegp->verts[Side_to_verts[sidenum][vertnum]];
949
                                                        vms_vector vert_location = *vcvertptr(abs_vertnum);
950
                                                        distance_to_point = vm_vec_dist_quick(vert_location, light_location);
951
                                                        const auto vector_to_light = vm_vec_normalized(vm_vec_sub(light_location, vert_location));
952
 
953
                                                        //      Hack: In oblong segments, it's possible to get a very small dot product
954
                                                        //      but the light source is very nearby (eg, illuminating light itself!).
955
                                                        light_dot = vm_vec_dot(vector_to_light, side_normalp);
956
                                                        if (distance_to_point < F1_0)
957
                                                                if (light_dot > 0)
958
                                                                        light_dot = (light_dot + F1_0)/2;
959
 
960
                                                        if (light_dot > 0) {
961
                                                                light_at_point = fixdiv(fixmul(light_dot, light_dot), distance_to_point);
962
                                                                light_at_point = fixmul(light_at_point, Magical_light_constant);
963
                                                                if (light_at_point >= 0) {
964
                                                                        fvi_info        hit_data;
965
                                                                        int             hit_type;
966
                                                                        fix             inverse_segment_magnitude;
967
 
968
                                                                        const auto r_vector_to_center = vm_vec_sub(r_segment_center, vert_location);
969
                                                                        inverse_segment_magnitude = fixdiv(F1_0/3, vm_vec_mag(r_vector_to_center));
970
                                                                        const auto vert_location_1 = vm_vec_scale_add(vert_location, r_vector_to_center, inverse_segment_magnitude);
971
                                                                        vert_location = vert_location_1;
972
 
973
//if ((segp-Segments == 199) && (rsegp-Segments==199))
974
//      Int3();
975
// Seg0 = segp-Segments;
976
// Seg1 = rsegp-Segments;
977
                                                                        if (!quick_light) {
978
                                                                                int hash_value = Side_to_verts[sidenum][vertnum];
979
                                                                                hash_info       *hashp = &fvi_cache[hash_value];
980
                                                                                while (1) {
981
                                                                                        if (hashp->flag) {
982
                                                                                                if ((hashp->vector.x == vector_to_light.x) && (hashp->vector.y == vector_to_light.y) && (hashp->vector.z == vector_to_light.z)) {
983
                                                                                                        hit_type = hashp->hit_type;
984
                                                                                                        Hash_hits++;
985
                                                                                                        break;
986
                                                                                                } else {
987
                                                                                                        Int3(); // How is this possible?  Should be no hits!
988
                                                                                                        Hash_retries++;
989
                                                                                                        hash_value = (hash_value+1) & FVI_HASH_AND_MASK;
990
                                                                                                        hashp = &fvi_cache[hash_value];
991
                                                                                                }
992
                                                                                        } else {
993
                                                                                                fvi_query fq;
994
 
995
                                                                                                Hash_calcs++;
996
                                                                                                hashp->vector = vector_to_light;
997
                                                                                                hashp->flag = 1;
998
 
999
                                                                                                fq.p0                                           = &light_location;
1000
                                                                                                fq.startseg                             = segp;
1001
                                                                                                fq.p1                                           = &vert_location;
1002
                                                                                                fq.rad                                  = 0;
1003
                                                                                                fq.thisobjnum                   = object_none;
1004
                                                                                                fq.ignore_obj_list.first = nullptr;
1005
                                                                                                fq.flags                                        = 0;
1006
 
1007
                                                                                                hit_type = find_vector_intersection(fq, hit_data);
1008
                                                                                                hashp->hit_type = hit_type;
1009
                                                                                                break;
1010
                                                                                        }
1011
                                                                                }
1012
                                                                        } else
1013
                                                                                hit_type = HIT_NONE;
1014
                                                                        switch (hit_type) {
1015
                                                                                case HIT_NONE:
1016
                                                                                        light_at_point = fixmul(light_at_point, light_intensity);
1017
                                                                                        urside.uvls[vertnum].l += light_at_point;
1018
                                                                                        if (urside.uvls[vertnum].l > F1_0)
1019
                                                                                                urside.uvls[vertnum].l = F1_0;
1020
                                                                                        break;
1021
                                                                                case HIT_WALL:
1022
                                                                                        break;
1023
                                                                                case HIT_OBJECT:
1024
                                                                                        Int3(); // Hit object, should be ignoring objects!
1025
                                                                                        break;
1026
                                                                                case HIT_BAD_P0:
1027
                                                                                        Int3(); //      Ugh, this thing again, what happened, what does it mean?
1028
                                                                                        break;
1029
                                                                        }
1030
                                                                }       //      end if (light_at_point...
1031
                                                        }       // end if (light_dot >...
1032
                                                }       //      end for (vertnum=0...
1033
                                        }       //      end if (rsegp...
1034
                                }       //      end for (sidenum=0...
1035
                        }       //      end if (dist_to_rseg...
1036
 
1037
                }       //      end for (segnum=0...
1038
 
1039
        }       //      end for (lightnum=0...
1040
}
1041
 
1042
 
1043
//      ------------------------------------------------------------------------------------------
1044
//      Zero all lighting values.
1045
static void calim_zero_light_values(void)
1046
{
1047
        range_for (unique_segment &segp, vmsegptr)
1048
        {
1049
                range_for (auto &side, segp.sides)
1050
                {
1051
                        range_for (auto &uvl, side.uvls)
1052
                                uvl.l = F1_0/64;        // Put a tiny bit of light here.
1053
                }
1054
                segp.static_light = F1_0 / 64;
1055
        }
1056
}
1057
 
1058
 
1059
//      ------------------------------------------------------------------------------------------
1060
//      Used in setting average light value in a segment, cast light from a side to the center
1061
//      of all segments.
1062
static void cast_light_from_side_to_center(const vmsegptridx_t segp, int light_side, fix light_intensity, int quick_light)
1063
{
1064
        auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
1065
        auto &Vertices = LevelSharedVertexState.get_vertices();
1066
        auto &vcvertptr = Vertices.vcptr;
1067
        const auto &&segment_center = compute_segment_center(vcvertptr, segp);
1068
        //      Do for four lights, one just inside each corner of side containing light.
1069
        range_for (const auto lightnum, Side_to_verts[light_side])
1070
        {
1071
                const auto light_vertex_num = segp->verts[lightnum];
1072
                auto &vert_light_location = *vcvertptr(light_vertex_num);
1073
                const auto vector_to_center = vm_vec_sub(segment_center, vert_light_location);
1074
                const auto light_location = vm_vec_scale_add(vert_light_location, vector_to_center, F1_0/64);
1075
 
1076
                range_for (const auto &&rsegp, vmsegptr)
1077
                {
1078
                        fix                     dist_to_rseg;
1079
//if ((segp == &Segments[Bugseg]) && (rsegp == &Segments[Bugseg]))
1080
//      Int3();
1081
                        const auto r_segment_center = compute_segment_center(vcvertptr, rsegp);
1082
                        dist_to_rseg = vm_vec_dist_quick(r_segment_center, segment_center);
1083
 
1084
                        if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
1085
                                fix     light_at_point;
1086
                                if (dist_to_rseg > F1_0)
1087
                                        light_at_point = fixdiv(Magical_light_constant, dist_to_rseg);
1088
                                else
1089
                                        light_at_point = Magical_light_constant;
1090
 
1091
                                if (light_at_point >= 0) {
1092
                                        int             hit_type;
1093
 
1094
                                        if (!quick_light) {
1095
                                                fvi_query fq;
1096
                                                fvi_info        hit_data;
1097
 
1098
                                                fq.p0                                           = &light_location;
1099
                                                fq.startseg                             = segp;
1100
                                                fq.p1                                           = &r_segment_center;
1101
                                                fq.rad                                  = 0;
1102
                                                fq.thisobjnum                   = object_none;
1103
                                                fq.ignore_obj_list.first = nullptr;
1104
                                                fq.flags                                        = 0;
1105
 
1106
                                                hit_type = find_vector_intersection(fq, hit_data);
1107
                                        }
1108
                                        else
1109
                                                hit_type = HIT_NONE;
1110
 
1111
                                        switch (hit_type) {
1112
                                                case HIT_NONE:
1113
                                                        light_at_point = fixmul(light_at_point, light_intensity);
1114
                                                        if (light_at_point >= F1_0)
1115
                                                                light_at_point = F1_0-1;
1116
                                                        rsegp->static_light += light_at_point;
1117
                                                        if (segp->static_light < 0)     // if it went negative, saturate
1118
                                                                segp->static_light = 0;
1119
                                                        break;
1120
                                                case HIT_WALL:
1121
                                                        break;
1122
                                                case HIT_OBJECT:
1123
                                                        Int3(); // Hit object, should be ignoring objects!
1124
                                                        break;
1125
                                                case HIT_BAD_P0:
1126
                                                        Int3(); //      Ugh, this thing again, what happened, what does it mean?
1127
                                                        break;
1128
                                        }
1129
                                }       //      end if (light_at_point...
1130
                        }       //      end if (dist_to_rseg...
1131
 
1132
                }       //      end for (segnum=0...
1133
 
1134
        }       //      end for (lightnum=0...
1135
 
1136
}
1137
 
1138
//      ------------------------------------------------------------------------------------------
1139
//      Process all lights.
1140
static void calim_process_all_lights(int quick_light)
1141
{
1142
        auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
1143
        auto &Walls = LevelUniqueWallSubsystemState.Walls;
1144
        auto &vcwallptr = Walls.vcptr;
1145
        range_for (const auto &&segp, vmsegptridx)
1146
        {
1147
                range_for (const auto &&es, enumerate(segp->unique_segment::sides))
1148
                {
1149
                        const uint_fast32_t sidenum = es.idx;
1150
                        if (WALL_IS_DOORWAY(GameBitmaps, Textures, vcwallptr, segp, sidenum) != WID_NO_WALL)
1151
                        {
1152
                                const auto sidep = &es.value;
1153
                                fix     light_intensity;
1154
 
1155
                                light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting;
1156
 
1157
//                              if (segp->sides[sidenum].wall_num != -1) {
1158
//                                      int     wall_num, bitmap_num, effect_num;
1159
//                                      wall_num = segp->sides[sidenum].wall_num;
1160
//                                      effect_num = Walls[wall_num].type;
1161
//                                      bitmap_num = effects_bm_num[effect_num];
1162
//
1163
//                                      light_intensity += TmapInfo[bitmap_num].lighting;
1164
//                              }
1165
 
1166
                                if (light_intensity) {
1167
                                        light_intensity /= 4;                   // casting light from four spots, so divide by 4.
1168
                                        cast_light_from_side(segp, sidenum, light_intensity, quick_light);
1169
                                        cast_light_from_side_to_center(segp, sidenum, light_intensity, quick_light);
1170
                                }
1171
                        }
1172
                }
1173
        }
1174
}
1175
 
1176
//      ------------------------------------------------------------------------------------------
1177
//      Apply static light in mine.
1178
//      First, zero all light values.
1179
//      Then, for all light sources, cast their light.
1180
static void cast_all_light_in_mine(int quick_flag)
1181
{
1182
        validate_segment_all(LevelSharedSegmentState);
1183
        calim_zero_light_values();
1184
 
1185
        calim_process_all_lights(quick_flag);
1186
}
1187
 
1188
}
1189
 
1190
// int  Fvit_num = 1000;
1191
// 
1192
// fix find_vector_intersection_test(void)
1193
// {
1194
//      int             i;
1195
//      fvi_info        hit_data;
1196
//      int             p0_seg, p1_seg, this_objnum, ignore_obj, check_obj_flag;
1197
//      fix             rad;
1198
//      int             start_time = timer_get_milliseconds();;
1199
//      vms_vector      p0,p1;
1200
// 
1201
//      ignore_obj = 1;
1202
//      check_obj_flag = 0;
1203
//      this_objnum = -1;
1204
//      rad = F1_0/4;
1205
// 
1206
//      for (i=0; i<Fvit_num; i++) {
1207
//              p0_seg = d_rand()*(Highest_segment_index+1)/32768;
1208
//              compute_segment_center(&p0, &Segments[p0_seg]);
1209
// 
1210
//              p1_seg = d_rand()*(Highest_segment_index+1)/32768;
1211
//              compute_segment_center(&p1, &Segments[p1_seg]);
1212
// 
1213
//              find_vector_intersection(&hit_data, &p0, p0_seg, &p1, rad, this_objnum, ignore_obj, check_obj_flag);
1214
//      }
1215
// 
1216
//      return timer_get_milliseconds() - start_time;
1217
// }