avoid assignments between sbyte * and char *, ubyte * and char * to fix warnings...
[btb/d2x.git] / main / editor / seguvs.c
1 /* $Id: seguvs.c,v 1.6 2005-07-25 04:09:40 chris 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  * u,v coordinate computation for segment faces
18  *
19  */
20
21 #ifdef RCS
22 static char rcsid[] = "$Id: seguvs.c,v 1.6 2005-07-25 04:09:40 chris Exp $";
23 #endif
24
25 #ifdef HAVE_CONFIG_H
26 #include "conf.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <math.h>
33 #include <string.h>
34
35 #include "inferno.h"
36 #include "segment.h"
37 #include "editor/editor.h"
38
39 #include "gameseg.h"
40
41 #include "fix.h"
42 #include "mono.h"
43 #include "error.h"
44
45 #include "wall.h"
46 #include "editor/kdefs.h"
47 #include "bm.h"         //      Needed for TmapInfo
48 #include        "effects.h"     //      Needed for effects_bm_num
49 #include "fvi.h"
50
51 void cast_all_light_in_mine(int quick_flag);
52 //--rotate_uvs-- vms_vector Rightvec;
53
54 //      ---------------------------------------------------------------------------------------------
55 //      Returns approximate area of a side
56 fix area_on_side(side *sidep)
57 {
58         fix     du,dv,width,height;
59
60         du = sidep->uvls[1].u - sidep->uvls[0].u;
61         dv = sidep->uvls[1].v - sidep->uvls[0].v;
62
63         width = fix_sqrt(fixmul(du,du) + fixmul(dv,dv));
64
65         du = sidep->uvls[3].u - sidep->uvls[0].u;
66         dv = sidep->uvls[3].v - sidep->uvls[0].v;
67
68         height = fix_sqrt(fixmul(du,du) + fixmul(dv,dv));
69
70         return fixmul(width, height);
71 }
72
73 //      -------------------------------------------------------------------------------------------
74 //      DEBUG function -- callable from debugger.
75 //      Returns approximate area of all sides which get mapped (ie, are not a connection).
76 //      I wrote this because I was curious how much memory would be required to texture map all
77 //      sides individually with custom artwork.  For demo1.min on 2/18/94, it would be about 5 meg.
78 int area_on_all_sides(void)
79 {
80         int     i,s;
81         int     total_area = 0;
82
83         for (i=0; i<=Highest_segment_index; i++) {
84                 segment *segp = &Segments[i];
85
86                 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
87                         if (!IS_CHILD(segp->children[s]))
88                                 total_area += f2i(area_on_side(&segp->sides[s]));
89         }
90
91         return total_area;
92 }
93
94 fix average_connectivity(void)
95 {
96         int     i,s;
97         int     total_sides = 0, total_mapped_sides = 0;
98
99         for (i=0; i<=Highest_segment_index; i++) {
100                 segment *segp = &Segments[i];
101
102                 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
103                         if (!IS_CHILD(segp->children[s]))
104                                 total_mapped_sides++;
105                         total_sides++;
106                 }
107         }
108
109         return 6 * fixdiv(total_mapped_sides, total_sides);
110 }
111
112 #define MAX_LIGHT_SEGS 16
113
114 //      ---------------------------------------------------------------------------------------------
115 //      Scan all polys in all segments, return average light value for vnum.
116 //      segs = output array for segments containing vertex, terminated by -1.
117 fix get_average_light_at_vertex(int vnum, short *segs)
118 {
119         int     segnum, relvnum, sidenum;
120         fix     total_light;
121         int     num_occurrences;
122 //      #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
123         short   *original_segs;
124
125         original_segs = segs;
126 //      #endif
127
128
129         num_occurrences = 0;
130         total_light = 0;
131
132         for (segnum=0; segnum<=Highest_segment_index; segnum++) {
133                 segment *segp = &Segments[segnum];
134                 short *vp = segp->verts;
135
136                 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
137                         if (*vp++ == vnum)
138                                 break;
139
140                 if (relvnum < MAX_VERTICES_PER_SEGMENT) {
141
142                         *segs++ = segnum;
143                         Assert(segs - original_segs < MAX_LIGHT_SEGS);
144
145                         for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
146                                 if (!IS_CHILD(segp->children[sidenum])) {
147                                         side    *sidep = &segp->sides[sidenum];
148                                         sbyte   *vp = Side_to_verts[sidenum];
149                                         int     v;
150
151                                         for (v=0; v<4; v++)
152                                                 if (*vp++ == relvnum) {
153                                                         total_light += sidep->uvls[v].l;
154                                                         num_occurrences++;
155                                                 }
156                                 }       // end if
157                         }       // end sidenum
158                 }
159         }       // end segnum
160
161         *segs = -1;
162
163         if (num_occurrences)
164                 return total_light/num_occurrences;
165         else
166                 return 0;
167
168 }
169
170 void set_average_light_at_vertex(int vnum)
171 {
172         int     relvnum, sidenum;
173         short   Segment_indices[MAX_LIGHT_SEGS];
174         int     segind;
175
176         fix average_light;
177
178         average_light = get_average_light_at_vertex(vnum, Segment_indices);
179
180         if (!average_light)
181                 return;
182
183         segind = 0;
184         while (Segment_indices[segind] != -1) {
185                 int segnum = Segment_indices[segind++];
186
187                 segment *segp = &Segments[segnum];
188
189                 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
190                         if (segp->verts[relvnum] == vnum)
191                                 break;
192
193                 if (relvnum < MAX_VERTICES_PER_SEGMENT) {
194                         for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
195                                 if (!IS_CHILD(segp->children[sidenum])) {
196                                         side *sidep = &segp->sides[sidenum];
197                                         sbyte   *vp = Side_to_verts[sidenum];
198                                         int     v;
199
200                                         for (v=0; v<4; v++)
201                                                 if (*vp++ == relvnum)
202                                                         sidep->uvls[v].l = average_light;
203                                 }       // end if
204                         }       // end sidenum
205                 }       // end if
206         }       // end while
207
208         Update_flags |= UF_WORLD_CHANGED;
209 }
210
211 void set_average_light_on_side(segment *segp, int sidenum)
212 {
213         int     v;
214
215         if (!IS_CHILD(segp->children[sidenum]))
216                 for (v=0; v<4; v++) {
217 //                      mprintf((0,"Vertex %i\n", segp->verts[Side_to_verts[side][v]]));
218                         set_average_light_at_vertex(segp->verts[Side_to_verts[sidenum][v]]);
219                 }
220
221 }
222
223 int set_average_light_on_curside(void)
224 {
225         set_average_light_on_side(Cursegp, Curside);
226         return 0;
227 }
228
229 //      -----------------------------------------------------------------------------------------
230 void set_average_light_on_all_fast(void)
231 {
232         int     s,v,relvnum;
233         fix     al;
234         int     alc;
235         int     seglist[MAX_LIGHT_SEGS];
236         int     *segptr;
237
238         set_vertex_counts();
239
240         //      Set total light value for all vertices in array average_light.
241         for (v=0; v<=Highest_vertex_index; v++) {
242                 al = 0;
243                 alc = 0;
244
245                 if (Vertex_active[v]) {
246                         segptr = seglist;
247
248                         for (s=0; s<=Highest_segment_index; s++) {
249                                 segment *segp = &Segments[s];
250                                 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
251                                         if (segp->verts[relvnum] == v)
252                                                 break;
253
254                                         if (relvnum != MAX_VERTICES_PER_SEGMENT) {
255                                                 int             si;
256
257                                                 *segptr++ = s;                  // Note this segment in list, so we can process it below.
258                                                 Assert(segptr - seglist < MAX_LIGHT_SEGS);
259
260                                                 for (si=0; si<MAX_SIDES_PER_SEGMENT; si++) {
261                                                         if (!IS_CHILD(segp->children[si])) {
262                                                                 side    *sidep = &segp->sides[si];
263                                                                 sbyte   *vp = Side_to_verts[si];
264                                                                 int     vv;
265
266                                                                 for (vv=0; vv<4; vv++)
267                                                                         if (*vp++ == relvnum) {
268                                                                                 al += sidep->uvls[vv].l;
269                                                                                 alc++;
270                                                                         }
271                                                         }       // if (segp->children[si == -1) {
272                                                 }       // for (si=0...
273                                         }       // if (relvnum != ...
274                         }       // for (s=0; ...
275
276                         *segptr = -1;
277
278                         //      Now, divide average_light by number of number of occurrences for each vertex
279                         if (alc)
280                                 al /= alc;
281                         else
282                                 al = 0;
283
284                         segptr = seglist;
285                         while (*segptr != -1) {
286                                 int             segnum = *segptr++;
287                                 segment *segp = &Segments[segnum];
288                                 int             sidenum;
289
290                                 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
291                                         if (segp->verts[relvnum] == v)
292                                                 break;
293
294                                 Assert(relvnum < MAX_VERTICES_PER_SEGMENT);     // IMPOSSIBLE! This segment is in seglist, but vertex v does not occur!
295                                 for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
296                                         int     wid_result;
297                                         wid_result = WALL_IS_DOORWAY(segp, sidenum);
298                                         if ((wid_result != WID_FLY_FLAG) && (wid_result != WID_NO_WALL)) {
299                                                 side *sidep = &segp->sides[sidenum];
300                                                 sbyte   *vp = Side_to_verts[sidenum];
301                                                 int     v;
302
303                                                 for (v=0; v<4; v++)
304                                                         if (*vp++ == relvnum)
305                                                                 sidep->uvls[v].l = al;
306                                         }       // end if
307                                 }       // end sidenum
308                         }       // end while
309
310                 }       // if (Vertex_active[v]...
311
312         }       // for (v=0...
313
314 }
315
316 extern int Doing_lighting_hack_flag;    //      If set, don't mprintf warning messages in gameseg.c/find_point_seg
317 int set_average_light_on_all(void)
318 {
319 //      set_average_light_on_all_fast();
320
321         Doing_lighting_hack_flag = 1;
322         cast_all_light_in_mine(0);
323         Doing_lighting_hack_flag = 0;
324         Update_flags |= UF_WORLD_CHANGED;
325
326 //      int seg, side;
327
328 //      for (seg=0; seg<=Highest_segment_index; seg++)
329 //              for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
330 //                      if (Segments[seg].segnum != -1)
331 //                              set_average_light_on_side(&Segments[seg], side);
332         return 0;
333 }
334
335 int set_average_light_on_all_quick(void)
336 {
337         cast_all_light_in_mine(1);
338         Update_flags |= UF_WORLD_CHANGED;
339
340         return 0;
341 }
342
343 //      ---------------------------------------------------------------------------------------------
344 fix compute_uv_dist(uvl *uv0, uvl *uv1)
345 {
346         vms_vector      v0,v1;
347
348         v0.x = uv0->u;
349         v0.y = 0;
350         v0.z = uv0->v;
351
352         v1.x = uv1->u;
353         v1.y = 0;
354         v1.z = uv1->v;
355
356         return vm_vec_dist(&v0,&v1);
357 }
358
359 //      ---------------------------------------------------------------------------------------------
360 //      Given a polygon, compress the uv coordinates so that they are as close to 0 as possible.
361 //      Do this by adding a constant u and v to each uv pair.
362 void compress_uv_coordinates(side *sidep)
363 {
364         int     v;
365         fix     uc, vc;
366
367         uc = 0;
368         vc = 0;
369
370         for (v=0; v<4; v++) {
371                 uc += sidep->uvls[v].u;
372                 vc += sidep->uvls[v].v;
373         }
374
375         uc /= 4;
376         vc /= 4;
377         uc = uc & 0xffff0000;
378         vc = vc & 0xffff0000;
379
380         for (v=0; v<4; v++) {
381                 sidep->uvls[v].u -= uc;
382                 sidep->uvls[v].v -= vc;
383         }
384
385 }
386
387 //      ---------------------------------------------------------------------------------------------
388 void compress_uv_coordinates_on_side(side *sidep)
389 {
390         compress_uv_coordinates(sidep);
391 }
392
393 //      ---------------------------------------------------------------------------------------------
394 void validate_uv_coordinates_on_side(segment *segp, int sidenum)
395 {
396 //      int                     v;
397 //      fix                     uv_dist,threed_dist;
398 //      vms_vector      tvec;
399 //      fix                     dist_ratios[MAX_VERTICES_PER_POLY];
400         side                    *sidep = &segp->sides[sidenum];
401 //      sbyte                   *vp = Side_to_verts[sidenum];
402
403 //      This next hunk doesn't seem to affect anything. @mk, 02/13/94
404 //      for (v=1; v<4; v++) {
405 //              uv_dist = compute_uv_dist(&sidep->uvls[v],&sidep->uvls[0]);
406 //              threed_dist = vm_vec_mag(vm_vec_sub(&tvec,&Vertices[segp->verts[vp[v]],&Vertices[vp[0]]));
407 //              dist_ratios[v-1] = fixdiv(uv_dist,threed_dist);
408 //      }
409
410         compress_uv_coordinates_on_side(sidep);
411 }
412
413 void compress_uv_coordinates_in_segment(segment *segp)
414 {
415         int     side;
416
417         for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
418                 compress_uv_coordinates_on_side(&segp->sides[side]);
419 }
420
421 void compress_uv_coordinates_all(void)
422 {
423         int     seg;
424
425         for (seg=0; seg<=Highest_segment_index; seg++)
426                 if (Segments[seg].segnum != -1)
427                         compress_uv_coordinates_in_segment(&Segments[seg]);
428 }
429
430 void check_lighting_side(segment *sp, int sidenum)
431 {
432         int     v;
433         side    *sidep = &sp->sides[sidenum];
434
435         for (v=0; v<4; v++)
436                 if ((sidep->uvls[v].l > F1_0*16) || (sidep->uvls[v].l < 0))
437                         Int3(); //mprintf(0,"Bogus lighting value in segment %i, side %i, vert %i = %x\n",sp-Segments, side, v, sidep->uvls[v].l);
438 }
439
440 void check_lighting_segment(segment *segp)
441 {
442         int     side;
443
444         for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
445                 check_lighting_side(segp, side);
446 }
447
448 //      Flag bogus lighting values.
449 void check_lighting_all(void)
450 {
451         int     seg;
452
453         for (seg=0; seg<=Highest_segment_index; seg++)
454                 if (Segments[seg].segnum != -1)
455                         check_lighting_segment(&Segments[seg]);
456 }
457
458 void assign_default_lighting_on_side(segment *segp, int sidenum)
459 {
460         int     v;
461         side    *sidep = &segp->sides[sidenum];
462
463         for (v=0; v<4; v++)
464                 sidep->uvls[v].l = DEFAULT_LIGHTING;
465 }
466
467 void assign_default_lighting(segment *segp)
468 {
469         int     sidenum;
470
471         for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
472                 assign_default_lighting_on_side(segp, sidenum);
473 }
474
475 void assign_default_lighting_all(void)
476 {
477         int     seg;
478
479         for (seg=0; seg<=Highest_segment_index; seg++)
480                 if (Segments[seg].segnum != -1)
481                         assign_default_lighting(&Segments[seg]);
482 }
483
484 //      ---------------------------------------------------------------------------------------------
485 void validate_uv_coordinates(segment *segp)
486 {
487         int     s;
488
489         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
490                 validate_uv_coordinates_on_side(segp,s);
491
492 }
493
494 //      ---------------------------------------------------------------------------------------------
495 //      For all faces in side, copy uv coordinates from uvs array to face.
496 void copy_uvs_from_side_to_faces(segment *segp, int sidenum, uvl uvls[])
497 {
498         int     v;
499         side    *sidep = &segp->sides[sidenum];
500
501         for (v=0; v<4; v++)
502                 sidep->uvls[v] = uvls[v];
503
504 }
505
506 #ifdef __WATCOMC__
507 fix zhypot(fix a,fix b);
508 #pragma aux zhypot parm [eax] [ebx] value [eax] modify [eax ebx ecx edx] = \
509         "imul   eax" \
510         "xchg eax,ebx" \
511         "mov    ecx,edx" \
512         "imul eax" \
513         "add    eax,ebx" \
514         "adc    edx,ecx" \
515         "call   quad_sqrt";
516 #else
517 fix zhypot(fix a,fix b) {
518         double x = (double)a / 65536;
519         double y = (double)b / 65536;
520         return (long)(sqrt(x * x + y * y) * 65536);
521 }
522 #endif
523
524 //      ---------------------------------------------------------------------------------------------
525 //      Assign lighting value to side, a function of the normal vector.
526 void assign_light_to_side(segment *sp, int sidenum)
527 {
528         int     v;
529         side    *sidep = &sp->sides[sidenum];
530
531         for (v=0; v<4; v++)
532                 sidep->uvls[v].l = DEFAULT_LIGHTING;
533 }
534
535 fix     Stretch_scale_x = F1_0;
536 fix     Stretch_scale_y = F1_0;
537
538 //      ---------------------------------------------------------------------------------------------
539 //      Given u,v coordinates at two vertices, assign u,v coordinates to other two vertices on a side.
540 //      (Actually, assign them to the coordinates in the faces.)
541 //      va, vb = face-relative vertex indices corresponding to uva, uvb.  Ie, they are always in 0..3 and should be looked up in
542 //      Side_to_verts[side] to get the segment relative index.
543 void assign_uvs_to_side(segment *segp, int sidenum, uvl *uva, uvl *uvb, int va, int vb)
544 {
545         int                     vlo,vhi,v0,v1,v2,v3;
546         vms_vector      fvec,rvec,tvec;
547         vms_matrix      rotmat;
548         uvl                     uvls[4],ruvmag,fuvmag,uvlo,uvhi;
549         fix                     fmag,mag01;
550         sbyte                   *vp;
551
552         Assert( (va<4) && (vb<4) );
553         Assert((abs(va - vb) == 1) || (abs(va - vb) == 3));             // make sure the verticies specify an edge
554
555         vp = (sbyte *)&Side_to_verts[sidenum];
556
557         // We want vlo precedes vhi, ie vlo < vhi, or vlo = 3, vhi = 0
558         if (va == ((vb + 1) % 4)) {             // va = vb + 1
559                 vlo = vb;
560                 vhi = va;
561                 uvlo = *uvb;
562                 uvhi = *uva;
563         } else {
564                 vlo = va;
565                 vhi = vb;
566                 uvlo = *uva;
567                 uvhi = *uvb;
568         }
569
570         Assert(((vlo+1) % 4) == vhi);   // If we are on an edge, then uvhi is one more than uvlo (mod 4)
571         uvls[vlo] = uvlo;
572         uvls[vhi] = uvhi;
573
574         // Now we have vlo precedes vhi, compute vertices ((vhi+1) % 4) and ((vhi+2) % 4)
575
576         // Assign u,v scale to a unit length right vector.
577         fmag = zhypot(uvhi.v - uvlo.v,uvhi.u - uvlo.u);
578         if (fmag < 64) {                // this is a fix, so 64 = 1/1024
579                 mprintf((0,"Warning: fmag = %7.3f, using approximate u,v values\n",f2fl(fmag)));
580                 ruvmag.u = F1_0*256;
581                 ruvmag.v = F1_0*256;
582                 fuvmag.u = F1_0*256;
583                 fuvmag.v = F1_0*256;
584         } else {
585                 ruvmag.u = uvhi.v - uvlo.v;
586                 ruvmag.v = uvlo.u - uvhi.u;
587
588                 fuvmag.u = uvhi.u - uvlo.u;
589                 fuvmag.v = uvhi.v - uvlo.v;
590         }
591
592         v0 = segp->verts[vp[vlo]];
593         v1 = segp->verts[vp[vhi]];
594         v2 = segp->verts[vp[(vhi+1)%4]];
595         v3 = segp->verts[vp[(vhi+2)%4]];
596
597         //      Compute right vector by computing orientation matrix from:
598         //              forward vector = vlo:vhi
599         //                right vector = vlo:(vhi+2) % 4
600         vm_vec_sub(&fvec,&Vertices[v1],&Vertices[v0]);
601         vm_vec_sub(&rvec,&Vertices[v3],&Vertices[v0]);
602
603         if (((fvec.x == 0) && (fvec.y == 0) && (fvec.z == 0)) || ((rvec.x == 0) && (rvec.y == 0) && (rvec.z == 0))) {
604                 mprintf((1, "Trapped null vector in assign_uvs_to_side, using identity matrix.\n"));
605                 rotmat = vmd_identity_matrix;
606         } else
607                 vm_vector_2_matrix(&rotmat,&fvec,0,&rvec);
608
609         rvec = rotmat.rvec; vm_vec_negate(&rvec);
610         fvec = rotmat.fvec;
611
612         // mprintf((0, "va = %i, vb = %i\n", va, vb));
613         mag01 = vm_vec_dist(&Vertices[v1],&Vertices[v0]);
614         if ((va == 0) || (va == 2))
615                 mag01 = fixmul(mag01, Stretch_scale_x);
616         else
617                 mag01 = fixmul(mag01, Stretch_scale_y);
618
619         if (mag01 < F1_0/1024 )
620                 editor_status("U, V bogosity in segment #%i, probably on side #%i.  CLEAN UP YOUR MESS!", segp-Segments, sidenum);
621         else {
622                 vm_vec_sub(&tvec,&Vertices[v2],&Vertices[v1]);
623                 uvls[(vhi+1)%4].u = uvhi.u + 
624                         fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) +
625                         fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01);
626
627                 uvls[(vhi+1)%4].v = uvhi.v + 
628                         fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) +
629                         fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01);
630
631
632                 vm_vec_sub(&tvec,&Vertices[v3],&Vertices[v0]);
633                 uvls[(vhi+2)%4].u = uvlo.u + 
634                         fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) +
635                         fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01);
636
637                 uvls[(vhi+2)%4].v = uvlo.v + 
638                         fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) +
639                         fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01);
640
641                 uvls[(vhi+1)%4].l = uvhi.l;
642                 uvls[(vhi+2)%4].l = uvlo.l;
643
644                 copy_uvs_from_side_to_faces(segp, sidenum, uvls);
645         }
646 }
647
648
649 int Vmag = VMAG;
650
651 // -----------------------------------------------------------------------------------------------------------
652 //      Assign default uvs to side.
653 //      This means:
654 //              v0 = 0,0
655 //              v1 = k,0 where k is 3d size dependent
656 //      v2, v3 assigned by assign_uvs_to_side
657 void assign_default_uvs_to_side(segment *segp,int side)
658 {
659         uvl                     uv0,uv1;
660         sbyte                   *vp;
661
662         uv0.u = 0;
663         uv0.v = 0;
664
665         vp = Side_to_verts[side];
666
667         uv1.u = 0;
668         uv1.v = Num_tilings * fixmul(Vmag, vm_vec_dist(&Vertices[segp->verts[vp[1]]],&Vertices[segp->verts[vp[0]]]));
669
670         assign_uvs_to_side(segp, side, &uv0, &uv1, 0, 1);
671 }
672
673 // -----------------------------------------------------------------------------------------------------------
674 //      Assign default uvs to side.
675 //      This means:
676 //              v0 = 0,0
677 //              v1 = k,0 where k is 3d size dependent
678 //      v2, v3 assigned by assign_uvs_to_side
679 void stretch_uvs_from_curedge(segment *segp, int side)
680 {
681         uvl                     uv0,uv1;
682         int                     v0, v1;
683
684         v0 = Curedge;
685         v1 = (v0 + 1) % 4;
686
687         uv0.u = segp->sides[side].uvls[v0].u;
688         uv0.v = segp->sides[side].uvls[v0].v;
689
690         uv1.u = segp->sides[side].uvls[v1].u;
691         uv1.v = segp->sides[side].uvls[v1].v;
692
693         assign_uvs_to_side(segp, side, &uv0, &uv1, v0, v1);
694 }
695
696 // --------------------------------------------------------------------------------------------------------------
697 //      Assign default uvs to a segment.
698 void assign_default_uvs_to_segment(segment *segp)
699 {
700         int     s;
701
702         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
703                 assign_default_uvs_to_side(segp,s);
704                 assign_light_to_side(segp, s);
705         }
706 }
707
708
709 // -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
710 // -- mk021394 -- //    Find the face:poly:vertex index in base_seg:base_common_side which is segment relative vertex v1
711 // -- mk021394 -- //    This very specific routine is subsidiary to med_assign_uvs_to_side.
712 // -- mk021394 -- void get_face_and_vert(segment *base_seg, int base_common_side, int v1, int *ff, int *vv, int *pi)
713 // -- mk021394 -- {
714 // -- mk021394 --       int     p,f,v;
715 // -- mk021394 -- 
716 // -- mk021394 --       for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
717 // -- mk021394 --               face *fp = &base_seg->sides[base_common_side].faces[f];
718 // -- mk021394 --               for (p=0; p<fp->num_polys; p++) {
719 // -- mk021394 --                       poly *pp = &fp->polys[p];
720 // -- mk021394 --                       for (v=0; v<pp->num_vertices; v++)
721 // -- mk021394 --                               if (pp->verts[v] == v1) {
722 // -- mk021394 --                                       *ff = f;
723 // -- mk021394 --                                       *vv = v;
724 // -- mk021394 --                                       *pi = p;
725 // -- mk021394 --                                       return;
726 // -- mk021394 --                               }
727 // -- mk021394 --               }
728 // -- mk021394 --       }
729 // -- mk021394 -- 
730 // -- mk021394 --       Assert(0);      // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
731 // -- mk021394 -- }
732
733 // -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
734 // -- mk021394 -- //    Find the vertex index in base_seg:base_common_side which is segment relative vertex v1
735 // -- mk021394 -- //    This very specific routine is subsidiary to med_assign_uvs_to_side.
736 // -- mk021394 -- void get_side_vert(segment *base_seg,int base_common_side,int v1,int *vv)
737 // -- mk021394 -- {
738 // -- mk021394 --       int     p,f,v;
739 // -- mk021394 -- 
740 // -- mk021394 --       Assert((base_seg->sides[base_common_side].tri_edge == 0) || (base_seg->sides[base_common_side].tri_edge == 1));
741 // -- mk021394 --       Assert(base_seg->sides[base_common_side].num_faces <= 2);
742 // -- mk021394 -- 
743 // -- mk021394 --       for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
744 // -- mk021394 --               face *fp = &base_seg->sides[base_common_side].faces[f];
745 // -- mk021394 --               for (p=0; p<fp->num_polys; p++) {
746 // -- mk021394 --                       poly    *pp = &fp->polys[p];
747 // -- mk021394 --                       for (v=0; v<pp->num_vertices; v++)
748 // -- mk021394 --                               if (pp->verts[v] == v1) {
749 // -- mk021394 --                                       if (pp->num_vertices == 4) {
750 // -- mk021394 --                                               *vv = v;
751 // -- mk021394 --                                               return;
752 // -- mk021394 --                                       }
753 // -- mk021394 -- 
754 // -- 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
755 // -- mk021394 --                                               if ((f == 1) && (v > 0))
756 // -- mk021394 --                                                       v++;
757 // -- mk021394 --                                               *vv = v;
758 // -- mk021394 --                                               return;
759 // -- mk021394 --                                       } else {                                                                // triangulated 013, 123
760 // -- mk021394 --                                               if (f == 0) {
761 // -- mk021394 --                                                       if (v == 2)
762 // -- mk021394 --                                                               v++;
763 // -- mk021394 --                                               } else
764 // -- mk021394 --                                                       v++;
765 // -- mk021394 --                                               *vv = v;
766 // -- mk021394 --                                               return;
767 // -- mk021394 --                                       }
768 // -- mk021394 --                               }
769 // -- mk021394 --               }
770 // -- mk021394 --       }
771 // -- mk021394 -- 
772 // -- mk021394 --       Assert(0);      // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
773 // -- mk021394 -- }
774
775 //--rotate_uvs-- // --------------------------------------------------------------------------------------------------------------
776 //--rotate_uvs-- //     Rotate uvl coordinates uva, uvb about their center point by heading
777 //--rotate_uvs-- void rotate_uvs(uvl *uva, uvl *uvb, vms_vector *rvec)
778 //--rotate_uvs-- {
779 //--rotate_uvs--        uvl     uvc, uva1, uvb1;
780 //--rotate_uvs-- 
781 //--rotate_uvs--        uvc.u = (uva->u + uvb->u)/2;
782 //--rotate_uvs--        uvc.v = (uva->v + uvb->v)/2;
783 //--rotate_uvs-- 
784 //--rotate_uvs--        uva1.u = fixmul(uva->u - uvc.u, rvec->x) - fixmul(uva->v - uvc.v, rvec->z);
785 //--rotate_uvs--        uva1.v = fixmul(uva->u - uvc.u, rvec->z) + fixmul(uva->v - uvc.v, rvec->x);
786 //--rotate_uvs-- 
787 //--rotate_uvs--        uva->u = uva1.u + uvc.u;
788 //--rotate_uvs--        uva->v = uva1.v + uvc.v;
789 //--rotate_uvs-- 
790 //--rotate_uvs--        uvb1.u = fixmul(uvb->u - uvc.u, rvec->x) - fixmul(uvb->v - uvc.v, rvec->z);
791 //--rotate_uvs--        uvb1.v = fixmul(uvb->u - uvc.u, rvec->z) + fixmul(uvb->v - uvc.v, rvec->x);
792 //--rotate_uvs-- 
793 //--rotate_uvs--        uvb->u = uvb1.u + uvc.u;
794 //--rotate_uvs--        uvb->v = uvb1.v + uvc.v;
795 //--rotate_uvs-- }
796
797
798 // --------------------------------------------------------------------------------------------------------------
799 void med_assign_uvs_to_side(segment *con_seg, int con_common_side, segment *base_seg, int base_common_side, int abs_id1, int abs_id2)
800 {
801         uvl             uv1,uv2;
802         int             v,bv1,bv2, vv1, vv2;
803         int             cv1=0, cv2=0;
804
805         bv1 = -1;       bv2 = -1;
806
807         // Find which vertices in segment match abs_id1, abs_id2
808         for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
809                 if (base_seg->verts[v] == abs_id1)
810                         bv1 = v;
811                 if (base_seg->verts[v] == abs_id2)
812                         bv2 = v;
813                 if (con_seg->verts[v] == abs_id1)
814                         cv1 = v;
815                 if (con_seg->verts[v] == abs_id2)
816                         cv2 = v;
817         }
818
819         //      Now, bv1, bv2 are segment relative vertices in base segment which are the same as absolute vertices abs_id1, abs_id2
820         //           cv1, cv2 are segment relative vertices in conn segment which are the same as absolute vertices abs_id1, abs_id2
821
822         Assert((bv1 != -1) && (bv2 != -1) && (cv1 != -1) && (cv2 != -1));
823
824         //      Now, scan 4 vertices in base side and 4 vertices in connected side.
825         //      Set uv1, uv2 to uv coordinates from base side which correspond to vertices bv1, bv2.
826         //      Set vv1, vv2 to relative vertex ids (in 0..3) in connecting side which correspond to cv1, cv2
827         vv1 = -1;       vv2 = -1;
828         for (v=0; v<4; v++) {
829                 if (bv1 == Side_to_verts[base_common_side][v])
830                         uv1 = base_seg->sides[base_common_side].uvls[v];
831
832                 if (bv2 == Side_to_verts[base_common_side][v])
833                         uv2 = base_seg->sides[base_common_side].uvls[v];
834
835                 if (cv1 == Side_to_verts[con_common_side][v])
836                         vv1 = v;
837
838                 if (cv2 == Side_to_verts[con_common_side][v])
839                         vv2 = v;
840         }
841
842         Assert((uv1.u != uv2.u) || (uv1.v != uv2.v));
843         Assert( (vv1 != -1) && (vv2 != -1) );
844         assign_uvs_to_side(con_seg, con_common_side, &uv1, &uv2, vv1, vv2);
845 }
846
847
848 // -----------------------------------------------------------------------------
849 //      Given a base and a connecting segment, a side on each of those segments and two global vertex ids,
850 //      determine which side in each of the segments shares those two vertices.
851 //      This is used to propagate a texture map id to a connecting segment in an expected and desired way.
852 //      Since we can attach any side of a segment to any side of another segment, and do so in each case in
853 //      four different rotations (for a total of 6*6*4 = 144 ways), not having this nifty function will cause
854 //      great confusion.
855 void get_side_ids(segment *base_seg, segment *con_seg, int base_side, int con_side, int abs_id1, int abs_id2, int *base_common_side, int *con_common_side)
856 {
857         sbyte   *base_vp,*con_vp;
858         int             v0,side;
859
860         *base_common_side = -1;
861
862         //      Find side in base segment which contains the two global vertex ids.
863         for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
864                 if (side != base_side) {
865                         base_vp = Side_to_verts[side];
866                         for (v0=0; v0<4; v0++)
867                                 if (((base_seg->verts[(int) base_vp[v0]] == abs_id1) && (base_seg->verts[(int) base_vp[(v0+1) % 4]] == abs_id2)) || ((base_seg->verts[(int) base_vp[v0]] == abs_id2) && (base_seg->verts[(int)base_vp[ (v0+1) % 4]] == abs_id1))) {
868                                         Assert(*base_common_side == -1);                // This means two different sides shared the same edge with base_side == impossible!
869                                         *base_common_side = side;
870                                 }
871                 }
872         }
873
874         // Note: For connecting segment, process vertices in reversed order.
875         *con_common_side = -1;
876
877         //      Find side in connecting segment which contains the two global vertex ids.
878         for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
879                 if (side != con_side) {
880                         con_vp = Side_to_verts[side];
881                         for (v0=0; v0<4; v0++)
882                                 if (((con_seg->verts[(int) con_vp[(v0 + 1) % 4]] == abs_id1) && (con_seg->verts[(int) con_vp[v0]] == abs_id2)) || ((con_seg->verts[(int) con_vp[(v0 + 1) % 4]] == abs_id2) && (con_seg->verts[(int) con_vp[v0]] == abs_id1))) {
883                                         Assert(*con_common_side == -1);         // This means two different sides shared the same edge with con_side == impossible!
884                                         *con_common_side = side;
885                                 }
886                 }
887         }
888
889 // mprintf((0,"side %3i adjacent to side %3i\n",*base_common_side,*con_common_side));
890
891         Assert((*base_common_side != -1) && (*con_common_side != -1));
892 }
893
894 // -----------------------------------------------------------------------------
895 //      Propagate texture map u,v coordinates from base_seg:base_side to con_seg:con_side.
896 //      The two vertices abs_id1 and abs_id2 are the only two vertices common to the two sides.
897 //      If uv_only_flag is 1, then don't assign texture map ids, only update the uv coordinates
898 //      If uv_only_flag is -1, then ONLY assign texture map ids, don't update the uv coordinates
899 void propagate_tmaps_to_segment_side(segment *base_seg, int base_side, segment *con_seg, int con_side, int abs_id1, int abs_id2, int uv_only_flag)
900 {
901         int             base_common_side,con_common_side;
902         int             tmap_num;
903
904         Assert ((uv_only_flag == -1) || (uv_only_flag == 0) || (uv_only_flag == 1));
905
906         // Set base_common_side = side in base_seg which contains edge abs_id1:abs_id2
907         // Set con_common_side = side in con_seg which contains edge abs_id1:abs_id2
908         if (base_seg != con_seg)
909                 get_side_ids(base_seg, con_seg, base_side, con_side, abs_id1, abs_id2, &base_common_side, &con_common_side);
910         else {
911                 base_common_side = base_side;
912                 con_common_side = con_side;
913         }
914
915         // Now, all faces in con_seg which are on side con_common_side get their tmap_num set to whatever tmap is assigned
916         // to whatever face I find which is on side base_common_side.
917         // First, find tmap_num for base_common_side.  If it doesn't exist (ie, there is a connection there), look at the segment
918         // that is connected through it.
919         if (!IS_CHILD(con_seg->children[con_common_side])) {
920                 if (!IS_CHILD(base_seg->children[base_common_side])) {
921                         // There is at least one face here, so get the tmap_num from there.
922                         tmap_num = base_seg->sides[base_common_side].tmap_num;
923
924                         // Now assign all faces in the connecting segment on side con_common_side to tmap_num.
925                         if ((uv_only_flag == -1) || (uv_only_flag == 0))
926                                 con_seg->sides[con_common_side].tmap_num = tmap_num;
927
928                         if (uv_only_flag != -1)
929                                 med_assign_uvs_to_side(con_seg, con_common_side, base_seg, base_common_side, abs_id1, abs_id2);
930
931                 } else {                        // There are no faces here, there is a connection, trace through the connection.
932                         int     cside;
933
934                         cside = find_connect_side(base_seg, &Segments[base_seg->children[base_common_side]]);
935                         propagate_tmaps_to_segment_side(&Segments[base_seg->children[base_common_side]], cside, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
936                 }
937         }
938
939 }
940
941 sbyte   Edge_between_sides[MAX_SIDES_PER_SEGMENT][MAX_SIDES_PER_SEGMENT][2] = {
942 //              left            top             right           bottom  back            front
943         { {-1,-1}, { 3, 7}, {-1,-1}, { 2, 6}, { 6, 7}, { 2, 3} },       // left
944         { { 3, 7}, {-1,-1}, { 0, 4}, {-1,-1}, { 4, 7}, { 0, 3} },       // top
945         { {-1,-1}, { 0, 4}, {-1,-1}, { 1, 5}, { 4, 5}, { 0, 1} },       // right
946         { { 2, 6}, {-1,-1}, { 1, 5}, {-1,-1}, { 5, 6}, { 1, 2} },       // bottom
947         { { 6, 7}, { 4, 7}, { 4, 5}, { 5, 6}, {-1,-1}, {-1,-1} },       // back
948         { { 2, 3}, { 0, 3}, { 0, 1}, { 1, 2}, {-1,-1}, {-1,-1} }};      // front
949
950 // -----------------------------------------------------------------------------
951 //      Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side
952 //      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.
953 void med_propagate_tmaps_to_back_side(segment *base_seg, int back_side, int uv_only_flag)
954 {
955         int     v1=0,v2=0;
956         int     s,ss,tmap_num,back_side_tmap;
957
958         if (IS_CHILD(base_seg->children[back_side]))
959                 return;         // connection, so no sides here.
960
961         //      Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side]
962         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
963                 if ((s != back_side) && (s != Side_opposite[back_side])) {
964                         v1 = Edge_between_sides[s][back_side][0];
965                         v2 = Edge_between_sides[s][back_side][1];
966                         goto found1;
967                 }
968         Assert(0);              // Error -- couldn't find edge != back_side and Side_opposite[back_side]
969 found1: ;
970         Assert( (v1 != -1) && (v2 != -1));              // This means there was no shared edge between the two sides.
971
972         propagate_tmaps_to_segment_side(base_seg, s, base_seg, back_side, base_seg->verts[v1], base_seg->verts[v2], uv_only_flag);
973
974         //      Assign an unused tmap id to the back side.
975         //      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
976         //      both do attaches).
977         //      First see if tmap on back side is anywhere else.
978         if (!uv_only_flag) {
979                 back_side_tmap = base_seg->sides[back_side].tmap_num;
980                 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
981                         if (s != back_side)
982                                 if (base_seg->sides[s].tmap_num == back_side_tmap) {
983                                         for (tmap_num=0; tmap_num < MAX_SIDES_PER_SEGMENT; tmap_num++) {
984                                                 for (ss=0; ss<MAX_SIDES_PER_SEGMENT; ss++)
985                                                         if (ss != back_side)
986                                                                 if (base_seg->sides[ss].tmap_num == New_segment.sides[tmap_num].tmap_num)
987                                                                         goto found2;            // current texture map (tmap_num) is used on current (ss) side, so try next one
988                                                 // Current texture map (tmap_num) has not been used, assign to all faces on back_side.
989                                                 base_seg->sides[back_side].tmap_num = New_segment.sides[tmap_num].tmap_num;
990                                                 goto done1;
991                                         found2: ;
992                                         }
993                                 }
994                 }
995         done1: ;
996         }
997
998 }
999
1000 int fix_bogus_uvs_on_side(void)
1001 {
1002         med_propagate_tmaps_to_back_side(Cursegp, Curside, 1);
1003         return 0;
1004 }
1005
1006 void fix_bogus_uvs_on_side1(segment *sp, int sidenum, int uvonly_flag)
1007 {
1008         side    *sidep = &sp->sides[sidenum];
1009
1010         if ((sidep->uvls[0].u == 0) && (sidep->uvls[1].u == 0) && (sidep->uvls[2].u == 0)) {
1011                 mprintf((0,"Found bogus segment %i, side %i\n", sp-Segments, sidenum));
1012                 med_propagate_tmaps_to_back_side(sp, sidenum, uvonly_flag);
1013         }
1014 }
1015
1016 void fix_bogus_uvs_seg(segment *segp)
1017 {
1018         int     s;
1019
1020         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1021                 if (!IS_CHILD(segp->children[s]))
1022                         fix_bogus_uvs_on_side1(segp, s, 1);
1023         }
1024 }
1025
1026 int fix_bogus_uvs_all(void)
1027 {
1028         int     seg;
1029
1030         for (seg=0; seg<=Highest_segment_index; seg++)
1031                 if (Segments[seg].segnum != -1)
1032                         fix_bogus_uvs_seg(&Segments[seg]);
1033         return 0;
1034 }
1035
1036 // -----------------------------------------------------------------------------
1037 //      Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side
1038 //      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.
1039 void med_propagate_tmaps_to_any_side(segment *base_seg, int back_side, int tmap_num, int uv_only_flag)
1040 {
1041         int     v1=0,v2=0;
1042         int     s;
1043
1044         //      Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side]
1045         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1046                 if ((s != back_side) && (s != Side_opposite[back_side])) {
1047                         v1 = Edge_between_sides[s][back_side][0];
1048                         v2 = Edge_between_sides[s][back_side][1];
1049                         goto found1;
1050                 }
1051         Assert(0);              // Error -- couldn't find edge != back_side and Side_opposite[back_side]
1052 found1: ;
1053         Assert( (v1 != -1) && (v2 != -1));              // This means there was no shared edge between the two sides.
1054
1055         propagate_tmaps_to_segment_side(base_seg, s, base_seg, back_side, base_seg->verts[v1], base_seg->verts[v2], uv_only_flag);
1056
1057         base_seg->sides[back_side].tmap_num = tmap_num;
1058
1059 }
1060
1061 // -----------------------------------------------------------------------------
1062 //      Segment base_seg is connected through side base_side to segment con_seg on con_side.
1063 //      For all walls in con_seg, find the wall in base_seg which shares an edge.  Copy tmap_num
1064 //      from that side in base_seg to the wall in con_seg.  If the wall in base_seg is not present
1065 //      (ie, there is another segment connected through it), follow the connection through that
1066 //      segment to get the wall in the connected segment which shares the edge, and get tmap_num from there.
1067 void propagate_tmaps_to_segment_sides(segment *base_seg, int base_side, segment *con_seg, int con_side, int uv_only_flag)
1068 {
1069         sbyte           *base_vp,*con_vp;
1070         short           abs_id1,abs_id2;
1071         int             v;
1072
1073         base_vp = Side_to_verts[base_side];
1074         con_vp = Side_to_verts[con_side];
1075
1076         // Do for each edge on connecting face.
1077         for (v=0; v<4; v++) {
1078                 abs_id1 = base_seg->verts[(int) base_vp[v]];
1079                 abs_id2 = base_seg->verts[(int) base_vp[(v+1) % 4]];
1080                 propagate_tmaps_to_segment_side(base_seg, base_side, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
1081         }
1082
1083 }
1084
1085 // -----------------------------------------------------------------------------
1086 //      Propagate texture maps in base_seg to con_seg.
1087 //      For each wall in con_seg, find the wall in base_seg which shared an edge.  Copy tmap_num from that
1088 //      wall in base_seg to the wall in con_seg.  If the wall in base_seg is not present, then look at the
1089 //      segment connected through base_seg through the wall.  The wall with a common edge is the new wall
1090 //      of interest.  Continue searching in this way until a wall of interest is present.
1091 void med_propagate_tmaps_to_segments(segment *base_seg,segment *con_seg, int uv_only_flag)
1092 {
1093         int             s;
1094
1095 // mprintf((0,"Propagating segments from %i to %i\n",base_seg-Segments,con_seg-Segments));
1096         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1097                 if (base_seg->children[s] == con_seg-Segments)
1098                         propagate_tmaps_to_segment_sides(base_seg, s, con_seg, find_connect_side(base_seg, con_seg), uv_only_flag);
1099
1100         s2s2(con_seg)->static_light = s2s2(base_seg)->static_light;
1101
1102         validate_uv_coordinates(con_seg);
1103 }
1104
1105
1106 // -------------------------------------------------------------------------------
1107 //      Copy texture map uvs from srcseg to destseg.
1108 //      If two segments have different face structure (eg, destseg has two faces on side 3, srcseg has only 1)
1109 //      then assign uvs according to side vertex id, not face vertex id.
1110 void copy_uvs_seg_to_seg(segment *destseg,segment *srcseg)
1111 {
1112         int     s;
1113
1114         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1115                 destseg->sides[s].tmap_num = srcseg->sides[s].tmap_num;
1116                 destseg->sides[s].tmap_num2 = srcseg->sides[s].tmap_num2;
1117         }
1118
1119         s2s2(destseg)->static_light = s2s2(srcseg)->static_light;
1120 }
1121
1122 //      _________________________________________________________________________________________________________________________
1123 //      Maximum distance between a segment containing light to a segment to receive light.
1124 #define LIGHT_DISTANCE_THRESHOLD        (F1_0*80)
1125 fix     Magical_light_constant = (F1_0*16);
1126
1127 // int  Seg0, Seg1;
1128
1129 //int   Bugseg = 27;
1130
1131 typedef struct {
1132         sbyte                   flag, hit_type;
1133         vms_vector      vector;
1134 } hash_info;
1135
1136 #define FVI_HASH_SIZE 8
1137 #define FVI_HASH_AND_MASK (FVI_HASH_SIZE - 1)
1138
1139 //      Note: This should be malloced.
1140 //                      Also, the vector should not be 12 bytes, you should only care about some smaller portion of it.
1141 hash_info       fvi_cache[FVI_HASH_SIZE];
1142 int     Hash_hits=0, Hash_retries=0, Hash_calcs=0;
1143
1144 //      -----------------------------------------------------------------------------------------
1145 //      Set light from a light source.
1146 //      Light incident on a surface is defined by the light incident at its points.
1147 //      Light at a point = K * (V . N) / d
1148 //      where:
1149 //              K = some magical constant to make everything look good
1150 //              V = normalized vector from light source to point
1151 //              N = surface normal at point
1152 //              d = distance from light source to point
1153 //      (Note that the above equation can be simplified to K * (VV . N) / d^2 where VV = non-normalized V)
1154 //      Light intensity emitted from a light source is defined to be cast from four points.
1155 //      These four points are 1/64 of the way from the corners of the light source to the center
1156 //      of its segment.  By assuming light is cast from these points, rather than from on the
1157 //      light surface itself, light will be properly cast on the light surface.  Otherwise, the
1158 //      vector V would be the null vector.
1159 //      If quick_light set, then don't use find_vector_intersection
1160 void cast_light_from_side(segment *segp, int light_side, fix light_intensity, int quick_light)
1161 {
1162         vms_vector      segment_center;
1163         int                     segnum,sidenum,vertnum, lightnum;
1164
1165         compute_segment_center(&segment_center, segp);
1166
1167 //mprintf((0, "From [%i %i %7.3f]:  ", segp-Segments, light_side, f2fl(light_intensity)));
1168
1169         //      Do for four lights, one just inside each corner of side containing light.
1170         for (lightnum=0; lightnum<4; lightnum++) {
1171                 int                     light_vertex_num, i;
1172                 vms_vector      vector_to_center;
1173                 vms_vector      light_location;
1174                 // fix                  inverse_segment_magnitude;
1175
1176                 light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]];
1177                 light_location = Vertices[light_vertex_num];
1178
1179
1180         //      New way, 5/8/95: Move towards center irrespective of size of segment.
1181         vm_vec_sub(&vector_to_center, &segment_center, &light_location);
1182         vm_vec_normalize_quick(&vector_to_center);
1183         vm_vec_add2(&light_location, &vector_to_center);
1184
1185 // -- Old way, before 5/8/95 --         // -- This way was kind of dumb.  In larger segments, you move LESS towards the center.
1186 // -- 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.
1187 // -- Old way, before 5/8/95 --         vm_vec_sub(&vector_to_center, &segment_center, &light_location);
1188 // -- Old way, before 5/8/95 --         inverse_segment_magnitude = fixdiv(F1_0/5, vm_vec_mag(&vector_to_center));
1189 // -- Old way, before 5/8/95 --         vm_vec_scale_add(&light_location, &light_location, &vector_to_center, inverse_segment_magnitude);
1190
1191                 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1192                         segment         *rsegp = &Segments[segnum];
1193                         vms_vector      r_segment_center;
1194                         fix                     dist_to_rseg;
1195
1196                         for (i=0; i<FVI_HASH_SIZE; i++)
1197                                 fvi_cache[i].flag = 0;
1198
1199                         //      efficiency hack (I hope!), for faraway segments, don't check each point.
1200                         compute_segment_center(&r_segment_center, rsegp);
1201                         dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center);
1202
1203                         if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
1204                                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1205                                         if (WALL_IS_DOORWAY(rsegp, sidenum) != WID_NO_WALL) {
1206                                                 side                    *rsidep = &rsegp->sides[sidenum];
1207                                                 vms_vector      *side_normalp = &rsidep->normals[0];    //      kinda stupid? always use vector 0.
1208
1209 //mprintf((0, "[%i %i], ", rsegp-Segments, sidenum));
1210                                                 for (vertnum=0; vertnum<4; vertnum++) {
1211                                                         fix                     distance_to_point, light_at_point, light_dot;
1212                                                         vms_vector      vert_location, vector_to_light;
1213                                                         int                     abs_vertnum;
1214
1215                                                         abs_vertnum = rsegp->verts[Side_to_verts[sidenum][vertnum]];
1216                                                         vert_location = Vertices[abs_vertnum];
1217                                                         distance_to_point = vm_vec_dist_quick(&vert_location, &light_location);
1218                                                         vm_vec_sub(&vector_to_light, &light_location, &vert_location);
1219                                                         vm_vec_normalize(&vector_to_light);
1220
1221                                                         //      Hack: In oblong segments, it's possible to get a very small dot product
1222                                                         //      but the light source is very nearby (eg, illuminating light itself!).
1223                                                         light_dot = vm_vec_dot(&vector_to_light, side_normalp);
1224                                                         if (distance_to_point < F1_0)
1225                                                                 if (light_dot > 0)
1226                                                                         light_dot = (light_dot + F1_0)/2;
1227
1228                                                         if (light_dot > 0) {
1229                                                                 light_at_point = fixdiv(fixmul(light_dot, light_dot), distance_to_point);
1230                                                                 light_at_point = fixmul(light_at_point, Magical_light_constant);
1231                                                                 if (light_at_point >= 0) {
1232                                                                         fvi_info        hit_data;
1233                                                                         int             hit_type;
1234                                                                         vms_vector      vert_location_1, r_vector_to_center;
1235                                                                         fix             inverse_segment_magnitude;
1236
1237                                                                         vm_vec_sub(&r_vector_to_center, &r_segment_center, &vert_location);
1238                                                                         inverse_segment_magnitude = fixdiv(F1_0/3, vm_vec_mag(&r_vector_to_center));
1239                                                                         vm_vec_scale_add(&vert_location_1, &vert_location, &r_vector_to_center, inverse_segment_magnitude);
1240                                                                         vert_location = vert_location_1;
1241
1242 //if ((segp-Segments == 199) && (rsegp-Segments==199))
1243 //      Int3();
1244 // Seg0 = segp-Segments;
1245 // Seg1 = rsegp-Segments;
1246                                                                         if (!quick_light) {
1247                                                                                 int hash_value = Side_to_verts[sidenum][vertnum];
1248                                                                                 hash_info       *hashp = &fvi_cache[hash_value];
1249                                                                                 while (1) {
1250                                                                                         if (hashp->flag) {
1251                                                                                                 if ((hashp->vector.x == vector_to_light.x) && (hashp->vector.y == vector_to_light.y) && (hashp->vector.z == vector_to_light.z)) {
1252 //mprintf((0, "{CACHE %4x} ", hash_value));
1253                                                                                                         hit_type = hashp->hit_type;
1254                                                                                                         Hash_hits++;
1255                                                                                                         break;
1256                                                                                                 } else {
1257                                                                                                         Int3(); // How is this possible?  Should be no hits!
1258                                                                                                         Hash_retries++;
1259                                                                                                         hash_value = (hash_value+1) & FVI_HASH_AND_MASK;
1260                                                                                                         hashp = &fvi_cache[hash_value];
1261                                                                                                 }
1262                                                                                         } else {
1263 //mprintf((0, "\nH:%04x ", hash_value));
1264                                                                                                 fvi_query fq;
1265
1266                                                                                                 Hash_calcs++;
1267                                                                                                 hashp->vector = vector_to_light;
1268                                                                                                 hashp->flag = 1;
1269
1270                                                                                                 fq.p0                                           = &light_location;
1271                                                                                                 fq.startseg                             = segp-Segments;
1272                                                                                                 fq.p1                                           = &vert_location;
1273                                                                                                 fq.rad                                  = 0;
1274                                                                                                 fq.thisobjnum                   = -1;
1275                                                                                                 fq.ignore_obj_list      = NULL;
1276                                                                                                 fq.flags                                        = 0;
1277
1278                                                                                                 hit_type = find_vector_intersection(&fq,&hit_data);
1279                                                                                                 hashp->hit_type = hit_type;
1280                                                                                                 break;
1281                                                                                         }
1282                                                                                 }
1283                                                                         } else
1284                                                                                 hit_type = HIT_NONE;
1285 //mprintf((0, "hit=%i ", hit_type));
1286                                                                         switch (hit_type) {
1287                                                                                 case HIT_NONE:
1288                                                                                         light_at_point = fixmul(light_at_point, light_intensity);
1289                                                                                         rsidep->uvls[vertnum].l += light_at_point;
1290 //mprintf((0, "(%5.2f) ", f2fl(light_at_point)));
1291                                                                                         if (rsidep->uvls[vertnum].l > F1_0)
1292                                                                                                 rsidep->uvls[vertnum].l = F1_0;
1293                                                                                         break;
1294                                                                                 case HIT_WALL:
1295                                                                                         break;
1296                                                                                 case HIT_OBJECT:
1297                                                                                         Int3(); // Hit object, should be ignoring objects!
1298                                                                                         break;
1299                                                                                 case HIT_BAD_P0:
1300                                                                                         Int3(); //      Ugh, this thing again, what happened, what does it mean?
1301                                                                                         break;
1302                                                                         }
1303                                                                 }       //      end if (light_at_point...
1304                                                         }       // end if (light_dot >...
1305                                                 }       //      end for (vertnum=0...
1306                                         }       //      end if (rsegp...
1307                                 }       //      end for (sidenum=0...
1308                         }       //      end if (dist_to_rseg...
1309
1310                 }       //      end for (segnum=0...
1311
1312         }       //      end for (lightnum=0...
1313
1314 //mprintf((0, "\n"));
1315 }
1316
1317
1318 //      ------------------------------------------------------------------------------------------
1319 //      Zero all lighting values.
1320 void calim_zero_light_values(void)
1321 {
1322         int     segnum, sidenum, vertnum;
1323
1324         for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1325                 segment *segp = &Segments[segnum];
1326                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1327                         side    *sidep = &segp->sides[sidenum];
1328                         for (vertnum=0; vertnum<4; vertnum++)
1329                                 sidep->uvls[vertnum].l = F1_0/64;       // Put a tiny bit of light here.
1330                 }
1331                 Segment2s[segnum].static_light = F1_0 / 64;
1332         }
1333 }
1334
1335
1336 //      ------------------------------------------------------------------------------------------
1337 //      Used in setting average light value in a segment, cast light from a side to the center
1338 //      of all segments.
1339 void cast_light_from_side_to_center(segment *segp, int light_side, fix light_intensity, int quick_light)
1340 {
1341         vms_vector      segment_center;
1342         int                     segnum, lightnum;
1343
1344         compute_segment_center(&segment_center, segp);
1345
1346         //      Do for four lights, one just inside each corner of side containing light.
1347         for (lightnum=0; lightnum<4; lightnum++) {
1348                 int                     light_vertex_num;
1349                 vms_vector      vector_to_center;
1350                 vms_vector      light_location;
1351
1352                 light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]];
1353                 light_location = Vertices[light_vertex_num];
1354                 vm_vec_sub(&vector_to_center, &segment_center, &light_location);
1355                 vm_vec_scale_add(&light_location, &light_location, &vector_to_center, F1_0/64);
1356
1357                 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1358                         segment         *rsegp = &Segments[segnum];
1359                         vms_vector      r_segment_center;
1360                         fix                     dist_to_rseg;
1361 //if ((segp == &Segments[Bugseg]) && (rsegp == &Segments[Bugseg]))
1362 //      Int3();
1363                         compute_segment_center(&r_segment_center, rsegp);
1364                         dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center);
1365
1366                         if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
1367                                 fix     light_at_point;
1368                                 if (dist_to_rseg > F1_0)
1369                                         light_at_point = fixdiv(Magical_light_constant, dist_to_rseg);
1370                                 else
1371                                         light_at_point = Magical_light_constant;
1372
1373                                 if (light_at_point >= 0) {
1374                                         int             hit_type;
1375
1376                                         if (!quick_light) {
1377                                                 fvi_query fq;
1378                                                 fvi_info        hit_data;
1379
1380                                                 fq.p0                                           = &light_location;
1381                                                 fq.startseg                             = segp-Segments;
1382                                                 fq.p1                                           = &r_segment_center;
1383                                                 fq.rad                                  = 0;
1384                                                 fq.thisobjnum                   = -1;
1385                                                 fq.ignore_obj_list      = NULL;
1386                                                 fq.flags                                        = 0;
1387
1388                                                 hit_type = find_vector_intersection(&fq,&hit_data);
1389                                         }
1390                                         else
1391                                                 hit_type = HIT_NONE;
1392
1393                                         switch (hit_type) {
1394                                                 case HIT_NONE:
1395                                                         light_at_point = fixmul(light_at_point, light_intensity);
1396                                                         if (light_at_point >= F1_0)
1397                                                                 light_at_point = F1_0-1;
1398                                                         s2s2(rsegp)->static_light += light_at_point;
1399                                                         if (s2s2(segp)->static_light < 0)       // if it went negative, saturate
1400                                                                 s2s2(segp)->static_light = 0;
1401                                                         break;
1402                                                 case HIT_WALL:
1403                                                         break;
1404                                                 case HIT_OBJECT:
1405                                                         Int3(); // Hit object, should be ignoring objects!
1406                                                         break;
1407                                                 case HIT_BAD_P0:
1408                                                         Int3(); //      Ugh, this thing again, what happened, what does it mean?
1409                                                         break;
1410                                         }
1411                                 }       //      end if (light_at_point...
1412                         }       //      end if (dist_to_rseg...
1413
1414                 }       //      end for (segnum=0...
1415
1416         }       //      end for (lightnum=0...
1417
1418 }
1419
1420 //      ------------------------------------------------------------------------------------------
1421 //      Process all lights.
1422 void calim_process_all_lights(int quick_light)
1423 {
1424         int     segnum, sidenum;
1425
1426         for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1427                 segment *segp = &Segments[segnum];
1428                 mprintf((0, "."));
1429                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1430                         // if (!IS_CHILD(segp->children[sidenum])) {
1431                         if (WALL_IS_DOORWAY(segp, sidenum) != WID_NO_WALL) {
1432                                 side    *sidep = &segp->sides[sidenum];
1433                                 fix     light_intensity;
1434
1435                                 light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting;
1436
1437 //                              if (segp->sides[sidenum].wall_num != -1) {
1438 //                                      int     wall_num, bitmap_num, effect_num;
1439 //                                      wall_num = segp->sides[sidenum].wall_num;
1440 //                                      effect_num = Walls[wall_num].type;
1441 //                                      bitmap_num = effects_bm_num[effect_num];
1442 //
1443 //                                      light_intensity += TmapInfo[bitmap_num].lighting;
1444 //                              }
1445
1446                                 if (light_intensity) {
1447                                         light_intensity /= 4;                   // casting light from four spots, so divide by 4.
1448                                         cast_light_from_side(segp, sidenum, light_intensity, quick_light);
1449                                         cast_light_from_side_to_center(segp, sidenum, light_intensity, quick_light);
1450                                 }
1451                         }
1452                 }
1453         }
1454 }
1455
1456 //      ------------------------------------------------------------------------------------------
1457 //      Apply static light in mine.
1458 //      First, zero all light values.
1459 //      Then, for all light sources, cast their light.
1460 void cast_all_light_in_mine(int quick_flag)
1461 {
1462
1463         validate_segment_all();
1464
1465         calim_zero_light_values();
1466
1467         calim_process_all_lights(quick_flag);
1468
1469 }
1470
1471 // int  Fvit_num = 1000;
1472 // 
1473 // fix find_vector_intersection_test(void)
1474 // {
1475 //      int             i;
1476 //      fvi_info        hit_data;
1477 //      int             p0_seg, p1_seg, this_objnum, ignore_obj, check_obj_flag;
1478 //      fix             rad;
1479 //      int             start_time = timer_get_milliseconds();;
1480 //      vms_vector      p0,p1;
1481 // 
1482 //      ignore_obj = 1;
1483 //      check_obj_flag = 0;
1484 //      this_objnum = -1;
1485 //      rad = F1_0/4;
1486 // 
1487 //      for (i=0; i<Fvit_num; i++) {
1488 //              p0_seg = d_rand()*(Highest_segment_index+1)/32768;
1489 //              compute_segment_center(&p0, &Segments[p0_seg]);
1490 // 
1491 //              p1_seg = d_rand()*(Highest_segment_index+1)/32768;
1492 //              compute_segment_center(&p1, &Segments[p1_seg]);
1493 // 
1494 //              find_vector_intersection(&hit_data, &p0, p0_seg, &p1, rad, this_objnum, ignore_obj, check_obj_flag);
1495 //      }
1496 // 
1497 //      return timer_get_milliseconds() - start_time;
1498 // }
1499
1500 vms_vector      Normals[MAX_SEGMENTS*12];
1501
1502 int     Normal_nearness = 4;
1503
1504 int normal_near(vms_vector *v1, vms_vector *v2)
1505 {
1506         if (abs(v1->x - v2->x) < Normal_nearness)
1507                 if (abs(v1->y - v2->y) < Normal_nearness)
1508                         if (abs(v1->z - v2->z) < Normal_nearness)
1509                                 return 1;
1510         return 0;
1511 }
1512
1513 int     Total_normals=0;
1514 int     Diff_normals=0;
1515
1516 void print_normals(void)
1517 {
1518         int                     i,j,s,n,nn;
1519         // vms_vector   *normal;
1520         int                     num_normals=0;
1521
1522         Total_normals = 0;
1523         Diff_normals = 0;
1524
1525         for (i=0; i<=Highest_segment_index; i++)
1526                 for (s=0; s<6; s++) {
1527                         if (Segments[i].sides[s].type == SIDE_IS_QUAD)
1528                                 nn=1;
1529                         else
1530                                 nn=2;
1531                         for (n=0; n<nn; n++) {
1532                                 for (j=0; j<num_normals; j++)
1533                                         if (normal_near(&Segments[i].sides[s].normals[n],&Normals[j]))
1534                                                 break;
1535                                 if (j == num_normals) {
1536                                         Normals[num_normals++] = Segments[i].sides[s].normals[n];
1537                                         Diff_normals++;
1538                                 }
1539                                 Total_normals++;
1540                         }
1541                 }
1542
1543 }
1544